Full Code of LemmyNet/lemmy for AI

main 51254f3c169b cached
1431 files
3.9 MB
1.1M tokens
4492 symbols
1 requests
Download .txt
Showing preview only (4,361K chars total). Download the full file or copy to clipboard to get everything.
Repository: LemmyNet/lemmy
Branch: main
Commit: 51254f3c169b
Files: 1431
Total size: 3.9 MB

Directory structure:
gitextract__t6y25uc/

├── .gitattributes
├── .github/
│   ├── CODEOWNERS
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── BUG_REPORT.yml
│   │   ├── FEATURE_REQUEST.yml
│   │   └── QUESTION.yml
│   └── SECURITY.md
├── .gitignore
├── .gitmodules
├── .rustfmt.toml
├── .woodpecker.yml
├── Cargo.toml
├── LICENSE
├── README.md
├── api_tests/
│   ├── .npmrc
│   ├── .prettierrc.json
│   ├── eslint.config.mjs
│   ├── jest.config.js
│   ├── package.json
│   ├── pnpm-workspace.yaml
│   ├── prepare-drone-federation-test.sh
│   ├── run-federation-test.sh
│   ├── src/
│   │   ├── apiv3.spec.ts
│   │   ├── comment.spec.ts
│   │   ├── community.spec.ts
│   │   ├── follow.spec.ts
│   │   ├── image.spec.ts
│   │   ├── post.spec.ts
│   │   ├── private_comm.spec.ts
│   │   ├── private_message.spec.ts
│   │   ├── shared.ts
│   │   ├── speed.spec.ts
│   │   ├── tags.spec.ts
│   │   └── user.spec.ts
│   └── tsconfig.json
├── cliff.toml
├── config/
│   ├── config.hjson
│   └── defaults.hjson
├── crates/
│   ├── api/
│   │   ├── api/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── comment/
│   │   │       │   ├── distinguish.rs
│   │   │       │   ├── like.rs
│   │   │       │   ├── list_comment_likes.rs
│   │   │       │   ├── lock.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── save.rs
│   │   │       │   └── warning.rs
│   │   │       ├── community/
│   │   │       │   ├── add_mod.rs
│   │   │       │   ├── ban.rs
│   │   │       │   ├── block.rs
│   │   │       │   ├── follow.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── multi_community_follow.rs
│   │   │       │   ├── pending_follows/
│   │   │       │   │   ├── approve.rs
│   │   │       │   │   ├── list.rs
│   │   │       │   │   └── mod.rs
│   │   │       │   ├── random.rs
│   │   │       │   ├── tag.rs
│   │   │       │   ├── transfer.rs
│   │   │       │   └── update_notifications.rs
│   │   │       ├── federation/
│   │   │       │   ├── fetcher.rs
│   │   │       │   ├── list_comments.rs
│   │   │       │   ├── list_person_content.rs
│   │   │       │   ├── list_posts.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── read_community.rs
│   │   │       │   ├── read_multi_community.rs
│   │   │       │   ├── read_person.rs
│   │   │       │   ├── resolve_object.rs
│   │   │       │   ├── search.rs
│   │   │       │   └── user_settings_backup.rs
│   │   │       ├── lib.rs
│   │   │       ├── local_user/
│   │   │       │   ├── add_admin.rs
│   │   │       │   ├── ban_person.rs
│   │   │       │   ├── block.rs
│   │   │       │   ├── change_password.rs
│   │   │       │   ├── change_password_after_reset.rs
│   │   │       │   ├── donation_dialog_shown.rs
│   │   │       │   ├── export_data.rs
│   │   │       │   ├── generate_totp_secret.rs
│   │   │       │   ├── get_captcha.rs
│   │   │       │   ├── list_hidden.rs
│   │   │       │   ├── list_liked.rs
│   │   │       │   ├── list_logins.rs
│   │   │       │   ├── list_media.rs
│   │   │       │   ├── list_read.rs
│   │   │       │   ├── list_saved.rs
│   │   │       │   ├── login.rs
│   │   │       │   ├── logout.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── note_person.rs
│   │   │       │   ├── notifications/
│   │   │       │   │   ├── list.rs
│   │   │       │   │   ├── mark_all_read.rs
│   │   │       │   │   ├── mark_notification_read.rs
│   │   │       │   │   └── mod.rs
│   │   │       │   ├── resend_verification_email.rs
│   │   │       │   ├── reset_password.rs
│   │   │       │   ├── save_settings.rs
│   │   │       │   ├── unread_counts.rs
│   │   │       │   ├── update_totp.rs
│   │   │       │   ├── user_block_instance.rs
│   │   │       │   ├── validate_auth.rs
│   │   │       │   └── verify_email.rs
│   │   │       ├── post/
│   │   │       │   ├── feature.rs
│   │   │       │   ├── get_link_metadata.rs
│   │   │       │   ├── hide.rs
│   │   │       │   ├── like.rs
│   │   │       │   ├── list_post_likes.rs
│   │   │       │   ├── lock.rs
│   │   │       │   ├── mark_many_read.rs
│   │   │       │   ├── mark_read.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── mod_update.rs
│   │   │       │   ├── save.rs
│   │   │       │   ├── update_notifications.rs
│   │   │       │   └── warning.rs
│   │   │       ├── reports/
│   │   │       │   ├── comment_report/
│   │   │       │   │   ├── create.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   └── resolve.rs
│   │   │       │   ├── community_report/
│   │   │       │   │   ├── create.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   └── resolve.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── post_report/
│   │   │       │   │   ├── create.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   └── resolve.rs
│   │   │       │   ├── private_message_report/
│   │   │       │   │   ├── create.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   └── resolve.rs
│   │   │       │   └── report_combined/
│   │   │       │       ├── list.rs
│   │   │       │       └── mod.rs
│   │   │       ├── site/
│   │   │       │   ├── admin_allow_instance.rs
│   │   │       │   ├── admin_block_instance.rs
│   │   │       │   ├── admin_list_users.rs
│   │   │       │   ├── federated_instances.rs
│   │   │       │   ├── list_all_media.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── mod_log.rs
│   │   │       │   ├── purge/
│   │   │       │   │   ├── comment.rs
│   │   │       │   │   ├── community.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   ├── person.rs
│   │   │       │   │   └── post.rs
│   │   │       │   └── registration_applications/
│   │   │       │       ├── approve.rs
│   │   │       │       ├── get.rs
│   │   │       │       ├── list.rs
│   │   │       │       ├── mod.rs
│   │   │       │       └── tests.rs
│   │   │       └── sitemap.rs
│   │   ├── api_common/
│   │   │   ├── Cargo.toml
│   │   │   ├── README.md
│   │   │   └── src/
│   │   │       ├── account.rs
│   │   │       ├── comment.rs
│   │   │       ├── community.rs
│   │   │       ├── custom_emoji.rs
│   │   │       ├── error.rs
│   │   │       ├── federation.rs
│   │   │       ├── language.rs
│   │   │       ├── lib.rs
│   │   │       ├── media.rs
│   │   │       ├── modlog.rs
│   │   │       ├── notification.rs
│   │   │       ├── oauth.rs
│   │   │       ├── person.rs
│   │   │       ├── plugin.rs
│   │   │       ├── post.rs
│   │   │       ├── private_message.rs
│   │   │       ├── report.rs
│   │   │       ├── search.rs
│   │   │       ├── site.rs
│   │   │       └── tagline.rs
│   │   ├── api_crud/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── comment/
│   │   │       │   ├── create.rs
│   │   │       │   ├── delete.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── read.rs
│   │   │       │   ├── remove.rs
│   │   │       │   └── update.rs
│   │   │       ├── community/
│   │   │       │   ├── create.rs
│   │   │       │   ├── delete.rs
│   │   │       │   ├── list.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── remove.rs
│   │   │       │   └── update.rs
│   │   │       ├── custom_emoji/
│   │   │       │   ├── create.rs
│   │   │       │   ├── delete.rs
│   │   │       │   ├── list.rs
│   │   │       │   ├── mod.rs
│   │   │       │   └── update.rs
│   │   │       ├── lib.rs
│   │   │       ├── multi_community/
│   │   │       │   ├── create.rs
│   │   │       │   ├── create_entry.rs
│   │   │       │   ├── delete_entry.rs
│   │   │       │   ├── list.rs
│   │   │       │   ├── mod.rs
│   │   │       │   └── update.rs
│   │   │       ├── oauth_provider/
│   │   │       │   ├── create.rs
│   │   │       │   ├── delete.rs
│   │   │       │   ├── mod.rs
│   │   │       │   └── update.rs
│   │   │       ├── post/
│   │   │       │   ├── create.rs
│   │   │       │   ├── delete.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── read.rs
│   │   │       │   ├── remove.rs
│   │   │       │   └── update.rs
│   │   │       ├── private_message/
│   │   │       │   ├── create.rs
│   │   │       │   ├── delete.rs
│   │   │       │   ├── mod.rs
│   │   │       │   └── update.rs
│   │   │       ├── site/
│   │   │       │   ├── create.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── read.rs
│   │   │       │   └── update.rs
│   │   │       ├── tagline/
│   │   │       │   ├── create.rs
│   │   │       │   ├── delete.rs
│   │   │       │   ├── list.rs
│   │   │       │   ├── mod.rs
│   │   │       │   └── update.rs
│   │   │       └── user/
│   │   │           ├── create.rs
│   │   │           ├── delete.rs
│   │   │           ├── mod.rs
│   │   │           └── my_user.rs
│   │   ├── api_utils/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── build_response.rs
│   │   │       ├── claims.rs
│   │   │       ├── context.rs
│   │   │       ├── lib.rs
│   │   │       ├── notify.rs
│   │   │       ├── plugins.rs
│   │   │       ├── request.rs
│   │   │       ├── send_activity.rs
│   │   │       └── utils.rs
│   │   ├── routes/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       └── lib.rs
│   │   └── routes_v3/
│   │       ├── Cargo.toml
│   │       └── src/
│   │           ├── convert.rs
│   │           ├── handlers.rs
│   │           └── lib.rs
│   ├── apub/
│   │   ├── activities/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── activity_lists.rs
│   │   │       ├── block/
│   │   │       │   ├── block_user.rs
│   │   │       │   ├── mod.rs
│   │   │       │   └── undo_block_user.rs
│   │   │       ├── community/
│   │   │       │   ├── announce.rs
│   │   │       │   ├── collection_add.rs
│   │   │       │   ├── collection_remove.rs
│   │   │       │   ├── lock.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── report.rs
│   │   │       │   ├── resolve_report.rs
│   │   │       │   └── update.rs
│   │   │       ├── create_or_update/
│   │   │       │   ├── comment.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── note_wrapper.rs
│   │   │       │   ├── post.rs
│   │   │       │   └── private_message.rs
│   │   │       ├── deletion/
│   │   │       │   ├── delete.rs
│   │   │       │   ├── mod.rs
│   │   │       │   └── undo_delete.rs
│   │   │       ├── following/
│   │   │       │   ├── accept.rs
│   │   │       │   ├── follow.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── reject.rs
│   │   │       │   └── undo_follow.rs
│   │   │       ├── lib.rs
│   │   │       ├── protocol/
│   │   │       │   ├── block/
│   │   │       │   │   ├── block_user.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   └── undo_block_user.rs
│   │   │       │   ├── community/
│   │   │       │   │   ├── announce.rs
│   │   │       │   │   ├── collection_add.rs
│   │   │       │   │   ├── collection_remove.rs
│   │   │       │   │   ├── lock.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   ├── report.rs
│   │   │       │   │   ├── resolve_report.rs
│   │   │       │   │   └── update.rs
│   │   │       │   ├── create_or_update/
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   ├── note.rs
│   │   │       │   │   ├── note_wrapper.rs
│   │   │       │   │   ├── page.rs
│   │   │       │   │   └── private_message.rs
│   │   │       │   ├── deletion/
│   │   │       │   │   ├── delete.rs
│   │   │       │   │   ├── delete_user.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   └── undo_delete.rs
│   │   │       │   ├── following/
│   │   │       │   │   ├── accept.rs
│   │   │       │   │   ├── follow.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   ├── reject.rs
│   │   │       │   │   └── undo_follow.rs
│   │   │       │   ├── mod.rs
│   │   │       │   └── voting/
│   │   │       │       ├── mod.rs
│   │   │       │       ├── undo_vote.rs
│   │   │       │       └── vote.rs
│   │   │       └── voting/
│   │   │           ├── mod.rs
│   │   │           ├── undo_vote.rs
│   │   │           └── vote.rs
│   │   ├── apub/
│   │   │   ├── Cargo.toml
│   │   │   ├── assets/
│   │   │   │   ├── discourse/
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── group.json
│   │   │   │   │       ├── page.json
│   │   │   │   │       └── person.json
│   │   │   │   ├── friendica/
│   │   │   │   │   ├── activities/
│   │   │   │   │   │   ├── create_note.json
│   │   │   │   │   │   ├── create_page_1.json
│   │   │   │   │   │   ├── create_page_2.json
│   │   │   │   │   │   ├── delete.json
│   │   │   │   │   │   ├── dislike_page.json
│   │   │   │   │   │   ├── like_page.json
│   │   │   │   │   │   ├── undo_dislike_page.json
│   │   │   │   │   │   └── update_note.json
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── note_1.json
│   │   │   │   │       ├── note_2.json
│   │   │   │   │       ├── page_1.json
│   │   │   │   │       ├── page_2.json
│   │   │   │   │       ├── person_1.json
│   │   │   │   │       └── person_2.json
│   │   │   │   ├── gnusocial/
│   │   │   │   │   ├── activities/
│   │   │   │   │   │   ├── create_note.json
│   │   │   │   │   │   ├── create_page.json
│   │   │   │   │   │   └── like_note.json
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── group.json
│   │   │   │   │       ├── note.json
│   │   │   │   │       ├── page.json
│   │   │   │   │       └── person.json
│   │   │   │   ├── lemmy/
│   │   │   │   │   ├── activities/
│   │   │   │   │   │   ├── block/
│   │   │   │   │   │   │   ├── block_user.json
│   │   │   │   │   │   │   └── undo_block_user.json
│   │   │   │   │   │   ├── community/
│   │   │   │   │   │   │   ├── add_featured_post.json
│   │   │   │   │   │   │   ├── add_mod.json
│   │   │   │   │   │   │   ├── announce_create_page.json
│   │   │   │   │   │   │   ├── lock_note.json
│   │   │   │   │   │   │   ├── lock_page.json
│   │   │   │   │   │   │   ├── remove_featured_post.json
│   │   │   │   │   │   │   ├── remove_mod.json
│   │   │   │   │   │   │   ├── report_page.json
│   │   │   │   │   │   │   ├── resolve_report_page.json
│   │   │   │   │   │   │   ├── undo_lock_note.json
│   │   │   │   │   │   │   ├── undo_lock_page.json
│   │   │   │   │   │   │   └── update_community.json
│   │   │   │   │   │   ├── create_or_update/
│   │   │   │   │   │   │   ├── create_comment.json
│   │   │   │   │   │   │   ├── create_page.json
│   │   │   │   │   │   │   ├── create_private_message.json
│   │   │   │   │   │   │   └── update_page.json
│   │   │   │   │   │   ├── deletion/
│   │   │   │   │   │   │   ├── delete_page.json
│   │   │   │   │   │   │   ├── delete_private_message.json
│   │   │   │   │   │   │   ├── delete_user.json
│   │   │   │   │   │   │   ├── remove_note.json
│   │   │   │   │   │   │   ├── undo_delete_page.json
│   │   │   │   │   │   │   ├── undo_delete_private_message.json
│   │   │   │   │   │   │   └── undo_remove_note.json
│   │   │   │   │   │   ├── following/
│   │   │   │   │   │   │   ├── accept.json
│   │   │   │   │   │   │   ├── follow.json
│   │   │   │   │   │   │   └── undo_follow.json
│   │   │   │   │   │   └── voting/
│   │   │   │   │   │       ├── dislike_page.json
│   │   │   │   │   │       ├── like_note.json
│   │   │   │   │   │       ├── undo_dislike_page.json
│   │   │   │   │   │       └── undo_like_note.json
│   │   │   │   │   ├── collections/
│   │   │   │   │   │   ├── group_featured_posts.json
│   │   │   │   │   │   ├── group_followers.json
│   │   │   │   │   │   ├── group_moderators.json
│   │   │   │   │   │   ├── group_outbox.json
│   │   │   │   │   │   └── person_outbox.json
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── comment.json
│   │   │   │   │       ├── group.json
│   │   │   │   │       ├── instance.json
│   │   │   │   │       ├── page.json
│   │   │   │   │       ├── person.json
│   │   │   │   │       ├── private_message.json
│   │   │   │   │       └── tombstone.json
│   │   │   │   ├── lotide/
│   │   │   │   │   ├── activities/
│   │   │   │   │   │   ├── create_note_reply.json
│   │   │   │   │   │   ├── create_page.json
│   │   │   │   │   │   ├── create_page_image.json
│   │   │   │   │   │   ├── delete_note.json
│   │   │   │   │   │   └── follow.json
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── group.json
│   │   │   │   │       ├── note.json
│   │   │   │   │       ├── page.json
│   │   │   │   │       ├── person.json
│   │   │   │   │       └── tombstone.json
│   │   │   │   ├── mastodon/
│   │   │   │   │   ├── activities/
│   │   │   │   │   │   ├── create_note.json
│   │   │   │   │   │   ├── delete.json
│   │   │   │   │   │   ├── flag.json
│   │   │   │   │   │   ├── follow.json
│   │   │   │   │   │   ├── like_page.json
│   │   │   │   │   │   ├── private_message.json
│   │   │   │   │   │   ├── undo_follow.json
│   │   │   │   │   │   └── undo_like_page.json
│   │   │   │   │   ├── collections/
│   │   │   │   │   │   └── featured.json
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── note_1.json
│   │   │   │   │       ├── note_2.json
│   │   │   │   │       ├── page.json
│   │   │   │   │       └── person.json
│   │   │   │   ├── mbin/
│   │   │   │   │   ├── activities/
│   │   │   │   │   │   ├── accept.json
│   │   │   │   │   │   └── flag.json
│   │   │   │   │   └── objects/
│   │   │   │   │       └── instance.json
│   │   │   │   ├── mobilizon/
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── event.json
│   │   │   │   │       ├── group.json
│   │   │   │   │       └── person.json
│   │   │   │   ├── nodebb/
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── group.json
│   │   │   │   │       ├── page.json
│   │   │   │   │       └── person.json
│   │   │   │   ├── peertube/
│   │   │   │   │   ├── activities/
│   │   │   │   │   │   └── announce_video.json
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── group.json
│   │   │   │   │       ├── note.json
│   │   │   │   │       ├── person.json
│   │   │   │   │       └── video.json
│   │   │   │   ├── pleroma/
│   │   │   │   │   ├── activities/
│   │   │   │   │   │   ├── create_note.json
│   │   │   │   │   │   ├── delete.json
│   │   │   │   │   │   └── follow.json
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── chat_message.json
│   │   │   │   │       ├── note.json
│   │   │   │   │       └── person.json
│   │   │   │   ├── smithereen/
│   │   │   │   │   ├── activities/
│   │   │   │   │   │   └── create_note.json
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── note.json
│   │   │   │   │       └── person.json
│   │   │   │   └── wordpress/
│   │   │   │       ├── activities/
│   │   │   │       │   └── announce.json
│   │   │   │       └── objects/
│   │   │   │           ├── group.json
│   │   │   │           ├── note.json
│   │   │   │           ├── page.json
│   │   │   │           └── person.json
│   │   │   └── src/
│   │   │       ├── collections/
│   │   │       │   ├── community_featured.rs
│   │   │       │   ├── community_follower.rs
│   │   │       │   ├── community_moderators.rs
│   │   │       │   ├── community_outbox.rs
│   │   │       │   └── mod.rs
│   │   │       ├── http/
│   │   │       │   ├── comment.rs
│   │   │       │   ├── community.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── person.rs
│   │   │       │   ├── post.rs
│   │   │       │   ├── routes.rs
│   │   │       │   └── site.rs
│   │   │       ├── lib.rs
│   │   │       └── protocol/
│   │   │           ├── collections/
│   │   │           │   ├── group_featured.rs
│   │   │           │   ├── group_followers.rs
│   │   │           │   ├── group_moderators.rs
│   │   │           │   ├── group_outbox.rs
│   │   │           │   ├── mod.rs
│   │   │           │   └── url_collection.rs
│   │   │           └── mod.rs
│   │   ├── objects/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── lib.rs
│   │   │       ├── objects/
│   │   │       │   ├── comment.rs
│   │   │       │   ├── community.rs
│   │   │       │   ├── instance.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── multi_community.rs
│   │   │       │   ├── multi_community_collection.rs
│   │   │       │   ├── person.rs
│   │   │       │   ├── post.rs
│   │   │       │   └── private_message.rs
│   │   │       ├── protocol/
│   │   │       │   ├── group.rs
│   │   │       │   ├── instance.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── multi_community.rs
│   │   │       │   ├── note.rs
│   │   │       │   ├── page.rs
│   │   │       │   ├── person.rs
│   │   │       │   ├── private_message.rs
│   │   │       │   └── tags.rs
│   │   │       └── utils/
│   │   │           ├── functions.rs
│   │   │           ├── markdown_links.rs
│   │   │           ├── mentions.rs
│   │   │           ├── mod.rs
│   │   │           ├── protocol.rs
│   │   │           └── test.rs
│   │   └── send/
│   │       ├── Cargo.toml
│   │       └── src/
│   │           ├── inboxes.rs
│   │           ├── lib.rs
│   │           ├── send.rs
│   │           ├── stats.rs
│   │           ├── util.rs
│   │           └── worker.rs
│   ├── db_schema/
│   │   ├── Cargo.toml
│   │   └── src/
│   │       ├── impls/
│   │       │   ├── activity.rs
│   │       │   ├── actor_language.rs
│   │       │   ├── comment.rs
│   │       │   ├── comment_report.rs
│   │       │   ├── community.rs
│   │       │   ├── community_community_follow.rs
│   │       │   ├── community_report.rs
│   │       │   ├── community_tag.rs
│   │       │   ├── custom_emoji.rs
│   │       │   ├── email_verification.rs
│   │       │   ├── federation_allowlist.rs
│   │       │   ├── federation_blocklist.rs
│   │       │   ├── federation_queue_state.rs
│   │       │   ├── images.rs
│   │       │   ├── instance.rs
│   │       │   ├── keyword_block.rs
│   │       │   ├── language.rs
│   │       │   ├── local_site.rs
│   │       │   ├── local_site_rate_limit.rs
│   │       │   ├── local_site_url_blocklist.rs
│   │       │   ├── local_user.rs
│   │       │   ├── login_token.rs
│   │       │   ├── mod.rs
│   │       │   ├── modlog.rs
│   │       │   ├── multi_community.rs
│   │       │   ├── notification.rs
│   │       │   ├── oauth_account.rs
│   │       │   ├── oauth_provider.rs
│   │       │   ├── password_reset_request.rs
│   │       │   ├── person.rs
│   │       │   ├── post.rs
│   │       │   ├── post_report.rs
│   │       │   ├── private_message.rs
│   │       │   ├── private_message_report.rs
│   │       │   ├── registration_application.rs
│   │       │   ├── secret.rs
│   │       │   ├── site.rs
│   │       │   └── tagline.rs
│   │       ├── lib.rs
│   │       ├── newtypes.rs
│   │       ├── source/
│   │       │   ├── activity.rs
│   │       │   ├── actor_language.rs
│   │       │   ├── combined/
│   │       │   │   ├── mod.rs
│   │       │   │   ├── person_content.rs
│   │       │   │   ├── person_liked.rs
│   │       │   │   ├── person_saved.rs
│   │       │   │   ├── report.rs
│   │       │   │   └── search.rs
│   │       │   ├── comment.rs
│   │       │   ├── comment_report.rs
│   │       │   ├── community.rs
│   │       │   ├── community_community_follow.rs
│   │       │   ├── community_report.rs
│   │       │   ├── community_tag.rs
│   │       │   ├── custom_emoji.rs
│   │       │   ├── custom_emoji_keyword.rs
│   │       │   ├── email_verification.rs
│   │       │   ├── federation_allowlist.rs
│   │       │   ├── federation_blocklist.rs
│   │       │   ├── federation_queue_state.rs
│   │       │   ├── images.rs
│   │       │   ├── instance.rs
│   │       │   ├── keyword_block.rs
│   │       │   ├── language.rs
│   │       │   ├── local_site.rs
│   │       │   ├── local_site_rate_limit.rs
│   │       │   ├── local_site_url_blocklist.rs
│   │       │   ├── local_user.rs
│   │       │   ├── login_token.rs
│   │       │   ├── mod.rs
│   │       │   ├── modlog.rs
│   │       │   ├── multi_community.rs
│   │       │   ├── notification.rs
│   │       │   ├── oauth_account.rs
│   │       │   ├── oauth_provider.rs
│   │       │   ├── password_reset_request.rs
│   │       │   ├── person.rs
│   │       │   ├── post.rs
│   │       │   ├── post_report.rs
│   │       │   ├── private_message.rs
│   │       │   ├── private_message_report.rs
│   │       │   ├── registration_application.rs
│   │       │   ├── secret.rs
│   │       │   ├── site.rs
│   │       │   └── tagline.rs
│   │       ├── test_data.rs
│   │       ├── traits.rs
│   │       └── utils/
│   │           ├── mod.rs
│   │           └── queries/
│   │               ├── filters.rs
│   │               ├── mod.rs
│   │               └── selects.rs
│   ├── db_schema_file/
│   │   ├── Cargo.toml
│   │   ├── diesel_ltree.patch
│   │   └── src/
│   │       ├── enums.rs
│   │       ├── joins.rs
│   │       ├── lib.rs
│   │       ├── schema.rs
│   │       └── table_impls.rs
│   ├── db_views/
│   │   ├── comment/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── community/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── community_follower/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── community_follower_approval/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── community_moderator/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── custom_emoji/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── local_image/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── local_user/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── modlog/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── notification/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       ├── lib.rs
│   │   │       └── tests.rs
│   │   ├── notification_sql/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       └── lib.rs
│   │   ├── person/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── person_content_combined/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── person_liked_combined/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── person_saved_combined/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── post/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── db_perf/
│   │   │       │   ├── mod.rs
│   │   │       │   └── series.rs
│   │   │       ├── impls.rs
│   │   │       ├── lib.rs
│   │   │       └── test.rs
│   │   ├── post_comment_combined/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       └── lib.rs
│   │   ├── private_message/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── registration_applications/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── report_combined/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── report_combined_sql/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       └── lib.rs
│   │   ├── search_combined/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── site/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   └── vote/
│   │       ├── Cargo.toml
│   │       └── src/
│   │           ├── impls.rs
│   │           └── lib.rs
│   ├── diesel_utils/
│   │   ├── Cargo.toml
│   │   ├── build.rs
│   │   ├── replaceable_schema/
│   │   │   ├── triggers.sql
│   │   │   └── utils.sql
│   │   └── src/
│   │       ├── connection.rs
│   │       ├── dburl.rs
│   │       ├── lib.rs
│   │       ├── main.rs
│   │       ├── pagination.rs
│   │       ├── schema_setup/
│   │       │   ├── diff_check.rs
│   │       │   └── mod.rs
│   │       ├── sensitive.rs
│   │       ├── traits.rs
│   │       └── utils.rs
│   ├── email/
│   │   ├── Cargo.toml
│   │   ├── build.rs
│   │   └── src/
│   │       ├── account.rs
│   │       ├── admin.rs
│   │       ├── lib.rs
│   │       ├── notifications.rs
│   │       └── send.rs
│   ├── routes/
│   │   ├── Cargo.toml
│   │   └── src/
│   │       ├── feeds/
│   │       │   ├── mod.rs
│   │       │   └── negotiate_content.rs
│   │       ├── images/
│   │       │   ├── delete.rs
│   │       │   ├── download.rs
│   │       │   ├── mod.rs
│   │       │   ├── upload.rs
│   │       │   └── utils.rs
│   │       ├── lib.rs
│   │       ├── middleware/
│   │       │   ├── idempotency.rs
│   │       │   ├── mod.rs
│   │       │   └── session.rs
│   │       ├── nodeinfo.rs
│   │       ├── utils/
│   │       │   ├── mod.rs
│   │       │   ├── prometheus_metrics.rs
│   │       │   ├── scheduled_tasks.rs
│   │       │   └── setup_local_site.rs
│   │       └── webfinger.rs
│   ├── server/
│   │   ├── Cargo.toml
│   │   └── src/
│   │       ├── lib.rs
│   │       └── main.rs
│   └── utils/
│       ├── Cargo.toml
│       ├── src/
│       │   ├── cache_header.rs
│       │   ├── error.rs
│       │   ├── lib.rs
│       │   ├── main.rs
│       │   ├── rate_limit/
│       │   │   ├── backend.rs
│       │   │   ├── input.rs
│       │   │   └── mod.rs
│       │   ├── response.rs
│       │   ├── settings/
│       │   │   ├── mod.rs
│       │   │   └── structs.rs
│       │   └── utils/
│       │       ├── markdown/
│       │       │   ├── identifier_rule.rs
│       │       │   ├── image_links.rs
│       │       │   ├── link_rule.rs
│       │       │   └── mod.rs
│       │       ├── mention.rs
│       │       ├── mod.rs
│       │       ├── slurs.rs
│       │       └── validation.rs
│       └── tests/
│           └── test_errors_used.rs
├── diesel.toml
├── docker/
│   ├── Dockerfile
│   ├── README.md
│   ├── customPostgresql.conf
│   ├── docker-compose.yml
│   ├── docker_db_backup.sh
│   ├── docker_update.sh
│   ├── federation/
│   │   ├── docker-compose.yml
│   │   ├── lemmy_alpha.hjson
│   │   ├── lemmy_beta.hjson
│   │   ├── lemmy_delta.hjson
│   │   ├── lemmy_epsilon.hjson
│   │   ├── lemmy_gamma.hjson
│   │   ├── nginx.conf
│   │   └── start-local-instances.bash
│   ├── lemmy.hjson
│   ├── nginx.conf
│   └── test_deploy.sh
├── migrations/
│   ├── 00000000000000_diesel_initial_setup/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-02-26-002946_create_user/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-02-27-170003_create_community/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-03-03-163336_create_post/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-03-05-233828_create_comment/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-03-30-212058_create_post_view/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-04-03-155205_create_community_view/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-04-03-155309_create_comment_view/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-04-07-003142_create_moderation_logs/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-04-08-015947_create_user_view/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-04-11-144915_create_mod_views/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-04-29-175834_add_delete_columns/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-05-02-051656_community_view_hot_rank/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-06-01-222649_remove_admin/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-08-11-000918_add_nsfw_columns/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-08-29-040006_add_community_count/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-09-05-230317_add_mod_ban_views/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-09-09-042010_add_stickied_posts/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-10-15-181630_add_themes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-10-19-052737_create_user_mention/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-10-21-011237_add_default_sorts/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-10-24-002614_create_password_reset_request/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-12-09-060754_add_lang/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-12-11-181820_add_site_fields/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-12-29-164820_add_avatar/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-01-01-200418_add_email_to_user_view/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-01-02-172755_add_show_avatar_and_email_notifications_to_user/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-01-11-012452_add_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-01-13-025151_create_materialized_views/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-01-21-001001_create_private_message/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-01-29-011901_create_reply_materialized_view/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-01-29-030825_create_user_mention_materialized_view/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-02-02-004806_add_case_insensitive_usernames/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-02-06-165953_change_post_title_length/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-02-07-210055_add_comment_subscribed/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-02-08-145624_add_post_newest_activity_time/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-03-06-202329_add_post_iframely_data/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-03-26-192410_add_activitypub_tables/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-04-03-194936_add_activitypub_for_posts_and_comments/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-04-07-135912_add_user_community_apub_constraints/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-04-14-163701_update_views_for_activitypub/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-04-21-123957_remove_unique_user_constraints/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-05-05-210233_add_activitypub_for_private_messages/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-06-30-135809_remove_mat_views/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-07-08-202609_add_creator_published/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-07-12-100442_add_post_title_to_comments_view/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-07-18-234519_add_unique_community_user_actor_ids/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-08-03-000110_add_preferred_usernames_banners_and_icons/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-08-06-205355_update_community_post_count/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-08-25-132005_add_unique_ap_ids/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-09-07-231141_add_migration_utils/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-10-07-234221_fix_fast_triggers/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-10-10-035723_fix_fast_triggers_2/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-10-13-212240_create_report_tables/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-10-23-115011_activity_ap_id_column/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-11-05-152724_activity_remove_user_id/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-11-10-150835_community_follower_pending/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-11-26-134531_delete_user/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-12-02-152437_create_site_aggregates/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-12-03-035643_create_user_aggregates/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-12-04-183345_create_community_aggregates/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-12-10-152350_create_post_aggregates/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-12-14-020038_create_comment_aggregates/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-12-17-030456_create_alias_views/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-12-17-031053_remove_fast_tables_and_views/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-01-05-200932_add_hot_rank_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-01-26-173850_default_actor_id/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-01-27-202728_active_users_monthly/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-01-31-050334_add_forum_sort_index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-02-02-153240_apub_columns/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-02-10-164051_add_new_comments_sort_index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-02-13-210612_set_correct_aggregates_time_columns/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-02-25-112959_remove-categories/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-02-28-162616_clean_empty_post_urls/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-03-04-040229_clean_icon_urls/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-03-09-171136_split_user_table_2/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-03-19-014144_add_col_local_user_validator_time/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-03-20-185321_move_matrix_id_to_person/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-03-31-103917_add_show_score_setting/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-03-31-105915_add_bot_account/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-03-31-144349_add_site_short_description/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-04-01-173552_rename_preferred_username_to_display_name/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-04-01-181826_add_community_agg_active_monthly_index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-04-02-021422_remove_community_creator/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-04-20-155001_limit-admins-create-community/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-04-24-174047_add_show_read_post_setting/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-07-19-130929_add_show_new_post_notifs_setting/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-07-20-102033_actor_name_length/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-08-02-002342_comment_count_fixes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-08-04-223559_create_user_community_block/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-08-16-004209_fix_remove_bots_from_aggregates/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-08-17-210508_create_mod_transfer_community/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-09-20-112945_jwt-secret/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-10-01-141650_create_admin_purge/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-11-22-135324_add_activity_ap_id_index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-11-22-143904_add_required_public_key/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-11-23-031528_add_report_published_index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-11-23-132840_email_verification/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-11-23-153753_add_invite_only_columns/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-12-09-225529_add_published_to_email_verification/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-12-14-181537_add_temporary_bans/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-01-04-034553_add_hidden_column/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-01-20-160328_remove_site_creator/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-01-28-104106_instance-actor/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-02-01-154240_add_community_title_index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-02-18-210946_default_theme/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-04-04-183652_update_community_aggregates_on_soft_delete/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-04-11-210137_fix_unique_changeme/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-04-12-114352_default_post_listing_type/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-04-12-185205_change_default_listing_type_to_local/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-04-19-111004_default_require_application/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-04-26-105145_only_mod_can_post/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-05-19-153931_legal-information/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-05-20-135341_embed-url/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-06-12-012121_add_site_hide_modlog_names/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-06-13-124806_post_report_name_length/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-06-21-123144_language-tags/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-07-07-182650_comment_ltrees/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-08-04-150644_add_application_email_admins/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-08-04-214722_add_distinguished_comment/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-08-05-203502_add_person_post_aggregates/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-08-22-193848_comment-language-tags/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-09-07-113813_drop_ccnew_indexes_function/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-09-07-114618_pm-reports/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-09-08-102358_site-and-community-languages/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-09-24-161829_remove_table_aliases/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-10-06-183632_move_blocklist_to_db/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-11-13-181529_create_taglines/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-11-20-032430_sticky_local/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-11-21-143249_remove-federation-settings/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-11-21-204256_user-following/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-12-05-110642_registration_mode/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-01-17-165819_cleanup_post_aggregates_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-02-01-012747_fix_active_index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-02-05-102549_drop-site-federation-debug/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-02-07-030958_community-collections/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-02-11-173347_custom_emojis/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-02-13-172528_add_report_email_admins/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-02-13-221303_add_instance_software_and_version/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-02-15-212546_add_post_comment_saved_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-02-16-194139_add_totp_secret/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-04-14-175955_add_listingtype_sorttype_enums/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-04-23-164732_add_person_details_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-05-10-095739_force_enable_undetermined_language/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-06-104440_index_post_url/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-07-105918_add_hot_rank_columns/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-17-175955_add_listingtype_sorttype_hour_enums/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-19-055530_add_retry_worker_setting/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-19-120700_no_double_deletion/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-20-191145_add_listingtype_sorttype_3_6_9_months_enums/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-21-153242_add_captcha/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-22-051755_fix_local_communities_marked_non_local/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-22-101245_increase_user_theme_column_size/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-24-072904_add_open_links_in_new_tab_setting/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-24-185942_aggegates_published_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-27-065106_add_ui_settings/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-04-153335_add_optimized_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-05-000058_person-admin/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-06-151124_hot-rank-future/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-08-101154_fix_soft_delete_aggregates/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-10-075550_add-infinite-scroll-setting/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-11-084714_receive_activity_table/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-14-154840_add_optimized_indexes_published/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-14-215339_aggregates_nonzero_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-18-082614_post_aggregates_community_id/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-19-163511_comment_sort_hot_rank_then_score/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-24-232635_trigram-index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-26-000217_create_controversial_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-26-222023_site-aggregates-one/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-27-134652_remove-expensive-broken-trigger/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-08-01-101826_admin_flag_local_user/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-08-01-115243_persistent-activity-queue/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-08-02-144930_password-reset-token/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-08-02-174444_fix-timezones/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-08-08-163911_add_post_listing_mode_setting/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-08-09-101305_user_instance_block/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-08-23-182533_scaled_rank/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-08-29-183053_add_listing_type_moderator_view/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-08-31-205559_add_image_upload/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-09-01-112158_auto_resolve_report/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-09-07-215546_post-queries-efficient/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-09-11-110040_rework-2fa-setup/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-09-12-194850_add_federation_worker_index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-09-18-141700_login-token/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-09-20-110614_drop-show-new-post-notifs/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-09-28-084231_import_user_settings_rate_limit/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-10-02-145002_community_followers_count_federated/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-10-06-133405_add_keyboard_navigation_setting/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-10-13-175712_allow_animated_avatars/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-10-17-181800_drop_remove_community_expires/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-10-23-184941_hot_rank_greatest_fix/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-10-24-030352_change_primary_keys_and_remove_some_id_columns/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-10-24-131607_proxy_links/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-10-24-183747_autocollapse_bot_comments/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-10-27-142514_post_url_content_type/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-11-01-223740_federation-published/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-11-02-120140_apub-signed-fetch/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-11-07-135409_inbox_unique/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-11-22-194806_low_rank_defaults/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-12-06-180359_edit_active_users/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-12-19-210053_tolerable-batch-insert-speed/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-12-22-040137_make-mixed-sorting-directions-work-with-tuple-comparison/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-01-02-094916_site-name-not-unique/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-01-05-213000_community_aggregates_add_local_subscribers/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-01-15-100133_local-only-community/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-01-22-105746_lemmynsfw-changes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-01-25-151400_remove_auto_resolve_report_trigger/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-02-12-211114_add_vote_display_mode_setting/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-02-15-171358_default_instance_sort_type/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-02-24-034523_replaceable-schema/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-02-27-204628_add_post_alt_text/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-02-28-144211_hide_posts/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-03-06-104706_local_image_user_opt/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-03-06-201637_url_blocklist/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-04-05-153647_alter_vote_display_mode_defaults/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-04-15-105932_community_followers_url_optional/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-04-23-020604_add_post_id_index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-05-04-140749_separate_triggers/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-05-05-162540_add_image_detail_table/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-06-17-160323_fix_post_aggregates_featured_local/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-06-24-000000_ap_id_triggers/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-07-01-014711_exponential_controversy/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-08-03-155932_increase_post_url_max_length/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-11-12-090437_move-triggers/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-01-10-135505_donation-dialog/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-02-11-131045_ban-remove-content-pm/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-02-24-173152_search-alt-text-of-posts/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-03-07-094522_enable_english_for_all/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-04-07-100344_registration-rate-limit/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-05-15-154113_missing_post_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-07-29-152742_add_indexes_for_aggregates_activity/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-07-29-152743_post-aggregates-creator-community-indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000000_enable_private_messages/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000002_error_if_code_migrations_needed/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000003_remove_show_scores_column/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000004_custom_emoji_tagline_changes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000005_drop-enable-nsfw/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000006_default_comment_sort_type/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000007_schedule-post/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000008_create_oauth_provider/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000009_add_federation_vote_rejection/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000010_remove_auto_expand/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000011_add_short_community_description/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000012_no-individual-inboxes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000013_comment-vote-remote-postid/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000014_private-community/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000015_add_mark_fetched_posts_as_read/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000016_smoosh-tables-together/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000017_forbid_diesel_cli/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000018_custom_migration_runner/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000019_add_report_count/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000020_oauth_pkce/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000021_add_blurhash_to_image_details/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000022_instance-block-mod-log/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000023_add_report_combined_table/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000024_add_person_content_combined_table/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000025_add_modlog_combined_table/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000026_add_inbox_combined_table/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000027_add_search_combined_table/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000028_add_index_on_person_id_read_for_read_only_post_actions/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000029_community-post-tags/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000030_optimize_get_random_community/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000031_update-replaceable-schema/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000032_community_report/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000033_add_post_keyword_block_table/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000034_no-image-token/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000035_media_filter/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000036_interactions_per_month_schema/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000037_report_to_admins/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000038_ap_id/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000039_remove_post_sort_type_enums/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000040_block_nsfw/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000041_remove-aggregate-tables/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000042_community-hidden-visibility/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000043_community-local-removed/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000044_post_comment_pending/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000045_site_person_ban/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000047_disable-email-notifications/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000048_cursor_pagination_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000049_add_liked_combined/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000050_show_downvotes_for_others_only/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000051_local_image_person/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000052_lock_reason/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000053_remove_hide_modlog_names/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000054_mod-change-community-vis/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000055_rename_timestamp_add_at/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000056_person_note/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000057_multi-community/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000058_instance_block_communities_persons/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000059_person_votes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000060_rename-rate-limit-columns/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000061_drop-person-ban/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000062_username-instance-unique/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000063_post-or-comment-notification/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000064_add_missing_foreign_key_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000065_group-follow/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000066_modlog-rename/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000067_add_default_items_per_page/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000068_local_user_trigger/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-06-170325_add_indexes_for_aggregates_activity_new/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-20-000000_comment-lock/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-09-01-141127_local-community-collections/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-09-08-000001_add-video-dimensions/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-09-08-140711_remove-actor-name-max-length/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-09-12-093537_mod-reason-mandatory/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-09-15-090401_remove-keyboard-nav/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-09-19-090047_notify-mod-action/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-09-19-132648-0000_theme-instance-default/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-10-08-084508-0000_multi-comm-index-lower/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-10-09-101527-0000_community-follower-denied/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-10-15-114811-0000_merge-modlog-tables/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-11-05-181519-0000_add_registration_application_updated_at/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-11-08-123111-0000_add_multi_community_subscribers_community_count/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-01-08-132525-0000_community-sidebar-summary/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-01-19-122321-0000_add_community_tag_color/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-01-23-094410-0000_rename-sidebar-again/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-01-23-140244-0000_rename-tag-to-community-tag/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-01-28-115414-0000_captcha-plugin/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-02-01-205644-0000_add_moderator_warn_modlog_kind/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-02-03-235249-0000_add_moderator_warn_constraint_check/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-02-19-120000-0000_add_bulk_to_modlog/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-02-19-192014-0000_rename_suggested_communities/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-02-24-205759-0000_add_notification_creator_id/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-03-02-231448-0000_add_multi_community_sidebar/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-03-03-211442-0000_move_config_pictrs_to_db/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-03-04-143123-0000_add_deleted_by_recip_to_pm/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-03-08-021022-0000_fixup_post_action_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-03-08-202630-0000_add_modlog_foreign_keys/
│   │   ├── down.sql
│   │   └── up.sql
│   └── 2026-03-09-014616-0000_add_resolved_report_combined/
│       ├── down.sql
│       └── up.sql
├── readmes/
│   ├── README.es.md
│   ├── README.ja.md
│   ├── README.ru.md
│   ├── README.zh.hans.md
│   └── README.zh.hant.md
├── rust-toolchain.toml
└── scripts/
    ├── alpine_install_pg_formatter.sh
    ├── clean-workspace.sh
    ├── clear_db.sh
    ├── compilation_benchmark.sh
    ├── db-init.sh
    ├── db_perf.sh
    ├── dump_schema.sh
    ├── install.sh
    ├── lint.sh
    ├── postgres_12_to_15_upgrade.sh
    ├── postgres_15_to_16_upgrade.sh
    ├── query_testing/
    │   ├── apache_bench_report.sh
    │   ├── api_benchmark.sh
    │   ├── bulk_upsert_timings.md
    │   ├── post_query_hot_rank.sh
    │   ├── views_old/
    │   │   ├── generate_reports.sh
    │   │   └── timings-2021-01-05_21-06-37.out
    │   └── views_to_diesel_migration/
    │       ├── generate_reports.sh
    │       └── timings-2021-01-05_21-32-54.out
    ├── release.bash
    ├── restore_db.sh
    ├── sql_format_check.sh
    ├── start_dev_db.sh
    ├── test-with-coverage.sh
    ├── test.sh
    ├── update_config_defaults.sh
    ├── update_schema_file.sh
    ├── update_translations.sh
    └── upgrade_deps.sh

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf


================================================
FILE: .github/CODEOWNERS
================================================
* @Nutomic @dessalines @phiresky @dullbananas
crates/apub/ @Nutomic
migrations/ @dessalines @phiresky @dullbananas


================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

patreon: dessalines
liberapay: Lemmy


================================================
FILE: .github/ISSUE_TEMPLATE/BUG_REPORT.yml
================================================
name: "\U0001F41E Bug Report"
description: Create a report to help us improve lemmy
title: "[Bug]: "
labels: ["bug", "triage"]
body:
  - type: markdown
    attributes:
      value: |
        Found a bug? Please fill out the sections below. 👍
        Thanks for taking the time to fill out this bug report!
        For front end issues, use [lemmy](https://github.com/LemmyNet/lemmy-ui)
  - type: checkboxes
    attributes:
      label: Requirements
      description: Before you create a bug report please do the following.
      options:
        - label: Is this a bug report? For questions or discussions use https://lemmy.ml/c/lemmy_support or the [matrix chat](https://matrix.to/#/#lemmy:matrix.org).
          required: true
        - label: Did you check to see if this issue already exists?
          required: true
        - label: Is this only a single bug? Do not put multiple bugs in one issue.
          required: true
        - label: Do you agree to follow the rules in our [Code of Conduct](https://join-lemmy.org/docs/code_of_conduct.html)?
          required: true
        - label: Is this a backend issue? Use the [lemmy-ui](https://github.com/LemmyNet/lemmy-ui) repo for UI / frontend issues.
          required: true
  - type: textarea
    id: summary
    attributes:
      label: Summary
      description: A summary of the bug.
    validations:
      required: true
  - type: textarea
    id: reproduce
    attributes:
      label: Steps to Reproduce
      description: |
        Describe the steps to reproduce the bug.
        The better your description is _(go 'here', click 'there'...)_ the fastest you'll get an _(accurate)_ resolution.
      value: |
        1.
        2.
        3.
    validations:
      required: true
  - type: textarea
    id: technical
    attributes:
      label: Technical Details
      description: |
        - Please post your log: `sudo docker-compose logs > lemmy_log.out`.
        - What OS are you trying to install lemmy on?
        - Any browser console errors?
    validations:
      required: true
  - type: input
    id: lemmy-backend-version
    attributes:
      label: Version
      description: Which Lemmy backend version do you use? Displayed in the footer.
      placeholder: ex. BE 0.17.4
    validations:
      required: true
  - type: input
    id: lemmy-instance
    attributes:
      label: Lemmy Instance URL
      description: Which Lemmy instance do you use? The address
      placeholder: lemmy.ml, lemmy.world, etc


================================================
FILE: .github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml
================================================
name: "\U0001F680 Feature request"
description: Suggest an idea for improving Lemmy
labels: ["enhancement"]
body:
  - type: markdown
    attributes:
      value: |
        Have a suggestion about Lemmy's UI?
        For backend issues, use [lemmy](https://github.com/LemmyNet/lemmy)
  - type: checkboxes
    attributes:
      label: Requirements
      description: Before you create a bug report please do the following.
      options:
        - label: Is this a feature request? For questions or discussions use https://lemmy.ml/c/lemmy_support or the [matrix chat](https://matrix.to/#/#lemmy:matrix.org).
          required: true
        - label: Did you check to see if this issue already exists?
          required: true
        - label: Is this only a feature request? Do not put multiple feature requests in one issue.
          required: true
        - label: Is this a backend issue? Use the [lemmy-ui](https://github.com/LemmyNet/lemmy-ui) repo for UI / frontend issues.
          required: true
        - label: Do you agree to follow the rules in our [Code of Conduct](https://join-lemmy.org/docs/code_of_conduct.html)?
          required: true
  - type: textarea
    id: problem
    attributes:
      label: Is your proposal related to a problem?
      description: |
        Provide a clear and concise description of what the problem is.
        For example, "I'm always frustrated when..."
    validations:
      required: true
  - type: textarea
    id: solution
    attributes:
      label: Describe the solution you'd like.
      description: |
        Provide a clear and concise description of what you want to happen.
    validations:
      required: true
  - type: textarea
    id: alternatives
    attributes:
      label: Describe alternatives you've considered.
      description: |
        Let us know about other solutions you've tried or researched.
    validations:
      required: true
  - type: textarea
    id: context
    attributes:
      label: Additional context
      description: |
        Is there anything else you can add about the proposal?
        You might want to link to related issues here, if you haven't already.


================================================
FILE: .github/ISSUE_TEMPLATE/QUESTION.yml
================================================
name: "? Question"
description: General questions about Lemmy
title: "Question: "
labels: ["question", "triage"]
body:
  - type: markdown
    attributes:
      value: |
        For questions or discussions use https://lemmy.ml/c/lemmy_support or the [matrix chat](https://matrix.to/#/#lemmy:matrix.org).

        Have a question about how Lemmy works?
        Please check the docs first: https://join-lemmy.org/docs/en/index.html
  - type: textarea
    id: question
    attributes:
      label: Question
      description: What's the question you have about Lemmy?
    validations:
      required: true


================================================
FILE: .github/SECURITY.md
================================================
# Security Policy

## Reporting a Vulnerability

Use [Github's security advisory issue system](https://github.com/LemmyNet/lemmy/security/advisories/new).


================================================
FILE: .gitignore
================================================
# local ansible configuration
ansible/inventory
ansible/passwords/

# docker build files
docker/lemmy_mine.hjson
docker/dev/env_deploy.sh
docker/volumes
docker/*.sql.xz

# ide config
.idea
.vscode

# local build files
target
env_setup.sh
query_testing/**/reports/*.json

# API tests
api_tests/node_modules
api_tests/.yalc
api_tests/yalc.lock
api_tests/pict-rs
api_tests/speed_tests.sh

# pictrs data
pictrs/

# The generated typescript bindings
bindings

# database dumps
*.sqldump

# diesel
migrations/.diesel_lock


================================================
FILE: .gitmodules
================================================
[submodule "crates/utils/translations"]
	path = crates/email/translations
	url = https://github.com/LemmyNet/lemmy-translations.git
        branch = main


================================================
FILE: .rustfmt.toml
================================================
tab_spaces = 2
edition = "2024"
imports_layout = "HorizontalVertical"
imports_granularity = "Crate"
group_imports = "One"
wrap_comments = true
comment_width = 100


================================================
FILE: .woodpecker.yml
================================================
# TODO: The when: platform conditionals aren't working currently
# See https://github.com/woodpecker-ci/woodpecker/issues/1677

variables:
  # When updating the rust version here, be sure to update versions in `docker/Dockerfile`
  # as well. Otherwise release builds can fail if Lemmy or dependencies rely on new Rust
  # features. In particular the ARM builder image needs to be updated manually in the repo below:
  # https://github.com/raskyld/lemmy-cross-toolchains
  # Also be sure to change the version in `rust-toolchain.toml`
  - &rust_image "rust:1.94"
  - &rust_nightly_image "rustlang/rust:nightly"
  - &install_pnpm "npm install -g corepack@latest && corepack enable pnpm"
  - &install_binstall "wget -q -O- https://github.com/cargo-bins/cargo-binstall/releases/latest/download/cargo-binstall-x86_64-unknown-linux-musl.tgz | tar -xvz -C /usr/local/cargo/bin"
  - &slow_check_paths
    - event: pull_request
      path:
        include: [
            # rust source code
            "crates/**",
            "**/Cargo.toml",
            "Cargo.lock",
            # database migrations
            "migrations/**",
            # typescript tests
            "api_tests/**",
            # config files and scripts used by ci
            ".woodpecker.yml",
            ".rustfmt.toml",
            "scripts/update_config_defaults.sh",
            "diesel.toml",
            ".gitmodules",
          ]

steps:
  prepare_repo:
    image: alpine:3
    commands:
      - apk add git
      - git submodule init
      - git submodule update
    when:
      - event: [pull_request, tag]

  prettier_check:
    image: jauderho/prettier:3.7.4-alpine
    commands:
      - prettier -c . '!**/volumes' '!**/dist' '!target' '!**/translations' '!api_tests/pnpm-lock.yaml'
    when:
      - event: pull_request

  bash_fmt:
    image: alpine:3
    commands:
      - apk add shfmt
      - shfmt -i 2 -d */**.bash
      - shfmt -i 2 -d */**.sh
    when:
      - event: pull_request

  toml_fmt:
    image: ghcr.io/shaddydc/taplo
    commands:
      - taplo format --check
    when:
      - event: pull_request

  sql_fmt:
    image: *rust_image
    commands:
      - apt-get install perl make bash
      - ./scripts/alpine_install_pg_formatter.sh
      - ./scripts/sql_format_check.sh
    when:
      - event: pull_request

  cargo_fmt:
    image: *rust_nightly_image
    environment:
      # store cargo data in repo folder so that it gets cached between steps
      CARGO_HOME: .cargo_home
      RUSTUP_HOME: .rustup_home
    commands:
      - rustup component add rustfmt --toolchain nightly
      - cargo +nightly fmt -- --check
    when:
      - event: pull_request

  cargo_shear:
    image: *rust_nightly_image
    commands:
      - *install_binstall
      - cargo binstall -y cargo-shear --disable-strategies compile
      - cargo shear --deny-warnings
    when:
      - event: pull_request

  api_tests_lint:
    image: node:24-trixie-slim
    commands:
      - *install_pnpm
      - cd api_tests/
      - pnpm i
      - pnpm lint
    when: *slow_check_paths

  ignored_files:
    image: alpine:3
    commands:
      - apk add git
      - IGNORED=$(git ls-files --cached -i --exclude-standard)
      - if [[ "$IGNORED" ]]; then echo "Ignored files present:\n$IGNORED\n"; exit 1; fi
    when:
      - event: pull_request

  no_empty_files:
    image: alpine:3
    commands:
      # Makes sure there are no files smaller than 2 bytes
      # Don't use completely empty, as some editors use newlines
      - EMPTY_FILES=$(find crates migrations api_tests/src config -type f -size -2c)
      - if [[ "$EMPTY_FILES" ]]; then echo "Empty files present:\n$EMPTY_FILES\n"; exit 1; fi
    when:
      - event: pull_request

  cargo_build:
    image: *rust_image
    environment:
      CARGO_HOME: .cargo_home
      RUSTUP_HOME: .rustup_home
    commands:
      - cargo build
      - mv target/debug/lemmy_server target/lemmy_server
    when: *slow_check_paths

  # `DROP OWNED` doesn't work for default user
  create_database_user:
    image: pgautoupgrade/pgautoupgrade:18-alpine
    environment:
      PGUSER: postgres
      PGPASSWORD: password
      PGHOST: database
      PGDATABASE: lemmy
    commands:
      - psql -c "CREATE USER lemmy WITH PASSWORD 'password' SUPERUSER;"
    when: *slow_check_paths

  cargo_test:
    image: *rust_image
    environment:
      LEMMY_DATABASE_URL: postgres://lemmy:password@database:5432/lemmy
      RUST_BACKTRACE: "1"
      CARGO_HOME: .cargo_home
      RUSTUP_HOME: .rustup_home
      LEMMY_TEST_FAST_FEDERATION: "1"
      LEMMY_CONFIG_LOCATION: /woodpecker/src/github.com/LemmyNet/lemmy/config/config.hjson
    commands:
      # Install pg_dump for the schema setup test (must match server version)
      - apt update && apt install -y lsb-release
      - sh -c 'echo "deb [signed-by=/usr/share/keyrings/postgres-keyring.gpg] https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
      - wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor -o /usr/share/keyrings/postgres-keyring.gpg
      - apt update && apt install -y postgresql-client-18
      # Run tests (if they fail, try again)
      - cargo test --workspace || cargo test --workspace
    when: *slow_check_paths

  cargo_clippy:
    image: *rust_image
    environment:
      CARGO_HOME: .cargo_home
      RUSTUP_HOME: .rustup_home
    commands:
      - rustup component add clippy
      - cargo clippy --workspace --tests --all-targets --all-features -- -D warnings
    when: *slow_check_paths

  # make sure api builds with default features (used by other crates relying on lemmy api)
  check_api_common_default_features:
    image: *rust_image
    environment:
      CARGO_HOME: .cargo_home
      RUSTUP_HOME: .rustup_home
    commands:
      - cargo check --package lemmy_api_common
    when: *slow_check_paths

  check_disallowed_dependencies:
    image: *rust_image
    environment:
      CARGO_HOME: .cargo_home
      RUSTUP_HOME: .rustup_home
    commands:
      - "! cargo tree -p lemmy_api_common --no-default-features -i diesel"
      - "! cargo tree -i aws-lc-sys"
    when: *slow_check_paths

  lemmy_api_common_works_with_wasm:
    image: *rust_image
    environment:
      CARGO_HOME: .cargo_home
      RUSTUP_HOME: .rustup_home
    commands:
      - "rustup target add wasm32-unknown-unknown"
      - "cargo check --target wasm32-unknown-unknown -p lemmy_api_common"
    when: *slow_check_paths

  check_diesel_schema:
    image: *rust_image
    environment:
      LEMMY_DATABASE_URL: postgres://lemmy:password@database:5432/lemmy
      DATABASE_URL: postgres://lemmy:password@database:5432/lemmy
      RUST_BACKTRACE: "1"
      CARGO_HOME: .cargo_home
      RUSTUP_HOME: .rustup_home
    commands:
      - *install_binstall
      - cp crates/db_schema_file/src/schema.rs tmp.schema
      - target/lemmy_server migration --all run
      - apt-get update && apt-get install -y postgresql-client
      - cargo binstall diesel_cli@2.3.2 -y --disable-strategies compile
      - export PATH="$CARGO_HOME/bin:$PATH"
      - diesel print-schema
      - diff tmp.schema crates/db_schema_file/src/schema.rs
    when: *slow_check_paths

  run_federation_tests:
    image: node:24-trixie-slim
    environment:
      LEMMY_DATABASE_URL: postgres://lemmy:password@database:5432
      DO_WRITE_HOSTS_FILE: "1"
    commands:
      - *install_pnpm
      - apt-get update && apt-get install -y bash curl postgresql-client
      - bash api_tests/prepare-drone-federation-test.sh
      - cd api_tests/
      - pnpm i
      # Unfortunately these tests are unstable on slower CI machines, so try it a few times.
      - pnpm api-test-multiple
    when: *slow_check_paths

  federation_tests_server_output:
    image: alpine:3
    commands:
      # `|| true` prevents this step from appearing to fail if the server output files don't exist
      - cat target/log/lemmy_*.out || true
      - "# If you can't see all output, then use the download button"
    when:
      - event: pull_request
        status: failure

  publish_release_docker:
    image: woodpeckerci/plugin-docker-buildx
    settings:
      repo: dessalines/lemmy
      dockerfile: docker/Dockerfile
      username:
        from_secret: docker_username
      password:
        from_secret: docker_password
      # On release builds, switch these comment lines to also do arm64 qemu builds.
      # This takes 8 hours, so its not a good idea to do it for any other release.
      platforms: linux/amd64
      # platforms: linux/amd64,linux/arm64
      build_args:
        RUST_RELEASE_MODE: release
      build_args_from_env:
        - CI_PIPELINE_EVENT
      tag: ${CI_COMMIT_TAG=nightly}
    when:
      - event: tag
      - event: cron

  # lemmy container doesnt run as root so we need to change permissions to let it copy the binary
  chmod_for_native_binary:
    image: alpine:3
    commands:
      - chmod 777 .
    when:
      - event: tag

  # extract lemmy binary from newly built docker image into workspace folder
  extract_native_binary:
    image: dessalines/lemmy:${CI_COMMIT_TAG=default}
    commands:
      - cp /usr/local/bin/lemmy_server .
    when:
      - event: tag

  prepare_native_binary:
    image: alpine:3
    commands:
      - sha256sum lemmy_server > sha256sum.txt
      - gzip lemmy_server
    when:
      - event: tag

  # https://woodpecker-ci.org/plugins/Release
  publish_native_binary:
    image: woodpeckerci/plugin-release
    settings:
      files:
        - lemmy_server.gz
        - sha256sum.txt
      title: ${CI_COMMIT_TAG}
      prerelease: true
      api-key:
        from_secret: github_token
    when:
      - event: tag

  # using https://github.com/pksunkara/cargo-workspaces
  publish_to_crates_io:
    image: *rust_image
    environment:
      CARGO_API_TOKEN:
        from_secret: cargo_api_token
    commands:
      - *install_binstall
      - cargo binstall -y cargo-workspaces@0.4.1 --disable-strategies compile
      - cp -r migrations crates/db_schema/
      - cargo workspaces publish --token "$CARGO_API_TOKEN" --from-git --allow-dirty --no-verify --allow-branch "${CI_COMMIT_TAG}" --yes custom "${CI_COMMIT_TAG}"
    when:
      - event: tag

  notify_success:
    image: alpine:3
    commands:
      - apk add curl
      - "curl -H'Title: ✔️ ${CI_REPO_NAME}/${CI_COMMIT_SOURCE_BRANCH}' -d'${CI_PIPELINE_URL}' ntfy.sh/lemmy_drone_ci"
    when:
      - event: pull_request
        status: [success]

  notify_failure:
    image: alpine:3
    commands:
      - apk add curl
      - "curl -H'Title: ❌ ${CI_REPO_NAME}/${CI_COMMIT_SOURCE_BRANCH}' -d'${CI_PIPELINE_URL}' ntfy.sh/lemmy_drone_ci"
    when:
      - event: pull_request
        status: [failure]

  notify_on_tag_deploy:
    image: alpine:3
    commands:
      - apk add curl
      - "curl -H'Title: ${CI_REPO_NAME}:${CI_COMMIT_TAG} deployed' -d'${CI_PIPELINE_URL}' ntfy.sh/lemmy_drone_ci"
    when:
      event: tag

services:
  database:
    image: pgautoupgrade/pgautoupgrade:18-alpine
    environment:
      POSTGRES_DB: lemmy
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password


================================================
FILE: Cargo.toml
================================================
[workspace.package]
version = "1.0.0-test-arm-qemu.0"
edition = "2024"
description = "A link aggregator for the fediverse"
license = "AGPL-3.0"
homepage = "https://join-lemmy.org/"
documentation = "https://join-lemmy.org/docs/en/index.html"
repository = "https://github.com/LemmyNet/lemmy"
rust-version = "1.92"

# See https://github.com/johnthagen/min-sized-rust for additional optimizations
[profile.release]
lto = "fat"
opt-level = 3     # Optimize for speed, not size.
codegen-units = 1 # Reduce parallel code generation.

# This profile significantly speeds up build time. If debug info is needed you can comment the line
# out temporarily, but make sure to leave this in the main branch.
[profile.dev]
debug = 0

# Optimize procedural macros
[profile.dev.build-override]
opt-level = 1

[workspace]
members = [
  "crates/utils",
  "crates/db_schema",
  "crates/db_schema_file",
  "crates/diesel_utils",
  "crates/email",
  "crates/db_views/private_message",
  "crates/db_views/local_user",
  "crates/db_views/local_image",
  "crates/db_views/person",
  "crates/db_views/post",
  "crates/db_views/vote",
  "crates/db_views/local_image",
  "crates/db_views/comment",
  "crates/db_views/community",
  "crates/db_views/community_moderator",
  "crates/db_views/community_follower",
  "crates/db_views/community_follower_approval",
  "crates/db_views/custom_emoji",
  "crates/db_views/notification",
  "crates/db_views/notification_sql",
  "crates/db_views/modlog",
  "crates/db_views/person_content_combined",
  "crates/db_views/person_saved_combined",
  "crates/db_views/person_liked_combined",
  "crates/db_views/post_comment_combined",
  "crates/db_views/report_combined",
  "crates/db_views/report_combined_sql",
  "crates/db_views/search_combined",
  "crates/db_views/site",
  "crates/api/api",
  "crates/api/api_crud",
  "crates/api/api_common",
  "crates/api/api_utils",
  "crates/api/routes",
  "crates/api/routes_v3",
  "crates/apub/apub",
  "crates/apub/activities",
  "crates/apub/objects",
  "crates/apub/send",
  "crates/routes",
  "crates/server",
]
resolver = "3"

[workspace.lints.clippy]
cast_lossless = "deny"
complexity = { level = "deny", priority = -1 }
correctness = { level = "deny", priority = -1 }
dbg_macro = "deny"
explicit_into_iter_loop = "deny"
explicit_iter_loop = "deny"
get_first = "deny"
implicit_clone = "deny"
indexing_slicing = "deny"
inefficient_to_string = "deny"
items-after-statements = "deny"
manual_string_new = "deny"
needless_collect = "deny"
perf = { level = "deny", priority = -1 }
redundant_closure_for_method_calls = "deny"
style = { level = "deny", priority = -1 }
suspicious = { level = "deny", priority = -1 }
uninlined_format_args = "allow"
unused_self = "deny"
unwrap_used = "deny"
unimplemented = "deny"
unused_async = "deny"
map_err_ignore = "deny"
expect_used = "deny"
as_conversions = "deny"
large_futures = "deny"
tests_outside_test_module = "deny"
try_err = "deny"
unreachable = "deny"
string_slice = "deny"
same_name_method = "deny"
return_and_then = "deny"
ref_patterns = "deny"
redundant_type_annotations = "deny"
if_then_some_else_none = "deny"
allow_attributes = "deny"

[workspace.dependencies]
lemmy_api = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/api/api" }
lemmy_api_crud = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/api/api_crud" }
lemmy_api_routes = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/api/routes" }
lemmy_api_routes_v3 = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/api/routes_v3" }
lemmy_apub = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/apub/apub" }
lemmy_apub_activities = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/apub/activities" }
lemmy_apub_objects = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/apub/objects" }
lemmy_utils = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/utils", default-features = false }
lemmy_db_schema = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_schema" }
lemmy_db_schema_file = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_schema_file" }
lemmy_diesel_utils = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/diesel_utils" }
lemmy_api_utils = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/api/api_utils" }
lemmy_routes = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/routes" }
lemmy_apub_send = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/apub/send" }
lemmy_email = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/email" }
lemmy_db_views_comment = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/comment" }
lemmy_db_views_community = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/community" }
lemmy_db_views_community_follower = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/community_follower" }
lemmy_db_views_community_follower_approval = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/community_follower_approval" }
lemmy_db_views_community_moderator = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/community_moderator" }
lemmy_db_views_custom_emoji = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/custom_emoji" }
lemmy_db_views_notification = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/notification" }
lemmy_db_views_notification_sql = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/notification_sql" }
lemmy_db_views_local_image = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/local_image" }
lemmy_db_views_local_user = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/local_user" }
lemmy_db_views_modlog = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/modlog" }
lemmy_db_views_person = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/person" }
lemmy_db_views_person_content_combined = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/person_content_combined" }
lemmy_db_views_person_liked_combined = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/person_liked_combined" }
lemmy_db_views_person_saved_combined = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/person_saved_combined" }
lemmy_db_views_post_comment_combined = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/post_comment_combined" }
lemmy_db_views_post = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/post" }
lemmy_db_views_private_message = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/private_message" }
lemmy_db_views_registration_applications = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/registration_applications" }
lemmy_db_views_report_combined = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/report_combined" }
lemmy_db_views_report_combined_sql = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/report_combined_sql" }
lemmy_db_views_search_combined = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/search_combined" }
lemmy_db_views_site = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/site" }
lemmy_db_views_vote = { version = "=1.0.0-test-arm-qemu.0", path = "./crates/db_views/vote" }
activitypub_federation = { version = "0.7.0-beta.9", default-features = false, features = [
  "actix-web",
] }
diesel = { version = "2.3.6", features = [
  "64-column-tables",
  "chrono",
  "postgres",
  "serde_json",
  "uuid",
] }
diesel_migrations = "2.3.1"
diesel-async = "0.7.4"
serde = { version = "1.0.228", features = ["derive"] }
serde_with = "3.17.0"
actix-web = { version = "4.13.0", default-features = false, features = [
  "compress-brotli",
  "compress-gzip",
  "compress-zstd",
  "cookies",
  "macros",
  "rustls-0_23",
] }
tracing = { version = "0.1.44", default-features = false }
tracing-actix-web = { version = "0.7.21", default-features = false }
tracing-subscriber = { version = "0.3.22", features = ["env-filter", "json"] }
url = { version = "2.5.8", features = ["serde"] }
reqwest = { version = "0.13.2", default-features = false, features = [
  "gzip",
  "json",
  "rustls-no-provider",
] }
reqwest-middleware = "0.5.1"
reqwest-tracing = "0.7.0"
clokwerk = "0.4.0"
doku = { version = "0.21.1", features = ["url-2"] }
bcrypt = "0.19.0"
chrono = { version = "0.4.44", features = [
  "now",
  "serde",
], default-features = false }
serde_json = { version = "1.0.149", features = ["preserve_order"] }
base64 = "0.22.1"
uuid = { version = "1.22.0", features = ["serde"] }
anyhow = { version = "1.0.102", features = ["backtrace"] }
diesel_ltree = "0.4.0"
serial_test = "3.4.0"
tokio = { version = "1.50.0", features = ["full"] }
regex = "1.12.3"
diesel-derive-newtype = "2.1.2"
diesel-derive-enum = { version = "2.1.0", features = ["postgres"] }
enum-map = { version = "2.7" }
strum = { version = "0.28.0", features = ["derive"] }
itertools = "0.14.0"
futures = "0.3.32"
futures-util = "0.3.32"
http = "1.3"
rosetta-i18n = "0.1.3"
ts-rs = { version = "12.0.1", features = [
  "chrono-impl",
  "no-serde-warnings",
  "url-impl",
] }
rustls = { version = "0.23.37", features = ["ring"], default-features = false }
tokio-postgres = "0.7.16"
tokio-postgres-rustls = "0.13.0"
urlencoding = "2.1.3"
moka = { version = "0.12.14", features = ["future"] }
i-love-jesus = { version = "0.3.0" }
clap = { version = "4.5.60", features = ["derive", "env"] }
pretty_assertions = "1.4.1"
derive-new = "0.7.0"
html2text = "0.16.7"
async-trait = "0.1.89"
either = { version = "1.15.0", features = ["serde"] }
extism = { version = "1.13.0", default-features = false, features = [
  "http",
  "register-filesystem",
  "register-http",
] }
extism-convert = "1.13.0"
unified-diff = "0.2.1"
diesel-uplete = { version = "0.2.0" }
cfg-if = "1"

# Speedup RSA key generation
# https://github.com/RustCrypto/RSA/blob/master/README.md#example
[profile.dev.package.num-bigint-dig]
opt-level = 3


================================================
FILE: LICENSE
================================================
                    GNU AFFERO GENERAL PUBLIC LICENSE
                       Version 3, 19 November 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.

  A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate.  Many developers of free software are heartened and
encouraged by the resulting cooperation.  However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.

  The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community.  It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server.  Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.

  An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals.  This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU Affero General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Remote Network Interaction; Use with the GNU General Public License.

  Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software.  This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time.  Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published
    by the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source.  For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code.  There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.


================================================
FILE: README.md
================================================
<div align="center">

[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/LemmyNet/lemmy.svg)](https://github.com/LemmyNet/lemmy/releases)
[![Build Status](https://woodpecker.join-lemmy.org/api/badges/LemmyNet/lemmy/status.svg)](https://woodpecker.join-lemmy.org/LemmyNet/lemmy)
[![GitHub issues](https://img.shields.io/github/issues-raw/LemmyNet/lemmy.svg)](https://github.com/LemmyNet/lemmy/issues)
[![Docker Pulls](https://img.shields.io/docker/pulls/dessalines/lemmy.svg)](https://cloud.docker.com/repository/docker/dessalines/lemmy/)
[![Translation status](http://weblate.join-lemmy.org/widgets/lemmy/-/lemmy/svg-badge.svg)](http://weblate.join-lemmy.org/engage/lemmy/)
[![License](https://img.shields.io/github/license/LemmyNet/lemmy.svg)](LICENSE)
[![GitHub stars](https://img.shields.io/github/stars/LemmyNet/lemmy?style=social)](https://github.com/LemmyNet/lemmy/stargazers)
<a href="https://endsoftwarepatents.org/innovating-without-patents"><img style="height: 20px;" src="https://static.fsf.org/nosvn/esp/logos/patent-free.svg"></a>

</div>

<p align="center">
  <span>English</span> |
  <a href="readmes/README.es.md">Español</a> |
  <a href="readmes/README.ru.md">Русский</a> |
  <a href="readmes/README.zh.hans.md">汉语</a> |
  <a href="readmes/README.zh.hant.md">漢語</a> |
  <a href="readmes/README.ja.md">日本語</a>
</p>

<p align="center">
  <a href="https://join-lemmy.org/" rel="noopener">
 <img width=200px height=200px src="https://raw.githubusercontent.com/LemmyNet/lemmy-ui/main/src/assets/icons/favicon.svg"></a>

 <h3 align="center"><a href="https://join-lemmy.org">Lemmy</a></h3>
  <p align="center">
    A link aggregator and forum for the fediverse.
    <br />
    <br />
    <a href="https://join-lemmy.org">Join Lemmy</a>
    ·
    <a href="https://join-lemmy.org/docs/index.html">Documentation</a>
    ·
    <a href="https://matrix.to/#/#lemmy-space:matrix.org">Matrix Chat</a>
    ·
    <a href="https://github.com/LemmyNet/lemmy/issues">Report Bug</a>
    ·
    <a href="https://github.com/LemmyNet/lemmy/issues">Request Feature</a>
    ·
    <a href="https://github.com/LemmyNet/lemmy/blob/main/RELEASES.md">Releases</a>
    ·
    <a href="https://join-lemmy.org/docs/code_of_conduct.html">Code of Conduct</a>
  </p>
</p>

## About The Project

| Desktop                                                                                                         | Mobile                                                                                                      |
| --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| ![desktop](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/main_screen_2.webp) | ![mobile](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/mobile_pic.webp) |

[Lemmy](https://github.com/LemmyNet/lemmy) is similar to sites like [Reddit](https://reddit.com), [Lobste.rs](https://lobste.rs), 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.

It is 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=3mbvWn1EY6g).
- 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/)

## Features

- Open source, [AGPL License](/LICENSE).
- Self hostable, easy to deploy.
  - Comes with [Docker](https://join-lemmy.org/docs/administration/install_docker.html) and [Ansible](https://join-lemmy.org/docs/administration/install_ansible.html).
- 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.
    - Private messaging support.
  - 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.
  - Supports arm64 / Raspberry Pi.

## Installation

- [Lemmy Administration Docs](https://join-lemmy.org/docs/administration/administration.html)

## Lemmy Projects

- [awesome-lemmy - A community driven list of apps and tools for lemmy](https://github.com/dbeley/awesome-lemmy)

## Support / Donate

Lemmy is free, open-source software, meaning no advertising, monetizing, or venture capital, ever. Your donations directly support full-time development of the project.

Lemmy is made possible by a generous grant from the [NLnet foundation](https://nlnet.nl/).

- [Support on Liberapay](https://liberapay.com/Lemmy).
- [Support on Ko-fi](https://ko-fi.com/lemmynet).
- [Support on OpenCollective](https://opencollective.com/lemmy).
- [Support on Patreon](https://www.patreon.com/dessalines).

### Crypto

- bitcoin: `1Hefs7miXS5ff5Ck5xvmjKjXf5242KzRtK`
- ethereum: `0x400c96c96acbC6E7B3B43B1dc1BB446540a88A01`
- monero: `41taVyY6e1xApqKyMVDRVxJ76sPkfZhALLTjRvVKpaAh2pBd4wv9RgYj1tSPrx8wc6iE1uWUfjtQdTmTy2FGMeChGVKPQuV`

## Contributing

Read the following documentation to setup the development environment and start coding:

- [Contributing instructions](https://join-lemmy.org/docs/contributors/01-overview.html)
- [Docker Development](https://join-lemmy.org/docs/contributors/03-docker-development.html)
- [Local Development](https://join-lemmy.org/docs/contributors/02-local-development.html)

When working on an issue or pull request, you can comment with any questions you may have so that maintainers can answer them. You can also join the [Matrix Development Chat](https://matrix.to/#/#lemmydev:matrix.org) for general assistance.

### Translations

- If you want to help with translating, take a look at [Weblate](https://weblate.join-lemmy.org/projects/lemmy/). You can also help by [translating the documentation](https://github.com/LemmyNet/lemmy-docs#adding-a-new-language).

## Community

- [Matrix Space](https://matrix.to/#/#lemmy-space:matrix.org)
- [Lemmy Forum](https://lemmy.ml/c/lemmy)
- [Lemmy Support Forum](https://lemmy.ml/c/lemmy_support)

## Code Mirrors

- [GitHub](https://github.com/LemmyNet/lemmy)
- [Gitea](https://git.join-lemmy.org/LemmyNet/lemmy)
- [Codeberg](https://codeberg.org/LemmyNet/lemmy)

## Credits

Logo made by Andy Cuccaro (@andycuccaro) under the CC-BY-SA 4.0 license.


================================================
FILE: api_tests/.npmrc
================================================
package-manager-strict=false


================================================
FILE: api_tests/.prettierrc.json
================================================
{
  "arrowParens": "avoid",
  "semi": true
}


================================================
FILE: api_tests/eslint.config.mjs
================================================
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";

export default [
  pluginJs.configs.recommended,
  ...tseslint.configs.recommended,
  {
    languageOptions: {
      parser: tseslint.parser,
    },
  },
  // For some reason this has to be in its own block
  {
    ignores: [
      "putTypesInIndex.js",
      "dist/*",
      "docs/*",
      ".yalc",
      "jest.config.js",
    ],
  },
  {
    files: ["src/**/*"],
    rules: {
      "@typescript-eslint/no-empty-interface": 0,
      "@typescript-eslint/no-empty-function": 0,
      "@typescript-eslint/ban-ts-comment": 0,
      "@typescript-eslint/no-explicit-any": 0,
      "@typescript-eslint/explicit-module-boundary-types": 0,
      "@typescript-eslint/no-var-requires": 0,
      "arrow-body-style": 0,
      curly: 0,
      "eol-last": 0,
      eqeqeq: 0,
      "func-style": 0,
      "import/no-duplicates": 0,
      "max-statements": 0,
      "max-params": 0,
      "new-cap": 0,
      "no-console": 0,
      "no-duplicate-imports": 0,
      "no-extra-parens": 0,
      "no-return-assign": 0,
      "no-throw-literal": 0,
      "no-trailing-spaces": 0,
      "no-unused-expressions": 0,
      "no-useless-constructor": 0,
      "no-useless-escape": 0,
      "no-var": 0,
      "prefer-const": 0,
      "prefer-rest-params": 0,
      "quote-props": 0,
      "unicorn/filename-case": 0,
    },
  },
];


================================================
FILE: api_tests/jest.config.js
================================================
module.exports = {
  preset: "ts-jest",
  testEnvironment: "node",
};


================================================
FILE: api_tests/package.json
================================================
{
  "name": "api_tests",
  "version": "0.0.1",
  "description": "API tests for lemmy backend",
  "main": "index.js",
  "repository": "https://github.com/LemmyNet/lemmy",
  "author": "Dessalines",
  "license": "AGPL-3.0",
  "packageManager": "pnpm@10.25.0+sha512.5e82639027af37cf832061bcc6d639c219634488e0f2baebe785028a793de7b525ffcd3f7ff574f5e9860654e098fe852ba8ac5dd5cefe1767d23a020a92f501",
  "scripts": {
    "lint": "tsc --noEmit && eslint --report-unused-disable-directives && prettier --check 'src/**/*.ts'",
    "fix": "prettier --write src && eslint --fix src",
    "api-test": "jest -i --bail --verbose --silent --testPathIgnorePatterns speed.spec.ts",
    "api-test-multiple": "pnpm run api-test || pnpm run api-test || pnpm run api-test || pnpm run api-test",
    "api-test-follow": "jest -i follow.spec.ts",
    "api-test-comment": "jest -i comment.spec.ts",
    "api-test-post": "jest -i post.spec.ts",
    "api-test-user": "jest -i user.spec.ts",
    "api-test-community": "jest -i community.spec.ts",
    "api-test-private-community": "jest -i private_comm.spec.ts",
    "api-test-private-message": "jest -i private_message.spec.ts",
    "api-test-image": "jest -i image.spec.ts",
    "api-test-tags": "jest -i tags.spec.ts",
    "api-test-speed": "jest -i speed.spec.ts",
    "api-test-apiv3": "jest -i apiv3.spec.ts"
  },
  "devDependencies": {
    "@eslint/js": "^9.29.0",
    "@types/jest": "^30.0.0",
    "@types/node": "^24.0.3",
    "@typescript-eslint/eslint-plugin": "^8.34.1",
    "@typescript-eslint/parser": "^8.34.1",
    "eslint": "^9.29.0",
    "eslint-plugin-prettier": "^5.5.0",
    "jest": "^30.0.0",
    "joi": "^18.0.0",
    "lemmy-js-client": "1.0.0-pictrs-fields-db.0",
    "lemmy-js-client-019": "npm:lemmy-js-client@0.19.9",
    "prettier": "^3.5.3",
    "ts-jest": "^29.4.0",
    "tsoa": "^6.6.0",
    "typescript": "^5.8.3",
    "typescript-eslint": "^8.34.1"
  }
}


================================================
FILE: api_tests/pnpm-workspace.yaml
================================================
onlyBuiltDependencies:
  - unrs-resolver


================================================
FILE: api_tests/prepare-drone-federation-test.sh
================================================
#!/usr/bin/env bash
# IMPORTANT NOTE: this script does not use the normal LEMMY_DATABASE_URL format
#   it is expected that this script is called by run-federation-test.sh script.
set -e

if [ -z "$LEMMY_LOG_LEVEL" ]; then
  LEMMY_LOG_LEVEL=info
fi

export RUST_BACKTRACE=1
export RUST_LOG="warn,lemmy_server=$LEMMY_LOG_LEVEL,lemmy_federate=$LEMMY_LOG_LEVEL,lemmy_api=$LEMMY_LOG_LEVEL,lemmy_api_common=$LEMMY_LOG_LEVEL,lemmy_api_crud=$LEMMY_LOG_LEVEL,lemmy_apub=$LEMMY_LOG_LEVEL,lemmy_db_schema=$LEMMY_LOG_LEVEL,lemmy_db_views=$LEMMY_LOG_LEVEL,lemmy_routes=$LEMMY_LOG_LEVEL,lemmy_utils=$LEMMY_LOG_LEVEL,lemmy_websocket=$LEMMY_LOG_LEVEL"

export LEMMY_TEST_FAST_FEDERATION=1 # by default, the persistent federation queue has delays in the scale of 30s-5min

PICTRS_PATH="api_tests/pict-rs"
PICTRS_EXPECTED_HASH="7f7ac2a45ef9b13403ee139b7512135be6b060ff2f6460e0c800e18e1b49d2fd  api_tests/pict-rs"

# Pictrs setup. Download file with hash check and up to 3 retries.
if [ ! -f "$PICTRS_PATH" ]; then
  count=0
  while [ ! -f "$PICTRS_PATH" ] && [ "$count" -lt 3 ]; do
    # This one sometimes goes down
    curl "https://git.asonix.dog/asonix/pict-rs/releases/download/v0.5.17-pre.9/pict-rs-linux-amd64" -o "$PICTRS_PATH"
    # curl "https://codeberg.org/asonix/pict-rs/releases/download/v0.5.5/pict-rs-linux-amd64" -o "$PICTRS_PATH"
    PICTRS_HASH=$(sha256sum "$PICTRS_PATH")
    if [[ "$PICTRS_HASH" != "$PICTRS_EXPECTED_HASH" ]]; then
      echo "Pictrs binary hash mismatch, was $PICTRS_HASH but expected $PICTRS_EXPECTED_HASH"
      rm "$PICTRS_PATH"
      let count=count+1
    fi
  done
  chmod +x "$PICTRS_PATH"
fi

./api_tests/pict-rs \
  run -a 0.0.0.0:8080 \
  --danger-dummy-mode \
  --api-key "my-pictrs-key" \
  filesystem -p /tmp/pictrs/files \
  sled -p /tmp/pictrs/sled-repo 2>&1 &

for INSTANCE in lemmy_alpha lemmy_beta lemmy_gamma lemmy_delta lemmy_epsilon; do
  echo "DB URL: ${LEMMY_DATABASE_URL} INSTANCE: $INSTANCE"
  psql "${LEMMY_DATABASE_URL}/lemmy" -c "DROP DATABASE IF EXISTS $INSTANCE"
  echo "create database"
  psql "${LEMMY_DATABASE_URL}/lemmy" -c "CREATE DATABASE $INSTANCE"
done

if [ -z "$DO_WRITE_HOSTS_FILE" ]; then
  if ! grep -q lemmy-alpha /etc/hosts; then
    echo "Please add the following to your /etc/hosts file, then press enter:

      127.0.0.1       lemmy-alpha
      127.0.0.1       lemmy-beta
      127.0.0.1       lemmy-gamma
      127.0.0.1       lemmy-delta
      127.0.0.1       lemmy-epsilon"
    read -p ""
  fi
else
  for INSTANCE in lemmy-alpha lemmy-beta lemmy-gamma lemmy-delta lemmy-epsilon; do
    echo "127.0.0.1 $INSTANCE" >>/etc/hosts
  done
fi

echo "$PWD"

LOG_DIR=target/log
mkdir -p $LOG_DIR

echo "start alpha"
LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_alpha.hjson \
  LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_alpha" \
  target/lemmy_server >$LOG_DIR/lemmy_alpha.out 2>&1 &

echo "start beta"
LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_beta.hjson \
  LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_beta" \
  target/lemmy_server >$LOG_DIR/lemmy_beta.out 2>&1 &

echo "start gamma"
LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_gamma.hjson \
  LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_gamma" \
  target/lemmy_server >$LOG_DIR/lemmy_gamma.out 2>&1 &

echo "start delta"
LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_delta.hjson \
  LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_delta" \
  target/lemmy_server >$LOG_DIR/lemmy_delta.out 2>&1 &

echo "start epsilon"
LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_epsilon.hjson \
  LEMMY_PLUGIN_PATH=api_tests/plugins \
  LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_epsilon" \
  target/lemmy_server >$LOG_DIR/lemmy_epsilon.out 2>&1 &

echo "wait for all instances to start"
while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'lemmy-alpha:8541/api/v4/site')" != "200" ]]; do sleep 1; done
echo "alpha started"
while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'lemmy-beta:8551/api/v4/site')" != "200" ]]; do sleep 1; done
echo "beta started"
while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'lemmy-gamma:8561/api/v4/site')" != "200" ]]; do sleep 1; done
echo "gamma started"
while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'lemmy-delta:8571/api/v4/site')" != "200" ]]; do sleep 1; done
echo "delta started"
while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'lemmy-epsilon:8581/api/v4/site')" != "200" ]]; do sleep 1; done
echo "epsilon started. All started"


================================================
FILE: api_tests/run-federation-test.sh
================================================
#!/usr/bin/env bash
set -e

export LEMMY_DATABASE_URL=postgres://lemmy:password@localhost:5432
pushd ..
cargo build
rm target/lemmy_server || true
cp target/debug/lemmy_server target/lemmy_server
killall -s1 lemmy_server || true
./api_tests/prepare-drone-federation-test.sh
popd

pnpm i
pnpm api-test || true

killall -s1 lemmy_server || true
killall -s1 pict-rs || true
for INSTANCE in lemmy_alpha lemmy_beta lemmy_gamma lemmy_delta lemmy_epsilon; do
  psql "$LEMMY_DATABASE_URL" -c "DROP DATABASE $INSTANCE"
done
rm -r /tmp/pictrs


================================================
FILE: api_tests/src/apiv3.spec.ts
================================================
jest.setTimeout(180000);

import {
  LemmyHttp,
  Login,
  CreatePost,
  ResolveObject,
} from "lemmy-js-client-019";
import { beta, betaUrl, setupLogins, unfollows } from "./shared";
import { CreateComment } from "lemmy-js-client";

beforeAll(async () => {
  await setupLogins();
});

afterAll(unfollows);

test("API v3", async () => {
  let login_form: Login = {
    username_or_email: "lemmy_beta",
    password: "lemmylemmy",
  };
  const login = await beta.login(login_form);
  expect(login.jwt).toBeDefined();

  let user = new LemmyHttp(betaUrl, {
    headers: { Authorization: `Bearer ${login.jwt ?? ""}` },
  });

  let resolve_form: ResolveObject = {
    q: "!main@lemmy-beta:8551",
  };
  const community = await user
    .resolveObject(resolve_form)
    .then(a => a.community);
  expect(community?.community).toBeDefined();

  const post_form: CreatePost = {
    name: "post from api v3",
    community_id: community!.community.id,
  };
  const post = await user.createPost(post_form);
  expect(post.post_view.post).toBeDefined();
  const post_id = post.post_view.post.id;

  const post_listing = await user.getPosts();
  expect(
    post_listing.posts.find(p => {
      return p.post.id === post_id;
    })?.post,
  ).toStrictEqual(post.post_view.post);

  const comment_form: CreateComment = {
    content: "comment from api v3",
    post_id,
  };
  const comment = await user.createComment(comment_form);
  expect(comment.comment_view.comment).toBeDefined();

  const comment_listing = await user.getComments({ post_id });
  expect(comment_listing.comments[0].comment).toStrictEqual(
    comment.comment_view.comment,
  );
});


================================================
FILE: api_tests/src/comment.spec.ts
================================================
jest.setTimeout(180000);

import { PostResponse } from "lemmy-js-client/dist/types/PostResponse";
import {
  alpha,
  beta,
  gamma,
  setupLogins,
  createPost,
  getPost,
  resolveComment,
  likeComment,
  followBeta,
  resolveBetaCommunity,
  createComment,
  editComment,
  deleteComment,
  removeComment,
  resolvePost,
  unfollowRemotes,
  createCommunity,
  registerUser,
  reportComment,
  randomString,
  unfollows,
  getComment,
  getComments,
  getCommentParentId,
  resolveCommunity,
  waitUntil,
  waitForPost,
  alphaUrl,
  betaUrl,
  followCommunity,
  blockCommunity,
  saveUserSettings,
  listReports,
  listPersonContent,
  listNotifications,
  lockComment,
  statusNotFound,
  statusBadRequest,
  jestLemmyError,
  getUnreadCounts,
} from "./shared";
import {
  CommentReportView,
  CommentView,
  CommunityView,
  DistinguishComment,
  LemmyError,
  ReportCombinedView,
  SaveUserSettings,
} from "lemmy-js-client";

let betaCommunity: CommunityView | undefined;
let postOnAlphaRes: PostResponse;

beforeAll(async () => {
  await setupLogins();
  await Promise.allSettled([followBeta(alpha), followBeta(gamma)]);
  betaCommunity = await resolveBetaCommunity(alpha);
  if (betaCommunity) {
    postOnAlphaRes = await createPost(alpha, betaCommunity.community.id);
  }
});

afterAll(unfollows);

function assertCommentFederation(
  commentOne?: CommentView,
  commentTwo?: CommentView,
) {
  expect(commentOne?.comment.ap_id).toBe(commentTwo?.comment.ap_id);
  expect(commentOne?.comment.content).toBe(commentTwo?.comment.content);
  expect(commentOne?.creator.name).toBe(commentTwo?.creator.name);
  expect(commentOne?.community.ap_id).toBe(commentTwo?.community.ap_id);
  expect(commentOne?.comment.published_at).toBe(
    commentTwo?.comment.published_at,
  );
  expect(commentOne?.comment.updated_at).toBe(commentOne?.comment.updated_at);
  expect(commentOne?.comment.deleted).toBe(commentOne?.comment.deleted);
  expect(commentOne?.comment.removed).toBe(commentOne?.comment.removed);
}

test("Create a comment", async () => {
  let commentRes = await createComment(alpha, postOnAlphaRes.post_view.post.id);
  expect(commentRes.comment_view.comment.content).toBeDefined();
  expect(commentRes.comment_view.community.local).toBe(false);
  expect(commentRes.comment_view.creator.local).toBe(true);
  expect(commentRes.comment_view.comment.score).toBe(1);

  // Make sure that comment is liked on beta
  let betaComment = await waitUntil(
    () => resolveComment(beta, commentRes.comment_view.comment),
    c => c?.comment.score === 1,
  );
  expect(betaComment).toBeDefined();
  expect(betaComment?.community.local).toBe(true);
  expect(betaComment?.creator.local).toBe(false);
  expect(betaComment?.comment.score).toBe(1);
  assertCommentFederation(betaComment, commentRes.comment_view);
});

test("Create a comment in a non-existent post", async () => {
  await jestLemmyError(
    () => createComment(alpha, -1),
    new LemmyError("not_found", statusNotFound),
  );
});

test("Update a comment", async () => {
  let commentRes = await createComment(alpha, postOnAlphaRes.post_view.post.id);
  // Federate the comment first
  let betaComment = await resolveComment(beta, commentRes.comment_view.comment);
  assertCommentFederation(betaComment, commentRes.comment_view);

  let updateCommentRes = await editComment(
    alpha,
    commentRes.comment_view.comment.id,
  );
  expect(updateCommentRes.comment_view.comment.content).toBe(
    "A jest test federated comment update",
  );
  expect(updateCommentRes.comment_view.community.local).toBe(false);
  expect(updateCommentRes.comment_view.creator.local).toBe(true);

  // Make sure that post is updated on beta
  let betaCommentUpdated = await waitUntil(
    () => resolveComment(beta, commentRes.comment_view.comment),
    c => c?.comment.content === "A jest test federated comment update",
  );
  assertCommentFederation(betaCommentUpdated, updateCommentRes.comment_view);
});

test("Delete a comment", async () => {
  let post = await createPost(alpha, betaCommunity!.community.id);
  // creating a comment on alpha (remote from home of community)
  let commentRes = await createComment(alpha, post.post_view.post.id);

  // Find the comment on beta (home of community)
  let betaComment = await resolveComment(beta, commentRes.comment_view.comment);
  if (!betaComment) {
    throw "Missing beta comment before delete";
  }

  // Find the comment on remote instance gamma
  let gammaComment = (
    await waitUntil(
      () =>
        resolveComment(gamma, commentRes.comment_view.comment).catch(e => e),
      r => r.message !== "not_found",
    )
  ).comment;
  if (!gammaComment) {
    throw "Missing gamma comment (remote-home-remote replication) before delete";
  }

  let deleteCommentRes = await deleteComment(
    alpha,
    true,
    commentRes.comment_view.comment.id,
  );
  expect(deleteCommentRes.comment_view.comment.deleted).toBe(true);

  // Make sure that comment is deleted on beta
  await waitUntil(
    () => resolveComment(beta, commentRes.comment_view.comment),
    c => c?.comment.deleted === true,
  );

  // Make sure that comment is deleted on gamma after delete
  await waitUntil(
    () => resolveComment(gamma, commentRes.comment_view.comment),
    c => c?.comment.deleted === true,
  );

  // Test undeleting the comment
  let undeleteCommentRes = await deleteComment(
    alpha,
    false,
    commentRes.comment_view.comment.id,
  );
  expect(undeleteCommentRes.comment_view.comment.deleted).toBe(false);

  // Make sure that comment is undeleted on beta
  let betaComment2 = await waitUntil(
    () => resolveComment(beta, commentRes.comment_view.comment),
    c => c?.comment.deleted === false,
  );
  assertCommentFederation(betaComment2, undeleteCommentRes.comment_view);
});

test.skip("Remove a comment from admin and community on the same instance", async () => {
  let commentRes = await createComment(alpha, postOnAlphaRes.post_view.post.id);

  // Get the id for beta
  let betaCommentId = (
    await resolveComment(beta, commentRes.comment_view.comment)
  )?.comment.id;

  if (!betaCommentId) {
    throw "beta comment id is missing";
  }

  // The beta admin removes it (the community lives on beta)
  let removeCommentRes = await removeComment(beta, true, betaCommentId);
  expect(removeCommentRes.comment_view.comment.removed).toBe(true);

  // Make sure that comment is removed on alpha (it gets pushed since an admin from beta removed it)
  let refetchedPostComments = await listPersonContent(
    alpha,
    commentRes.comment_view.comment.creator_id,
    "comments",
  );
  let firstRefetchedComment = refetchedPostComments.items[0] as CommentView;
  expect(firstRefetchedComment.comment.removed).toBe(true);

  // beta will unremove the comment
  let unremoveCommentRes = await removeComment(beta, false, betaCommentId);
  expect(unremoveCommentRes.comment_view.comment.removed).toBe(false);

  // Make sure that comment is unremoved on alpha
  let refetchedPostComments2 = await getComments(
    alpha,
    postOnAlphaRes.post_view.post.id,
  );
  expect(refetchedPostComments2.items[0].comment.removed).toBe(false);
  assertCommentFederation(
    refetchedPostComments2.items[0],
    unremoveCommentRes.comment_view,
  );
});

test("Remove a comment from admin and community on different instance", async () => {
  let newAlphaApi = await registerUser(alpha, alphaUrl);

  // New alpha user creates a community, post, and comment.
  let newCommunity = await createCommunity(newAlphaApi);
  let newPost = await createPost(
    newAlphaApi,
    newCommunity.community_view.community.id,
  );
  let commentRes = await createComment(newAlphaApi, newPost.post_view.post.id);
  expect(commentRes.comment_view.comment.content).toBeDefined();

  // Beta searches that to cache it, then removes it
  let betaComment = await waitUntil(
    () => resolveComment(beta, commentRes.comment_view.comment),
    c => c?.comment !== undefined,
  );

  if (!betaComment) {
    throw "beta comment missing";
  }

  let removeCommentRes = await removeComment(
    beta,
    true,
    betaComment.comment.id,
  );
  expect(removeCommentRes.comment_view.comment.removed).toBe(true);

  // Comment text is also hidden from list
  let listComments = await getComments(
    beta,
    removeCommentRes.comment_view.post.id,
  );
  expect(listComments.items.length).toBe(1);
  expect(listComments.items[0].comment.removed).toBe(true);

  // Make sure its not removed on alpha
  let refetchedPostComments = await getComments(
    alpha,
    newPost.post_view.post.id,
  );
  expect(refetchedPostComments.items[0].comment.removed).toBe(false);
  assertCommentFederation(
    refetchedPostComments.items[0],
    commentRes.comment_view,
  );
});

test("Unlike a comment", async () => {
  let commentRes = await createComment(alpha, postOnAlphaRes.post_view.post.id);

  // Lemmy automatically creates 1 like (vote) by author of comment.
  // Make sure that comment is liked (voted up) on gamma, downstream peer
  // This is testing replication from remote-home-remote (alpha-beta-gamma)

  let gammaComment1 = await waitUntil(
    () => resolveComment(gamma, commentRes.comment_view.comment),
    c => c?.comment.score === 1,
  );
  expect(gammaComment1).toBeDefined();
  expect(gammaComment1?.community.local).toBe(false);
  expect(gammaComment1?.creator.local).toBe(false);
  expect(gammaComment1?.comment.score).toBe(1);

  let unlike = await likeComment(
    alpha,
    undefined,
    commentRes.comment_view.comment,
  );
  expect(unlike.comment_view.comment.score).toBe(0);

  // Make sure that comment is unliked on beta
  let betaComment = await waitUntil(
    () => resolveComment(beta, commentRes.comment_view.comment),
    c => c?.comment.score === 0,
  );
  expect(betaComment).toBeDefined();
  expect(betaComment?.community.local).toBe(true);
  expect(betaComment?.creator.local).toBe(false);
  expect(betaComment?.comment.score).toBe(0);

  // Make sure that comment is unliked on gamma, downstream peer
  // This is testing replication from remote-home-remote (alpha-beta-gamma)
  let gammaComment = await waitUntil(
    () => resolveComment(gamma, commentRes.comment_view.comment),
    c => c?.comment.score === 0,
  );
  expect(gammaComment).toBeDefined();
  expect(gammaComment?.community.local).toBe(false);
  expect(gammaComment?.creator.local).toBe(false);
  expect(gammaComment?.comment.score).toBe(0);
});

test("Federated comment like", async () => {
  let commentRes = await createComment(alpha, postOnAlphaRes.post_view.post.id);
  await waitUntil(
    () => resolveComment(beta, commentRes.comment_view.comment),
    c => c?.comment.score === 1,
  );
  // Find the comment on beta
  let betaComment = await resolveComment(beta, commentRes.comment_view.comment);

  if (!betaComment) {
    throw "Missing beta comment";
  }

  let like = await likeComment(beta, true, betaComment.comment);
  expect(like.comment_view.comment.score).toBe(2);

  // Get the post from alpha, check the likes
  let postComments = await waitUntil(
    () => getComments(alpha, postOnAlphaRes.post_view.post.id),
    c => c.items[0].comment.score === 2,
  );
  expect(postComments.items[0].comment.score).toBe(2);
});

test("Reply to a comment from another instance, get notification", async () => {
  await alpha.markAllNotificationsAsRead();

  let betaCommunity = await waitUntil(
    () => resolveBetaCommunity(alpha),
    c => !!c?.community.instance_id,
  );
  if (!betaCommunity) {
    throw "Missing beta community";
  }

  const postOnAlphaRes = await createPost(alpha, betaCommunity.community.id);

  // Create a root-level trunk-branch comment on alpha
  let commentRes = await createComment(alpha, postOnAlphaRes.post_view.post.id);
  // find that comment id on beta
  let betaComment = await waitUntil(
    () => resolveComment(beta, commentRes.comment_view.comment),
    c => c?.comment.score === 1,
  );

  if (!betaComment) {
    throw "Missing beta comment";
  }

  // Reply from beta, extending the branch
  let replyRes = await createComment(
    beta,
    betaComment.post.id,
    betaComment.comment.id,
  );
  expect(replyRes.comment_view.comment.content).toBeDefined();
  expect(replyRes.comment_view.community.local).toBe(true);
  expect(replyRes.comment_view.creator.local).toBe(true);
  expect(getCommentParentId(replyRes.comment_view.comment)).toBe(
    betaComment.comment.id,
  );
  expect(replyRes.comment_view.comment.score).toBe(1);

  // Make sure that reply comment is seen on alpha
  let commentSearch = await waitUntil(
    () => resolveComment(alpha, replyRes.comment_view.comment),
    c => c?.comment.score === 1,
  );
  let alphaComment = commentSearch!;
  let postComments = await waitUntil(
    () => getComments(alpha, postOnAlphaRes.post_view.post.id),
    pc => pc.items.length >= 2,
  );
  // Note: this test fails when run twice and this count will differ
  expect(postComments.items.length).toBeGreaterThanOrEqual(2);
  expect(alphaComment.comment.content).toBeDefined();

  expect(getCommentParentId(alphaComment.comment)).toBe(
    postComments.items[1].comment.id,
  );
  expect(alphaComment.community.local).toBe(false);
  expect(alphaComment.creator.local).toBe(false);
  expect(alphaComment.comment.score).toBe(1);
  assertCommentFederation(alphaComment, replyRes.comment_view);

  // Did alpha get notified of the reply from beta?
  let alphaUnreadCountRes = await waitUntil(
    () => getUnreadCounts(alpha),
    e => e.notification_count >= 1,
  );
  expect(alphaUnreadCountRes.notification_count).toBeGreaterThanOrEqual(1);

  // check inbox of replies on alpha, fetching read/unread both
  let alphaRepliesRes = await waitUntil(
    () => listNotifications(alpha, "reply"),
    r => r.items.length > 0,
  );
  const alphaReply = alphaRepliesRes.items.find(
    r =>
      r.data.type_ == "comment" &&
      r.data.comment.id === alphaComment.comment.id,
  );
  expect(alphaReply).toBeDefined();
  if (!alphaReply) throw Error();
  const alphaReplyData = alphaReply.data as CommentView;
  expect(alphaReplyData.comment!.content).toBeDefined();
  expect(alphaReplyData.community!.local).toBe(false);
  expect(alphaReplyData.creator.local).toBe(false);
  expect(alphaReplyData.comment!.score).toBe(1);
  // ToDo: interesting alphaRepliesRes.replies[0].comment_reply.id is 1, meaning? how did that come about?
  expect(alphaReplyData.comment!.id).toBe(alphaComment.comment.id);
  // this is a new notification, getReplies fetch was for read/unread both, confirm it is unread.
  expect(alphaReply.notification.read).toBe(false);
});

test("Bot reply notifications are filtered when bots are hidden", async () => {
  const newAlphaBot = await registerUser(alpha, alphaUrl);
  let form: SaveUserSettings = {
    bot_account: true,
  };
  await saveUserSettings(newAlphaBot, form);

  const alphaCommunity = await resolveCommunity(
    alpha,
    "!main@lemmy-alpha:8541",
  );

  if (!alphaCommunity) {
    throw "Missing alpha community";
  }

  await alpha.markAllNotificationsAsRead();
  form = {
    show_bot_accounts: false,
  };
  await saveUserSettings(alpha, form);
  const postOnAlphaRes = await createPost(alpha, alphaCommunity.community.id);

  // Bot reply to alpha's post
  let commentRes = await createComment(
    newAlphaBot,
    postOnAlphaRes.post_view.post.id,
  );
  expect(commentRes).toBeDefined();

  let alphaUnreadCountRes = await getUnreadCounts(alpha);
  expect(alphaUnreadCountRes.notification_count).toBe(0);

  // This both restores the original state that may be expected by other tests
  // implicitly and is used by the next steps to ensure replies are still
  // returned when a user later decides to show bot accounts again.
  form = {
    show_bot_accounts: true,
  };
  await saveUserSettings(alpha, form);

  alphaUnreadCountRes = await getUnreadCounts(alpha);
  expect(alphaUnreadCountRes.notification_count).toBe(1);

  let alphaUnreadRepliesRes = await listNotifications(alpha, "reply", true);
  expect(alphaUnreadRepliesRes.items.length).toBe(1);
  expect(alphaUnreadRepliesRes.items[0].notification.comment_id).toBe(
    commentRes.comment_view.comment.id,
  );
});

test("Mention beta from alpha comment", async () => {
  if (!betaCommunity) throw Error("no community");
  const postOnAlphaRes = await createPost(alpha, betaCommunity.community.id);
  // Create a new branch, trunk-level comment branch, from alpha instance
  let commentRes = await createComment(alpha, postOnAlphaRes.post_view.post.id);
  // Create a reply comment to previous comment, this has a mention in body
  let mentionContent = "A test mention of @lemmy_beta@lemmy-beta:8551";
  let mentionRes = await createComment(
    alpha,
    postOnAlphaRes.post_view.post.id,
    commentRes.comment_view.comment.id,
    mentionContent,
  );
  expect(mentionRes.comment_view.comment.content).toBeDefined();
  expect(mentionRes.comment_view.community.local).toBe(false);
  expect(mentionRes.comment_view.creator.local).toBe(true);
  expect(mentionRes.comment_view.comment.score).toBe(1);

  // get beta's localized copy of the alpha post
  let betaPost = await waitForPost(beta, postOnAlphaRes.post_view.post);
  if (!betaPost) {
    throw "unable to locate post on beta";
  }
  expect(betaPost.post.ap_id).toBe(postOnAlphaRes.post_view.post.ap_id);
  expect(betaPost.post.name).toBe(postOnAlphaRes.post_view.post.name);

  // Make sure that both new comments are seen on beta and have parent/child relationship
  let betaPostComments = await waitUntil(
    () => getComments(beta, betaPost!.post.id),
    c => c.items[1]?.comment.score === 1,
  );
  expect(betaPostComments.items.length).toEqual(2);
  // the trunk-branch root comment will be older than the mention reply comment, so index 1
  let betaRootComment = betaPostComments.items[1];
  // the trunk-branch root comment should not have a parent
  expect(getCommentParentId(betaRootComment.comment)).toBeUndefined();
  expect(betaRootComment.comment.content).toBeDefined();
  // the mention reply comment should have parent that points to the branch root level comment
  expect(getCommentParentId(betaPostComments.items[0].comment)).toBe(
    betaPostComments.items[1].comment.id,
  );
  expect(betaRootComment.community.local).toBe(true);
  expect(betaRootComment.creator.local).toBe(false);
  expect(betaRootComment.comment.score).toBe(1);
  assertCommentFederation(betaRootComment, commentRes.comment_view);

  let mentionsRes = await waitUntil(
    () => listNotifications(beta, "mention"),
    m => !!m.items[0],
  );

  const firstMention = mentionsRes.items[0];
  let firstMentionData = firstMention.data as CommentView;
  expect(firstMentionData.comment!.content).toBeDefined();
  expect(firstMentionData.community!.local).toBe(true);
  expect(firstMentionData.creator.local).toBe(false);
  expect(firstMentionData.comment!.score).toBe(1);
  // the reply comment with mention should be the most fresh, newest, index 0
  expect(firstMentionData.comment!.id).toBe(
    betaPostComments.items[0].comment.id,
  );
});

test("Comment Search", async () => {
  let commentRes = await createComment(alpha, postOnAlphaRes.post_view.post.id);
  let betaComment = await resolveComment(beta, commentRes.comment_view.comment);
  assertCommentFederation(betaComment, commentRes.comment_view);
});

test("A and G subscribe to B (center) A posts, G mentions B, it gets announced to A", async () => {
  // Create a local post
  let alphaCommunity = await resolveCommunity(alpha, "!main@lemmy-alpha:8541");
  if (!alphaCommunity) {
    throw "Missing alpha community";
  }

  // follow community from beta so that it accepts the mention
  let betaCommunity = await resolveCommunity(
    beta,
    alphaCommunity.community.ap_id,
  );
  await followCommunity(beta, true, betaCommunity!.community.id);

  let alphaPost = await createPost(alpha, alphaCommunity.community.id);
  expect(alphaPost.post_view.community.local).toBe(true);

  // Make sure gamma sees it
  let gammaPost = await resolvePost(gamma, alphaPost.post_view.post);

  if (!gammaPost) {
    throw "Missing gamma post";
  }

  let commentContent =
    "A jest test federated comment announce, lets mention @lemmy_beta@lemmy-beta:8551";
  let commentRes = await createComment(
    gamma,
    gammaPost.post.id,
    undefined,
    commentContent,
  );
  expect(commentRes.comment_view.comment.content).toBe(commentContent);
  expect(commentRes.comment_view.community.local).toBe(false);
  expect(commentRes.comment_view.creator.local).toBe(true);
  expect(commentRes.comment_view.comment.score).toBe(1);

  // Make sure alpha sees it
  let alphaPostComments2 = await waitUntil(
    () => getComments(alpha, alphaPost.post_view.post.id),
    e => e.items[0]?.comment.score === 1,
  );
  expect(alphaPostComments2.items[0].comment.content).toBe(commentContent);
  expect(alphaPostComments2.items[0].community.local).toBe(true);
  expect(alphaPostComments2.items[0].creator.local).toBe(false);
  expect(alphaPostComments2.items[0].comment.score).toBe(1);
  assertCommentFederation(alphaPostComments2.items[0], commentRes.comment_view);

  // Make sure beta has mentions
  let relevantMention = await waitUntil(
    () =>
      listNotifications(beta, "mention").then(m =>
        m.items.find(m => {
          let data = m.data as CommentView;
          return (
            m.notification.kind == "mention" &&
            data.comment.ap_id === commentRes.comment_view.comment.ap_id
          );
        }),
      ),
    e => !!e,
  );
  if (!relevantMention) throw Error("could not find mention");
  let relevantMentionData = relevantMention.data as CommentView;
  expect(relevantMentionData.comment!.content).toBe(commentContent);
  expect(relevantMentionData.community!.local).toBe(false);
  expect(relevantMentionData.creator.local).toBe(false);
  // TODO this is failing because fetchInReplyTos aren't getting score
  // expect(mentionsRes.mentions[0].score).toBe(1);
});

test("Check that activity from another instance is sent to third instance", async () => {
  // Alpha and gamma users follow beta community
  let alphaFollow = await followBeta(alpha);
  expect(alphaFollow.community_view.community.local).toBe(false);
  expect(alphaFollow.community_view.community.name).toBe("main");

  let gammaFollow = await followBeta(gamma);
  expect(gammaFollow.community_view.community.local).toBe(false);
  expect(gammaFollow.community_view.community.name).toBe("main");
  await waitUntil(
    () => resolveBetaCommunity(alpha),
    c => c?.community_actions?.follow_state === "accepted",
  );
  await waitUntil(
    () => resolveBetaCommunity(gamma),
    c => c?.community_actions?.follow_state === "accepted",
  );

  // Create a post on beta
  let betaPost = await createPost(beta, 2);
  expect(betaPost.post_view.community.local).toBe(true);

  // Make sure gamma and alpha see it
  let gammaPost = await waitForPost(gamma, betaPost.post_view.post);
  if (!gammaPost) {
    throw "Missing gamma post";
  }
  expect(gammaPost.post).toBeDefined();

  let alphaPost = await waitForPost(alpha, betaPost.post_view.post);
  if (!alphaPost) {
    throw "Missing alpha post";
  }
  expect(alphaPost.post).toBeDefined();

  // The bug: gamma comments, and alpha should see it.
  let commentContent = "Comment from gamma";
  let commentRes = await createComment(
    gamma,
    gammaPost.post.id,
    undefined,
    commentContent,
  );
  expect(commentRes.comment_view.comment.content).toBe(commentContent);
  expect(commentRes.comment_view.community.local).toBe(false);
  expect(commentRes.comment_view.creator.local).toBe(true);
  expect(commentRes.comment_view.comment.score).toBe(1);

  // Make sure alpha sees it
  let alphaPostComments2 = await waitUntil(
    () => getComments(alpha, alphaPost!.post.id),
    e => e.items[0]?.comment.score === 1,
  );
  expect(alphaPostComments2.items[0].comment.content).toBe(commentContent);
  expect(alphaPostComments2.items[0].community.local).toBe(false);
  expect(alphaPostComments2.items[0].creator.local).toBe(false);
  expect(alphaPostComments2.items[0].comment.score).toBe(1);
  assertCommentFederation(alphaPostComments2.items[0], commentRes.comment_view);

  await Promise.allSettled([unfollowRemotes(alpha), unfollowRemotes(gamma)]);
});

test("Fetch in_reply_tos: A is unsubbed from B, B makes a post, and some embedded comments, A subs to B, B updates the lowest level comment, A fetches both the post and all the inreplyto comments for that post.", async () => {
  // Unfollow all remote communities
  let my_user = await unfollowRemotes(alpha);
  expect(my_user.follows.filter(c => c.community.local == false).length).toBe(
    0,
  );

  // B creates a post, and two comments, should be invisible to A
  let postOnBetaRes = await createPost(beta, 2);
  expect(postOnBetaRes.post_view.post.name).toBeDefined();

  let parentCommentContent = "An invisible top level comment from beta";
  let parentCommentRes = await createComment(
    beta,
    postOnBetaRes.post_view.post.id,
    undefined,
    parentCommentContent,
  );
  expect(parentCommentRes.comment_view.comment.content).toBe(
    parentCommentContent,
  );

  // B creates a comment, then a child one of that.
  let childCommentContent = "An invisible child comment from beta";
  let childCommentRes = await createComment(
    beta,
    postOnBetaRes.post_view.post.id,
    parentCommentRes.comment_view.comment.id,
    childCommentContent,
  );
  expect(childCommentRes.comment_view.comment.content).toBe(
    childCommentContent,
  );

  // Follow beta again
  let follow = await followBeta(alpha);
  expect(follow.community_view.community.local).toBe(false);
  expect(follow.community_view.community.name).toBe("main");

  // An update to the child comment on beta, should push the post, parent, and child to alpha now
  let updatedCommentContent = "An update child comment from beta";
  let updateRes = await editComment(
    beta,
    childCommentRes.comment_view.comment.id,
    updatedCommentContent,
  );
  expect(updateRes.comment_view.comment.content).toBe(updatedCommentContent);

  // Get the post from alpha
  let alphaPostB = await waitForPost(alpha, postOnBetaRes.post_view.post);

  if (!alphaPostB) {
    throw "Missing alpha post B";
  }

  let alphaPost = await getPost(alpha, alphaPostB.post.id);
  let alphaPostComments = await waitUntil(
    () => getComments(alpha, alphaPostB!.post.id),
    c =>
      c.items[1]?.comment.content ===
        parentCommentRes.comment_view.comment.content &&
      c.items[0]?.comment.content === updateRes.comment_view.comment.content,
  );
  expect(alphaPost.post_view.post.name).toBeDefined();
  assertCommentFederation(
    alphaPostComments.items[1],
    parentCommentRes.comment_view,
  );
  assertCommentFederation(alphaPostComments.items[0], updateRes.comment_view);
  expect(alphaPost.post_view.community.local).toBe(false);
  expect(alphaPost.post_view.creator.local).toBe(false);

  await unfollowRemotes(alpha);
});

test("Report a comment", async () => {
  let betaCommunity = await resolveBetaCommunity(beta);
  if (!betaCommunity) {
    throw "Missing beta community";
  }
  let postOnBetaRes = (await createPost(beta, betaCommunity.community.id))
    .post_view.post;
  expect(postOnBetaRes).toBeDefined();
  let commentRes = (await createComment(beta, postOnBetaRes.id)).comment_view
    .comment;
  expect(commentRes).toBeDefined();

  let alphaComment = await resolveComment(alpha, commentRes);
  if (!alphaComment) {
    throw "Missing alpha comment";
  }

  const reason = randomString(10);
  let alphaReport = (
    await reportComment(alpha, alphaComment.comment.id, reason)
  ).comment_report_view.comment_report;

  let betaReport = (
    (await waitUntil(
      () =>
        listReports(beta).then(p =>
          p.items.find(r => {
            return checkCommentReportReason(r, reason);
          }),
        ),
      e => !!e,
    )!) as CommentReportView
  ).comment_report;
  expect(betaReport).toBeDefined();
  expect(betaReport.resolved).toBe(false);
  expect(betaReport.original_comment_text).toBe(
    alphaReport.original_comment_text,
  );
  expect(betaReport.reason).toBe(alphaReport.reason);
});

test("Dont send a comment reply to a blocked community", async () => {
  await beta.markAllNotificationsAsRead();
  let newCommunity = await createCommunity(beta);
  let newCommunityId = newCommunity.community_view.community.id;

  // Create a post on beta
  let betaPost = await createPost(beta, newCommunityId);

  let alphaPost = await resolvePost(alpha, betaPost.post_view.post);
  if (!alphaPost) {
    throw "unable to locate post on alpha";
  }

  // Check beta's inbox count
  let unreadCount = await getUnreadCounts(beta);
  expect(unreadCount.notification_count).toBe(0);

  // Beta blocks the new beta community
  let blockRes = await blockCommunity(beta, newCommunityId, true);
  expect(blockRes.community_view.community_actions?.blocked_at).toBeDefined();

  // Alpha creates a comment
  let commentRes = await createComment(alpha, alphaPost.post.id);
  expect(commentRes.comment_view.comment.content).toBeDefined();
  let alphaComment = await resolveComment(
    beta,
    commentRes.comment_view.comment,
  );
  if (!alphaComment) {
    throw "Missing alpha comment before block";
  }

  // Check beta's inbox count, make sure it stays the same
  unreadCount = await getUnreadCounts(beta);
  expect(unreadCount.notification_count).toBe(0);

  let replies = await listNotifications(beta, "reply", true);
  expect(replies.items.length).toBe(0);

  // Unblock the community
  blockRes = await blockCommunity(beta, newCommunityId, false);
  expect(blockRes.community_view.community_actions?.blocked_at).toBeUndefined();
});

/// Fetching a deeply nested comment can lead to stack overflow as all parent comments are also
/// fetched recursively. Ensure that it works properly.
test("Fetch a deeply nested comment", async () => {
  const alphaCommunity = await resolveCommunity(
    alpha,
    "!main@lemmy-alpha:8541",
  );
  if (!alphaCommunity) {
    throw "Missing alpha community";
  }
  const postOnAlphaRes = await createPost(alpha, alphaCommunity.community.id);
  let lastComment;
  for (let i = 1; i < 50; i++) {
    let commentRes = await createComment(
      alpha,
      postOnAlphaRes.post_view.post.id,
      lastComment?.comment_view.comment.id,
    );
    expect(commentRes.comment_view.comment).toBeDefined();
    lastComment = commentRes;
  }

  let betaComment = await resolveComment(
    beta,
    lastComment!.comment_view.comment,
  );

  expect(betaComment?.comment).toBeDefined();
  expect(betaComment?.post).toBeDefined();
});

test("Distinguish comment", async () => {
  const community = (await resolveBetaCommunity(beta))?.community;
  let post = await createPost(beta, community!.id);
  let commentRes = await createComment(beta, post.post_view.post.id);
  const form: DistinguishComment = {
    comment_id: commentRes.comment_view.comment.id,
    distinguished: true,
  };
  await beta.distinguishComment(form);

  let alphaPost = await resolvePost(alpha, post.post_view.post);

  // Find the comment on alpha (home of community)
  let alphaComments = await waitUntil(
    () => getComments(alpha, alphaPost?.post.id),
    c => c.items[0].comment.distinguished,
  );

  assertCommentFederation(alphaComments.items[0], commentRes.comment_view);
});

test("Lock comment", async () => {
  let newBetaApi = await registerUser(beta, betaUrl);

  const alphaCommunity = await resolveCommunity(
    alpha,
    "!main@lemmy-alpha:8541",
  );
  if (!alphaCommunity) {
    throw "Missing alpha community";
  }

  let post = await createPost(alpha, alphaCommunity.community.id);
  let betaPost = await resolvePost(beta, post.post_view.post);

  if (!betaPost) {
    throw "unable to locate post on beta";
  }

  // Create a comment hierarchy like this:
  // 1
  // | \
  // 2  4
  // |
  // 3

  let comment1 = await createComment(alpha, post.post_view.post.id);
  let betaComment1 = await resolveComment(beta, comment1.comment_view.comment);
  if (!betaComment1) {
    throw "unable to locate comment on beta";
  }
  await followCommunity(newBetaApi, true, betaComment1!.community.id);

  let comment2 = await createComment(
    alpha,
    post.post_view.post.id,
    comment1.comment_view.comment.id,
  );
  let betaComment2 = await resolveComment(beta, comment2.comment_view.comment);
  if (!betaComment2) {
    throw "unable to locate comment on beta";
  }
  let comment3 = await createComment(
    newBetaApi,
    betaPost.post.id,
    betaComment2.comment.id,
  );

  // Lock comment2 and wait for it to federate
  await lockComment(alpha, true, comment2.comment_view.comment);

  const comment_ap_id = comment3.comment_view.comment.ap_id;
  await waitUntil(
    () => getComments(newBetaApi, betaPost.post.id),
    c => {
      const find = c.items.find(c => c.comment.ap_id == comment_ap_id);
      return find?.comment.locked ?? false;
    },
  );

  // Make sure newBeta can't respond to comment3
  await jestLemmyError(
    () =>
      createComment(
        newBetaApi,
        betaPost.post.id,
        comment3.comment_view.comment.id,
      ),
    new LemmyError("locked", statusBadRequest),
  );

  // newBeta should still be able to respond to comment1
  expect(
    await createComment(newBetaApi, betaPost.post.id, betaComment1.comment.id),
  ).toBeDefined();
});

test("Remove children", async () => {
  const alphaCommunity = await resolveCommunity(
    alpha,
    "!main@lemmy-alpha:8541",
  );
  if (!alphaCommunity) {
    throw "Missing alpha community";
  }

  let post = await createPost(alpha, alphaCommunity.community.id);
  let betaPost = await resolvePost(beta, post.post_view.post);

  if (!betaPost) {
    throw "unable to locate post on beta";
  }
  await followCommunity(beta, true, betaPost.community.id);

  let comment1 = await createComment(beta, betaPost.post.id);
  let comment2 = await createComment(
    beta,
    betaPost.post.id,
    comment1.comment_view.comment.id,
  );
  await createComment(beta, betaPost.post.id, comment2.comment_view.comment.id);
  await createComment(beta, betaPost.post.id, comment1.comment_view.comment.id);

  // Wait until the comments have federated
  await waitUntil(
    () => getPost(alpha, post.post_view.post.id),
    p => p.post_view.post.comments == 4,
  );

  let commentOnAlpha = await resolveComment(
    alpha,
    comment1.comment_view.comment,
  );
  if (!commentOnAlpha) {
    throw "unable to locate comment on alpha";
  }

  await removeComment(alpha, true, commentOnAlpha.comment.id, true);

  let post2 = await getPost(alpha, post.post_view.post.id);
  expect(post2.post_view.post.comments).toBe(0);

  // Wait until the remove has federated
  await waitUntil(
    () => getComment(beta, comment1.comment_view.comment.id),
    c => c.comment_view.comment.removed,
  );

  // Make sure removal federates properly
  let betaPost2 = await resolvePost(beta, post.post_view.post);
  if (!betaPost2) {
    throw "unable to locate post on beta";
  }
  expect(betaPost2.post.comments).toBe(0);
});

function checkCommentReportReason(rcv: ReportCombinedView, reason: string) {
  switch (rcv.type_) {
    case "comment":
      return rcv.comment_report.reason === reason;
    default:
      return false;
  }
}


================================================
FILE: api_tests/src/community.spec.ts
================================================
jest.setTimeout(120000);

import { AddModToCommunity } from "lemmy-js-client/dist/types/AddModToCommunity";
import {
  alpha,
  beta,
  gamma,
  setupLogins,
  resolveCommunity,
  createCommunity,
  deleteCommunity,
  removeCommunity,
  getCommunity,
  followCommunity,
  banPersonFromCommunity,
  resolvePerson,
  createPost,
  getPost,
  resolvePost,
  registerUser,
  getPosts,
  getComments,
  createComment,
  getCommunityByName,
  waitUntil,
  alphaUrl,
  delta,
  editCommunity,
  unfollows,
  getMyUser,
  userBlockInstanceCommunities,
  resolveBetaCommunity,
  reportCommunity,
  randomString,
  assertCommunityFederation,
  listReports,
  statusBadRequest,
  jestLemmyError,
} from "./shared";
import { AdminAllowInstanceParams } from "lemmy-js-client/dist/types/AdminAllowInstanceParams";
import {
  CommunityReport,
  CommunityReportView,
  EditCommunity,
  FollowMultiCommunity,
  GetPosts,
  LemmyError,
  MultiCommunityView,
  ReportCombinedView,
  ResolveCommunityReport,
  Search,
} from "lemmy-js-client";

beforeAll(setupLogins);
afterAll(unfollows);

test("Create community", async () => {
  let communityRes = await createCommunity(alpha);
  expect(communityRes.community_view.community.name).toBeDefined();

  // A dupe check
  let prevName = communityRes.community_view.community.name;
  await jestLemmyError(
    () => createCommunity(alpha, prevName),
    new LemmyError("already_exists", statusBadRequest),
  );

  // Cache the community on beta, make sure it has the other fields
  let searchShort = `!${prevName}@lemmy-alpha:8541`;
  let betaCommunity = await resolveCommunity(beta, searchShort);
  assertCommunityFederation(betaCommunity, communityRes.community_view);
});

test("Delete community", async () => {
  let communityRes = await createCommunity(beta);

  // Cache the community on Alpha
  let searchShort = `!${communityRes.community_view.community.name}@lemmy-beta:8551`;
  let alphaCommunity = await resolveCommunity(alpha, searchShort);
  if (!alphaCommunity) {
    throw "Missing alpha community";
  }
  assertCommunityFederation(alphaCommunity, communityRes.community_view);

  // Follow the community from alpha
  let follow = await followCommunity(alpha, true, alphaCommunity.community.id);

  // Make sure the follow response went through
  expect(follow.community_view.community.local).toBe(false);

  let deleteCommunityRes = await deleteCommunity(
    beta,
    true,
    communityRes.community_view.community.id,
  );
  expect(deleteCommunityRes.community_view.community.deleted).toBe(true);
  expect(deleteCommunityRes.community_view.community.title).toBe(
    communityRes.community_view.community.title,
  );

  // Make sure it got deleted on A
  let communityOnAlphaDeleted = await waitUntil(
    () => getCommunity(alpha, alphaCommunity!.community.id),
    g => g.community_view.community.deleted,
  );
  expect(communityOnAlphaDeleted.community_view.community.deleted).toBe(true);

  // Undelete
  let undeleteCommunityRes = await deleteCommunity(
    beta,
    false,
    communityRes.community_view.community.id,
  );
  expect(undeleteCommunityRes.community_view.community.deleted).toBe(false);

  // Make sure it got undeleted on A
  let communityOnAlphaUnDeleted = await waitUntil(
    () => getCommunity(alpha, alphaCommunity!.community.id),
    g => !g.community_view.community.deleted,
  );
  expect(communityOnAlphaUnDeleted.community_view.community.deleted).toBe(
    false,
  );
});

test("Remove community", async () => {
  let communityRes = await createCommunity(beta);

  // Cache the community on Alpha
  let searchShort = `!${communityRes.community_view.community.name}@lemmy-beta:8551`;
  let alphaCommunity = await resolveCommunity(alpha, searchShort);
  if (!alphaCommunity) {
    throw "Missing alpha community";
  }
  assertCommunityFederation(alphaCommunity, communityRes.community_view);

  // Follow the community from alpha
  let follow = await followCommunity(alpha, true, alphaCommunity.community.id);

  // Make sure the follow response went through
  expect(follow.community_view.community.local).toBe(false);

  let removeCommunityRes = await removeCommunity(
    beta,
    true,
    communityRes.community_view.community.id,
  );
  expect(removeCommunityRes.community_view.community.removed).toBe(true);
  expect(removeCommunityRes.community_view.community.title).toBe(
    communityRes.community_view.community.title,
  );

  // Make sure it got Removed on A
  let communityOnAlphaRemoved = await waitUntil(
    () => getCommunity(alpha, alphaCommunity!.community.id),
    g => g.community_view.community.removed,
  );
  expect(communityOnAlphaRemoved.community_view.community.removed).toBe(true);

  // unremove
  let unremoveCommunityRes = await removeCommunity(
    beta,
    false,
    communityRes.community_view.community.id,
  );
  expect(unremoveCommunityRes.community_view.community.removed).toBe(false);

  // Make sure it got undeleted on A
  let communityOnAlphaUnRemoved = await waitUntil(
    () => getCommunity(alpha, alphaCommunity!.community.id),
    g => !g.community_view.community.removed,
  );
  expect(communityOnAlphaUnRemoved.community_view.community.removed).toBe(
    false,
  );
});

test("Report a community", async () => {
  // Create community on alpha
  let alphaCommunity = await createCommunity(alpha);
  expect(alphaCommunity.community_view.community).toBeDefined();

  // Send report from beta
  let betaCommunity = await resolveCommunity(
    beta,
    alphaCommunity.community_view.community.ap_id,
  );
  let betaReport = (
    await reportCommunity(beta, betaCommunity!.community.id, randomString(10))
  ).community_report_view.community_report;
  expect(betaReport).toBeDefined();

  // Report was federated to alpha
  let alphaReport = (
    (await waitUntil(
      () =>
        listReports(alpha).then(p =>
          p.items.find(r => {
            return checkCommunityReportName(r, betaReport);
          }),
        ),
      res => !!res,
    ))! as CommunityReportView
  ).community_report;
  expect(alphaReport).toBeDefined();
  expect(alphaReport.resolved).toBe(false);
  expect(alphaReport.original_community_name).toBe(
    betaReport.original_community_name,
  );
  expect(alphaReport.original_community_title).toBe(
    betaReport.original_community_title,
  );
  expect(alphaReport.original_community_banner).toBe(
    betaReport.original_community_banner,
  );
  expect(alphaReport.original_community_sidebar).toBe(
    betaReport.original_community_sidebar,
  );
  expect(alphaReport.original_community_icon).toBe(
    betaReport.original_community_icon,
  );
  expect(alphaReport.original_community_sidebar).toBe(
    betaReport.original_community_sidebar,
  );
  expect(alphaReport.reason).toBe(betaReport.reason);

  // Resolve report as admin of the community's instance
  let resolveParams: ResolveCommunityReport = {
    report_id: alphaReport.id,
    resolved: true,
  };
  let resolve = await alpha.resolveCommunityReport(resolveParams);
  expect(resolve.community_report_view.community_report.resolved).toBeTruthy();

  // Report should be marked resolved on reporter's instance
  let resolvedReport = (
    (await waitUntil(
      () =>
        listReports(beta).then(p =>
          p.items.find(r => {
            return (
              checkCommunityReportName(r, alphaReport) && r.resolver != null
            );
          }),
        ),
      res => !!res,
    ))! as CommunityReportView
  ).community_report;
  expect(resolvedReport).toBeDefined();
  expect(resolvedReport.resolved).toBe(true);
});

test("Search for beta community", async () => {
  let communityRes = await createCommunity(beta);
  expect(communityRes.community_view.community.name).toBeDefined();

  let searchShort = `!${communityRes.community_view.community.name}@lemmy-beta:8551`;
  let alphaCommunity = await resolveCommunity(alpha, searchShort);
  assertCommunityFederation(alphaCommunity, communityRes.community_view);
});

test("Admin actions in remote community are not federated to origin", async () => {
  // create a community on alpha
  let communityRes = (await createCommunity(alpha)).community_view;
  expect(communityRes.community.name).toBeDefined();

  // gamma follows community and posts in it
  let gammaCommunity = await resolveCommunity(
    gamma,
    communityRes.community.ap_id,
  );
  if (!gammaCommunity) {
    throw "Missing gamma community";
  }
  await followCommunity(gamma, true, gammaCommunity.community.id);
  gammaCommunity = await waitUntil(
    () => resolveCommunity(gamma, communityRes.community.ap_id),
    g => g?.community_actions?.follow_state == "accepted",
  );
  if (!gammaCommunity) {
    throw "Missing gamma community";
  }
  expect(gammaCommunity.community_actions?.follow_state).toBe("accepted");
  let gammaPost = (await createPost(gamma, gammaCommunity.community.id))
    .post_view;
  expect(gammaPost.post.id).toBeDefined();
  expect(gammaPost.creator_banned_from_community).toBe(false);

  // admin of beta decides to ban gamma from community
  let betaCommunity = await resolveCommunity(
    beta,
    communityRes.community.ap_id,
  );
  if (!betaCommunity) {
    throw "Missing beta community";
  }
  let bannedUserInfo1 = (await getMyUser(gamma)).local_user_view.person;
  if (!bannedUserInfo1) {
    throw "Missing banned user 1";
  }
  let bannedUserInfo2 = await resolvePerson(beta, bannedUserInfo1.ap_id);

  if (!bannedUserInfo2) {
    throw "Missing banned user 2";
  }
  let banRes = await banPersonFromCommunity(
    beta,
    bannedUserInfo2.person.id,
    betaCommunity.community.id,
    true,
    true,
  );
  expect(banRes).toBeDefined();

  // ban doesn't federate to community's origin instance alpha
  let alphaPost = await resolvePost(alpha, gammaPost.post);
  expect(alphaPost?.creator_banned_from_community).toBe(false);

  // and neither to gamma
  let gammaPost2 = await getPost(gamma, gammaPost.post.id);
  expect(gammaPost2.post_view.creator_banned_from_community).toBe(false);
});

test("moderator view", async () => {
  // register a new user with their own community on alpha and post to it
  let otherUser = await registerUser(alpha, alphaUrl);

  let otherCommunity = (await createCommunity(otherUser)).community_view;
  expect(otherCommunity.community.name).toBeDefined();
  let otherPost = (await createPost(otherUser, otherCommunity.community.id))
    .post_view;
  expect(otherPost.post.id).toBeDefined();

  let otherComment = (await createComment(otherUser, otherPost.post.id))
    .comment_view;
  expect(otherComment.comment.id).toBeDefined();

  // create a community and post on alpha
  let alphaCommunity = (await createCommunity(alpha)).community_view;
  expect(alphaCommunity.community.name).toBeDefined();
  let alphaPost = (await createPost(alpha, alphaCommunity.community.id))
    .post_view;
  expect(alphaPost.post.id).toBeDefined();

  let alphaComment = (await createComment(otherUser, alphaPost.post.id))
    .comment_view;
  expect(alphaComment.comment.id).toBeDefined();

  // other user also posts on alpha's community
  let otherAlphaPost = (
    await createPost(otherUser, alphaCommunity.community.id)
  ).post_view;
  expect(otherAlphaPost.post.id).toBeDefined();

  let otherAlphaComment = (
    await createComment(otherUser, otherAlphaPost.post.id)
  ).comment_view;
  expect(otherAlphaComment.comment.id).toBeDefined();

  // alpha lists posts and comments on home page, should contain all posts that were made
  let posts = (await getPosts(alpha, "all")).items;
  expect(posts).toBeDefined();
  let postIds = posts.map(post => post.post.id);

  let comments = (await getComments(alpha, undefined, "all")).items;
  expect(comments).toBeDefined();
  let commentIds = comments.map(comment => comment.comment.id);

  expect(postIds).toContain(otherPost.post.id);
  expect(commentIds).toContain(otherComment.comment.id);

  expect(postIds).toContain(alphaPost.post.id);
  expect(commentIds).toContain(alphaComment.comment.id);

  expect(postIds).toContain(otherAlphaPost.post.id);
  expect(commentIds).toContain(otherAlphaComment.comment.id);

  // in moderator view, alpha should not see otherPost, wich was posted on a community alpha doesn't moderate
  posts = (await getPosts(alpha, "moderator_view")).items;
  expect(posts).toBeDefined();
  postIds = posts.map(post => post.post.id);

  comments = (await getComments(alpha, undefined, "moderator_view")).items;
  expect(comments).toBeDefined();
  commentIds = comments.map(comment => comment.comment.id);

  expect(postIds).not.toContain(otherPost.post.id);
  expect(commentIds).not.toContain(otherComment.comment.id);

  expect(postIds).toContain(alphaPost.post.id);
  expect(commentIds).toContain(alphaComment.comment.id);

  expect(postIds).toContain(otherAlphaPost.post.id);
  expect(commentIds).toContain(otherAlphaComment.comment.id);
});

test("Get community for different casing on domain", async () => {
  let communityRes = await createCommunity(alpha);
  expect(communityRes.community_view.community.name).toBeDefined();

  // A dupe check
  let prevName = communityRes.community_view.community.name;
  await jestLemmyError(
    () => createCommunity(alpha, prevName),
    new LemmyError("already_exists", statusBadRequest),
  );

  // Cache the community on beta, make sure it has the other fields
  let communityName = `${communityRes.community_view.community.name}@LEMMY-ALPHA:8541`;
  let betaCommunity = (await getCommunityByName(beta, communityName))
    .community_view;
  assertCommunityFederation(betaCommunity, communityRes.community_view);
});

test("User blocks instance, communities are hidden", async () => {
  // create community and post on beta
  let communityRes = await createCommunity(beta);
  expect(communityRes.community_view.community.name).toBeDefined();
  let postRes = await createPost(
    beta,
    communityRes.community_view.community.id,
  );
  expect(postRes.post_view.post.id).toBeDefined();

  // fetch post to alpha
  let alphaPost = await resolvePost(alpha, postRes.post_view.post);
  expect(alphaPost?.post).toBeDefined();

  // post should be included in listing
  let listing = await getPosts(alpha, "all");
  let listing_ids = listing.items.map(p => p.post.ap_id);
  expect(listing_ids).toContain(postRes.post_view.post.ap_id);

  // block the beta instance
  await userBlockInstanceCommunities(
    alpha,
    alphaPost!.community.instance_id,
    true,
  );

  // after blocking, post should not be in listing
  let listing2 = await getPosts(alpha, "all");
  let listing_ids2 = listing2.items.map(p => p.post.ap_id);
  expect(listing_ids2.indexOf(postRes.post_view.post.ap_id)).toBe(-1);

  // unblock instance again
  await userBlockInstanceCommunities(
    alpha,
    alphaPost!.community.instance_id,
    false,
  );

  // post should be included in listing
  let listing3 = await getPosts(alpha, "all");
  let listing_ids3 = listing3.items.map(p => p.post.ap_id);
  expect(listing_ids3).toContain(postRes.post_view.post.ap_id);
});

// TODO: this test keeps failing randomly in CI
test.skip("Community follower count is federated", async () => {
  // Follow the beta community from alpha
  let community = await createCommunity(beta);
  let communityActorId = community.community_view.community.ap_id;
  let resolved = await resolveCommunity(alpha, communityActorId);
  if (!resolved?.community) {
    throw "Missing beta community";
  }

  await followCommunity(alpha, true, resolved.community.id);
  let followed = await waitUntil(
    () => resolveCommunity(alpha, communityActorId),
    c => c?.community_actions?.follow_state == "accepted",
  );

  // Make sure there is 1 subscriber
  expect(followed?.community.subscribers).toBe(1);

  // Follow the community from gamma
  resolved = await resolveCommunity(gamma, communityActorId);
  if (!resolved?.community) {
    throw "Missing beta community";
  }

  await followCommunity(gamma, true, resolved.community.id);
  followed = await waitUntil(
    () => resolveCommunity(gamma, communityActorId),
    c => c?.community_actions?.follow_state == "accepted",
  );

  // Make sure there are 2 subscribers
  expect(followed?.community?.subscribers).toBe(2);

  // Follow the community from delta
  resolved = await resolveCommunity(delta, communityActorId);
  if (!resolved?.community) {
    throw "Missing beta community";
  }

  await followCommunity(delta, true, resolved.community.id);
  followed = await waitUntil(
    () => resolveCommunity(delta, communityActorId),
    c => c?.community_actions?.follow_state == "accepted",
  );
});

test("Dont receive community activities after unsubscribe", async () => {
  let communityRes = await createCommunity(alpha);
  expect(communityRes.community_view.community.name).toBeDefined();
  expect(communityRes.community_view.community.subscribers).toBe(1);

  let betaCommunity = await resolveCommunity(
    beta,
    communityRes.community_view.community.ap_id,
  );
  assertCommunityFederation(betaCommunity, communityRes.community_view);

  // follow alpha community from beta
  await followCommunity(beta, true, betaCommunity!.community.id);

  // ensure that follower count was updated
  let communityRes1 = await getCommunity(
    alpha,
    communityRes.community_view.community.id,
  );
  expect(communityRes1.community_view.community.subscribers).toBe(2);

  // temporarily block alpha, so that it doesn't know about unfollow
  let allow_instance_params: AdminAllowInstanceParams = {
    instance: "lemmy-alpha",
    allow: false,
    reason: "allow",
  };
  await beta.adminAllowInstance(allow_instance_params);

  // unfollow
  await followCommunity(beta, false, betaCommunity!.community.id);

  // ensure that alpha still sees beta as follower
  let communityRes2 = await getCommunity(
    alpha,
    communityRes.community_view.community.id,
  );
  expect(communityRes2.community_view.community.subscribers).toBe(2);

  // unblock alpha
  allow_instance_params.allow = true;
  await beta.adminAllowInstance(allow_instance_params);

  // create a post, it shouldnt reach beta
  let postRes = await createPost(
    alpha,
    communityRes.community_view.community.id,
  );
  expect(postRes.post_view.post.id).toBeDefined();
  // await longDelay();

  let form: Search = {
    q: postRes.post_view.post.name,
    type_: "posts",
    listing_type: "all",
  };

  let res = await beta.search(form);
  expect(res.search.length).toBe(0);
});

test("Fetch community, includes posts", async () => {
  let communityRes = await createCommunity(alpha);
  expect(communityRes.community_view.community.name).toBeDefined();
  expect(communityRes.community_view.community.subscribers).toBe(1);

  let postRes = await createPost(
    alpha,
    communityRes.community_view.community.id,
  );
  expect(postRes.post_view.post).toBeDefined();

  let resolvedCommunity = await waitUntil(
    () => resolveCommunity(beta, communityRes.community_view.community.ap_id),
    c => c?.community.id != undefined,
  );
  let betaCommunity = resolvedCommunity;
  expect(betaCommunity?.community.ap_id).toBe(
    communityRes.community_view.community.ap_id,
  );

  let post_listing = await waitUntil(
    () => getPosts(beta, "all", betaCommunity?.community.id),
    p => p.items.length == 1,
  );
  expect(post_listing.items[0].post.ap_id).toBe(postRes.post_view.post.ap_id);
});

test("Content in local-only community doesn't federate", async () => {
  // create a community and set it local-only
  let communityRes = (await createCommunity(alpha)).community_view.community;
  let form: EditCommunity = {
    community_id: communityRes.id,
    visibility: "local_only_public",
  };
  await editCommunity(alpha, form);

  // cant resolve the community from another instance
  await jestLemmyError(
    () => resolveCommunity(beta, communityRes.ap_id),
    new LemmyError("resolve_object_failed", statusBadRequest),
    false,
  );

  // create a post, also cant resolve it
  let postRes = await createPost(alpha, communityRes.id);
  await jestLemmyError(
    () => resolvePost(beta, postRes.post_view.post),
    new LemmyError("resolve_object_failed", statusBadRequest),
    false,
  );
});

test("Remote mods can edit communities", async () => {
  let communityRes = await createCommunity(alpha);

  let betaCommunity = await resolveCommunity(
    beta,
    communityRes.community_view.community.ap_id,
  );
  if (!betaCommunity?.community) {
    throw "Missing beta community";
  }
  let betaOnAlpha = await resolvePerson(alpha, "lemmy_beta@lemmy-beta:8551");

  let form: AddModToCommunity = {
    community_id: communityRes.community_view.community.id,
    person_id: betaOnAlpha?.person.id as number,
    added: true,
  };
  alpha.addModToCommunity(form);

  let form2: EditCommunity = {
    community_id: betaCommunity.community.id as number,
    sidebar: "Example sidebar",
  };

  await editCommunity(beta, form2);

  const communityId = communityRes.community_view.community.id;
  await waitUntil(
    () => getCommunity(alpha, communityId),
    c => c.community_view.community.sidebar == "Example sidebar",
  );
});

test("Remote mods can add mods", async () => {
  let alphaCommunity = await createCommunity(alpha);

  let betaCommunity = await resolveCommunity(
    beta,
    alphaCommunity.community_view.community.ap_id,
  );
  if (!betaCommunity?.community) {
    throw "Missing beta community";
  }
  let betaOnAlpha = await resolvePerson(alpha, "lemmy_beta@lemmy-beta:8551");
  let gammaOnBeta = await resolvePerson(beta, "lemmy_gamma@lemmy-gamma:8561");

  // Follow so we get activities
  await followCommunity(beta, true, betaCommunity.community.id);

  let form: AddModToCommunity = {
    community_id: alphaCommunity.community_view.community.id,
    person_id: betaOnAlpha?.person.id as number,
    added: true,
  };
  await alpha.addModToCommunity(form);

  await waitUntil(
    () => getCommunity(beta, betaCommunity.community.id),
    c => c.moderators.length == 2,
  );

  let form2: AddModToCommunity = {
    community_id: betaCommunity.community.id,
    person_id: gammaOnBeta?.person.id as number,
    added: true,
  };
  await beta.addModToCommunity(form2);

  await waitUntil(
    () => getCommunity(beta, betaCommunity.community.id),
    c => c.moderators.length == 3,
  );

  await waitUntil(
    () => getCommunity(alpha, alphaCommunity.community_view.community.id),
    c => c.moderators.length == 3,
  );
});

test("Community name with non-ascii chars", async () => {
  const name = "това_ме_ядосва" + Math.random().toString().slice(2, 6);
  let communityRes = await createCommunity(alpha, name);

  let betaCommunity1 = await resolveCommunity(
    beta,
    communityRes.community_view.community.ap_id,
  );
  expect(betaCommunity1?.community.name).toBe(name);

  let alphaCommunity2 = await getCommunityByName(alpha, name);
  expect(alphaCommunity2.community_view.community.name).toBe(name);

  let fediName = `${communityRes.community_view.community.name}@LEMMY-ALPHA:8541`;
  let betaCommunity2 = await getCommunityByName(beta, fediName);
  expect(betaCommunity2.community_view.community.name).toBe(name);

  let postRes = await createPost(beta, betaCommunity1!.community.id);

  let form: GetPosts = {
    community_name: fediName,
  };
  let posts = await beta.getPosts(form);
  expect(posts.items.length).toBe(1);
  expect(posts.items[0].post.name).toBe(postRes.post_view.post.name);
});

test("Multi-community", async () => {
  // create multi
  const multiName = randomString(10);
  let res = await alpha.createMultiCommunity({ name: multiName });
  let myUser = await getMyUser(alpha);
  expect(res.multi_community_view.multi.name).toBe(multiName);
  expect(res.multi_community_view.multi.ap_id).toBe(
    `http://lemmy-alpha:8541/m/${multiName}`,
  );
  expect(res.multi_community_view.owner.id).toBe(
    myUser.local_user_view.person.id,
  );

  // add initial community
  let community1 = (await createCommunity(alpha)).community_view.community;
  let entryRes = await alpha.createMultiCommunityEntry({
    id: res.multi_community_view.multi.id,
    community_id: community1.id,
  });
  expect(entryRes.community_view.community.id).toBe(community1.id);

  // resolve over federation
  let betaMulti = (
    await beta.resolveObject({ q: res.multi_community_view.multi.ap_id })
  ).resolve as MultiCommunityView;
  expect(betaMulti.multi.ap_id).toBe(res.multi_community_view.multi.ap_id);

  // follow multi over federation
  let form: FollowMultiCommunity = {
    multi_community_id: betaMulti.multi.id,
    follow: true,
  };
  await beta.followMultiCommunity(form);

  let betaRes = await waitUntil(
    () => beta.getMultiCommunity({ id: betaMulti.multi.id }),
    m => m.communities.length >= 1,
  );
  expect(betaRes.communities[0].community.ap_id).toBe(community1.ap_id);

  let followed = await waitUntil(
    () => beta.listMultiCommunities({}),
    m => m.items.length >= 1,
  );
  expect(followed.items[0].multi.ap_id).toBe(betaMulti.multi.ap_id);

  // add community to multi
  let community2 = await waitUntil(
    () => resolveBetaCommunity(alpha),
    c => !!c?.community.instance_id,
  );
  if (!community2) {
    throw "Missing beta community";
  }

  let entryRes2 = await alpha.createMultiCommunityEntry({
    id: res.multi_community_view.multi.id,
    community_id: community2!.community.id,
  });
  expect(entryRes2.community_view.community.id).toBe(community2.community.id);

  // federated to beta
  betaRes = await waitUntil(
    () => beta.getMultiCommunity({ id: betaMulti.multi.id }),
    m => m.communities.length >= 2,
  );
  let ap_ids = betaRes.communities.map(c => c.community.ap_id);
  expect(ap_ids.includes(community2!.community.ap_id)).toBeTruthy();

  let post = await createPost(alpha, community2!.community.id);

  await waitUntil(
    () =>
      beta.getPosts({
        multi_community_id: betaRes.multi_community_view.multi.id,
      }),
    p => p.items.map(p => p.post.ap_id).includes(post.post_view.post.ap_id),
  );
});

test("Mark existing community as local-only, ensure it federates", async () => {
  let communityRes = await createCommunity(alpha);
  expect(communityRes.community_view.community.name).toBeDefined();

  let community = communityRes.community_view.community;

  let betaCommunity = await resolveCommunity(beta, community.ap_id);
  assertCommunityFederation(betaCommunity, communityRes.community_view);

  await followCommunity(beta, true, betaCommunity!.community.id);
  await waitUntil(
    () => getCommunity(beta, betaCommunity!.community.id),
    g => g?.community_view.community_actions?.follow_state == "accepted",
  );

  let res = await editCommunity(alpha, {
    community_id: community.id,
    visibility: "local_only_private",
  });
  expect(res.community_view.community.visibility).toBe("local_only_private");

  await waitUntil(
    () => getCommunity(beta, betaCommunity!.community.id),
    g => g?.community_view.community?.deleted,
  );

  let res2 = await editCommunity(alpha, {
    community_id: community.id,
    visibility: "public",
  });
  expect(res2.community_view.community.visibility).toBe("public");

  await waitUntil(
    () => getCommunity(beta, betaCommunity!.community.id),
    g => !g?.community_view.community?.deleted,
  );
});

function checkCommunityReportName(
  rcv: ReportCombinedView,
  report: CommunityReport,
) {
  switch (rcv.type_) {
    case "community":
      return (
        rcv.community_report.original_community_name ===
        report.original_community_name
      );
    default:
      return false;
  }
}


================================================
FILE: api_tests/src/follow.spec.ts
================================================
jest.setTimeout(120000);

import {
  alpha,
  setupLogins,
  resolveBetaCommunity,
  followCommunity,
  waitUntil,
  beta,
  betaUrl,
  registerUser,
  unfollows,
  getMyUser,
  alphaUrl,
} from "./shared";

beforeAll(setupLogins);

afterAll(unfollows);

test("Follow local community", async () => {
  let user = await registerUser(beta, betaUrl);

  let community = await resolveBetaCommunity(user);
  let follow = await followCommunity(user, true, community!.community.id);

  // Make sure the follow response went through
  expect(follow.community_view.community.local).toBe(true);
  expect(follow.community_view.community_actions?.follow_state).toBe(
    "accepted",
  );
  expect(follow.community_view.community.subscribers).toBe(
    community!.community.subscribers + 1,
  );
  expect(follow.community_view.community.subscribers_local).toBe(
    community!.community.subscribers_local + 1,
  );

  // Test an unfollow
  let unfollow = await followCommunity(user, false, community!.community.id);
  expect(
    unfollow.community_view.community_actions?.follow_state,
  ).toBeUndefined();
  expect(unfollow.community_view.community.subscribers).toBe(
    community?.community.subscribers,
  );
  expect(unfollow.community_view.community.subscribers_local).toBe(
    community?.community.subscribers_local,
  );
});

test("Follow federated community", async () => {
  let user = await registerUser(alpha, alphaUrl);

  const betaCommunityInitial = await waitUntil(
    () => resolveBetaCommunity(user),
    c => !!c?.community && c.community.subscribers >= 1,
  );
  if (!betaCommunityInitial) {
    throw "Missing beta community";
  }

  let follow = await followCommunity(
    user,
    true,
    betaCommunityInitial.community.id,
  );
  expect(follow.community_view.community_actions?.follow_state).toBe("pending");
  const betaCommunity = await waitUntil(
    () => resolveBetaCommunity(user),
    c => c?.community_actions?.follow_state === "accepted",
  );

  // Make sure the follow response went through
  expect(betaCommunity?.community.local).toBe(false);
  expect(betaCommunity?.community.name).toBe("main");
  expect(betaCommunity?.community_actions?.follow_state).toBe("accepted");
  expect(betaCommunity?.community.subscribers_local).toBe(
    betaCommunityInitial.community.subscribers_local + 1,
  );

  // check that unfollow was federated
  let communityOnBeta1 = await resolveBetaCommunity(beta);
  expect(communityOnBeta1?.community.subscribers).toBe(
    betaCommunityInitial.community.subscribers + 1,
  );

  // Check it from local
  let my_user = await getMyUser(user);
  let remoteCommunityId = my_user?.follows.find(
    c =>
      c.community.local == false &&
      c.community.id === betaCommunityInitial.community.id,
  )?.community.id;
  expect(remoteCommunityId).toBeDefined();

  if (!remoteCommunityId) {
    throw "Missing remote community id";
  }

  // Test an unfollow
  let unfollow = await followCommunity(user, false, remoteCommunityId);
  expect(
    unfollow.community_view.community_actions?.follow_state,
  ).toBeUndefined();

  // Make sure you are unsubbed locally
  let siteUnfollowCheck = await getMyUser(user);
  expect(
    siteUnfollowCheck.follows.find(
      c => c.community.id === betaCommunityInitial.community.id,
    ),
  ).toBe(undefined);

  // check that unfollow was federated
  let communityOnBeta2 = await waitUntil(
    () => resolveBetaCommunity(beta),
    c =>
      c?.community.subscribers === betaCommunityInitial.community.subscribers,
  );
  expect(communityOnBeta2?.community.subscribers).toBe(
    betaCommunityInitial.community.subscribers,
  );
  expect(communityOnBeta2?.community.subscribers_local).toBe(1);
});


================================================
FILE: api_tests/src/image.spec.ts
================================================
jest.setTimeout(120000);

import {
  UploadImage,
  PurgePerson,
  PurgePost,
  DeleteImageParams,
} from "lemmy-js-client";
import {
  alpha,
  alphaImage,
  alphaUrl,
  beta,
  betaUrl,
  createCommunity,
  createPost,
  deleteAllMedia,
  epsilon,
  followCommunity,
  gamma,
  imageFetchLimit,
  registerUser,
  resolveBetaCommunity,
  resolveCommunity,
  resolvePost,
  setupLogins,
  waitForPost,
  unfollows,
  getPost,
  waitUntil,
  createPostWithThumbnail,
  sampleImage,
  sampleSite,
  getMyUser,
} from "./shared";

beforeAll(setupLogins);

afterAll(async () => {
  await Promise.allSettled([unfollows(), deleteAllMedia(alpha)]);
});

test("Upload image and delete it", async () => {
  const health = await alpha.imageHealth();
  expect(health.success).toBeTruthy();

  // Upload test image. We use a simple string buffer as pictrs doesn't require an actual image
  // in testing mode.
  const upload_form: UploadImage = {
    image: Buffer.from("test"),
  };
  const upload = await alphaImage.uploadImage(upload_form);
  expect(upload.image_url).toBeDefined();
  expect(upload.filename).toBeDefined();

  // ensure that image download is working. theres probably a better way to do this
  const response = await fetch(upload.image_url ?? "");
  const content = await response.text();
  expect(content.length).toBeGreaterThan(0);

  // Ensure that it comes back with the list_media endpoint
  const listMediaRes = await alphaImage.listMedia();
  expect(listMediaRes.items.length).toBe(1);

  // Ensure that it also comes back with the admin all images
  const listMediaAdminRes = await alpha.listMediaAdmin({
    limit: imageFetchLimit,
  });

  // This number comes from all the previous thumbnails fetched in other tests.
  const previousThumbnails = 1;
  expect(listMediaAdminRes.items.length).toBe(previousThumbnails);

  // Make sure the uploader is correct
  expect(listMediaRes.items[0].person.ap_id).toBe(
    `http://lemmy-alpha:8541/u/lemmy_alpha`,
  );

  // delete image
  const delete_form: DeleteImageParams = {
    filename: upload.filename,
  };
  const delete_ = await alphaImage.deleteMedia(delete_form);
  expect(delete_.success).toBe(true);

  // ensure that image is deleted
  const response2 = await fetch(upload.image_url ?? "");
  const content2 = await response2.text();
  expect(content2).toBe("");

  // Ensure that it shows the image is deleted
  const deletedListMediaRes = await alphaImage.listMedia();
  expect(deletedListMediaRes.items.length).toBe(0);

  // Ensure that the admin shows its deleted
  const deletedListAllMediaRes = await alphaImage.listMediaAdmin({
    limit: imageFetchLimit,
  });
  expect(deletedListAllMediaRes.items.length).toBe(previousThumbnails - 1);
});

test("Purge user, uploaded image removed", async () => {
  let user = await registerUser(alphaImage, alphaUrl);

  // upload test image
  const upload_form: UploadImage = {
    image: Buffer.from("test"),
  };
  const upload = await user.uploadImage(upload_form);
  expect(upload.filename).toBeDefined();
  expect(upload.image_url).toBeDefined();

  // ensure that image download is working. theres probably a better way to do this
  const response = await fetch(upload.image_url ?? "");
  const content = await response.text();
  expect(content.length).toBeGreaterThan(0);

  // purge user
  let my_user = await getMyUser(user);
  const purgeForm: PurgePerson = {
    person_id: my_user.local_user_view.person.id,
    reason: "purge",
  };
  const delete_ = await alphaImage.purgePerson(purgeForm);
  expect(delete_.success).toBe(true);

  // ensure that image is deleted
  const response2 = await fetch(upload.image_url ?? "");
  const content2 = await response2.text();
  expect(content2).toBe("");
});

test("Purge post, linked image removed", async () => {
  let user = await registerUser(beta, betaUrl);

  // upload test image
  const upload_form: UploadImage = {
    image: Buffer.from("test"),
  };
  const upload = await user.uploadImage(upload_form);
  expect(upload.filename).toBeDefined();
  expect(upload.image_url).toBeDefined();

  // ensure that image download is working. theres probably a better way to do this
  const response = await fetch(upload.image_url ?? "");
  const content = await response.text();
  expect(content.length).toBeGreaterThan(0);

  let community = await resolveBetaCommunity(user);
  let post = await createPost(user, community!.community.id, upload.image_url);
  expect(post.post_view.post.url).toBe(upload.image_url);
  expect(post.post_view.image_details).toBeDefined();

  // purge post
  const purgeForm: PurgePost = {
    post_id: post.post_view.post.id,
    reason: "purge",
  };
  const delete_ = await beta.purgePost(purgeForm);
  expect(delete_.success).toBe(true);

  // ensure that image is deleted
  const response2 = await fetch(upload.image_url ?? "");
  const content2 = await response2.text();
  expect(content2).toBe("");
});

test("Images in remote image post are proxied if setting enabled", async () => {
  let community = await createCommunity(gamma);
  let postRes = await createPost(
    gamma,
    community.community_view.community.id,
    sampleImage,
    `![](${sampleImage})`,
  );
  const post = postRes.post_view.post;
  expect(post).toBeDefined();

  // Make sure it fetched the image details
  expect(postRes.post_view.image_details).toBeDefined();

  // remote image gets proxied after upload
  expect(
    post.thumbnail_url?.startsWith(
      "http://lemmy-gamma:8561/api/v4/image/proxy?url",
    ),
  ).toBeTruthy();
  expect(
    post.body?.startsWith("![](http://lemmy-gamma:8561/api/v4/image/proxy?url"),
  ).toBeTruthy();

  // Make sure that it contains `jpg`, to be sure its an image
  expect(post.thumbnail_url?.includes(".jpg")).toBeTruthy();

  let epsilonPostRes = await resolvePost(epsilon, postRes.post_view.post);
  expect(epsilonPostRes?.post).toBeDefined();

  // Fetch the post again, the metadata should be backgrounded now
  // Wait for the metadata to get fetched, since this is backgrounded now
  let epsilonPostRes2 = await waitUntil(
    () => getPost(epsilon, epsilonPostRes!.post.id),
    p => p.post_view.post.thumbnail_url != undefined,
  );
  const epsilonPost = epsilonPostRes2.post_view.post;

  expect(
    epsilonPost.thumbnail_url?.startsWith(
      "http://lemmy-epsilon:8581/api/v4/image/proxy?url",
    ),
  ).toBeTruthy();
  expect(
    epsilonPost.body?.startsWith(
      "![](http://lemmy-epsilon:8581/api/v4/image/proxy?url",
    ),
  ).toBeTruthy();

  // Make sure that it contains `jpg`, to be sure its an image
  expect(epsilonPost.thumbnail_url?.includes(".jpg")).toBeTruthy();
});

test("Thumbnail of remote image link is proxied if setting enabled", async () => {
  let community = await createCommunity(gamma);
  let postRes = await createPost(
    gamma,
    community.community_view.community.id,
    // The sample site metadata thumbnail ends in png
    sampleSite,
  );
  const post = postRes.post_view.post;
  expect(post).toBeDefined();

  // remote image gets proxied after upload
  expect(
    post.thumbnail_url?.startsWith(
      "http://lemmy-gamma:8561/api/v4/image/proxy?url",
    ),
  ).toBeTruthy();

  // Make sure that it contains `png`, to be sure its an image
  expect(post.thumbnail_url?.includes(".png")).toBeTruthy();

  let epsilonPostRes = await resolvePost(epsilon, postRes.post_view.post);
  expect(epsilonPostRes?.post).toBeDefined();

  let epsilonPostRes2 = await waitUntil(
    () => getPost(epsilon, epsilonPostRes!.post.id),
    p => p.post_view.post.thumbnail_url != undefined,
  );
  const epsilonPost = epsilonPostRes2.post_view.post;

  expect(
    epsilonPost.thumbnail_url?.startsWith(
      "http://lemmy-epsilon:8581/api/v4/image/proxy?url",
    ),
  ).toBeTruthy();

  // Make sure that it contains `png`, to be sure its an image
  expect(epsilonPost.thumbnail_url?.includes(".png")).toBeTruthy();
});

test("No image proxying if setting is disabled", async () => {
  let user = await registerUser(beta, betaUrl);
  let community = await createCommunity(alpha);
  let betaCommunity = await resolveCommunity(
    beta,
    community.community_view.community.ap_id,
  );
  await followCommunity(beta, true, betaCommunity!.community.id);

  const upload_form: UploadImage = {
    image: Buffer.from("test"),
  };
  const upload = await user.uploadImage(upload_form);
  let post = await createPost(
    alpha,
    community.community_view.community.id,
    upload.image_url,
    `![](${sampleImage})`,
  );
  expect(post.post_view.post).toBeDefined();

  // remote image doesn't get proxied after upload
  expect(
    post.post_view.post.url?.startsWith("http://lemmy-beta:8551/api/v4/image/"),
  ).toBeTruthy();
  expect(post.post_view.post.body).toBe(`![](${sampleImage})`);

  let betaPost = await waitForPost(beta, post.post_view.post, res => {
    return res?.post.alt_text != null;
  });
  expect(betaPost.post).toBeDefined();

  // remote image doesn't get proxied after federation
  expect(
    betaPost.post.url?.startsWith("http://lemmy-beta:8551/api/v4/image/"),
  ).toBeTruthy();
  expect(betaPost.post.body).toBe(`![](${sampleImage})`);
  // Make sure the alt text got federated
  expect(post.post_view.post.alt_text).toBe(betaPost.post.alt_text);
});

test("Make regular post, and give it a custom thumbnail", async () => {
  const uploadForm1: UploadImage = {
    image: Buffer.from("testRegular1"),
  };
  const upload1 = await alphaImage.uploadImage(uploadForm1);

  const community = await createCommunity(alphaImage);

  // Use wikipedia since it has an opengraph image
  const wikipediaUrl = "https://wikipedia.org/";

  let post = await createPostWithThumbnail(
    alphaImage,
    community.community_view.community.id,
    wikipediaUrl,
    upload1.image_url!,
  );

  // Wait for the metadata to get fetched, since this is backgrounded now
  post = await waitUntil(
    () => getPost(alphaImage, post.post_view.post.id),
    p => p.post_view.post.thumbnail_url != undefined,
  );
  expect(post.post_view.post.url).toBe(wikipediaUrl);
  // Make sure it uses custom thumbnail
  expect(post.post_view.post.thumbnail_url).toBe(upload1.image_url);
});

test("Create an image post, and make sure a custom thumbnail doesn't overwrite it", async () => {
  const uploadForm1: UploadImage = {
    image: Buffer.from("test1"),
  };
  const upload1 = await alphaImage.uploadImage(uploadForm1);

  const uploadForm2: UploadImage = {
    image: Buffer.from("test2"),
  };
  const upload2 = await alphaImage.uploadImage(uploadForm2);

  const community = await createCommunity(alphaImage);

  let post = await createPostWithThumbnail(
    alphaImage,
    community.community_view.community.id,
    upload1.image_url!,
    upload2.image_url!,
  );
  post = await waitUntil(
    () => getPost(alphaImage, post.post_view.post.id),
    p => p.post_view.post.thumbnail_url != undefined,
  );
  expect(post.post_view.post.url).toBe(upload1.image_url);
  // Make sure the custom thumbnail is ignored
  expect(post.post_view.post.thumbnail_url == upload2.image_url).toBe(false);
});


================================================
FILE: api_tests/src/post.spec.ts
================================================
jest.setTimeout(120000);

import { CommunityView } from "lemmy-js-client/dist/types/CommunityView";
import {
  alpha,
  beta,
  gamma,
  delta,
  epsilon,
  setupLogins,
  createPost,
  editPost,
  featurePost,
  lockPost,
  resolvePost,
  likePost,
  followBeta,
  resolveBetaCommunity,
  createComment,
  deletePost,
  removePost,
  getPost,
  unfollowRemotes,
  resolvePerson,
  banPersonFromSite,
  followCommunity,
  banPersonFromCommunity,
  reportPost,
  randomString,
  registerUser,
  unfollows,
  resolveCommunity,
  waitUntil,
  waitForPost,
  alphaUrl,
  loginUser,
  createCommunity,
  listReports,
  getMyUser,
  listNotifications,
  getModlog,
  statusNotFound,
  statusBadRequest,
  getSite,
  jestLemmyError,
} from "./shared";
import { PostView } from "lemmy-js-client/dist/types/PostView";
import { AdminBlockInstanceParams } from "lemmy-js-client/dist/types/AdminBlockInstanceParams";
import {
  AddModToCommunity,
  EditSite,
  EditPost,
  PostReport,
  PostReportView,
  ReportCombinedView,
  ResolveObject,
  ResolvePostReport,
  LemmyError,
} from "lemmy-js-client";

let betaCommunity: CommunityView | undefined;

beforeAll(async () => {
  await setupLogins();
  betaCommunity = await resolveBetaCommunity(alpha);
  expect(betaCommunity).toBeDefined();

  // Hack: Force outgoing federation queue for beta to be created on epsilon,
  // otherwise report test fails
  let person = await resolvePerson(epsilon, "@lemmy_beta@lemmy-beta:8551");
  expect(person?.person).toBeDefined();
});

afterAll(unfollows);

async function assertPostFederation(
  postOne: PostView,
  postTwo: PostView,
  waitForMeta = true,
) {
  // Link metadata is generated in background task and may not be ready yet at this time,
  // so wait for it explicitly. For removed posts we cant refetch anything.
  if (waitForMeta) {
    postOne = await waitForPost(beta, postOne.post, res => {
      return res === null || !!res?.post.embed_title;
    });
    postTwo = await waitForPost(
      beta,
      postTwo.post,
      res => res === null || !!res?.post.embed_title,
    );
  }

  expect(postOne?.post.ap_id).toBe(postTwo?.post.ap_id);
  expect(postOne?.post.name).toBe(postTwo?.post.name);
  expect(postOne?.post.body).toBe(postTwo?.post.body);
  // TODO url clears arent working
  // expect(postOne?.post.url).toBe(postTwo?.post.url);
  expect(postOne?.post.nsfw).toBe(postTwo?.post.nsfw);
  expect(postOne?.post.embed_title).toBe(postTwo?.post.embed_title);
  expect(postOne?.post.embed_description).toBe(postTwo?.post.embed_description);
  expect(postOne?.post.embed_video_url).toBe(postTwo?.post.embed_video_url);
  expect(postOne?.post.published_at).toBe(postTwo?.post.published_at);
  expect(postOne?.community.ap_id).toBe(postTwo?.community.ap_id);
  expect(postOne?.post.locked).toBe(postTwo?.post.locked);
  expect(postOne?.post.removed).toBe(postTwo?.post.removed);
  expect(postOne?.post.deleted).toBe(postTwo?.post.deleted);
}

test("Create a post", async () => {
  // Block alpha
  let block_instance_params: AdminBlockInstanceParams = {
    instance: "lemmy-alpha",
    block: true,
    reason: "block",
  };
  await epsilon.adminBlockInstance(block_instance_params);

  if (!betaCommunity) {
    throw "Missing beta community";
  }

  let postRes = await createPost(
    alpha,
    betaCommunity.community.id,
    "https://example.com/",
    "აშშ ითხოვს ირანს დაუყოვნებლივ გაანთავისუფლოს დაკავებული ნავთობის ტანკერი",
  );
  expect(postRes.post_view.post).toBeDefined();
  expect(postRes.post_view.community.local).toBe(false);
  expect(postRes.post_view.creator.local).toBe(true);
  expect(postRes.post_view.post.score).toBe(1);

  // Make sure that post is liked on beta
  const betaPost = await waitForPost(
    beta,
    postRes.post_view.post,
    res => res?.post.score === 1,
  );

  expect(betaPost).toBeDefined();
  expect(betaPost?.community.local).toBe(true);
  expect(betaPost?.creator.local).toBe(false);
  expect(betaPost?.post.score).toBe(1);
  await assertPostFederation(betaPost, postRes.post_view);

  // Delta only follows beta, so it should not see an alpha ap_id
  await jestLemmyError(
    () => resolvePost(delta, postRes.post_view.post),
    new LemmyError(
      "resolve_object_failed",
      statusBadRequest,
      'Domain "lemmy-alpha" is not in allowlist',
    ),
  );

  // Epsilon has alpha blocked, it should not see the alpha post
  await jestLemmyError(
    () => resolvePost(epsilon, postRes.post_view.post),
    new LemmyError(
      "resolve_object_failed",
      statusBadRequest,
      'Domain "lemmy-alpha" is blocked',
    ),
  );

  // remove blocked instance
  block_instance_params.block = false;
  await epsilon.adminBlockInstance(block_instance_params);
});

test("Create a post in a non-existent community", async () => {
  await jestLemmyError(
    () => createPost(alpha, -2),
    new LemmyError("not_found", statusNotFound),
  );
});

test("Unlike a post", async () => {
  if (!betaCommunity) {
    throw "Missing beta community";
  }
  let postRes = await createPost(alpha, betaCommunity.community.id);
  let unlike = await likePost(alpha, undefined, postRes.post_view.post);
  expect(unlike.post_view.post.score).toBe(0);

  // Try to unlike it again, make sure it stays at 0
  let unlike2 = await likePost(alpha, undefined, postRes.post_view.post);
  expect(unlike2.post_view.post.score).toBe(0);

  // Make sure that post is unliked on beta
  const betaPost = await waitForPost(
    beta,
    postRes.post_view.post,
    post => post?.post.score === 0,
  );

  expect(betaPost).toBeDefined();
  expect(betaPost?.community.local).toBe(true);
  expect(betaPost?.creator.local).toBe(false);
  expect(betaPost?.post.score).toBe(0);
  await assertPostFederation(betaPost, postRes.post_view);
});

test("Update a post", async () => {
  if (!betaCommunity) {
    throw "Missing beta community";
  }
  let postRes = await createPost(alpha, betaCommunity.community.id);
  let updatedName = "A jest test federated post, updated";
  let updatedPost = await editPost(alpha, postRes.post_view.post);
  expect(updatedPost.post_view.post.name).toBe(updatedName);
  expect(updatedPost.post_view.community.local).toBe(false);
  expect(updatedPost.post_view.creator.local).toBe(true);

  // Make sure that post is updated on beta
  let betaPost = await waitForPost(beta, updatedPost.post_view.post);
  expect(betaPost.community.local).toBe(true);
  expect(betaPost.creator.local).toBe(false);
  expect(betaPost.post.name).toBe(updatedName);
  await assertPostFederation(betaPost, updatedPost.post_view);

  // Make sure lemmy beta cannot update the post
  await jestLemmyError(
    () => editPost(beta, betaPost.post),
    new LemmyError("no_post_edit_allowed", statusBadRequest),
  );
});

test("Sticky a post", async () => {
  if (!betaCommunity) {
    throw "Missing beta community";
  }
  let postRes = await createPost(alpha, betaCommunity.community.id);

  let betaPost1 = await waitForPost(beta, postRes.post_view.post);
  if (!betaPost1) {
    throw "Missing beta post1";
  }
  let stickiedPostRes = await featurePost(beta, true, betaPost1.post);
  expect(stickiedPostRes.post_view.post.featured_community).toBe(true);

  // Make sure that post is stickied on beta
  let betaPost = await resolvePost(beta, postRes.post_view.post);
  expect(betaPost?.community.local).toBe(true);
  expect(betaPost?.creator.local).toBe(false);
  expect(betaPost?.post.featured_community).toBe(true);

  // Unsticky a post
  let unstickiedPost = await featurePost(beta, false, betaPost1.post);
  expect(unstickiedPost.post_view.post.featured_community).toBe(false);

  // Make sure that post is unstickied on beta
  let betaPost2 = await resolvePost(beta, postRes.post_view.post);
  expect(betaPost2?.community.local).toBe(true);
  expect(betaPost2?.creator.local).toBe(false);
  expect(betaPost2?.post.featured_community).toBe(false);

  // Make sure that gamma cannot sticky the post on beta
  let gammaPost = await resolvePost(gamma, postRes.post_view.post);
  if (!gammaPost) {
    throw "Missing gamma post";
  }
  // This has been failing occasionally
  await featurePost(gamma, true, gammaPost.post);
  let betaPost3 = await resolvePost(beta, postRes.post_view.post);
  // expect(gammaTrySticky.post_view.post.featured_community).toBe(true);
  expect(betaPost3?.post.featured_community).toBe(false);
});

test("Collection of featured posts gets federated", async () => {
  // create a new community and feature a post
  let community = await createCommunity(alpha);
  let post = await createPost(alpha, community.community_view.community.id);
  let featuredPost = await featurePost(alpha, true, post.post_view.post);
  expect(featuredPost.post_view.post.featured_community).toBe(true);

  // fetch the community, ensure that post is also fetched and marked as featured
  let betaCommunity = await resolveCommunity(
    beta,
    community.community_view.community.ap_id,
  );
  expect(betaCommunity).toBeDefined();

  const betaPost = await waitForPost(
    beta,
    post.post_view.post,
    post => post?.post.featured_community === true,
  );
  expect(betaPost).toBeDefined();
});

test("Lock a post", async () => {
  if (!betaCommunity) {
    throw "Missing beta community";
  }
  await followCommunity(alpha, true, betaCommunity.community.id);
  await waitUntil(
    () => resolveBetaCommunity(alpha),
    c => c?.community_actions?.follow_state == "accepted",
  );

  let postRes = await createPost(alpha, betaCommunity.community.id);
  let betaPost1 = await waitForPost(beta, postRes.post_view.post);
  // Lock the post
  let lockedPostRes = await lockPost(beta, true, betaPost1.post);
  expect(lockedPostRes.post_view.post.locked).toBe(true);

  // Make sure that post is locked on alpha
  let alphaPost1 = await waitForPost(
    alpha,
    postRes.post_view.post,
    post => !!post && post.post.locked,
  );

  // Try to make a new comment there, on alpha. For this we need to create a normal
  // user account because admins/mods can comment in locked posts.
  let user = await registerUser(alpha, alphaUrl);
  await jestLemmyError(
    () => createComment(user, alphaPost1.post.id),
    new LemmyError("locked", statusBadRequest),
  );

  // Unlock a post
  let unlockedPost = await lockPost(beta, false, betaPost1.post);
  expect(unlockedPost.post_view.post.locked).toBe(false);

  // Make sure that post is unlocked on alpha
  let alphaPost2 = await waitForPost(
    alpha,
    postRes.post_view.post,
    post => !!post && !post.post.locked,
  );
  expect(alphaPost2.community.local).toBe(false);
  expect(alphaPost2.creator.local).toBe(true);
  expect(alphaPost2.post.locked).toBe(false);

  // Try to create a new comment, on alpha
  let commentAlpha = await createComment(user, alphaPost1.post.id);
  expect(commentAlpha).toBeDefined();
});

test("Delete a post", async () => {
  if (!betaCommunity) {
    throw "Missing beta community";
  }

  let postRes = await createPost(alpha, betaCommunity.community.id);
  expect(postRes.post_view.post).toBeDefined();

  await waitForPost(beta, postRes.post_view.post, p => p?.post.id != undefined);

  let deletedPost = await deletePost(alpha, true, postRes.post_view.post);
  // Make sure lemmy alpha sees post is deleted
  await waitUntil(
    () => getPost(alpha, postRes.post_view.post.id),
    p => p.post_view.post.deleted,
  );
  expect(deletedPost.post_view.post.name).toBe(postRes.post_view.post.name);

  // Make sure lemmy beta sees post is deleted
  // This will be undefined because of the tombstone
  await waitForPost(beta, postRes.post_view.post, p => p?.post == undefined);

  // Undelete
  let undeletedPost = await deletePost(alpha, false, postRes.post_view.post);
  await waitUntil(
    () => getPost(alpha, postRes.post_view.post.id),
    p => !p.post_view.post.deleted,
  );

  // Make sure lemmy beta sees post is undeleted
  let betaPost2 = await waitForPost(
    beta,
    postRes.post_view.post,
    p => !!p && !p.post.deleted,
  );

  if (!betaPost2) {
    throw "Missing beta post 2";
  }
  expect(betaPost2.post.deleted).toBe(false);
  await assertPostFederation(betaPost2, undeletedPost.post_view);

  // Make sure lemmy beta cannot delete the post
  await jestLemmyError(
    () => deletePost(beta, true, betaPost2.post),
    new LemmyError("no_post_edit_allowed", statusBadRequest),
  );
});

test("Remove a post from admin and community on different instance", async () => {
  if (!betaCommunity) {
    throw "Missing beta community";
  }

  let gammaCommunity = (
    await resolveCommunity(gamma, betaCommunity.community.ap_id)
  )?.community;
  if (!gammaCommunity) {
    throw "Missing gamma community";
  }
  let postRes = await createPost(gamma, gammaCommunity.id);

  let alphaPost = await resolvePost(alpha, postRes.post_view.post);
  if (!alphaPost) {
    throw "Missing alpha post";
  }
  let removedPost = await removePost(alpha, true, alphaPost.post);
  expect(removedPost.post_view.post.removed).toBe(true);
  expect(removedPost.post_view.post.name).toBe(postRes.post_view.post.name);

  // Make sure lemmy beta sees post is NOT removed
  let betaPost = await resolvePost(beta, postRes.post_view.post);
  if (!betaPost) {
    throw "Missing beta post";
  }
  expect(betaPost.post.removed).toBe(false);

  // Undelete
  let undeletedPost = await removePost(alpha, false, alphaPost.post);
  expect(undeletedPost.post_view.post.removed).toBe(false);

  // Make sure lemmy beta sees post is undeleted
  let betaPost2 = await resolvePost(beta, postRes.post_view.post);
  expect(betaPost2?.post.removed).toBe(false);
  await assertPostFederation(betaPost2!, undeletedPost.post_view);
});

test("Remove a post from admin and community on same instance", async () => {
  if (!betaCommunity) {
    throw "Missing beta community";
  }
  await followBeta(alpha);
  let gammaCommunity = await resolveCommunity(
    gamma,
    betaCommunity.community.ap_id,
  );
  let postRes = await createPost(gamma, gammaCommunity!.community.id);
  expect(postRes.post_view.post).toBeDefined();
  // Get the id for beta
  let betaPost = await waitForPost(beta, postRes.post_view.post);
  expect(betaPost).toBeDefined();

  let alphaPost0 = await waitForPost(alpha, postRes.post_view.post);
  expect(alphaPost0).toBeDefined();

  // The beta admin removes it (the community lives on beta)
  let removePostRes = await removePost(beta, true, betaPost.post);
  expect(removePostRes.post_view.post.removed).toBe(true);

  // Make sure lemmy alpha sees post is removed
  let alphaPost = await waitUntil(
    () => getPost(alpha, alphaPost0.post.id),
    p => p?.post_view.post.removed,
  );
  expect(alphaPost?.post_view.post.removed).toBe(true);
  await assertPostFederation(
    alphaPost.post_view,
    removePostRes.post_view,
    false,
  );

  // Undelete
  let undeletedPost = await removePost(beta, false, betaPost.post);
  expect(undeletedPost.post_view.post.removed).toBe(false);

  // Make sure lemmy alpha sees post is undeleted
  let alphaPost2 = await waitForPost(
    alpha,
    postRes.post_view.post,
    p => !!p && !p.post.removed,
  );
  expect(alphaPost2.post.removed).toBe(false);
  await assertPostFederation(alphaPost2, undeletedPost.post_view);
  await unfollowRemotes(alpha);
});

test("Search for a post", async () => {
  if (!betaCommunity) {
    throw "Missing beta community";
  }
  await unfollowRemotes(alpha);
  let postRes = await createPost(alpha, betaCommunity.community.id);
  expect(postRes.post_view.post).toBeDefined();

  let betaPost = await waitForPost(beta, postRes.post_view.post);
  expect(betaPost?.post.name).toBeDefined();
});

test("Enforce site ban federation for local user", async () => {
  if (!betaCommunity) {
    throw "Missing beta community";
  }

  // create a test user
  let alphaUserHttp = await registerUser(alpha, alphaUrl);
  let alphaUserPerson = (await getMyUser(alphaUserHttp)).local_user_view.person;
  let alphaUserActorId = alphaUserPerson?.ap_id;
  if (!alphaUserActorId) {
    throw "Missing alpha user actor id";
  }
  expect(alphaUserActorId).toBeDefined();
  await followBeta(alphaUserHttp);

  let alphaPerson = await resolvePerson(alphaUserHttp, alphaUserActorId!);
  if (!alphaPerson) {
    throw "Missing alpha person";
  }
  expect(alphaPerson).toBeDefined();

  // alpha makes post in beta community, it federates to beta instance
  let postRes1 = await createPost(alphaUserHttp, betaCommunity.community.id);
  let searchBeta1 = await waitForPost(beta, postRes1.post_view.post);

  // ban alpha from its own instance
  let banAlpha = await banPersonFromSite(
    alpha,
    alphaPerson.person.id,
    true,
    true,
  );
  expect(banAlpha.person_view.banned).toBe(true);

  // alpha ban should be federated to beta
  let alphaUserOnBeta1 = await waitUntil(
    () => resolvePerson(beta, alphaUserActorId!),
    res => res?.banned == true,
  );
  expect(alphaUserOnBeta1?.banned).toBe(true);

  // existing alpha post should be removed on beta
  let betaBanRes = await waitUntil(
    () => getPost(beta, searchBeta1.post.id),
    s => s.post_view.post.removed,
  );
  expect(betaBanRes.post_view.post.removed).toBe(true);

  // Unban alpha
  let unBanAlpha = await banPersonFromSite(
    alpha,
    alphaPerson.person.id,
    false,
    true,
  );
  expect(unBanAlpha.person_view.banned).toBe(false);

  // existing alpha post should be restored on beta
  betaBanRes = await waitUntil(
    () => getPost(beta, searchBeta1.post.id),
    s => !s.post_view.post.removed,
  );
  expect(betaBanRes.post_view.post.removed).toBe(false);

  // Login gets invalidated by ban, need to login again
  if (!alphaUserPerson) {
    throw "Missing alpha person";
  }
  let newAlphaUserJwt = await loginUser(alpha, alphaUserPerson.name);
  alphaUserHttp.setHeaders({
    Authorization: "Bearer " + newAlphaUserJwt.jwt,
  });
  // alpha makes new post in beta community, it federates
  let postRes2 = await createPost(alphaUserHttp, betaCommunity!.community.id);
  await waitForPost(beta, postRes2.post_view.post);

  await unfollowRemotes(alpha);
});

test("Enforce site ban federation for federated user", async () => {
  if (!betaCommunity) {
    throw "Missing beta community";
  }

  // create a test user
  let alphaUserHttp = await registerUser(alpha, alphaUrl);
  let alphaUserPerson = (await getMyUser(alphaUserHttp)).local_user_view.person;
  let alphaUserActorId = alphaUserPerson?.ap_id;
  if (!alphaUserActorId) {
    throw "Missing alpha user actor id";
  }
  expect(alphaUserActorId).toBeDefined();
  await followBeta(alphaUserHttp);

  let alphaUserOnBeta2 = await resolvePerson(beta, alphaUserActorId!);
  expect(alphaUserOnBeta2?.banned).toBe(false);

  if (!alphaUserOnBeta2?.person) {
    throw "Missing alpha person";
  }

  // alpha makes post in beta community, it federates to beta instance
  let postRes1 = await createPost(alphaUserHttp, betaCommunity.community.id);
  let searchBeta1 = await waitForPost(beta, postRes1.post_view.post);
  expect(searchBeta1.post).toBeDefined();

  // Now ban and remove their data from beta
  let banAlphaOnBeta = await banPersonFromSite(
    beta,
    alphaUserOnBeta2.person.id,
    true,
    true,
  );
  expect(banAlphaOnBeta.person_view.banned).toBe(true);

  // existing alpha post should be removed on beta
  let betaRemovedPost = await getPost(beta, searchBeta1.post.id);
  expect(betaRemovedPost.post_view.post.removed).toBe(true);

  // post should also be removed on alpha
  let alphaRemovedPost = await waitUntil(
    () => getPost(alpha, postRes1.post_view.post.id),
    s => s.post_view.post.removed,
  );
  expect(alphaRemovedPost.post_view.post.removed).toBe(true);

  // User should not be shown to be banned from alpha
  let alphaPerson2 = (await getMyUser(alphaUserHttp)).local_user_view;
  expect(alphaPerson2.banned).toBe(false);

  // post to beta community is rejected
  await jestLemmyError(
    () => createPost(alphaUserHttp, betaCommunity!.community.id),
    new LemmyError("site_ban", statusBadRequest),
  );

  await unfollowRemotes(alpha);
});

test("Enforce community ban for federated user", async () => {
  if (!betaCommunity) {
    throw "Missing beta community";
  }
  await followBeta(alpha);
  let alphaShortname = `@lemmy_alpha@lemmy-alpha:8541`;
  let alphaPerson = await resolvePerson(beta, alphaShortname);
  if (!alphaPerson) {
    throw "Missing alpha person";
  }
  expect(alphaPerson).toBeDefined();

  // make a post in beta, it goes through
  let postRes1 = await createPost(alpha, betaCommunity.community.id);
  let searchBeta1 = await waitForPost(beta, postRes1.post_view.post);
  expect(searchBeta1.post).toBeDefined();

  // ban alpha from beta community
  let banAlpha = await banPersonFromCommunity(
    beta,
    alphaPerson.person.id,
    searchBeta1.community.id,
    true,
    true,
  );
  expect(banAlpha).toBeDefined();

  // ensure that the post by alpha got removed
  let removePostRes = await waitUntil(
    () => getPost(alpha, postRes1.post_view.post.id),
    s => s.post_view.post.removed,
  );
  expect(removePostRes.post_view.post.removed).toBe(true);
  expect(removePostRes.post_view.creator_banned_from_community).toBe(true);
  expect(
    removePostRes.community_view.community_actions?.received_ban_at,
  ).toBeDefined();

  // Alpha tries to make post on beta, but it fails because of ban
  await jestLemmyError(
    () => createPost(alpha, betaCommunity!.community.id),
    new LemmyError("person_is_banned_from_community", statusBadRequest),
  );

  // Unban alpha
  let unBanAlpha = await banPersonFromCommunity(
    beta,
    alphaPerson.person.id,
    searchBeta1.community.id,
    false,
    false,
  );
  expect(unBanAlpha).toBeDefined();

  // Check that unban was federated to alpha
  await waitUntil(
    () => getModlog(alpha),
    m =>
      m.items[0].modlog.kind == "mod_ban_from_community" &&
      m.items[0].modlog.is_revert == true,
  );

  let postRes3 = await createPost(alpha, betaCommunity.community.id);
  expect(postRes3.post_view.post).toBeDefined();
  expect(postRes3.post_view.community.local).toBe(false);
  expect(postRes3.post_view.creator.local).toBe(true);
  expect(postRes3.post_view.post.score).toBe(1);

  // Make sure that post makes it to beta community
  let postRes4 = await waitForPost(beta, postRes3.post_view.post);
  expect(postRes4.post).toBeDefined();
  expect(postRes4.creator_banned).toBe(false);

  await unfollowRemotes(alpha);
});

test("A and G subscribe to B (center) A posts, it gets announced to G", async () => {
  if (!betaCommunity) {
    throw "Missing beta community";
  }
  await followBeta(alpha);

  let postRes = await createPost(alpha, betaCommunity.community.id);
  expect(postRes.post_view.post).toBeDefined();

  let betaPost = await resolvePost(gamma, postRes.post_view.post);
  expect(betaPost?.post.name).toBeDefined();
  await unfollowRemotes(alpha);
});

test("Report a post", async () => {
  // Create post from alpha
  let alphaCommunity = await resolveBetaCommunity(alpha);
  await followBeta(alpha);
  let alphaPost = await createPost(alpha, alphaCommunity!.community.id);
  expect(alphaPost.post_view.post).toBeDefined();

  // add remote mod on epsilon
  await followBeta(epsilon);

  let betaCommunity = await resolveBetaCommunity(beta);
  let epsilonUser = await resolvePerson(
    beta,
    "@lemmy_epsilon@lemmy-epsilon:8581",
  );
  let mod_params: AddModToCommunity = {
    community_id: betaCommunity!.community.id,
    person_id: epsilonUser!.person.id,
    added: true,
  };
  let res = await beta.addModToCommunity(mod_params);
  expect(res.moderators.length).toBe(2);

  // Send report from gamma
  let gammaPost = await resolvePost(gamma, alphaPost.post_view.post);
  let gammaReport = (
    await reportPost(gamma, gammaPost!.post.id, randomString(10))
  ).post_report_view.post_report;
  expect(gammaReport).toBeDefined();

  // Report was federated to community instance
  let betaReport = (
    (await waitUntil(
      () =>
        listReports(beta).then(p =>
          p.items.find(r => {
            return checkPostReportName(r, gammaReport);
          }),
        ),
      res => !!res,
    ))! as PostReportView
  ).post_report;
  expect(betaReport).toBeDefined();
  expect(betaReport.resolved).toBe(false);
  expect(betaReport.original_post_name).toBe(gammaReport.original_post_name);
  //expect(betaReport.original_post_url).toBe(gammaReport.original_post_url);
  expect(betaReport.original_post_body).toBe(gammaReport.original_post_body);
  expect(betaReport.reason).toBe(gammaReport.reason);
  await unfollowRemotes(alpha);

  // Report was federated to poster's instance. Alpha is not a community mod and doesnt see
  // the report by default, so we need to pass show_mod_reports = true.
  let alphaReport = (
    (await waitUntil(
      () =>
        listReports(alpha, true).then(p =>
          p.items.find(r => {
            return checkPostReportName(r, gammaReport);
          }),
        ),
      res => !!res,
    ))! as PostReportView
  ).post_report;
  expect(alphaReport).toBeDefined();
  expect(alphaReport.resolved).toBe(false);
  expect(alphaReport.original_post_name).toBe(gammaReport.original_post_name);
  //expect(alphaReport.original_post_url).toBe(gammaReport.original_post_url);
  expect(alphaReport.original_post_body).toBe(gammaReport.original_post_body);
  expect(alphaReport.reason).toBe(gammaReport.reason);

  // Report was federated to remote mod instance
  let epsilonReport = (
    (await waitUntil(
      () =>
        listReports(epsilon).then(p =>
          p.items.find(r => {
            return checkPostReportName(r, gammaReport);
          }),
        ),
      res => !!res,
    ))! as PostReportView
  ).post_report;
  expect(epsilonReport).toBeDefined();
  expect(epsilonReport.resolved).toBe(false);
  expect(epsilonReport.original_post_name).toBe(gammaReport.original_post_name);

  // Resolve report as remote mod
  let resolve_params: ResolvePostReport = {
    report_id: epsilonReport.id,
    resolved: true,
  };
  let resolve = await epsilon.resolvePostReport(resolve_params);
  expect(resolve.post_report_view.post_report.resolved).toBeTruthy();

  // Report should be marked resolved on community instance
  let resolvedReport = (
    (await waitUntil(
      () =>
        listReports(beta).then(p =>
          p.items.find(r => {
            return checkPostReportName(r, gammaReport) && !!r.resolver;
          }),
        ),
      res => !!res,
    ))! as PostReportView
  ).post_report;
  expect(resolvedReport).toBeDefined();
  expect(resolvedReport.resolved).toBe(true);
});

test("Fetch post via redirect", async () => {
  await followBeta(alpha);
  let alphaPost = await createPost(alpha, betaCommunity!.community.id);
  expect(alphaPost.post_view.post).toBeDefined();
  // Make sure that post is liked on beta
  const betaPost = await waitForPost(
    beta,
    alphaPost.post_view.post,
    res => res?.post.score === 1,
  );

  expect(betaPost).toBeDefined();
  expect(betaPost.post?.ap_id).toBe(alphaPost.post_view.post.ap_id);

  // Fetch post from url on beta instance instead of ap_id
  let q = `http://lemmy-beta:8551/post/${betaPost.post.id}`;
  let form: ResolveObject = {
    q,
  };
  let gammaPost = await gamma
    .resolveObject(form)
    .then(a => a.resolve)
    .then(a => (a?.type_ == "post" ? a : undefined));

  expect(gammaPost).toBeDefined();
  expect(gammaPost?.post.ap_id).toBe(alphaPost.post_view.post.ap_id);
  await unfollowRemotes(alpha);
});

test("Block post that contains banned URL", async () => {
  let editSiteForm: EditSite = {
    blocked_urls: ["https://evil.com/"],
  };

  await epsilon.editSite(editSiteForm);

  await waitUntil(
    () => epsilon.getSite(),
    s => s.blocked_urls.length == 1,
  );

  if (!betaCommunity) {
    throw "Missing beta community";
  }

  await jestLemmyError(
    () => createPost(epsilon, betaCommunity!.community.id, "https://evil.com"),
    new LemmyError("blocked_url", statusBadRequest),
  );

  // Later tests need this to be empty
  editSiteForm.blocked_urls = [];
  await epsilon.editSite(editSiteForm);
});

test("Fetch post with redirect", async () => {
  let alphaPost = await createPost(alpha, betaCommunity!.community.id);
  expect(alphaPost.post_view.post).toBeDefined();

  // beta fetches from alpha as usual
  let betaPost = await resolvePost(beta, alphaPost.post_view.post);
  expect(betaPost?.post).toBeDefined();

  // gamma fetches from beta, and gets redirected to alpha
  let gammaPost = await resolvePost(gamma, betaPost!.post);
  expect(gammaPost?.post).toBeDefined();

  // fetch remote object from local url, which redirects to the original url
  let form: ResolveObject = {
    q: `http://lemmy-gamma:8561/post/${gammaPost?.post.id}`,
  };
  let gammaPost2 = await gamma
    .resolveObject(form)
    .then(a => a.resolve)
    .then(a => (a?.type_ == "post" ? a : undefined));

  expect(gammaPost2?.post).toBeDefined();
});

test("Mention beta from alpha post body", async () => {
  if (!betaCommunity) throw Error("no community");
  let mentionContent = "A test mention of @lemmy_beta@lemmy-beta:8551";

  const postOnAlphaRes = await createPost(
    alpha,
    betaCommunity.community.id,
    undefined,
    mentionContent,
  );

  expect(postOnAlphaRes.post_view.post.body).toBeDefined();
  expect(postOnAlphaRes.post_view.community.local).toBe(false);
  expect(postOnAlphaRes.post_view.creator.local).toBe(true);
  expect(postOnAlphaRes.post_view.post.score).toBe(1);

  // get beta's localized copy of the alpha post
  let betaPost = await waitForPost(beta, postOnAlphaRes.post_view.post);
  if (!betaPost) {
    throw "unable to locate post on beta";
  }
  expect(betaPost.post.ap_id).toBe(postOnAlphaRes.post_view.post.ap_id);
  expect(betaPost.post.name).toBe(postOnAlphaRes.post_view.post.name);
  await assertPostFederation(betaPost, postOnAlphaRes.post_view);

  let mentionsRes = await waitUntil(
    () => listNotifications(beta, "mention"),
    m => !!m.items[0],
  );

  const firstMention = mentionsRes.items[0].data as PostView;
  expect(firstMention.post!.body).toBeDefined();
  expect(firstMention.community!.local).toBe(true);
  expect(firstMention.creator.local).toBe(false);
  expect(firstMention.post!.score).toBe(1);
});

test("Rewrite markdown links", async () => {
  const community = await resolveBetaCommunity(beta);

  // create a post
  let postRes1 = await createPost(beta, community!.community.id);

  // link to this post in markdown
  let postRes2 = await createPost(
    beta,
    community!.community.id,
    "https://example.com/",
    `[link](${postRes1.post_view.post.ap_id})`,
  );
  expect(postRes2.post_view.post).toBeDefined();

  // fetch both posts from another instance
  const alphaPost1 = await resolvePost(alpha, postRes1.post_view.post);
  const alphaPost2 = await resolvePost(alpha, postRes2.post_view.post);

  // remote markdown link is replaced with local link
  expect(alphaPost2?.post.body).toBe(
    `[link](http://lemmy-alpha:8541/post/${alphaPost1?.post.id})`,
  );
});

test("Don't allow NSFW posts on instances that disable it", async () => {
  // Disallow NSFW on gamma
  let editSiteForm: EditSite = {
    disallow_nsfw_content: true,
  };
  await gamma.editSite(editSiteForm);

  // Wait for cache on Gamma's LocalSite
  await waitUntil(
    () => getSite(gamma),
    s => s.site_view.local_site.disallow_nsfw_content,
  );

  if (!betaCommunity) {
    throw "Missing beta community";
  }

  // Make a NSFW post
  let postRes = await createPost(beta, betaCommunity.community.id);
  let form: EditPost = {
    nsfw: true,
    post_id: postRes.post_view.post.id,
  };
  let updatePost = await beta.editPost(form);

  // Gamma reject resolving the post
  await jestLemmyError(
    () => resolvePost(gamma, updatePost.post_view.post),
    new LemmyError("resolve_object_failed", statusBadRequest, "NsfwNotAllowed"),
  );

  // Local users can't create NSFW post on Gamma
  let gammaCommunity = await resolveCommunity(
    gamma,
    betaCommunity.community.ap_id,
  );
  if (!gammaCommunity) {
    throw "Missing gamma community";
  }
  let gammaPost = await createPost(gamma, gammaCommunity.community.id);
  let form2: EditPost = {
    nsfw: true,
    post_id: gammaPost.post_view.post.id,
  };
  await jestLemmyError(
    () => gamma.editPost(form2),
    new LemmyError("nsfw_not_allowed", statusBadRequest),
  );
});

test("Plugin test", async () => {
  let community = await createCommunity(epsilon);
  let postRes1 = await createPost(
    epsilon,
    community.community_view.community.id,
    "https://example.com/",
    randomString(10),
    "Rust",
  );
  expect(postRes1.post_view.post.name).toBe("Go");

  await jestLemmyError(
    () =>
      createPost(
        epsilon,
        community.community_view.community.id,
        "https://example.com/",
        randomString(10),
        "Java",
      ),
    new LemmyError("plugin_error", statusBadRequest, "We dont talk about Java"),
  );
});

function checkPostReportName(rcv: ReportCombinedView, report: PostReport) {
  switch (rcv.type_) {
    case "post":
      return rcv.post_report.original_post_name === report.original_post_name;
    default:
      return false;
  }
}


================================================
FILE: api_tests/src/private_comm.spec.ts
================================================
jest.setTimeout(120000);

import { FollowCommunity, LemmyError, LemmyHttp } from "lemmy-js-client";
import {
  alpha,
  setupLogins,
  createCommunity,
  unfollows,
  registerUser,
  listCommunityPendingFollows,
  getCommunity,
  approveCommunityPendingFollow,
  randomString,
  createPost,
  createComment,
  beta,
  resolveCommunity,
  betaUrl,
  resolvePost,
  resolveComment,
  likeComment,
  waitUntil,
  gamma,
  getPosts,
  getComments,
  statusNotFound,
  jestLemmyError,
  statusBadRequest,
  getUnreadCounts,
} from "./shared";

beforeAll(setupLogins);
afterAll(unfollows);

test("Follow a private community", async () => {
  // create private community
  const community = await createCommunity(alpha, randomString(10), "private");
  expect(community.community_view.community.visibility).toBe("private");
  const alphaCommunityId = community.community_view.community.id;

  // No pending follows yet
  const pendingFollows0 = await listCommunityPendingFollows(alpha);
  expect(pendingFollows0.items.length).toBe(0);
  const pendingFollowsCount0 = await getUnreadCounts(alpha);
  expect(pendingFollowsCount0.pending_follow_count).toBe(0);

  // follow as new user
  const user = await registerUser(beta, betaUrl);
  const betaCommunity = await resolveCommunity(
    user,
    community.community_view.community.ap_id,
  );
  expect(betaCommunity).toBeDefined();
  expect(betaCommunity?.community.visibility).toBe("private");
  const betaCommunityId = betaCommunity!.community.id;
  const follow_form: FollowCommunity = {
    community_id: betaCommunityId,
    follow: true,
  };
  await user.followCommunity(follow_form);

  // Follow listed as pending
  const follow1 = await getCommunity(user, betaCommunityId);
  expect(follow1.community_view.community_actions?.follow_state).toBe(
    "approval_required",
  );

  // Wait for follow to federate, shown as pending
  let pendingFollows1 = await waitUntil(
    () => listCommunityPendingFollows(alpha),
    f => f.items.length == 1,
  );
  expect(pendingFollows1.items[0].is_new_instance).toBe(true);
  const pendingFollowsCount1 = await getUnreadCounts(alpha);
  expect(pendingFollowsCount1.pending_follow_count).toBe(1);

  // user still sees approval required at this point
  const betaCommunity2 = await getCommunity(user, betaCommunityId);
  expect(betaCommunity2.community_view.community_actions?.follow_state).toBe(
    "approval_required",
  );

  // Approve the follow
  const approve = await approveCommunityPendingFollow(
    alpha,
    alphaCommunityId,
    pendingFollows1.items[0].person.id,
  );
  expect(approve.success).toBe(true);

  // Follow is confirmed
  await waitUntil(
    () => getCommunity(user, betaCommunityId),
    c => c.community_view.community_actions?.follow_state == "accepted",
  );
  const pendingFollows2 = await listCommunityPendingFollows(alpha);
  expect(pendingFollows2.items.length).toBe(0);
  const pendingFollowsCount2 = await getUnreadCounts(alpha);
  expect(pendingFollowsCount2.pending_follow_count).toBe(0);

  // follow with another user from that instance, is_new_instance should be false now
  const user2 = await registerUser(beta, betaUrl);
  await user2.followCommunity(follow_form);
  let pendingFollows3 = await waitUntil(
    () => listCommunityPendingFollows(alpha),
    f => f.items.length == 1,
  );
  expect(pendingFollows3.items[0].is_new_instance).toBe(false);

  // cleanup pending follow
  const approve2 = await approveCommunityPendingFollow(
    alpha,
    alphaCommunityId,
    pendingFollows3.items[0].person.id,
  );
  expect(approve2.success).toBe(true);
});

test("Only followers can view and interact with private community content", async () => {
  // create private community
  const community = await createCommunity(alpha, randomString(10), "private");
  expect(community.community_view.community.visibility).toBe("private");
  const alphaCommunityId = community.community_view.community.id;

  // create post and comment
  const post0 = await createPost(alpha, alphaCommunityId);
  const post_id = post0.post_view.post.id;
  expect(post_id).toBeDefined();
  const comment = await createComment(alpha, post_id);
  const comment_id = comment.comment_view.comment.id;
  expect(comment_id).toBeDefined();

  // user is not following the community and cannot view nor create posts
  const user = await registerUser(beta, betaUrl);
  const betaCommunity = (
    await resolveCommunity(user, community.community_view.community.ap_id)
  )?.community;
  await jestLemmyError(
    () => resolvePost(user, post0.post_view.post),
    new LemmyError("resolve_object_failed", statusBadRequest),
    false,
  );
  await jestLemmyError(
    () => resolveComment(user, comment.comment_view.comment),
    n
Download .txt
gitextract__t6y25uc/

├── .gitattributes
├── .github/
│   ├── CODEOWNERS
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── BUG_REPORT.yml
│   │   ├── FEATURE_REQUEST.yml
│   │   └── QUESTION.yml
│   └── SECURITY.md
├── .gitignore
├── .gitmodules
├── .rustfmt.toml
├── .woodpecker.yml
├── Cargo.toml
├── LICENSE
├── README.md
├── api_tests/
│   ├── .npmrc
│   ├── .prettierrc.json
│   ├── eslint.config.mjs
│   ├── jest.config.js
│   ├── package.json
│   ├── pnpm-workspace.yaml
│   ├── prepare-drone-federation-test.sh
│   ├── run-federation-test.sh
│   ├── src/
│   │   ├── apiv3.spec.ts
│   │   ├── comment.spec.ts
│   │   ├── community.spec.ts
│   │   ├── follow.spec.ts
│   │   ├── image.spec.ts
│   │   ├── post.spec.ts
│   │   ├── private_comm.spec.ts
│   │   ├── private_message.spec.ts
│   │   ├── shared.ts
│   │   ├── speed.spec.ts
│   │   ├── tags.spec.ts
│   │   └── user.spec.ts
│   └── tsconfig.json
├── cliff.toml
├── config/
│   ├── config.hjson
│   └── defaults.hjson
├── crates/
│   ├── api/
│   │   ├── api/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── comment/
│   │   │       │   ├── distinguish.rs
│   │   │       │   ├── like.rs
│   │   │       │   ├── list_comment_likes.rs
│   │   │       │   ├── lock.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── save.rs
│   │   │       │   └── warning.rs
│   │   │       ├── community/
│   │   │       │   ├── add_mod.rs
│   │   │       │   ├── ban.rs
│   │   │       │   ├── block.rs
│   │   │       │   ├── follow.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── multi_community_follow.rs
│   │   │       │   ├── pending_follows/
│   │   │       │   │   ├── approve.rs
│   │   │       │   │   ├── list.rs
│   │   │       │   │   └── mod.rs
│   │   │       │   ├── random.rs
│   │   │       │   ├── tag.rs
│   │   │       │   ├── transfer.rs
│   │   │       │   └── update_notifications.rs
│   │   │       ├── federation/
│   │   │       │   ├── fetcher.rs
│   │   │       │   ├── list_comments.rs
│   │   │       │   ├── list_person_content.rs
│   │   │       │   ├── list_posts.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── read_community.rs
│   │   │       │   ├── read_multi_community.rs
│   │   │       │   ├── read_person.rs
│   │   │       │   ├── resolve_object.rs
│   │   │       │   ├── search.rs
│   │   │       │   └── user_settings_backup.rs
│   │   │       ├── lib.rs
│   │   │       ├── local_user/
│   │   │       │   ├── add_admin.rs
│   │   │       │   ├── ban_person.rs
│   │   │       │   ├── block.rs
│   │   │       │   ├── change_password.rs
│   │   │       │   ├── change_password_after_reset.rs
│   │   │       │   ├── donation_dialog_shown.rs
│   │   │       │   ├── export_data.rs
│   │   │       │   ├── generate_totp_secret.rs
│   │   │       │   ├── get_captcha.rs
│   │   │       │   ├── list_hidden.rs
│   │   │       │   ├── list_liked.rs
│   │   │       │   ├── list_logins.rs
│   │   │       │   ├── list_media.rs
│   │   │       │   ├── list_read.rs
│   │   │       │   ├── list_saved.rs
│   │   │       │   ├── login.rs
│   │   │       │   ├── logout.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── note_person.rs
│   │   │       │   ├── notifications/
│   │   │       │   │   ├── list.rs
│   │   │       │   │   ├── mark_all_read.rs
│   │   │       │   │   ├── mark_notification_read.rs
│   │   │       │   │   └── mod.rs
│   │   │       │   ├── resend_verification_email.rs
│   │   │       │   ├── reset_password.rs
│   │   │       │   ├── save_settings.rs
│   │   │       │   ├── unread_counts.rs
│   │   │       │   ├── update_totp.rs
│   │   │       │   ├── user_block_instance.rs
│   │   │       │   ├── validate_auth.rs
│   │   │       │   └── verify_email.rs
│   │   │       ├── post/
│   │   │       │   ├── feature.rs
│   │   │       │   ├── get_link_metadata.rs
│   │   │       │   ├── hide.rs
│   │   │       │   ├── like.rs
│   │   │       │   ├── list_post_likes.rs
│   │   │       │   ├── lock.rs
│   │   │       │   ├── mark_many_read.rs
│   │   │       │   ├── mark_read.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── mod_update.rs
│   │   │       │   ├── save.rs
│   │   │       │   ├── update_notifications.rs
│   │   │       │   └── warning.rs
│   │   │       ├── reports/
│   │   │       │   ├── comment_report/
│   │   │       │   │   ├── create.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   └── resolve.rs
│   │   │       │   ├── community_report/
│   │   │       │   │   ├── create.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   └── resolve.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── post_report/
│   │   │       │   │   ├── create.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   └── resolve.rs
│   │   │       │   ├── private_message_report/
│   │   │       │   │   ├── create.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   └── resolve.rs
│   │   │       │   └── report_combined/
│   │   │       │       ├── list.rs
│   │   │       │       └── mod.rs
│   │   │       ├── site/
│   │   │       │   ├── admin_allow_instance.rs
│   │   │       │   ├── admin_block_instance.rs
│   │   │       │   ├── admin_list_users.rs
│   │   │       │   ├── federated_instances.rs
│   │   │       │   ├── list_all_media.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── mod_log.rs
│   │   │       │   ├── purge/
│   │   │       │   │   ├── comment.rs
│   │   │       │   │   ├── community.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   ├── person.rs
│   │   │       │   │   └── post.rs
│   │   │       │   └── registration_applications/
│   │   │       │       ├── approve.rs
│   │   │       │       ├── get.rs
│   │   │       │       ├── list.rs
│   │   │       │       ├── mod.rs
│   │   │       │       └── tests.rs
│   │   │       └── sitemap.rs
│   │   ├── api_common/
│   │   │   ├── Cargo.toml
│   │   │   ├── README.md
│   │   │   └── src/
│   │   │       ├── account.rs
│   │   │       ├── comment.rs
│   │   │       ├── community.rs
│   │   │       ├── custom_emoji.rs
│   │   │       ├── error.rs
│   │   │       ├── federation.rs
│   │   │       ├── language.rs
│   │   │       ├── lib.rs
│   │   │       ├── media.rs
│   │   │       ├── modlog.rs
│   │   │       ├── notification.rs
│   │   │       ├── oauth.rs
│   │   │       ├── person.rs
│   │   │       ├── plugin.rs
│   │   │       ├── post.rs
│   │   │       ├── private_message.rs
│   │   │       ├── report.rs
│   │   │       ├── search.rs
│   │   │       ├── site.rs
│   │   │       └── tagline.rs
│   │   ├── api_crud/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── comment/
│   │   │       │   ├── create.rs
│   │   │       │   ├── delete.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── read.rs
│   │   │       │   ├── remove.rs
│   │   │       │   └── update.rs
│   │   │       ├── community/
│   │   │       │   ├── create.rs
│   │   │       │   ├── delete.rs
│   │   │       │   ├── list.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── remove.rs
│   │   │       │   └── update.rs
│   │   │       ├── custom_emoji/
│   │   │       │   ├── create.rs
│   │   │       │   ├── delete.rs
│   │   │       │   ├── list.rs
│   │   │       │   ├── mod.rs
│   │   │       │   └── update.rs
│   │   │       ├── lib.rs
│   │   │       ├── multi_community/
│   │   │       │   ├── create.rs
│   │   │       │   ├── create_entry.rs
│   │   │       │   ├── delete_entry.rs
│   │   │       │   ├── list.rs
│   │   │       │   ├── mod.rs
│   │   │       │   └── update.rs
│   │   │       ├── oauth_provider/
│   │   │       │   ├── create.rs
│   │   │       │   ├── delete.rs
│   │   │       │   ├── mod.rs
│   │   │       │   └── update.rs
│   │   │       ├── post/
│   │   │       │   ├── create.rs
│   │   │       │   ├── delete.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── read.rs
│   │   │       │   ├── remove.rs
│   │   │       │   └── update.rs
│   │   │       ├── private_message/
│   │   │       │   ├── create.rs
│   │   │       │   ├── delete.rs
│   │   │       │   ├── mod.rs
│   │   │       │   └── update.rs
│   │   │       ├── site/
│   │   │       │   ├── create.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── read.rs
│   │   │       │   └── update.rs
│   │   │       ├── tagline/
│   │   │       │   ├── create.rs
│   │   │       │   ├── delete.rs
│   │   │       │   ├── list.rs
│   │   │       │   ├── mod.rs
│   │   │       │   └── update.rs
│   │   │       └── user/
│   │   │           ├── create.rs
│   │   │           ├── delete.rs
│   │   │           ├── mod.rs
│   │   │           └── my_user.rs
│   │   ├── api_utils/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── build_response.rs
│   │   │       ├── claims.rs
│   │   │       ├── context.rs
│   │   │       ├── lib.rs
│   │   │       ├── notify.rs
│   │   │       ├── plugins.rs
│   │   │       ├── request.rs
│   │   │       ├── send_activity.rs
│   │   │       └── utils.rs
│   │   ├── routes/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       └── lib.rs
│   │   └── routes_v3/
│   │       ├── Cargo.toml
│   │       └── src/
│   │           ├── convert.rs
│   │           ├── handlers.rs
│   │           └── lib.rs
│   ├── apub/
│   │   ├── activities/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── activity_lists.rs
│   │   │       ├── block/
│   │   │       │   ├── block_user.rs
│   │   │       │   ├── mod.rs
│   │   │       │   └── undo_block_user.rs
│   │   │       ├── community/
│   │   │       │   ├── announce.rs
│   │   │       │   ├── collection_add.rs
│   │   │       │   ├── collection_remove.rs
│   │   │       │   ├── lock.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── report.rs
│   │   │       │   ├── resolve_report.rs
│   │   │       │   └── update.rs
│   │   │       ├── create_or_update/
│   │   │       │   ├── comment.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── note_wrapper.rs
│   │   │       │   ├── post.rs
│   │   │       │   └── private_message.rs
│   │   │       ├── deletion/
│   │   │       │   ├── delete.rs
│   │   │       │   ├── mod.rs
│   │   │       │   └── undo_delete.rs
│   │   │       ├── following/
│   │   │       │   ├── accept.rs
│   │   │       │   ├── follow.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── reject.rs
│   │   │       │   └── undo_follow.rs
│   │   │       ├── lib.rs
│   │   │       ├── protocol/
│   │   │       │   ├── block/
│   │   │       │   │   ├── block_user.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   └── undo_block_user.rs
│   │   │       │   ├── community/
│   │   │       │   │   ├── announce.rs
│   │   │       │   │   ├── collection_add.rs
│   │   │       │   │   ├── collection_remove.rs
│   │   │       │   │   ├── lock.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   ├── report.rs
│   │   │       │   │   ├── resolve_report.rs
│   │   │       │   │   └── update.rs
│   │   │       │   ├── create_or_update/
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   ├── note.rs
│   │   │       │   │   ├── note_wrapper.rs
│   │   │       │   │   ├── page.rs
│   │   │       │   │   └── private_message.rs
│   │   │       │   ├── deletion/
│   │   │       │   │   ├── delete.rs
│   │   │       │   │   ├── delete_user.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   └── undo_delete.rs
│   │   │       │   ├── following/
│   │   │       │   │   ├── accept.rs
│   │   │       │   │   ├── follow.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   ├── reject.rs
│   │   │       │   │   └── undo_follow.rs
│   │   │       │   ├── mod.rs
│   │   │       │   └── voting/
│   │   │       │       ├── mod.rs
│   │   │       │       ├── undo_vote.rs
│   │   │       │       └── vote.rs
│   │   │       └── voting/
│   │   │           ├── mod.rs
│   │   │           ├── undo_vote.rs
│   │   │           └── vote.rs
│   │   ├── apub/
│   │   │   ├── Cargo.toml
│   │   │   ├── assets/
│   │   │   │   ├── discourse/
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── group.json
│   │   │   │   │       ├── page.json
│   │   │   │   │       └── person.json
│   │   │   │   ├── friendica/
│   │   │   │   │   ├── activities/
│   │   │   │   │   │   ├── create_note.json
│   │   │   │   │   │   ├── create_page_1.json
│   │   │   │   │   │   ├── create_page_2.json
│   │   │   │   │   │   ├── delete.json
│   │   │   │   │   │   ├── dislike_page.json
│   │   │   │   │   │   ├── like_page.json
│   │   │   │   │   │   ├── undo_dislike_page.json
│   │   │   │   │   │   └── update_note.json
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── note_1.json
│   │   │   │   │       ├── note_2.json
│   │   │   │   │       ├── page_1.json
│   │   │   │   │       ├── page_2.json
│   │   │   │   │       ├── person_1.json
│   │   │   │   │       └── person_2.json
│   │   │   │   ├── gnusocial/
│   │   │   │   │   ├── activities/
│   │   │   │   │   │   ├── create_note.json
│   │   │   │   │   │   ├── create_page.json
│   │   │   │   │   │   └── like_note.json
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── group.json
│   │   │   │   │       ├── note.json
│   │   │   │   │       ├── page.json
│   │   │   │   │       └── person.json
│   │   │   │   ├── lemmy/
│   │   │   │   │   ├── activities/
│   │   │   │   │   │   ├── block/
│   │   │   │   │   │   │   ├── block_user.json
│   │   │   │   │   │   │   └── undo_block_user.json
│   │   │   │   │   │   ├── community/
│   │   │   │   │   │   │   ├── add_featured_post.json
│   │   │   │   │   │   │   ├── add_mod.json
│   │   │   │   │   │   │   ├── announce_create_page.json
│   │   │   │   │   │   │   ├── lock_note.json
│   │   │   │   │   │   │   ├── lock_page.json
│   │   │   │   │   │   │   ├── remove_featured_post.json
│   │   │   │   │   │   │   ├── remove_mod.json
│   │   │   │   │   │   │   ├── report_page.json
│   │   │   │   │   │   │   ├── resolve_report_page.json
│   │   │   │   │   │   │   ├── undo_lock_note.json
│   │   │   │   │   │   │   ├── undo_lock_page.json
│   │   │   │   │   │   │   └── update_community.json
│   │   │   │   │   │   ├── create_or_update/
│   │   │   │   │   │   │   ├── create_comment.json
│   │   │   │   │   │   │   ├── create_page.json
│   │   │   │   │   │   │   ├── create_private_message.json
│   │   │   │   │   │   │   └── update_page.json
│   │   │   │   │   │   ├── deletion/
│   │   │   │   │   │   │   ├── delete_page.json
│   │   │   │   │   │   │   ├── delete_private_message.json
│   │   │   │   │   │   │   ├── delete_user.json
│   │   │   │   │   │   │   ├── remove_note.json
│   │   │   │   │   │   │   ├── undo_delete_page.json
│   │   │   │   │   │   │   ├── undo_delete_private_message.json
│   │   │   │   │   │   │   └── undo_remove_note.json
│   │   │   │   │   │   ├── following/
│   │   │   │   │   │   │   ├── accept.json
│   │   │   │   │   │   │   ├── follow.json
│   │   │   │   │   │   │   └── undo_follow.json
│   │   │   │   │   │   └── voting/
│   │   │   │   │   │       ├── dislike_page.json
│   │   │   │   │   │       ├── like_note.json
│   │   │   │   │   │       ├── undo_dislike_page.json
│   │   │   │   │   │       └── undo_like_note.json
│   │   │   │   │   ├── collections/
│   │   │   │   │   │   ├── group_featured_posts.json
│   │   │   │   │   │   ├── group_followers.json
│   │   │   │   │   │   ├── group_moderators.json
│   │   │   │   │   │   ├── group_outbox.json
│   │   │   │   │   │   └── person_outbox.json
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── comment.json
│   │   │   │   │       ├── group.json
│   │   │   │   │       ├── instance.json
│   │   │   │   │       ├── page.json
│   │   │   │   │       ├── person.json
│   │   │   │   │       ├── private_message.json
│   │   │   │   │       └── tombstone.json
│   │   │   │   ├── lotide/
│   │   │   │   │   ├── activities/
│   │   │   │   │   │   ├── create_note_reply.json
│   │   │   │   │   │   ├── create_page.json
│   │   │   │   │   │   ├── create_page_image.json
│   │   │   │   │   │   ├── delete_note.json
│   │   │   │   │   │   └── follow.json
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── group.json
│   │   │   │   │       ├── note.json
│   │   │   │   │       ├── page.json
│   │   │   │   │       ├── person.json
│   │   │   │   │       └── tombstone.json
│   │   │   │   ├── mastodon/
│   │   │   │   │   ├── activities/
│   │   │   │   │   │   ├── create_note.json
│   │   │   │   │   │   ├── delete.json
│   │   │   │   │   │   ├── flag.json
│   │   │   │   │   │   ├── follow.json
│   │   │   │   │   │   ├── like_page.json
│   │   │   │   │   │   ├── private_message.json
│   │   │   │   │   │   ├── undo_follow.json
│   │   │   │   │   │   └── undo_like_page.json
│   │   │   │   │   ├── collections/
│   │   │   │   │   │   └── featured.json
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── note_1.json
│   │   │   │   │       ├── note_2.json
│   │   │   │   │       ├── page.json
│   │   │   │   │       └── person.json
│   │   │   │   ├── mbin/
│   │   │   │   │   ├── activities/
│   │   │   │   │   │   ├── accept.json
│   │   │   │   │   │   └── flag.json
│   │   │   │   │   └── objects/
│   │   │   │   │       └── instance.json
│   │   │   │   ├── mobilizon/
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── event.json
│   │   │   │   │       ├── group.json
│   │   │   │   │       └── person.json
│   │   │   │   ├── nodebb/
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── group.json
│   │   │   │   │       ├── page.json
│   │   │   │   │       └── person.json
│   │   │   │   ├── peertube/
│   │   │   │   │   ├── activities/
│   │   │   │   │   │   └── announce_video.json
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── group.json
│   │   │   │   │       ├── note.json
│   │   │   │   │       ├── person.json
│   │   │   │   │       └── video.json
│   │   │   │   ├── pleroma/
│   │   │   │   │   ├── activities/
│   │   │   │   │   │   ├── create_note.json
│   │   │   │   │   │   ├── delete.json
│   │   │   │   │   │   └── follow.json
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── chat_message.json
│   │   │   │   │       ├── note.json
│   │   │   │   │       └── person.json
│   │   │   │   ├── smithereen/
│   │   │   │   │   ├── activities/
│   │   │   │   │   │   └── create_note.json
│   │   │   │   │   └── objects/
│   │   │   │   │       ├── note.json
│   │   │   │   │       └── person.json
│   │   │   │   └── wordpress/
│   │   │   │       ├── activities/
│   │   │   │       │   └── announce.json
│   │   │   │       └── objects/
│   │   │   │           ├── group.json
│   │   │   │           ├── note.json
│   │   │   │           ├── page.json
│   │   │   │           └── person.json
│   │   │   └── src/
│   │   │       ├── collections/
│   │   │       │   ├── community_featured.rs
│   │   │       │   ├── community_follower.rs
│   │   │       │   ├── community_moderators.rs
│   │   │       │   ├── community_outbox.rs
│   │   │       │   └── mod.rs
│   │   │       ├── http/
│   │   │       │   ├── comment.rs
│   │   │       │   ├── community.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── person.rs
│   │   │       │   ├── post.rs
│   │   │       │   ├── routes.rs
│   │   │       │   └── site.rs
│   │   │       ├── lib.rs
│   │   │       └── protocol/
│   │   │           ├── collections/
│   │   │           │   ├── group_featured.rs
│   │   │           │   ├── group_followers.rs
│   │   │           │   ├── group_moderators.rs
│   │   │           │   ├── group_outbox.rs
│   │   │           │   ├── mod.rs
│   │   │           │   └── url_collection.rs
│   │   │           └── mod.rs
│   │   ├── objects/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── lib.rs
│   │   │       ├── objects/
│   │   │       │   ├── comment.rs
│   │   │       │   ├── community.rs
│   │   │       │   ├── instance.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── multi_community.rs
│   │   │       │   ├── multi_community_collection.rs
│   │   │       │   ├── person.rs
│   │   │       │   ├── post.rs
│   │   │       │   └── private_message.rs
│   │   │       ├── protocol/
│   │   │       │   ├── group.rs
│   │   │       │   ├── instance.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── multi_community.rs
│   │   │       │   ├── note.rs
│   │   │       │   ├── page.rs
│   │   │       │   ├── person.rs
│   │   │       │   ├── private_message.rs
│   │   │       │   └── tags.rs
│   │   │       └── utils/
│   │   │           ├── functions.rs
│   │   │           ├── markdown_links.rs
│   │   │           ├── mentions.rs
│   │   │           ├── mod.rs
│   │   │           ├── protocol.rs
│   │   │           └── test.rs
│   │   └── send/
│   │       ├── Cargo.toml
│   │       └── src/
│   │           ├── inboxes.rs
│   │           ├── lib.rs
│   │           ├── send.rs
│   │           ├── stats.rs
│   │           ├── util.rs
│   │           └── worker.rs
│   ├── db_schema/
│   │   ├── Cargo.toml
│   │   └── src/
│   │       ├── impls/
│   │       │   ├── activity.rs
│   │       │   ├── actor_language.rs
│   │       │   ├── comment.rs
│   │       │   ├── comment_report.rs
│   │       │   ├── community.rs
│   │       │   ├── community_community_follow.rs
│   │       │   ├── community_report.rs
│   │       │   ├── community_tag.rs
│   │       │   ├── custom_emoji.rs
│   │       │   ├── email_verification.rs
│   │       │   ├── federation_allowlist.rs
│   │       │   ├── federation_blocklist.rs
│   │       │   ├── federation_queue_state.rs
│   │       │   ├── images.rs
│   │       │   ├── instance.rs
│   │       │   ├── keyword_block.rs
│   │       │   ├── language.rs
│   │       │   ├── local_site.rs
│   │       │   ├── local_site_rate_limit.rs
│   │       │   ├── local_site_url_blocklist.rs
│   │       │   ├── local_user.rs
│   │       │   ├── login_token.rs
│   │       │   ├── mod.rs
│   │       │   ├── modlog.rs
│   │       │   ├── multi_community.rs
│   │       │   ├── notification.rs
│   │       │   ├── oauth_account.rs
│   │       │   ├── oauth_provider.rs
│   │       │   ├── password_reset_request.rs
│   │       │   ├── person.rs
│   │       │   ├── post.rs
│   │       │   ├── post_report.rs
│   │       │   ├── private_message.rs
│   │       │   ├── private_message_report.rs
│   │       │   ├── registration_application.rs
│   │       │   ├── secret.rs
│   │       │   ├── site.rs
│   │       │   └── tagline.rs
│   │       ├── lib.rs
│   │       ├── newtypes.rs
│   │       ├── source/
│   │       │   ├── activity.rs
│   │       │   ├── actor_language.rs
│   │       │   ├── combined/
│   │       │   │   ├── mod.rs
│   │       │   │   ├── person_content.rs
│   │       │   │   ├── person_liked.rs
│   │       │   │   ├── person_saved.rs
│   │       │   │   ├── report.rs
│   │       │   │   └── search.rs
│   │       │   ├── comment.rs
│   │       │   ├── comment_report.rs
│   │       │   ├── community.rs
│   │       │   ├── community_community_follow.rs
│   │       │   ├── community_report.rs
│   │       │   ├── community_tag.rs
│   │       │   ├── custom_emoji.rs
│   │       │   ├── custom_emoji_keyword.rs
│   │       │   ├── email_verification.rs
│   │       │   ├── federation_allowlist.rs
│   │       │   ├── federation_blocklist.rs
│   │       │   ├── federation_queue_state.rs
│   │       │   ├── images.rs
│   │       │   ├── instance.rs
│   │       │   ├── keyword_block.rs
│   │       │   ├── language.rs
│   │       │   ├── local_site.rs
│   │       │   ├── local_site_rate_limit.rs
│   │       │   ├── local_site_url_blocklist.rs
│   │       │   ├── local_user.rs
│   │       │   ├── login_token.rs
│   │       │   ├── mod.rs
│   │       │   ├── modlog.rs
│   │       │   ├── multi_community.rs
│   │       │   ├── notification.rs
│   │       │   ├── oauth_account.rs
│   │       │   ├── oauth_provider.rs
│   │       │   ├── password_reset_request.rs
│   │       │   ├── person.rs
│   │       │   ├── post.rs
│   │       │   ├── post_report.rs
│   │       │   ├── private_message.rs
│   │       │   ├── private_message_report.rs
│   │       │   ├── registration_application.rs
│   │       │   ├── secret.rs
│   │       │   ├── site.rs
│   │       │   └── tagline.rs
│   │       ├── test_data.rs
│   │       ├── traits.rs
│   │       └── utils/
│   │           ├── mod.rs
│   │           └── queries/
│   │               ├── filters.rs
│   │               ├── mod.rs
│   │               └── selects.rs
│   ├── db_schema_file/
│   │   ├── Cargo.toml
│   │   ├── diesel_ltree.patch
│   │   └── src/
│   │       ├── enums.rs
│   │       ├── joins.rs
│   │       ├── lib.rs
│   │       ├── schema.rs
│   │       └── table_impls.rs
│   ├── db_views/
│   │   ├── comment/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── community/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── community_follower/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── community_follower_approval/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── community_moderator/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── custom_emoji/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── local_image/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── local_user/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── modlog/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── notification/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       ├── lib.rs
│   │   │       └── tests.rs
│   │   ├── notification_sql/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       └── lib.rs
│   │   ├── person/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── person_content_combined/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── person_liked_combined/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── person_saved_combined/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── post/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── db_perf/
│   │   │       │   ├── mod.rs
│   │   │       │   └── series.rs
│   │   │       ├── impls.rs
│   │   │       ├── lib.rs
│   │   │       └── test.rs
│   │   ├── post_comment_combined/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       └── lib.rs
│   │   ├── private_message/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── registration_applications/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── report_combined/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── report_combined_sql/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       └── lib.rs
│   │   ├── search_combined/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   ├── site/
│   │   │   ├── Cargo.toml
│   │   │   └── src/
│   │   │       ├── api.rs
│   │   │       ├── impls.rs
│   │   │       └── lib.rs
│   │   └── vote/
│   │       ├── Cargo.toml
│   │       └── src/
│   │           ├── impls.rs
│   │           └── lib.rs
│   ├── diesel_utils/
│   │   ├── Cargo.toml
│   │   ├── build.rs
│   │   ├── replaceable_schema/
│   │   │   ├── triggers.sql
│   │   │   └── utils.sql
│   │   └── src/
│   │       ├── connection.rs
│   │       ├── dburl.rs
│   │       ├── lib.rs
│   │       ├── main.rs
│   │       ├── pagination.rs
│   │       ├── schema_setup/
│   │       │   ├── diff_check.rs
│   │       │   └── mod.rs
│   │       ├── sensitive.rs
│   │       ├── traits.rs
│   │       └── utils.rs
│   ├── email/
│   │   ├── Cargo.toml
│   │   ├── build.rs
│   │   └── src/
│   │       ├── account.rs
│   │       ├── admin.rs
│   │       ├── lib.rs
│   │       ├── notifications.rs
│   │       └── send.rs
│   ├── routes/
│   │   ├── Cargo.toml
│   │   └── src/
│   │       ├── feeds/
│   │       │   ├── mod.rs
│   │       │   └── negotiate_content.rs
│   │       ├── images/
│   │       │   ├── delete.rs
│   │       │   ├── download.rs
│   │       │   ├── mod.rs
│   │       │   ├── upload.rs
│   │       │   └── utils.rs
│   │       ├── lib.rs
│   │       ├── middleware/
│   │       │   ├── idempotency.rs
│   │       │   ├── mod.rs
│   │       │   └── session.rs
│   │       ├── nodeinfo.rs
│   │       ├── utils/
│   │       │   ├── mod.rs
│   │       │   ├── prometheus_metrics.rs
│   │       │   ├── scheduled_tasks.rs
│   │       │   └── setup_local_site.rs
│   │       └── webfinger.rs
│   ├── server/
│   │   ├── Cargo.toml
│   │   └── src/
│   │       ├── lib.rs
│   │       └── main.rs
│   └── utils/
│       ├── Cargo.toml
│       ├── src/
│       │   ├── cache_header.rs
│       │   ├── error.rs
│       │   ├── lib.rs
│       │   ├── main.rs
│       │   ├── rate_limit/
│       │   │   ├── backend.rs
│       │   │   ├── input.rs
│       │   │   └── mod.rs
│       │   ├── response.rs
│       │   ├── settings/
│       │   │   ├── mod.rs
│       │   │   └── structs.rs
│       │   └── utils/
│       │       ├── markdown/
│       │       │   ├── identifier_rule.rs
│       │       │   ├── image_links.rs
│       │       │   ├── link_rule.rs
│       │       │   └── mod.rs
│       │       ├── mention.rs
│       │       ├── mod.rs
│       │       ├── slurs.rs
│       │       └── validation.rs
│       └── tests/
│           └── test_errors_used.rs
├── diesel.toml
├── docker/
│   ├── Dockerfile
│   ├── README.md
│   ├── customPostgresql.conf
│   ├── docker-compose.yml
│   ├── docker_db_backup.sh
│   ├── docker_update.sh
│   ├── federation/
│   │   ├── docker-compose.yml
│   │   ├── lemmy_alpha.hjson
│   │   ├── lemmy_beta.hjson
│   │   ├── lemmy_delta.hjson
│   │   ├── lemmy_epsilon.hjson
│   │   ├── lemmy_gamma.hjson
│   │   ├── nginx.conf
│   │   └── start-local-instances.bash
│   ├── lemmy.hjson
│   ├── nginx.conf
│   └── test_deploy.sh
├── migrations/
│   ├── 00000000000000_diesel_initial_setup/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-02-26-002946_create_user/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-02-27-170003_create_community/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-03-03-163336_create_post/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-03-05-233828_create_comment/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-03-30-212058_create_post_view/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-04-03-155205_create_community_view/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-04-03-155309_create_comment_view/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-04-07-003142_create_moderation_logs/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-04-08-015947_create_user_view/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-04-11-144915_create_mod_views/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-04-29-175834_add_delete_columns/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-05-02-051656_community_view_hot_rank/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-06-01-222649_remove_admin/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-08-11-000918_add_nsfw_columns/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-08-29-040006_add_community_count/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-09-05-230317_add_mod_ban_views/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-09-09-042010_add_stickied_posts/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-10-15-181630_add_themes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-10-19-052737_create_user_mention/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-10-21-011237_add_default_sorts/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-10-24-002614_create_password_reset_request/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-12-09-060754_add_lang/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-12-11-181820_add_site_fields/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2019-12-29-164820_add_avatar/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-01-01-200418_add_email_to_user_view/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-01-02-172755_add_show_avatar_and_email_notifications_to_user/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-01-11-012452_add_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-01-13-025151_create_materialized_views/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-01-21-001001_create_private_message/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-01-29-011901_create_reply_materialized_view/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-01-29-030825_create_user_mention_materialized_view/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-02-02-004806_add_case_insensitive_usernames/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-02-06-165953_change_post_title_length/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-02-07-210055_add_comment_subscribed/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-02-08-145624_add_post_newest_activity_time/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-03-06-202329_add_post_iframely_data/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-03-26-192410_add_activitypub_tables/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-04-03-194936_add_activitypub_for_posts_and_comments/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-04-07-135912_add_user_community_apub_constraints/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-04-14-163701_update_views_for_activitypub/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-04-21-123957_remove_unique_user_constraints/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-05-05-210233_add_activitypub_for_private_messages/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-06-30-135809_remove_mat_views/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-07-08-202609_add_creator_published/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-07-12-100442_add_post_title_to_comments_view/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-07-18-234519_add_unique_community_user_actor_ids/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-08-03-000110_add_preferred_usernames_banners_and_icons/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-08-06-205355_update_community_post_count/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-08-25-132005_add_unique_ap_ids/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-09-07-231141_add_migration_utils/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-10-07-234221_fix_fast_triggers/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-10-10-035723_fix_fast_triggers_2/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-10-13-212240_create_report_tables/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-10-23-115011_activity_ap_id_column/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-11-05-152724_activity_remove_user_id/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-11-10-150835_community_follower_pending/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-11-26-134531_delete_user/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-12-02-152437_create_site_aggregates/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-12-03-035643_create_user_aggregates/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-12-04-183345_create_community_aggregates/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-12-10-152350_create_post_aggregates/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-12-14-020038_create_comment_aggregates/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-12-17-030456_create_alias_views/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2020-12-17-031053_remove_fast_tables_and_views/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-01-05-200932_add_hot_rank_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-01-26-173850_default_actor_id/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-01-27-202728_active_users_monthly/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-01-31-050334_add_forum_sort_index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-02-02-153240_apub_columns/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-02-10-164051_add_new_comments_sort_index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-02-13-210612_set_correct_aggregates_time_columns/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-02-25-112959_remove-categories/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-02-28-162616_clean_empty_post_urls/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-03-04-040229_clean_icon_urls/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-03-09-171136_split_user_table_2/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-03-19-014144_add_col_local_user_validator_time/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-03-20-185321_move_matrix_id_to_person/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-03-31-103917_add_show_score_setting/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-03-31-105915_add_bot_account/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-03-31-144349_add_site_short_description/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-04-01-173552_rename_preferred_username_to_display_name/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-04-01-181826_add_community_agg_active_monthly_index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-04-02-021422_remove_community_creator/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-04-20-155001_limit-admins-create-community/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-04-24-174047_add_show_read_post_setting/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-07-19-130929_add_show_new_post_notifs_setting/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-07-20-102033_actor_name_length/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-08-02-002342_comment_count_fixes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-08-04-223559_create_user_community_block/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-08-16-004209_fix_remove_bots_from_aggregates/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-08-17-210508_create_mod_transfer_community/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-09-20-112945_jwt-secret/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-10-01-141650_create_admin_purge/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-11-22-135324_add_activity_ap_id_index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-11-22-143904_add_required_public_key/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-11-23-031528_add_report_published_index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-11-23-132840_email_verification/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-11-23-153753_add_invite_only_columns/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-12-09-225529_add_published_to_email_verification/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2021-12-14-181537_add_temporary_bans/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-01-04-034553_add_hidden_column/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-01-20-160328_remove_site_creator/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-01-28-104106_instance-actor/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-02-01-154240_add_community_title_index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-02-18-210946_default_theme/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-04-04-183652_update_community_aggregates_on_soft_delete/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-04-11-210137_fix_unique_changeme/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-04-12-114352_default_post_listing_type/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-04-12-185205_change_default_listing_type_to_local/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-04-19-111004_default_require_application/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-04-26-105145_only_mod_can_post/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-05-19-153931_legal-information/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-05-20-135341_embed-url/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-06-12-012121_add_site_hide_modlog_names/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-06-13-124806_post_report_name_length/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-06-21-123144_language-tags/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-07-07-182650_comment_ltrees/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-08-04-150644_add_application_email_admins/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-08-04-214722_add_distinguished_comment/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-08-05-203502_add_person_post_aggregates/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-08-22-193848_comment-language-tags/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-09-07-113813_drop_ccnew_indexes_function/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-09-07-114618_pm-reports/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-09-08-102358_site-and-community-languages/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-09-24-161829_remove_table_aliases/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-10-06-183632_move_blocklist_to_db/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-11-13-181529_create_taglines/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-11-20-032430_sticky_local/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-11-21-143249_remove-federation-settings/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-11-21-204256_user-following/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2022-12-05-110642_registration_mode/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-01-17-165819_cleanup_post_aggregates_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-02-01-012747_fix_active_index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-02-05-102549_drop-site-federation-debug/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-02-07-030958_community-collections/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-02-11-173347_custom_emojis/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-02-13-172528_add_report_email_admins/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-02-13-221303_add_instance_software_and_version/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-02-15-212546_add_post_comment_saved_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-02-16-194139_add_totp_secret/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-04-14-175955_add_listingtype_sorttype_enums/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-04-23-164732_add_person_details_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-05-10-095739_force_enable_undetermined_language/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-06-104440_index_post_url/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-07-105918_add_hot_rank_columns/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-17-175955_add_listingtype_sorttype_hour_enums/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-19-055530_add_retry_worker_setting/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-19-120700_no_double_deletion/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-20-191145_add_listingtype_sorttype_3_6_9_months_enums/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-21-153242_add_captcha/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-22-051755_fix_local_communities_marked_non_local/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-22-101245_increase_user_theme_column_size/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-24-072904_add_open_links_in_new_tab_setting/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-24-185942_aggegates_published_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-06-27-065106_add_ui_settings/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-04-153335_add_optimized_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-05-000058_person-admin/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-06-151124_hot-rank-future/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-08-101154_fix_soft_delete_aggregates/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-10-075550_add-infinite-scroll-setting/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-11-084714_receive_activity_table/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-14-154840_add_optimized_indexes_published/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-14-215339_aggregates_nonzero_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-18-082614_post_aggregates_community_id/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-19-163511_comment_sort_hot_rank_then_score/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-24-232635_trigram-index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-26-000217_create_controversial_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-26-222023_site-aggregates-one/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-07-27-134652_remove-expensive-broken-trigger/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-08-01-101826_admin_flag_local_user/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-08-01-115243_persistent-activity-queue/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-08-02-144930_password-reset-token/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-08-02-174444_fix-timezones/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-08-08-163911_add_post_listing_mode_setting/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-08-09-101305_user_instance_block/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-08-23-182533_scaled_rank/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-08-29-183053_add_listing_type_moderator_view/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-08-31-205559_add_image_upload/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-09-01-112158_auto_resolve_report/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-09-07-215546_post-queries-efficient/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-09-11-110040_rework-2fa-setup/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-09-12-194850_add_federation_worker_index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-09-18-141700_login-token/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-09-20-110614_drop-show-new-post-notifs/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-09-28-084231_import_user_settings_rate_limit/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-10-02-145002_community_followers_count_federated/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-10-06-133405_add_keyboard_navigation_setting/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-10-13-175712_allow_animated_avatars/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-10-17-181800_drop_remove_community_expires/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-10-23-184941_hot_rank_greatest_fix/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-10-24-030352_change_primary_keys_and_remove_some_id_columns/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-10-24-131607_proxy_links/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-10-24-183747_autocollapse_bot_comments/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-10-27-142514_post_url_content_type/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-11-01-223740_federation-published/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-11-02-120140_apub-signed-fetch/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-11-07-135409_inbox_unique/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-11-22-194806_low_rank_defaults/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-12-06-180359_edit_active_users/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-12-19-210053_tolerable-batch-insert-speed/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2023-12-22-040137_make-mixed-sorting-directions-work-with-tuple-comparison/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-01-02-094916_site-name-not-unique/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-01-05-213000_community_aggregates_add_local_subscribers/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-01-15-100133_local-only-community/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-01-22-105746_lemmynsfw-changes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-01-25-151400_remove_auto_resolve_report_trigger/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-02-12-211114_add_vote_display_mode_setting/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-02-15-171358_default_instance_sort_type/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-02-24-034523_replaceable-schema/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-02-27-204628_add_post_alt_text/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-02-28-144211_hide_posts/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-03-06-104706_local_image_user_opt/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-03-06-201637_url_blocklist/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-04-05-153647_alter_vote_display_mode_defaults/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-04-15-105932_community_followers_url_optional/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-04-23-020604_add_post_id_index/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-05-04-140749_separate_triggers/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-05-05-162540_add_image_detail_table/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-06-17-160323_fix_post_aggregates_featured_local/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-06-24-000000_ap_id_triggers/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-07-01-014711_exponential_controversy/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-08-03-155932_increase_post_url_max_length/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2024-11-12-090437_move-triggers/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-01-10-135505_donation-dialog/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-02-11-131045_ban-remove-content-pm/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-02-24-173152_search-alt-text-of-posts/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-03-07-094522_enable_english_for_all/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-04-07-100344_registration-rate-limit/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-05-15-154113_missing_post_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-07-29-152742_add_indexes_for_aggregates_activity/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-07-29-152743_post-aggregates-creator-community-indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000000_enable_private_messages/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000002_error_if_code_migrations_needed/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000003_remove_show_scores_column/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000004_custom_emoji_tagline_changes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000005_drop-enable-nsfw/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000006_default_comment_sort_type/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000007_schedule-post/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000008_create_oauth_provider/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000009_add_federation_vote_rejection/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000010_remove_auto_expand/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000011_add_short_community_description/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000012_no-individual-inboxes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000013_comment-vote-remote-postid/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000014_private-community/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000015_add_mark_fetched_posts_as_read/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000016_smoosh-tables-together/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000017_forbid_diesel_cli/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000018_custom_migration_runner/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000019_add_report_count/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000020_oauth_pkce/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000021_add_blurhash_to_image_details/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000022_instance-block-mod-log/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000023_add_report_combined_table/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000024_add_person_content_combined_table/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000025_add_modlog_combined_table/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000026_add_inbox_combined_table/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000027_add_search_combined_table/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000028_add_index_on_person_id_read_for_read_only_post_actions/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000029_community-post-tags/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000030_optimize_get_random_community/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000031_update-replaceable-schema/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000032_community_report/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000033_add_post_keyword_block_table/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000034_no-image-token/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000035_media_filter/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000036_interactions_per_month_schema/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000037_report_to_admins/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000038_ap_id/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000039_remove_post_sort_type_enums/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000040_block_nsfw/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000041_remove-aggregate-tables/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000042_community-hidden-visibility/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000043_community-local-removed/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000044_post_comment_pending/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000045_site_person_ban/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000047_disable-email-notifications/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000048_cursor_pagination_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000049_add_liked_combined/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000050_show_downvotes_for_others_only/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000051_local_image_person/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000052_lock_reason/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000053_remove_hide_modlog_names/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000054_mod-change-community-vis/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000055_rename_timestamp_add_at/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000056_person_note/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000057_multi-community/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000058_instance_block_communities_persons/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000059_person_votes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000060_rename-rate-limit-columns/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000061_drop-person-ban/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000062_username-instance-unique/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000063_post-or-comment-notification/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000064_add_missing_foreign_key_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000065_group-follow/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000066_modlog-rename/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000067_add_default_items_per_page/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-01-000068_local_user_trigger/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-06-170325_add_indexes_for_aggregates_activity_new/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-08-20-000000_comment-lock/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-09-01-141127_local-community-collections/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-09-08-000001_add-video-dimensions/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-09-08-140711_remove-actor-name-max-length/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-09-12-093537_mod-reason-mandatory/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-09-15-090401_remove-keyboard-nav/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-09-19-090047_notify-mod-action/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-09-19-132648-0000_theme-instance-default/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-10-08-084508-0000_multi-comm-index-lower/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-10-09-101527-0000_community-follower-denied/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-10-15-114811-0000_merge-modlog-tables/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-11-05-181519-0000_add_registration_application_updated_at/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2025-11-08-123111-0000_add_multi_community_subscribers_community_count/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-01-08-132525-0000_community-sidebar-summary/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-01-19-122321-0000_add_community_tag_color/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-01-23-094410-0000_rename-sidebar-again/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-01-23-140244-0000_rename-tag-to-community-tag/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-01-28-115414-0000_captcha-plugin/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-02-01-205644-0000_add_moderator_warn_modlog_kind/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-02-03-235249-0000_add_moderator_warn_constraint_check/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-02-19-120000-0000_add_bulk_to_modlog/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-02-19-192014-0000_rename_suggested_communities/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-02-24-205759-0000_add_notification_creator_id/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-03-02-231448-0000_add_multi_community_sidebar/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-03-03-211442-0000_move_config_pictrs_to_db/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-03-04-143123-0000_add_deleted_by_recip_to_pm/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-03-08-021022-0000_fixup_post_action_indexes/
│   │   ├── down.sql
│   │   └── up.sql
│   ├── 2026-03-08-202630-0000_add_modlog_foreign_keys/
│   │   ├── down.sql
│   │   └── up.sql
│   └── 2026-03-09-014616-0000_add_resolved_report_combined/
│       ├── down.sql
│       └── up.sql
├── readmes/
│   ├── README.es.md
│   ├── README.ja.md
│   ├── README.ru.md
│   ├── README.zh.hans.md
│   └── README.zh.hant.md
├── rust-toolchain.toml
└── scripts/
    ├── alpine_install_pg_formatter.sh
    ├── clean-workspace.sh
    ├── clear_db.sh
    ├── compilation_benchmark.sh
    ├── db-init.sh
    ├── db_perf.sh
    ├── dump_schema.sh
    ├── install.sh
    ├── lint.sh
    ├── postgres_12_to_15_upgrade.sh
    ├── postgres_15_to_16_upgrade.sh
    ├── query_testing/
    │   ├── apache_bench_report.sh
    │   ├── api_benchmark.sh
    │   ├── bulk_upsert_timings.md
    │   ├── post_query_hot_rank.sh
    │   ├── views_old/
    │   │   ├── generate_reports.sh
    │   │   └── timings-2021-01-05_21-06-37.out
    │   └── views_to_diesel_migration/
    │       ├── generate_reports.sh
    │       └── timings-2021-01-05_21-32-54.out
    ├── release.bash
    ├── restore_db.sh
    ├── sql_format_check.sh
    ├── start_dev_db.sh
    ├── test-with-coverage.sh
    ├── test.sh
    ├── update_config_defaults.sh
    ├── update_schema_file.sh
    ├── update_translations.sh
    └── upgrade_deps.sh
Download .txt
Showing preview only (434K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (4492 symbols across 748 files)

FILE: api_tests/src/comment.spec.ts
  function assertCommentFederation (line 70) | function assertCommentFederation(
  function checkCommentReportReason (line 1044) | function checkCommentReportReason(rcv: ReportCombinedView, reason: strin...

FILE: api_tests/src/community.spec.ts
  function checkCommunityReportName (line 843) | function checkCommunityReportName(

FILE: api_tests/src/post.spec.ts
  function assertPostFederation (line 76) | async function assertPostFederation(
  function checkPostReportName (line 1045) | function checkPostReportName(rcv: ReportCombinedView, report: PostReport) {

FILE: api_tests/src/private_comm.spec.ts
  function approveFollower (line 359) | async function approveFollower(user: LemmyHttp, community_id: number) {

FILE: api_tests/src/shared.ts
  function setupLogins (line 116) | async function setupLogins() {
  function allowInstance (line 215) | async function allowInstance(api: LemmyHttp, instance: string) {
  function createPost (line 229) | async function createPost(
  function editPost (line 250) | async function editPost(
  function createPostWithThumbnail (line 262) | async function createPostWithThumbnail(
  function deletePost (line 277) | async function deletePost(
  function removePost (line 289) | async function removePost(
  function featurePost (line 302) | async function featurePost(
  function lockPost (line 315) | async function lockPost(
  function resolvePost (line 328) | async function resolvePost(
  function searchPostLocal (line 341) | async function searchPostLocal(
  function waitForPost (line 356) | async function waitForPost(
  function getPost (line 367) | async function getPost(
  function lockComment (line 377) | async function lockComment(
  function getComment (line 390) | async function getComment(
  function getComments (line 400) | async function getComments(
  function getUnreadCounts (line 414) | async function getUnreadCounts(
  function listNotifications (line 420) | async function listNotifications(
  function resolveComment (line 432) | async function resolveComment(
  function resolveBetaCommunity (line 445) | async function resolveBetaCommunity(
  function resolveCommunity (line 458) | async function resolveCommunity(
  function resolvePerson (line 471) | async function resolvePerson(
  function banPersonFromSite (line 484) | async function banPersonFromSite(
  function banPersonFromCommunity (line 500) | async function banPersonFromCommunity(
  function followCommunity (line 517) | async function followCommunity(
  function likePost (line 539) | async function likePost(
  function createComment (line 552) | async function createComment(
  function editComment (line 566) | async function editComment(
  function deleteComment (line 578) | async function deleteComment(
  function removeComment (line 590) | async function removeComment(
  function likeComment (line 605) | async function likeComment(
  function createCommunity (line 617) | async function createCommunity(
  function editCommunity (line 632) | async function editCommunity(
  function getCommunity (line 639) | async function getCommunity(
  function getCommunityByName (line 649) | async function getCommunityByName(
  function deleteCommunity (line 659) | async function deleteCommunity(
  function removeCommunity (line 671) | async function removeCommunity(
  function createPrivateMessage (line 684) | async function createPrivateMessage(
  function editPrivateMessage (line 696) | async function editPrivateMessage(
  function deletePrivateMessage (line 708) | async function deletePrivateMessage(
  function registerUser (line 720) | async function registerUser(
  function loginUser (line 740) | async function loginUser(
  function saveUserSettingsBio (line 751) | async function saveUserSettingsBio(
  function saveUserSettingsFederated (line 768) | async function saveUserSettingsFederated(
  function saveUserSettings (line 786) | async function saveUserSettings(
  function getPersonDetails (line 793) | async function getPersonDetails(
  function listPersonContent (line 803) | async function listPersonContent(
  function deleteUser (line 815) | async function deleteUser(
  function getSite (line 826) | async function getSite(api: LemmyHttp): Promise<GetSiteResponse> {
  function getMyUser (line 830) | async function getMyUser(api: LemmyHttp): Promise<MyUserInfo> {
  function unfollowRemotes (line 834) | async function unfollowRemotes(api: LemmyHttp): Promise<MyUserInfo> {
  function followBeta (line 846) | async function followBeta(api: LemmyHttp): Promise<CommunityResponse> {
  function reportPost (line 856) | async function reportPost(
  function reportCommunity (line 868) | async function reportCommunity(
  function listReports (line 880) | async function listReports(
  function reportComment (line 888) | async function reportComment(
  function reportPrivateMessage (line 900) | async function reportPrivateMessage(
  function getPosts (line 912) | function getPosts(
  function userBlockInstanceCommunities (line 925) | function userBlockInstanceCommunities(
  function blockCommunity (line 937) | function blockCommunity(
  function listCommunityPendingFollows (line 949) | function listCommunityPendingFollows(
  function approveCommunityPendingFollow (line 960) | function approveCommunityPendingFollow(
  function getModlog (line 973) | function getModlog(api: LemmyHttp): Promise<PagedResponse<ModlogView>> {
  function wrapper (line 978) | function wrapper(form: any): string {
  function randomString (line 982) | function randomString(length: number): string {
  function deleteAllMedia (line 993) | async function deleteAllMedia(api: LemmyHttp) {
  function unfollows (line 1009) | async function unfollows() {
  function purgeAllPosts (line 1026) | async function purgeAllPosts(api: LemmyHttp) {
  function getCommentParentId (line 1037) | function getCommentParentId(comment: Comment): number | undefined {
  function waitUntil (line 1050) | async function waitUntil<T>(
  function delay (line 1074) | function delay(millis = 500) {
  function assertCommunityFederation (line 1078) | function assertCommunityFederation(
  function jestLemmyError (line 1102) | async function jestLemmyError<T>(

FILE: api_tests/src/speed.spec.ts
  type Result (line 502) | type Result<T> = {
  function timeApiCall (line 541) | async function timeApiCall<T>(promise: () => Promise<T>): Promise<Result...
  function timeApiCalls (line 552) | async function timeApiCalls<T>(promise: () => Promise<T>, times = 10) {
  function timeDiff (line 561) | function timeDiff(start: number, end: number) {
  function average (line 565) | function average(arr: number[]) {
  function formatMs (line 569) | function formatMs(time: number): string {

FILE: api_tests/src/user.spec.ts
  function assertUserFederation (line 51) | function assertUserFederation(userOne?: PersonView, userTwo?: PersonView) {

FILE: crates/api/api/src/comment/distinguish.rs
  function distinguish_comment (line 17) | pub async fn distinguish_comment(

FILE: crates/api/api/src/comment/like.rs
  function like_comment (line 33) | pub async fn like_comment(

FILE: crates/api/api/src/comment/list_comment_likes.rs
  function list_comment_likes (line 10) | pub async fn list_comment_likes(

FILE: crates/api/api/src/comment/lock.rs
  function lock_comment (line 21) | pub async fn lock_comment(

FILE: crates/api/api/src/comment/save.rs
  function save_comment (line 14) | pub async fn save_comment(

FILE: crates/api/api/src/comment/warning.rs
  function create_comment_warning (line 17) | pub async fn create_comment_warning(

FILE: crates/api/api/src/community/add_mod.rs
  function add_mod_to_community (line 21) | pub async fn add_mod_to_community(

FILE: crates/api/api/src/community/ban.rs
  function ban_from_community (line 31) | pub async fn ban_from_community(

FILE: crates/api/api/src/community/block.rs
  function user_block_community (line 24) | pub async fn user_block_community(

FILE: crates/api/api/src/community/follow.rs
  function follow_community (line 14) | pub async fn follow_community(

FILE: crates/api/api/src/community/mod.rs
  function do_follow_community (line 29) | pub(super) async fn do_follow_community(

FILE: crates/api/api/src/community/multi_community_follow.rs
  function follow_multi_community (line 18) | pub async fn follow_multi_community(

FILE: crates/api/api/src/community/pending_follows/approve.rs
  function post_pending_follows_approve (line 15) | pub async fn post_pending_follows_approve(

FILE: crates/api/api/src/community/pending_follows/list.rs
  function get_pending_follows_list (line 11) | pub async fn get_pending_follows_list(

FILE: crates/api/api/src/community/random.rs
  function get_random_community (line 16) | pub async fn get_random_community(

FILE: crates/api/api/src/community/tag.rs
  function create_community_tag (line 28) | pub async fn create_community_tag(
  function edit_community_tag (line 71) | pub async fn edit_community_tag(
  function delete_community_tag (line 100) | pub async fn delete_community_tag(

FILE: crates/api/api/src/community/transfer.rs
  function transfer_community (line 28) | pub async fn transfer_community(

FILE: crates/api/api/src/community/update_notifications.rs
  function edit_community_notifications (line 13) | pub async fn edit_community_notifications(

FILE: crates/api/api/src/federation/fetcher.rs
  function resolve_ap_identifier (line 24) | async fn resolve_ap_identifier<ActorType, DbActor>(
  function resolve_community_identifier (line 73) | pub(crate) async fn resolve_community_identifier(
  function resolve_person_identifier (line 90) | pub(crate) async fn resolve_person_identifier(
  function resolve_multi_community_identifier (line 110) | pub(crate) async fn resolve_multi_community_identifier(

FILE: crates/api/api/src/federation/list_comments.rs
  function list_comments_common (line 19) | async fn list_comments_common(
  function list_comments (line 80) | pub async fn list_comments(
  function list_comments_slim (line 90) | pub async fn list_comments_slim(

FILE: crates/api/api/src/federation/list_person_content.rs
  function list_person_content (line 15) | pub async fn list_person_content(

FILE: crates/api/api/src/federation/list_posts.rs
  function list_posts (line 22) | pub async fn list_posts(

FILE: crates/api/api/src/federation/mod.rs
  function listing_type_with_default (line 20) | fn listing_type_with_default(
  function post_sort_type_with_default (line 41) | fn post_sort_type_with_default(
  function post_time_range_seconds_with_default (line 56) | fn post_time_range_seconds_with_default(
  function comment_sort_type_with_default (line 75) | fn comment_sort_type_with_default(
  function fetch_limit_with_default (line 89) | fn fetch_limit_with_default(

FILE: crates/api/api/src/federation/read_community.rs
  function get_community (line 18) | pub async fn get_community(

FILE: crates/api/api/src/federation/read_multi_community.rs
  function read_multi_community (line 14) | pub async fn read_multi_community(

FILE: crates/api/api/src/federation/read_person.rs
  function read_person (line 19) | pub async fn read_person(

FILE: crates/api/api/src/federation/resolve_object.rs
  function resolve_object (line 23) | pub async fn resolve_object(
  function resolve_object_internal (line 38) | pub(super) async fn resolve_object_internal(
  function search_query_to_object_id (line 88) | async fn search_query_to_object_id(
  function search_query_to_object_id_local (line 112) | async fn search_query_to_object_id_local(
  function test_object_visibility (line 137) | async fn test_object_visibility() -> LemmyResult<()> {
  function assert_response (line 203) | fn assert_response(res: SearchCombinedView, expected_post: &Post) {

FILE: crates/api/api/src/federation/search.rs
  function search (line 17) | pub async fn search(

FILE: crates/api/api/src/federation/user_settings_backup.rs
  constant PARALLELISM (line 42) | const PARALLELISM: usize = 10;
  function export_settings (line 44) | pub async fn export_settings(
  function import_settings (line 54) | pub async fn import_settings(
  function fetch_and_import (line 262) | async fn fetch_and_import<Kind, Fut>(
  function test_settings_export_import (line 322) | async fn test_settings_export_import() -> LemmyResult<()> {
  function disallow_large_backup (line 393) | async fn disallow_large_backup() -> LemmyResult<()> {
  function import_partial_backup (line 430) | async fn import_partial_backup() -> LemmyResult<()> {

FILE: crates/api/api/src/lib.rs
  function check_report_reason (line 21) | pub(crate) fn check_report_reason(reason: &str, slur_regex: &Regex) -> L...
  function check_totp_2fa_valid (line 32) | pub(crate) fn check_totp_2fa_valid(
  function generate_totp_2fa_secret (line 57) | pub(crate) fn generate_totp_2fa_secret() -> String {
  function build_totp_2fa (line 61) | fn build_totp_2fa(hostname: &str, username: &str, secret: &str) -> Lemmy...
  function hide_modlog_names (line 83) | async fn hide_modlog_names(
  function test_build_totp (line 105) | fn test_build_totp() {

FILE: crates/api/api/src/local_user/add_admin.rs
  function add_admin (line 14) | pub async fn add_admin(

FILE: crates/api/api/src/local_user/ban_person.rs
  function ban_from_site (line 27) | pub async fn ban_from_site(

FILE: crates/api/api/src/local_user/block.rs
  function user_block_person (line 14) | pub async fn user_block_person(

FILE: crates/api/api/src/local_user/change_password.rs
  function change_password (line 16) | pub async fn change_password(

FILE: crates/api/api/src/local_user/change_password_after_reset.rs
  function change_password_after_reset (line 11) | pub async fn change_password_after_reset(

FILE: crates/api/api/src/local_user/donation_dialog_shown.rs
  function donation_dialog_shown (line 9) | pub async fn donation_dialog_shown(

FILE: crates/api/api/src/local_user/export_data.rs
  function export_data (line 17) | pub async fn export_data(

FILE: crates/api/api/src/local_user/generate_totp_secret.rs
  function generate_totp_secret (line 12) | pub async fn generate_totp_secret(

FILE: crates/api/api/src/local_user/get_captcha.rs
  function get_captcha (line 14) | pub async fn get_captcha() -> LemmyResult<HttpResponse> {

FILE: crates/api/api/src/local_user/list_hidden.rs
  function list_person_hidden (line 10) | pub async fn list_person_hidden(

FILE: crates/api/api/src/local_user/list_liked.rs
  function list_person_liked (line 10) | pub async fn list_person_liked(

FILE: crates/api/api/src/local_user/list_logins.rs
  function list_logins (line 8) | pub async fn list_logins(

FILE: crates/api/api/src/local_user/list_media.rs
  function list_media (line 8) | pub async fn list_media(

FILE: crates/api/api/src/local_user/list_read.rs
  function list_person_read (line 10) | pub async fn list_person_read(

FILE: crates/api/api/src/local_user/list_saved.rs
  function list_person_saved (line 11) | pub async fn list_person_saved(

FILE: crates/api/api/src/local_user/login.rs
  function login (line 19) | pub async fn login(

FILE: crates/api/api/src/local_user/logout.rs
  function logout (line 12) | pub async fn logout(

FILE: crates/api/api/src/local_user/note_person.rs
  function user_note_person (line 18) | pub async fn user_note_person(

FILE: crates/api/api/src/local_user/notifications/list.rs
  function list_notifications (line 9) | pub async fn list_notifications(

FILE: crates/api/api/src/local_user/notifications/mark_all_read.rs
  function mark_all_notifications_read (line 8) | pub async fn mark_all_notifications_read(

FILE: crates/api/api/src/local_user/notifications/mark_notification_read.rs
  function mark_notification_as_read (line 9) | pub async fn mark_notification_as_read(

FILE: crates/api/api/src/local_user/resend_verification_email.rs
  function resend_verification_email (line 11) | pub async fn resend_verification_email(

FILE: crates/api/api/src/local_user/reset_password.rs
  function reset_password (line 15) | pub async fn reset_password(
  function try_reset_password (line 26) | async fn try_reset_password(email: &str, context: &LemmyContext) -> Lemm...

FILE: crates/api/api/src/local_user/save_settings.rs
  function save_user_settings (line 37) | pub async fn save_user_settings(

FILE: crates/api/api/src/local_user/unread_counts.rs
  function get_unread_counts (line 15) | pub async fn get_unread_counts(

FILE: crates/api/api/src/local_user/update_totp.rs
  function edit_totp (line 17) | pub async fn edit_totp(

FILE: crates/api/api/src/local_user/user_block_instance.rs
  function user_block_instance_communities (line 17) | pub async fn user_block_instance_communities(
  function user_block_instance_persons (line 40) | pub async fn user_block_instance_persons(

FILE: crates/api/api/src/local_user/validate_auth.rs
  function validate_auth (line 14) | pub async fn validate_auth(

FILE: crates/api/api/src/local_user/verify_email.rs
  function verify_email (line 15) | pub async fn verify_email(

FILE: crates/api/api/src/post/feature.rs
  function feature_post (line 22) | pub async fn feature_post(

FILE: crates/api/api/src/post/get_link_metadata.rs
  function get_link_metadata (line 8) | pub async fn get_link_metadata(

FILE: crates/api/api/src/post/hide.rs
  function hide_post (line 11) | pub async fn hide_post(

FILE: crates/api/api/src/post/like.rs
  function like_post (line 33) | pub async fn like_post(

FILE: crates/api/api/src/post/list_post_likes.rs
  function list_post_likes (line 11) | pub async fn list_post_likes(

FILE: crates/api/api/src/post/lock.rs
  function lock_post (line 22) | pub async fn lock_post(

FILE: crates/api/api/src/post/mark_many_read.rs
  function mark_posts_as_read (line 9) | pub async fn mark_posts_as_read(

FILE: crates/api/api/src/post/mark_read.rs
  function mark_post_as_read (line 11) | pub async fn mark_post_as_read(

FILE: crates/api/api/src/post/mod_update.rs
  function mod_edit_post (line 27) | pub async fn mod_edit_post(

FILE: crates/api/api/src/post/save.rs
  function save_post (line 14) | pub async fn save_post(

FILE: crates/api/api/src/post/update_notifications.rs
  function edit_post_notifications (line 16) | pub async fn edit_post_notifications(

FILE: crates/api/api/src/post/warning.rs
  function create_post_warning (line 18) | pub async fn create_post_warning(

FILE: crates/api/api/src/reports/comment_report/create.rs
  function create_comment_report (line 31) | pub async fn create_comment_report(

FILE: crates/api/api/src/reports/comment_report/resolve.rs
  function resolve_comment_report (line 18) | pub async fn resolve_comment_report(

FILE: crates/api/api/src/reports/community_report/create.rs
  function create_community_report (line 29) | pub async fn create_community_report(

FILE: crates/api/api/src/reports/community_report/resolve.rs
  function resolve_community_report (line 20) | pub async fn resolve_community_report(

FILE: crates/api/api/src/reports/post_report/create.rs
  function create_post_report (line 31) | pub async fn create_post_report(

FILE: crates/api/api/src/reports/post_report/resolve.rs
  function resolve_post_report (line 18) | pub async fn resolve_post_report(

FILE: crates/api/api/src/reports/private_message_report/create.rs
  function create_pm_report (line 25) | pub async fn create_pm_report(

FILE: crates/api/api/src/reports/private_message_report/resolve.rs
  function resolve_pm_report (line 11) | pub async fn resolve_pm_report(

FILE: crates/api/api/src/reports/report_combined/list.rs
  function list_reports (line 14) | pub async fn list_reports(

FILE: crates/api/api/src/site/admin_allow_instance.rs
  function admin_allow_instance (line 13) | pub async fn admin_allow_instance(

FILE: crates/api/api/src/site/admin_block_instance.rs
  function admin_block_instance (line 16) | pub async fn admin_block_instance(

FILE: crates/api/api/src/site/admin_list_users.rs
  function admin_list_users (line 7) | pub async fn admin_list_users(

FILE: crates/api/api/src/site/federated_instances.rs
  function get_federated_instances (line 7) | pub async fn get_federated_instances(

FILE: crates/api/api/src/site/list_all_media.rs
  function list_all_media (line 8) | pub async fn list_all_media(

FILE: crates/api/api/src/site/mod_log.rs
  function get_mod_log (line 10) | pub async fn get_mod_log(
  function test_mod_remove_or_restore_data (line 77) | async fn test_mod_remove_or_restore_data() -> LemmyResult<()> {
  function test_bulk_parent_id_propagated (line 369) | async fn test_bulk_parent_id_propagated() -> LemmyResult<()> {

FILE: crates/api/api/src/site/purge/comment.rs
  function purge_comment (line 19) | pub async fn purge_comment(

FILE: crates/api/api/src/site/purge/community.rs
  function purge_community (line 21) | pub async fn purge_community(

FILE: crates/api/api/src/site/purge/person.rs
  function purge_person (line 23) | pub async fn purge_person(

FILE: crates/api/api/src/site/purge/post.rs
  function purge_post (line 19) | pub async fn purge_post(

FILE: crates/api/api/src/site/registration_applications/approve.rs
  function approve_registration_application (line 19) | pub async fn approve_registration_application(

FILE: crates/api/api/src/site/registration_applications/get.rs
  function get_registration_application (line 11) | pub async fn get_registration_application(

FILE: crates/api/api/src/site/registration_applications/list.rs
  function list_registration_applications (line 15) | pub async fn list_registration_applications(

FILE: crates/api/api/src/site/registration_applications/tests.rs
  function create_test_site (line 32) | async fn create_test_site(context: &Data<LemmyContext>) -> LemmyResult<(...
  function signup (line 63) | async fn signup(
  function get_application_statuses (line 92) | async fn get_application_statuses(
  function test_application_approval (line 128) | async fn test_application_approval() -> LemmyResult<()> {

FILE: crates/api/api/src/sitemap.rs
  function generate_urlset (line 14) | fn generate_urlset(posts: Vec<(DbUrl, chrono::DateTime<chrono::Utc>)>) -...
  function get_sitemap (line 28) | pub async fn get_sitemap(context: Data<LemmyContext>) -> LemmyResult<Htt...
  function test_generate_urlset (line 59) | async fn test_generate_urlset() -> LemmyResult<()> {

FILE: crates/api/api_crud/src/comment/create.rs
  function create_comment (line 39) | pub async fn create_comment(

FILE: crates/api/api_crud/src/comment/delete.rs
  function delete_comment (line 18) | pub async fn delete_comment(

FILE: crates/api/api_crud/src/comment/read.rs
  function get_comment (line 12) | pub async fn get_comment(

FILE: crates/api/api_crud/src/comment/remove.rs
  function remove_comment (line 27) | pub async fn remove_comment(

FILE: crates/api/api_crud/src/comment/update.rs
  function edit_comment (line 28) | pub async fn edit_comment(

FILE: crates/api/api_crud/src/community/create.rs
  function create_community (line 50) | pub async fn create_community(

FILE: crates/api/api_crud/src/community/delete.rs
  function delete_community (line 16) | pub async fn delete_community(

FILE: crates/api/api_crud/src/community/list.rs
  function list_communities (line 9) | pub async fn list_communities(

FILE: crates/api/api_crud/src/community/remove.rs
  function remove_community (line 24) | pub async fn remove_community(

FILE: crates/api/api_crud/src/community/update.rs
  function edit_community (line 34) | pub async fn edit_community(

FILE: crates/api/api_crud/src/custom_emoji/create.rs
  function create_custom_emoji (line 16) | pub async fn create_custom_emoji(

FILE: crates/api/api_crud/src/custom_emoji/delete.rs
  function delete_custom_emoji (line 11) | pub async fn delete_custom_emoji(

FILE: crates/api/api_crud/src/custom_emoji/list.rs
  function list_custom_emojis (line 9) | pub async fn list_custom_emojis(

FILE: crates/api/api_crud/src/custom_emoji/update.rs
  function edit_custom_emoji (line 16) | pub async fn edit_custom_emoji(

FILE: crates/api/api_crud/src/lib.rs
  function community_use_pending (line 17) | async fn community_use_pending(community: &Community, context: &LemmyCon...

FILE: crates/api/api_crud/src/multi_community/create.rs
  function create_multi_community (line 33) | pub async fn create_multi_community(

FILE: crates/api/api_crud/src/multi_community/create_entry.rs
  function create_multi_community_entry (line 24) | pub async fn create_multi_community_entry(

FILE: crates/api/api_crud/src/multi_community/delete_entry.rs
  function delete_multi_community_entry (line 22) | pub async fn delete_multi_community_entry(

FILE: crates/api/api_crud/src/multi_community/list.rs
  function list_multi_communities (line 13) | pub async fn list_multi_communities(

FILE: crates/api/api_crud/src/multi_community/mod.rs
  function check_multi_community_creator (line 17) | fn check_multi_community_creator(
  function send_federation_update (line 30) | fn send_federation_update(

FILE: crates/api/api_crud/src/multi_community/update.rs
  function edit_multi_community (line 25) | pub async fn edit_multi_community(

FILE: crates/api/api_crud/src/oauth_provider/create.rs
  function create_oauth_provider (line 11) | pub async fn create_oauth_provider(

FILE: crates/api/api_crud/src/oauth_provider/delete.rs
  function delete_oauth_provider (line 10) | pub async fn delete_oauth_provider(

FILE: crates/api/api_crud/src/oauth_provider/update.rs
  function edit_oauth_provider (line 14) | pub async fn edit_oauth_provider(

FILE: crates/api/api_crud/src/post/create.rs
  function create_post (line 48) | pub async fn create_post(

FILE: crates/api/api_crud/src/post/delete.rs
  function delete_post (line 18) | pub async fn delete_post(

FILE: crates/api/api_crud/src/post/mod.rs
  function convert_published_time (line 13) | async fn convert_published_time(

FILE: crates/api/api_crud/src/post/read.rs
  function get_post (line 24) | pub async fn get_post(

FILE: crates/api/api_crud/src/post/remove.rs
  function remove_post (line 27) | pub async fn remove_post(

FILE: crates/api/api_crud/src/post/update.rs
  function edit_post (line 54) | pub async fn edit_post(

FILE: crates/api/api_crud/src/private_message/create.rs
  function create_private_message (line 32) | pub async fn create_private_message(

FILE: crates/api/api_crud/src/private_message/delete.rs
  function delete_private_message (line 17) | pub async fn delete_private_message(

FILE: crates/api/api_crud/src/private_message/update.rs
  function edit_private_message (line 24) | pub async fn edit_private_message(

FILE: crates/api/api_crud/src/site/create.rs
  function create_site (line 49) | pub async fn create_site(
  function validate_create_payload (line 171) | fn validate_create_payload(local_site: &LocalSite, create_site: &CreateS...
  function test_validate_invalid_create_payload (line 219) | fn test_validate_invalid_create_payload() {
  function test_validate_valid_create_payload (line 334) | fn test_validate_valid_create_payload() {

FILE: crates/api/api_crud/src/site/mod.rs
  function site_default_post_listing_type_check (line 9) | pub fn site_default_post_listing_type_check(
  function application_question_check (line 25) | pub fn application_question_check(
  function not_zero (line 43) | fn not_zero(val: Option<i32>) -> Option<i32> {
  function test_site_default_post_listing_type_check (line 57) | fn test_site_default_post_listing_type_check() {
  function test_application_question_check (line 65) | fn test_application_question_check() {
  function test_not_zero (line 118) | fn test_not_zero() {

FILE: crates/api/api_crud/src/site/read.rs
  function get_site (line 20) | pub async fn get_site(
  function read_site (line 41) | async fn read_site(context: &LemmyContext) -> LemmyResult<GetSiteRespons...

FILE: crates/api/api_crud/src/site/update.rs
  function edit_site (line 51) | pub async fn edit_site(
  function validate_update_payload (line 213) | fn validate_update_payload(local_site: &LocalSite, edit_site: &EditSite)...
  function test_validate_invalid_update_payload (line 260) | fn test_validate_invalid_update_payload() {
  function test_validate_valid_update_payload (line 353) | fn test_validate_valid_update_payload() {

FILE: crates/api/api_crud/src/tagline/create.rs
  function create_tagline (line 16) | pub async fn create_tagline(

FILE: crates/api/api_crud/src/tagline/delete.rs
  function delete_tagline (line 10) | pub async fn delete_tagline(

FILE: crates/api/api_crud/src/tagline/list.rs
  function list_taglines (line 8) | pub async fn list_taglines(

FILE: crates/api/api_crud/src/tagline/update.rs
  function edit_tagline (line 17) | pub async fn edit_tagline(

FILE: crates/api/api_crud/src/user/create.rs
  type TokenResponse (line 74) | struct TokenResponse {
  function register (line 82) | pub async fn register(
  function authenticate_with_oauth (line 228) | pub async fn authenticate_with_oauth(
  function create_person (line 464) | async fn create_person(
  function get_language_tags (line 492) | fn get_language_tags(req: &HttpRequest) -> Vec<String> {
  function create_local_user (line 504) | async fn create_local_user(
  function validate_registration_answer (line 550) | fn validate_registration_answer(
  function oauth_request_access_token (line 561) | async fn oauth_request_access_token(
  function oidc_get_user_info (line 601) | async fn oidc_get_user_info(
  function read_user_info (line 627) | fn read_user_info(user_info: &serde_json::Value, key: &str) -> LemmyResu...
  function check_code_verifier (line 637) | fn check_code_verifier(code_verifier: &str) -> LemmyResult<()> {
  function fetch_community_list (line 650) | fn fetch_community_list(context: Data<LemmyContext>) {
  function create_welcome_post (line 711) | fn create_welcome_post(local_user: LocalUser, context: &LemmyContext) {

FILE: crates/api/api_crud/src/user/delete.rs
  function delete_account (line 19) | pub async fn delete_account(

FILE: crates/api/api_crud/src/user/my_user.rs
  function get_my_user (line 22) | pub async fn get_my_user(

FILE: crates/api/api_utils/src/build_response.rs
  function build_comment_response (line 14) | pub async fn build_comment_response(
  function build_community_response (line 31) | pub async fn build_community_response(
  function build_post_response (line 55) | pub async fn build_post_response(

FILE: crates/api/api_utils/src/claims.rs
  type Claims (line 14) | pub struct Claims {
    method validate (line 26) | pub async fn validate(jwt: &str, context: &LemmyContext) -> LemmyResul...
    method generate (line 37) | pub async fn generate(
  function test_should_not_validate_user_token_after_password_change (line 99) | async fn test_should_not_validate_user_token_after_password_change() -> ...

FILE: crates/api/api_utils/src/context.rs
  type LemmyContext (line 13) | pub struct LemmyContext {
    method create (line 24) | pub fn create(
    method pool (line 39) | pub fn pool(&self) -> DbPool<'_> {
    method inner_pool (line 42) | pub fn inner_pool(&self) -> &ActualDbPool {
    method client (line 45) | pub fn client(&self) -> &ClientWithMiddleware {
    method pictrs_client (line 48) | pub fn pictrs_client(&self) -> &ClientWithMiddleware {
    method settings (line 51) | pub fn settings(&self) -> &'static Settings {
    method secret (line 54) | pub fn secret(&self) -> &Secret {
    method rate_limit_cell (line 57) | pub fn rate_limit_cell(&self) -> &RateLimit {
    method init_test_federation_config (line 65) | pub async fn init_test_federation_config() -> FederationConfig<LemmyCo...
    method init_test_context (line 97) | pub async fn init_test_context() -> Data<LemmyContext> {

FILE: crates/api/api_utils/src/notify.rs
  type NotifyData (line 35) | pub struct NotifyData {
    method send (line 73) | pub fn send(self, context: &LemmyContext) {
    method send_internal (line 79) | pub async fn send_internal(self, context: LemmyContext) -> LemmyResult...
    method check_notifications_allowed (line 129) | async fn check_notifications_allowed(
    method content (line 163) | fn content(&self) -> String {
    method link (line 171) | fn link(&self, context: &LemmyContext) -> LemmyResult<Url> {
    method notify_parent_creator (line 179) | async fn notify_parent_creator<'a>(
    method notify_mentions (line 209) | async fn notify_mentions<'a>(
    method notify_subscribers (line 246) | async fn notify_subscribers<'a>(
  type CollectedNotifyData (line 47) | struct CollectedNotifyData<'a> {
  method eq (line 56) | fn eq(&self, other: &CollectedNotifyData<'_>) -> bool {
  method hash (line 62) | fn hash<H: Hasher>(&self, state: &mut H) {
  function notify_private_message (line 285) | pub fn notify_private_message(view: &PrivateMessageView, is_create: bool...
  function notify_private_message_internal (line 290) | async fn notify_private_message_internal(
  function notify_mod_action (line 323) | pub fn notify_mod_action(actions: Vec<Modlog>, context: &LemmyContext) {
  type Data (line 406) | struct Data {
  function init_data (line 417) | async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
  function insert_private_message (line 459) | async fn insert_private_message(
  function setup_private_messages (line 469) | async fn setup_private_messages(data: &Data, context: &LemmyContext) -> ...
  function cleanup (line 501) | async fn cleanup(data: Data, pool: &mut DbPool<'_>) -> LemmyResult<()> {
  function replies (line 510) | async fn replies() -> LemmyResult<()> {
  function mentions (line 606) | async fn mentions() -> LemmyResult<()> {
  function to_pm (line 737) | fn to_pm(x: NotificationView) -> Option<PrivateMessageView> {
  function read_private_messages (line 747) | async fn read_private_messages() -> LemmyResult<()> {
  function ensure_private_message_person_block (line 796) | async fn ensure_private_message_person_block() -> LemmyResult<()> {
  function ensure_private_message_instance_block (line 838) | async fn ensure_private_message_instance_block() -> LemmyResult<()> {
  function private_message_delete_by_recipient (line 884) | async fn private_message_delete_by_recipient() -> LemmyResult<()> {

FILE: crates/api/api_utils/src/plugins.rs
  constant GET_PLUGIN_TIMEOUT (line 37) | const GET_PLUGIN_TIMEOUT: Duration = Duration::from_secs(1);
  function plugin_hook_after (line 40) | pub fn plugin_hook_after<T>(name: &'static str, data: &T)
  function plugin_hook_notification (line 55) | pub async fn plugin_hook_notification(
  function plugin_get_captcha (line 73) | pub async fn plugin_get_captcha() -> LemmyResult<CaptchaResponse> {
  function plugin_validate_captcha (line 77) | pub async fn plugin_validate_captcha(answer: String, uuid: String) -> Le...
  function call_captcha_plugin (line 81) | async fn call_captcha_plugin<
  function is_captcha_plugin_loaded (line 106) | pub fn is_captcha_plugin_loaded() -> bool {
  function run_plugin_hook_after (line 110) | fn run_plugin_hook_after<T>(name: &'static str, data: T) -> LemmyResult<()>
  function plugin_hook_before (line 127) | pub async fn plugin_hook_before<T>(name: &'static str, data: T) -> Lemmy...
  function plugin_metadata (line 151) | pub fn plugin_metadata() -> Vec<PluginMetadata> {
  type LemmyPlugins (line 190) | struct LemmyPlugins {
    method get_or_init (line 266) | fn get_or_init() -> Self {
    method function_exists (line 307) | fn function_exists(&self, name: &'static str) -> bool {
  type LemmyPlugin (line 196) | struct LemmyPlugin {
    method init (line 202) | fn init(settings: PluginSettings) -> LemmyResult<Self> {
    method get (line 250) | fn get(&self, name: &'static str) -> LemmyResult<Option<PoolPlugin>> {

FILE: crates/api/api_utils/src/request.rs
  function client_builder (line 42) | pub fn client_builder(settings: &Settings) -> ClientBuilder {
  function fetch_link_metadata (line 60) | pub async fn fetch_link_metadata(
  function v4_is_invalid (line 166) | fn v4_is_invalid(v4: Ipv4Addr) -> bool {
  function v6_is_invalid (line 176) | fn v6_is_invalid(v6: Ipv6Addr) -> bool {
  function collect_bytes_until_limit (line 190) | async fn collect_bytes_until_limit(
  function generate_post_link_metadata (line 216) | pub async fn generate_post_link_metadata(
  function extract_opengraph_data (line 294) | fn extract_opengraph_data(html_bytes: &[u8], url: &Url) -> LemmyResult<O...
  function extract_opengraph_width_and_height (line 357) | fn extract_opengraph_width_and_height(ogo: Option<&OpengraphObject>) -> ...
  function extract_opengraph_int_field (line 364) | fn extract_opengraph_int_field(ogo: &OpengraphObject, field: &str) -> Op...
  type PictrsResponse (line 370) | pub struct PictrsResponse {
  type PictrsFile (line 377) | pub struct PictrsFile {
    method image_url (line 383) | pub fn image_url(&self, protocol_and_hostname: &str) -> Result<Url, ur...
  type PictrsFileDetails (line 393) | pub struct PictrsFileDetails {
    method build_image_details_form (line 406) | pub fn build_image_details_form(&self, thumbnail_url: &Url) -> ImageDe...
  type PictrsPurgeResponse (line 418) | struct PictrsPurgeResponse {
  function purge_image_from_pictrs_url (line 428) | pub async fn purge_image_from_pictrs_url(
  function purge_image_from_pictrs (line 443) | pub async fn purge_image_from_pictrs(alias: &str, context: &LemmyContext...
  function delete_image_alias (line 482) | pub async fn delete_image_alias(alias: &str, context: &LemmyContext) -> ...
  function generate_pictrs_thumbnail (line 504) | async fn generate_pictrs_thumbnail(
  function fetch_pictrs_proxied_image_details (line 564) | pub async fn fetch_pictrs_proxied_image_details(
  function is_image_content_type (line 600) | async fn is_image_content_type(client: &ClientWithMiddleware, url: &Url)...
  function test_link_metadata (line 630) | async fn test_link_metadata() -> LemmyResult<()> {
  function test_resolve_image_url (line 659) | fn test_resolve_image_url() -> LemmyResult<()> {

FILE: crates/api/api_utils/src/send_activity.rs
  type SendActivityData (line 33) | pub enum SendActivityData {
  type ActivityChannel (line 127) | pub struct ActivityChannel {
    method retrieve_activity (line 134) | pub async fn retrieve_activity() -> Option<SendActivityData> {
    method submit_activity (line 139) | pub fn submit_activity(data: SendActivityData, _context: &Data<LemmyCo...
    method close (line 148) | pub async fn close(outgoing_activities_task: JoinHandle<()>) -> LemmyR...

FILE: crates/api/api_utils/src/utils.rs
  constant AUTH_COOKIE_NAME (line 71) | pub const AUTH_COOKIE_NAME: &str = "jwt";
  function check_is_mod_or_admin (line 73) | pub async fn check_is_mod_or_admin(
  function check_is_mod_of_any_or_admin (line 93) | pub(crate) async fn check_is_mod_of_any_or_admin(
  function is_mod_or_admin (line 111) | pub async fn is_mod_or_admin(
  function is_mod_or_admin_opt (line 120) | pub async fn is_mod_or_admin_opt(
  function check_community_mod_of_any_or_admin_action (line 139) | pub async fn check_community_mod_of_any_or_admin_action(
  function is_admin (line 149) | pub fn is_admin(local_user_view: &LocalUserView) -> LemmyResult<()> {
  function is_top_mod (line 158) | pub fn is_top_mod(
  function update_read_comments (line 176) | pub async fn update_read_comments(
  function check_local_user_valid (line 188) | pub fn check_local_user_valid(local_user_view: &LocalUserView) -> LemmyR...
  function check_local_user_deleted (line 197) | pub fn check_local_user_deleted(local_user_view: &LocalUserView) -> Lemm...
  function check_email_verified (line 207) | pub fn check_email_verified(
  function check_registration_application (line 220) | pub async fn check_registration_application(
  function check_community_user_action (line 249) | pub async fn check_community_user_action(
  function check_community_deleted_removed (line 263) | pub fn check_community_deleted_removed(community: &Community) -> LemmyRe...
  function check_community_mod_action (line 274) | pub async fn check_community_mod_action(
  function check_post_deleted_or_removed (line 291) | pub fn check_post_deleted_or_removed(post: &Post) -> LemmyResult<()> {
  function check_comment_deleted_or_removed (line 299) | pub fn check_comment_deleted_or_removed(comment: &Comment) -> LemmyResul...
  function check_local_vote_mode (line 307) | pub async fn check_local_vote_mode(
  function check_bot_account (line 339) | pub fn check_bot_account(person: &Person) -> LemmyResult<()> {
  function check_private_instance (line 347) | pub fn check_private_instance(
  function check_private_messages_enabled (line 359) | pub fn check_private_messages_enabled(local_user_view: &LocalUserView) -...
  function password_length_check (line 368) | pub fn password_length_check(pass: &str) -> LemmyResult<()> {
  function honeypot_check (line 377) | pub fn honeypot_check(honeypot: &Option<String>) -> LemmyResult<()> {
  function local_site_rate_limit_to_rate_limit_config (line 385) | pub fn local_site_rate_limit_to_rate_limit_config(
  function slur_regex (line 403) | pub async fn slur_regex(context: &LemmyContext) -> LemmyResult<Regex> {
  function get_url_blocklist (line 424) | pub async fn get_url_blocklist(context: &LemmyContext) -> LemmyResult<Re...
  function check_nsfw_allowed (line 451) | pub fn check_nsfw_allowed(nsfw: Option<bool>, local_site: Option<&LocalS...
  function read_site_for_actor (line 465) | pub async fn read_site_for_actor(
  function purge_post_images (line 474) | pub async fn purge_post_images(
  function delete_local_user_images (line 490) | fn delete_local_user_images(person_id: PersonId, context: &LemmyContext) {
  function remove_or_restore_user_data (line 507) | pub async fn remove_or_restore_user_data(
  function create_modlog_entries_for_removed_or_restored_posts (line 607) | async fn create_modlog_entries_for_removed_or_restored_posts(
  function create_modlog_entries_for_removed_or_restored_comments (line 634) | async fn create_modlog_entries_for_removed_or_restored_comments(
  function create_modlog_entries_for_removed_or_restored_comments_in_community (line 664) | async fn create_modlog_entries_for_removed_or_restored_comments_in_commu...
  function remove_or_restore_user_data_in_community (line 693) | pub async fn remove_or_restore_user_data_in_community(
  function purge_user_account (line 743) | pub async fn purge_user_account(
  function generate_followers_url (line 777) | pub fn generate_followers_url(ap_id: &DbUrl) -> Result<DbUrl, ParseError> {
  function generate_inbox_url (line 781) | pub fn generate_inbox_url() -> LemmyResult<DbUrl> {
  function generate_outbox_url (line 786) | pub fn generate_outbox_url(ap_id: &DbUrl) -> Result<DbUrl, ParseError> {
  function generate_featured_url (line 790) | pub fn generate_featured_url(ap_id: &DbUrl) -> Result<DbUrl, ParseError> {
  function generate_moderators_url (line 794) | pub fn generate_moderators_url(community_id: &DbUrl) -> LemmyResult<DbUr...
  function check_expire_time (line 800) | pub fn check_expire_time(expires_unix_opt: Option<i64>) -> LemmyResult<O...
  function limit_expire_time (line 813) | fn limit_expire_time(expires: DateTime<Utc>) -> LemmyResult<Option<DateT...
  function check_conflicting_like_filters (line 825) | pub fn check_conflicting_like_filters(
  function process_markdown (line 836) | pub async fn process_markdown(
  function process_markdown_opt (line 868) | pub async fn process_markdown_opt(
  function proxy_image_link_internal (line 887) | async fn proxy_image_link_internal(
  function proxy_image_link (line 916) | pub async fn proxy_image_link(
  function proxy_image_link_opt_apub (line 925) | pub async fn proxy_image_link_opt_apub(
  function build_proxied_image_url (line 939) | fn build_proxied_image_url(
  function local_user_view_from_jwt (line 956) | pub async fn local_user_view_from_jwt(
  function read_auth_token (line 969) | pub fn read_auth_token(req: &HttpRequest) -> LemmyResult<Option<String>> {
  function send_webmention (line 984) | pub fn send_webmention(post: Post, community: &Community) {
  function check_comment_depth (line 1008) | pub fn check_comment_depth(comment: &Comment) -> LemmyResult<()> {
  function update_post_tags (line 1019) | pub async fn update_post_tags(
  function password_length (line 1050) | fn password_length() {
  function honeypot (line 1058) | fn honeypot() {
  function test_limit_ban_term (line 1066) | fn test_limit_ban_term() -> LemmyResult<()> {
  function test_proxy_image_link (line 1084) | async fn test_proxy_image_link() -> LemmyResult<()> {
  function test_comment_depth (line 1118) | fn test_comment_depth() -> LemmyResult<()> {

FILE: crates/api/routes/src/lib.rs
  function config (line 191) | pub fn config(cfg: &mut ServiceConfig, rate_limit: &RateLimit) {

FILE: crates/api/routes_v3/src/convert.rs
  function convert_local_user_view2 (line 97) | pub(crate) fn convert_local_user_view2(local_user_view: LocalUserView) -...
  function convert_local_user (line 117) | pub(crate) fn convert_local_user(local_user: LocalUser) -> LocalUserV3 {
  function convert_community_view (line 171) | pub(crate) fn convert_community_view(community_view: CommunityView) -> C...
  function convert_subscribed_type (line 202) | fn convert_subscribed_type(state: Option<CommunityFollowerState>) -> Sub...
  function convert_post_view (line 212) | pub(crate) fn convert_post_view(post_view: PostView) -> PostViewV3 {
  function convert_comment_view (line 249) | pub(crate) fn convert_comment_view(comment_view: CommentView) -> Comment...
  function convert_comment (line 283) | pub(crate) fn convert_comment(comment: Comment) -> (CommentV3, CommentAg...
  function convert_my_user (line 336) | pub(crate) fn convert_my_user(my_user: Option<MyUserInfo>) -> Option<MyU...
  function convert_person (line 355) | pub(crate) fn convert_person(person: Person) -> (PersonV3, PersonAggrega...
  function convert_community (line 413) | pub(crate) fn convert_community(community: Community) -> CommunityV3 {
  function convert_post (line 463) | pub(crate) fn convert_post(post: Post) -> (PostV3, PostAggregates) {
  function convert_site_view (line 548) | pub(crate) fn convert_site_view(site_view: SiteView) -> SiteViewV3 {
  function convert_site (line 572) | pub(crate) fn convert_site(site: Site) -> SiteV3 {
  function convert_db_url (line 607) | pub(crate) fn convert_db_url(db_url: DbUrl) -> DbUrlV3 {
  function convert_local_site (line 612) | pub(crate) fn convert_local_site(local_site: LocalSite) -> LocalSiteV3 {
  function dummy_local_site_rate_limit (line 667) | fn dummy_local_site_rate_limit() -> LocalSiteRateLimitV3 {
  function convert_person_view (line 689) | pub(crate) fn convert_person_view(person_view: PersonView) -> PersonView...
  function convert_sensitive (line 699) | pub(crate) fn convert_sensitive(s: SensitiveString) -> SensitiveStringV3 {
  function convert_score (line 703) | pub(crate) fn convert_score(score: i16) -> Option<bool> {
  function convert_search_response (line 712) | pub(crate) fn convert_search_response(
  function convert_post_listing_sort (line 735) | pub(crate) fn convert_post_listing_sort(
  function convert_comment_listing_sort (line 772) | pub(crate) fn convert_comment_listing_sort(sort_type: CommentSortTypeV3)...
  function convert_community_listing_sort (line 782) | pub(crate) fn convert_community_listing_sort(
  function convert_listing_type (line 819) | pub(crate) fn convert_listing_type(listing_type: ListingTypeV3) -> Listi...
  function convert_post_response (line 827) | pub(crate) fn convert_post_response(res: Json<PostResponse>) -> LemmyRes...
  function convert_comment_response (line 832) | pub(crate) fn convert_comment_response(
  function convert_language_ids (line 841) | pub(crate) fn convert_language_ids(data: Vec<LanguageId>) -> Vec<Languag...
  function convert_login_response (line 845) | pub(crate) fn convert_login_response(res: LoginResponse) -> LemmyResult<...

FILE: crates/api/routes_v3/src/handlers.rs
  function get_post_v3 (line 141) | pub(crate) async fn get_post_v3(
  function list_posts_v3 (line 159) | pub(crate) async fn list_posts_v3(
  function list_comments_v3 (line 197) | pub(crate) async fn list_comments_v3(
  function logout_v3 (line 234) | pub(crate) async fn logout_v3(
  function get_site_v3 (line 242) | pub(crate) async fn get_site_v3(
  function login_v3 (line 298) | pub(crate) async fn login_v3(
  function like_comment_v3 (line 307) | pub(crate) async fn like_comment_v3(
  function like_post_v3 (line 321) | pub(crate) async fn like_post_v3(
  function create_comment_v3 (line 335) | pub(crate) async fn create_comment_v3(
  function create_post_v3 (line 344) | pub(crate) async fn create_post_v3(
  function search_v3 (line 377) | pub(crate) async fn search_v3(
  function resolve_object_v3 (line 403) | pub(crate) async fn resolve_object_v3(
  function save_post_v3 (line 418) | pub(crate) async fn save_post_v3(
  function save_comment_v3 (line 427) | pub(crate) async fn save_comment_v3(
  function unread_count_v3 (line 436) | pub async fn unread_count_v3(
  function mark_all_notifications_read_v3 (line 448) | pub async fn mark_all_notifications_read_v3(
  function create_post_report_v3 (line 456) | pub async fn create_post_report_v3(
  function create_comment_report_v3 (line 502) | pub async fn create_comment_report_v3(
  function get_community_v3 (line 544) | pub(crate) async fn get_community_v3(
  function follow_community_v3 (line 565) | pub(crate) async fn follow_community_v3(
  function block_community_v3 (line 577) | pub(crate) async fn block_community_v3(
  function delete_post_v3 (line 592) | pub(crate) async fn delete_post_v3(
  function update_post_v3 (line 600) | pub(crate) async fn update_post_v3(
  function delete_comment_v3 (line 608) | pub(crate) async fn delete_comment_v3(
  function update_comment_v3 (line 616) | pub(crate) async fn update_comment_v3(
  function list_communities_v3 (line 624) | pub(crate) async fn list_communities_v3(
  function register_v3 (line 653) | pub(crate) async fn register_v3(
  function block_person_v3 (line 662) | pub(crate) async fn block_person_v3(

FILE: crates/api/routes_v3/src/lib.rs
  function config (line 38) | pub fn config(cfg: &mut ServiceConfig, rate_limit: &RateLimit) {

FILE: crates/apub/activities/src/activity_lists.rs
  type SharedInboxActivities (line 41) | pub enum SharedInboxActivities {
  type AnnouncableActivities (line 56) | pub enum AnnouncableActivities {
  method community (line 77) | async fn community(&self, context: &Data<LemmyContext>) -> LemmyResult<A...
  function test_shared_inbox (line 108) | fn test_shared_inbox() -> LemmyResult<()> {

FILE: crates/apub/activities/src/block/block_user.rs
  method new (line 40) | pub(in crate::block) async fn new(
  method send (line 65) | pub async fn send(
  type DataType (line 101) | type DataType = LemmyContext;
  type Error (line 102) | type Error = LemmyError;
  method id (line 104) | fn id(&self) -> &Url {
  method actor (line 108) | fn actor(&self) -> &Url {
  method verify (line 112) | async fn verify(&self, context: &Data<LemmyContext>) -> LemmyResult<()> {
  method receive (line 126) | async fn receive(self, context: &Data<LemmyContext>) -> LemmyResult<()> {

FILE: crates/apub/activities/src/block/mod.rs
  type SiteOrCommunity (line 22) | pub type SiteOrCommunity = Either<ApubSite, ApubCommunity>;
  function generate_cc (line 24) | async fn generate_cc(target: &SiteOrCommunity, pool: &mut DbPool<'_>) ->...
  function send_ban_from_site (line 35) | pub(crate) async fn send_ban_from_site(
  function send_ban_from_community (line 71) | pub(crate) async fn send_ban_from_community(
  function to (line 107) | fn to(target: &SiteOrCommunity) -> LemmyResult<Vec<Url>> {
  function update_removed_for_instance (line 117) | async fn update_removed_for_instance(

FILE: crates/apub/activities/src/block/undo_block_user.rs
  method send (line 39) | pub async fn send(
  type DataType (line 78) | type DataType = LemmyContext;
  type Error (line 79) | type Error = LemmyError;
  method id (line 81) | fn id(&self) -> &Url {
  method actor (line 85) | fn actor(&self) -> &Url {
  method verify (line 89) | async fn verify(&self, context: &Data<LemmyContext>) -> LemmyResult<()> {
  method receive (line 95) | async fn receive(self, context: &Data<LemmyContext>) -> LemmyResult<()> {

FILE: crates/apub/activities/src/community/announce.rs
  type DataType (line 31) | type DataType = LemmyContext;
  type Error (line 32) | type Error = LemmyError;
  method id (line 34) | fn id(&self) -> &Url {
  method actor (line 38) | fn actor(&self) -> &Url {
  method verify (line 42) | async fn verify(&self, _data: &Data<Self::DataType>) -> Result<(), Self:...
  method receive (line 46) | async fn receive(self, context: &Data<Self::DataType>) -> Result<(), Sel...
  method id (line 76) | fn id(&self) -> &Url {
  method new (line 82) | pub fn new(
  method send (line 109) | pub async fn send(
  type DataType (line 141) | type DataType = LemmyContext;
  type Error (line 142) | type Error = LemmyError;
  method id (line 144) | fn id(&self) -> &Url {
  method actor (line 148) | fn actor(&self) -> &Url {
  method verify (line 152) | async fn verify(&self, _context: &Data<Self::DataType>) -> LemmyResult<(...
  method receive (line 156) | async fn receive(self, context: &Data<Self::DataType>) -> LemmyResult<()> {
  type Error (line 175) | type Error = serde_json::error::Error;
  method try_from (line 177) | fn try_from(value: RawAnnouncableActivities) -> Result<Self, Self::Error> {
  type Error (line 186) | type Error = serde_json::error::Error;
  method try_from (line 188) | fn try_from(value: AnnouncableActivities) -> Result<Self, Self::Error> {
  function can_accept_activity_in_community (line 199) | async fn can_accept_activity_in_community(

FILE: crates/apub/activities/src/community/collection_add.rs
  method send_add_mod (line 43) | async fn send_add_mod(
  method send_add_featured_post (line 66) | async fn send_add_featured_post(
  type DataType (line 98) | type DataType = LemmyContext;
  type Error (line 99) | type Error = LemmyError;
  method id (line 101) | fn id(&self) -> &Url {
  method actor (line 105) | fn actor(&self) -> &Url {
  method verify (line 109) | async fn verify(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
  method receive (line 117) | async fn receive(self, context: &Data<Self::DataType>) -> LemmyResult<()> {
  function send_add_mod_to_community (line 160) | pub(crate) async fn send_add_mod_to_community(
  function send_feature_post (line 181) | pub(crate) async fn send_feature_post(

FILE: crates/apub/activities/src/community/collection_remove.rs
  method send_remove_mod (line 40) | pub(super) async fn send_remove_mod(
  method send_remove_featured_post (line 63) | pub(super) async fn send_remove_featured_post(
  type DataType (line 95) | type DataType = LemmyContext;
  type Error (line 96) | type Error = LemmyError;
  method id (line 98) | fn id(&self) -> &Url {
  method actor (line 102) | fn actor(&self) -> &Url {
  method verify (line 106) | async fn verify(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
  method receive (line 114) | async fn receive(self, context: &Data<Self::DataType>) -> LemmyResult<()> {

FILE: crates/apub/activities/src/community/lock.rs
  type DataType (line 37) | type DataType = LemmyContext;
  type Error (line 38) | type Error = LemmyError;
  method id (line 40) | fn id(&self) -> &Url {
  method actor (line 44) | fn actor(&self) -> &Url {
  method verify (line 48) | async fn verify(&self, context: &Data<Self::DataType>) -> Result<(), Sel...
  method receive (line 56) | async fn receive(self, context: &Data<Self::DataType>) -> Result<(), Sel...
  type DataType (line 93) | type DataType = LemmyContext;
  type Error (line 94) | type Error = LemmyError;
  method id (line 96) | fn id(&self) -> &Url {
  method actor (line 100) | fn actor(&self) -> &Url {
  method verify (line 104) | async fn verify(&self, context: &Data<Self::DataType>) -> Result<(), Sel...
  method receive (line 112) | async fn receive(self, context: &Data<Self::DataType>) -> Result<(), Sel...
  function send_lock (line 150) | pub(crate) async fn send_lock(

FILE: crates/apub/activities/src/community/mod.rs
  function send_activity_in_community (line 51) | pub(crate) async fn send_activity_in_community(
  function report_inboxes (line 84) | async fn report_inboxes(
  function local_community (line 126) | fn local_community(site_or_community: &Either<ApubSite, ApubCommunity>) ...
  function verify_mod_or_admin_action (line 130) | async fn verify_mod_or_admin_action(

FILE: crates/apub/activities/src/community/report.rs
  method new (line 52) | pub(crate) fn new(
  method send (line 73) | pub(crate) async fn send(
  type DataType (line 89) | type DataType = LemmyContext;
  type Error (line 90) | type Error = LemmyError;
  method id (line 92) | fn id(&self) -> &Url {
  method actor (line 96) | fn actor(&self) -> &Url {
  method verify (line 100) | async fn verify(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
  method receive (line 128) | async fn receive(self, context: &Data<Self::DataType>) -> LemmyResult<()> {

FILE: crates/apub/activities/src/community/resolve_report.rs
  method send (line 42) | pub(crate) async fn send(
  type DataType (line 68) | type DataType = LemmyContext;
  type Error (line 69) | type Error = LemmyError;
  method id (line 71) | fn id(&self) -> &Url {
  method actor (line 75) | fn actor(&self) -> &Url {
  method verify (line 79) | async fn verify(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
  method receive (line 88) | async fn receive(self, context: &Data<Self::DataType>) -> LemmyResult<()> {

FILE: crates/apub/activities/src/community/update.rs
  function send_update_community (line 32) | pub(crate) async fn send_update_community(
  function send_update_multi_community (line 62) | pub(crate) async fn send_update_multi_community(
  type DataType (line 88) | type DataType = LemmyContext;
  type Error (line 89) | type Error = LemmyError;
  method id (line 91) | fn id(&self) -> &Url {
  method actor (line 95) | fn actor(&self) -> &Url {
  method verify (line 99) | async fn verify(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
  method receive (line 113) | async fn receive(self, context: &Data<Self::DataType>) -> LemmyResult<()> {

FILE: crates/apub/activities/src/create_or_update/comment.rs
  method send (line 43) | pub(crate) async fn send(
  type DataType (line 85) | type DataType = LemmyContext;
  type Error (line 86) | type Error = LemmyError;
  method id (line 88) | fn id(&self) -> &Url {
  method actor (line 92) | fn actor(&self) -> &Url {
  method verify (line 96) | async fn verify(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
  method receive (line 111) | async fn receive(self, context: &Data<Self::DataType>) -> LemmyResult<()> {

FILE: crates/apub/activities/src/create_or_update/mod.rs
  function tagged_user_inboxes (line 14) | async fn tagged_user_inboxes(
  function parse_apub_mentions (line 28) | async fn parse_apub_mentions(

FILE: crates/apub/activities/src/create_or_update/note_wrapper.rs
  type DataType (line 18) | type DataType = LemmyContext;
  type Error (line 19) | type Error = LemmyError;
  method id (line 21) | fn id(&self) -> &Url {
  method actor (line 25) | fn actor(&self) -> &Url {
  method verify (line 29) | async fn verify(&self, _context: &Data<Self::DataType>) -> LemmyResult<(...
  method receive (line 34) | async fn receive(self, context: &Data<Self::DataType>) -> LemmyResult<()> {
  method community (line 60) | async fn community(&self, context: &Data<LemmyContext>) -> LemmyResult<A...

FILE: crates/apub/activities/src/create_or_update/post.rs
  method new (line 42) | pub async fn new(
  method send (line 61) | pub(crate) async fn send(
  type DataType (line 84) | type DataType = LemmyContext;
  type Error (line 85) | type Error = LemmyError;
  method id (line 87) | fn id(&self) -> &Url {
  method actor (line 91) | fn actor(&self) -> &Url {
  method verify (line 95) | async fn verify(&self, context: &Data<LemmyContext>) -> LemmyResult<()> {
  method receive (line 104) | async fn receive(self, context: &Data<LemmyContext>) -> LemmyResult<()> {

FILE: crates/apub/activities/src/create_or_update/private_message.rs
  function send_create_or_update_pm (line 19) | pub(crate) async fn send_create_or_update_pm(
  type DataType (line 43) | type DataType = LemmyContext;
  type Error (line 44) | type Error = LemmyError;
  method id (line 46) | fn id(&self) -> &Url {
  method actor (line 50) | fn actor(&self) -> &Url {
  method verify (line 54) | async fn verify(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
  method receive (line 63) | async fn receive(self, context: &Data<Self::DataType>) -> LemmyResult<()> {

FILE: crates/apub/activities/src/deletion/delete.rs
  type DataType (line 29) | type DataType = LemmyContext;
  type Error (line 30) | type Error = LemmyError;
  method id (line 32) | fn id(&self) -> &Url {
  method actor (line 36) | fn actor(&self) -> &Url {
  method verify (line 40) | async fn verify(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
  method receive (line 45) | async fn receive(self, context: &Data<LemmyContext>) -> LemmyResult<()> {
  method new (line 76) | pub(in crate::deletion) fn new(
  function receive_remove_action (line 102) | pub(crate) async fn receive_remove_action(

FILE: crates/apub/activities/src/deletion/mod.rs
  function send_apub_delete_in_community (line 56) | pub(crate) async fn send_apub_delete_in_community(
  function send_apub_delete_private_message (line 106) | pub(crate) async fn send_apub_delete_private_message(
  function send_apub_delete_user (line 145) | pub async fn send_apub_delete_user(
  type DeletableObjects (line 170) | pub enum DeletableObjects {
    method read_from_db (line 179) | pub(crate) async fn read_from_db(
    method id (line 201) | pub(crate) fn id(&self) -> &Url {
  function verify_delete_activity (line 212) | pub(crate) async fn verify_delete_activity(
  function verify_delete_post_or_comment (line 266) | async fn verify_delete_post_or_comment(
  function receive_delete_action (line 285) | async fn receive_delete_action(

FILE: crates/apub/activities/src/deletion/undo_delete.rs
  type DataType (line 22) | type DataType = LemmyContext;
  type Error (line 23) | type Error = LemmyError;
  method id (line 25) | fn id(&self) -> &Url {
  method actor (line 29) | fn actor(&self) -> &Url {
  method verify (line 33) | async fn verify(&self, data: &Data<Self::DataType>) -> Result<(), Self::...
  method receive (line 39) | async fn receive(self, context: &Data<LemmyContext>) -> LemmyResult<()> {
  method new (line 56) | pub(in crate::deletion) fn new(
  method receive_undo_remove_action (line 88) | pub(crate) async fn receive_undo_remove_action(

FILE: crates/apub/activities/src/following/accept.rs
  method send (line 22) | pub async fn send(follow: Follow, context: &Data<LemmyContext>) -> Lemmy...
  type DataType (line 40) | type DataType = LemmyContext;
  type Error (line 41) | type Error = LemmyError;
  method id (line 43) | fn id(&self) -> &Url {
  method actor (line 47) | fn actor(&self) -> &Url {
  method verify (line 51) | async fn verify(&self, context: &Data<LemmyContext>) -> LemmyResult<()> {
  method receive (line 60) | async fn receive(self, context: &Data<LemmyContext>) -> LemmyResult<()> {

FILE: crates/apub/activities/src/following/follow.rs
  method new (line 33) | pub(in crate::following) fn new(
  method send (line 47) | pub async fn send(
  type DataType (line 60) | type DataType = LemmyContext;
  type Error (line 61) | type Error = LemmyError;
  method id (line 63) | fn id(&self) -> &Url {
  method actor (line 67) | fn actor(&self) -> &Url {
  method verify (line 71) | async fn verify(&self, _context: &Data<LemmyContext>) -> LemmyResult<()> {
  method receive (line 78) | async fn receive(self, context: &Data<LemmyContext>) -> LemmyResult<()> {

FILE: crates/apub/activities/src/following/mod.rs
  function send_follow (line 26) | pub async fn send_follow(
  function send_accept_or_reject_follow (line 40) | pub async fn send_accept_or_reject_follow(
  function send_activity_from_user_or_community_or_multi (line 64) | async fn send_activity_from_user_or_community_or_multi<A>(

FILE: crates/apub/activities/src/following/reject.rs
  method send (line 22) | pub async fn send(follow: Follow, context: &Data<LemmyContext>) -> Lemmy...
  type DataType (line 40) | type DataType = LemmyContext;
  type Error (line 41) | type Error = LemmyError;
  method id (line 43) | fn id(&self) -> &Url {
  method actor (line 47) | fn actor(&self) -> &Url {
  method verify (line 51) | async fn verify(&self, context: &Data<LemmyContext>) -> LemmyResult<()> {
  method receive (line 60) | async fn receive(self, context: &Data<LemmyContext>) -> LemmyResult<()> {

FILE: crates/apub/activities/src/following/undo_follow.rs
  method send (line 31) | pub async fn send(
  type DataType (line 51) | type DataType = LemmyContext;
  type Error (line 52) | type Error = LemmyError;
  method id (line 54) | fn id(&self) -> &Url {
  method actor (line 58) | fn actor(&self) -> &Url {
  method verify (line 62) | async fn verify(&self, context: &Data<LemmyContext>) -> LemmyResult<()> {
  method receive (line 71) | async fn receive(self, context: &Data<LemmyContext>) -> LemmyResult<()> {

FILE: crates/apub/activities/src/lib.rs
  constant MOD_ACTION_DEFAULT_REASON (line 62) | const MOD_ACTION_DEFAULT_REASON: &str = "No reason provided";
  function verify_person (line 66) | async fn verify_person(
  function check_community_deleted_or_removed (line 75) | pub(crate) fn check_community_deleted_or_removed(community: &Community) ...
  function generate_activity_id (line 85) | fn generate_activity_id<T>(kind: T, context: &LemmyContext) -> Result<Ur...
  function generate_announce_activity_id (line 99) | fn generate_announce_activity_id(
  function send_lemmy_activity (line 113) | async fn send_lemmy_activity<A, ActorT>(
  function handle_outgoing_activities (line 145) | pub async fn handle_outgoing_activities(context: Data<LemmyContext>) {
  function match_outgoing_activities (line 153) | pub async fn match_outgoing_activities(
  function post_or_comment_community (line 391) | pub(crate) async fn post_or_comment_community(

FILE: crates/apub/activities/src/protocol/block/block_user.rs
  type BlockUser (line 23) | pub struct BlockUser {
  method community (line 45) | async fn community(&self, context: &Data<LemmyContext>) -> LemmyResult<A...

FILE: crates/apub/activities/src/protocol/block/mod.rs
  function test_parse_lemmy_block (line 11) | fn test_parse_lemmy_block() -> LemmyResult<()> {

FILE: crates/apub/activities/src/protocol/block/undo_block_user.rs
  type UndoBlockUser (line 15) | pub struct UndoBlockUser {

FILE: crates/apub/activities/src/protocol/community/announce.rs
  type AnnounceActivity (line 14) | pub struct AnnounceActivity {
  type RawAnnouncableActivities (line 29) | pub struct RawAnnouncableActivities {

FILE: crates/apub/activities/src/protocol/community/collection_add.rs
  type CollectionAdd (line 19) | pub struct CollectionAdd {
  method community (line 34) | async fn community(&self, context: &Data<LemmyContext>) -> LemmyResult<A...

FILE: crates/apub/activities/src/protocol/community/collection_remove.rs
  type CollectionRemove (line 19) | pub struct CollectionRemove {
  method community (line 34) | async fn community(&self, context: &Data<LemmyContext>) -> LemmyResult<A...

FILE: crates/apub/activities/src/protocol/community/lock.rs
  type LockType (line 19) | pub enum LockType {
  type LockPageOrNote (line 25) | pub struct LockPageOrNote {
  type UndoLockPageOrNote (line 42) | pub struct UndoLockPageOrNote {
  method community (line 58) | async fn community(&self, context: &Data<LemmyContext>) -> LemmyResult<A...

FILE: crates/apub/activities/src/protocol/community/mod.rs
  function test_parse_lemmy_community_activities (line 24) | fn test_parse_lemmy_community_activities() -> LemmyResult<()> {

FILE: crates/apub/activities/src/protocol/community/report.rs
  type Report (line 19) | pub struct Report {
    method reason (line 35) | pub fn reason(&self) -> LemmyResult<String> {
  type ReportObject (line 46) | pub(crate) enum ReportObject {
    method dereference (line 53) | pub(crate) async fn dereference(
    method object_id (line 73) | pub(crate) async fn object_id(
  method community (line 96) | async fn community(&self, context: &Data<LemmyContext>) -> LemmyResult<A...

FILE: crates/apub/activities/src/protocol/community/resolve_report.rs
  type ResolveType (line 14) | pub enum ResolveType {
  type ResolveReport (line 20) | pub struct ResolveReport {

FILE: crates/apub/activities/src/protocol/community/update.rs
  type Update (line 22) | pub struct Update {
  method community (line 37) | async fn community(&self, context: &Data<LemmyContext>) -> LemmyResult<A...

FILE: crates/apub/activities/src/protocol/create_or_update/mod.rs
  function test_parse_lemmy_create_or_update (line 18) | fn test_parse_lemmy_create_or_update() -> LemmyResult<()> {

FILE: crates/apub/activities/src/protocol/create_or_update/note.rs
  type CreateOrUpdateNote (line 21) | pub struct CreateOrUpdateNote {
  method community (line 37) | async fn community(&self, context: &Data<LemmyContext>) -> LemmyResult<A...

FILE: crates/apub/activities/src/protocol/create_or_update/note_wrapper.rs
  type CreateOrUpdateNoteWrapper (line 8) | pub struct CreateOrUpdateNoteWrapper {
  type NoteWrapper (line 22) | pub(crate) struct NoteWrapper {

FILE: crates/apub/activities/src/protocol/create_or_update/page.rs
  type CreateOrUpdatePage (line 19) | pub struct CreateOrUpdatePage {
  method community (line 33) | async fn community(&self, context: &Data<LemmyContext>) -> LemmyResult<A...

FILE: crates/apub/activities/src/protocol/create_or_update/private_message.rs
  type CreateOrUpdatePrivateMessage (line 9) | pub struct CreateOrUpdatePrivateMessage {

FILE: crates/apub/activities/src/protocol/deletion/delete.rs
  type Delete (line 24) | pub struct Delete {
  method community (line 52) | async fn community(&self, context: &Data<LemmyContext>) -> LemmyResult<A...

FILE: crates/apub/activities/src/protocol/deletion/delete_user.rs
  type DeleteUser (line 14) | pub struct DeleteUser {

FILE: crates/apub/activities/src/protocol/deletion/mod.rs
  function test_parse_lemmy_deletion (line 16) | fn test_parse_lemmy_deletion() -> LemmyResult<()> {

FILE: crates/apub/activities/src/protocol/deletion/undo_delete.rs
  type UndoDelete (line 15) | pub struct UndoDelete {

FILE: crates/apub/activities/src/protocol/following/accept.rs
  type AcceptFollow (line 13) | pub struct AcceptFollow {

FILE: crates/apub/activities/src/protocol/following/follow.rs
  type Follow (line 12) | pub struct Follow {

FILE: crates/apub/activities/src/protocol/following/mod.rs
  function test_parse_lemmy_accept_follow (line 13) | fn test_parse_lemmy_accept_follow() -> LemmyResult<()> {

FILE: crates/apub/activities/src/protocol/following/reject.rs
  type RejectFollow (line 13) | pub struct RejectFollow {

FILE: crates/apub/activities/src/protocol/following/undo_follow.rs
  type UndoFollow (line 13) | pub struct UndoFollow {

FILE: crates/apub/activities/src/protocol/mod.rs
  type CreateOrUpdateType (line 17) | pub enum CreateOrUpdateType {
  type IdOrNestedObject (line 24) | pub enum IdOrNestedObject<Kind: Id> {
  function id (line 30) | pub(crate) fn id(&self) -> &Url {
  function object (line 36) | pub async fn object(self, context: &Data<LemmyContext>) -> LemmyResult<K...
  function test_parse_smithereen_activities (line 58) | fn test_parse_smithereen_activities() -> LemmyResult<()> {
  function test_parse_pleroma_activities (line 64) | fn test_parse_pleroma_activities() -> LemmyResult<()> {
  function test_parse_mastodon_activities (line 72) | fn test_parse_mastodon_activities() -> LemmyResult<()> {
  function test_parse_lotide_activities (line 84) | fn test_parse_lotide_activities() -> LemmyResult<()> {
  function test_parse_friendica_activities (line 93) | fn test_parse_friendica_activities() -> LemmyResult<()> {
  function test_parse_gnusocial_activities (line 106) | fn test_parse_gnusocial_activities() -> LemmyResult<()> {
  function test_parse_peertube_activities (line 114) | fn test_parse_peertube_activities() -> LemmyResult<()> {
  function test_parse_mbin_activities (line 120) | fn test_parse_mbin_activities() -> LemmyResult<()> {
  function test_parse_wordpress_activities (line 127) | fn test_parse_wordpress_activities() -> LemmyResult<()> {

FILE: crates/apub/activities/src/protocol/voting/mod.rs
  function test_parse_lemmy_voting (line 11) | fn test_parse_lemmy_voting() -> LemmyResult<()> {

FILE: crates/apub/activities/src/protocol/voting/undo_vote.rs
  type UndoVote (line 9) | pub struct UndoVote {

FILE: crates/apub/activities/src/protocol/voting/vote.rs
  type Vote (line 15) | pub struct Vote {
  type VoteType (line 25) | pub enum VoteType {
    method from (line 31) | fn from(value: bool) -> Self {
  function from (line 41) | fn from(value: &VoteType) -> Self {
  method community (line 47) | async fn community(&self, context: &Data<LemmyContext>) -> LemmyResult<A...

FILE: crates/apub/activities/src/voting/mod.rs
  function send_like_activity (line 37) | pub(crate) async fn send_like_activity(
  function vote_comment (line 68) | async fn vote_comment(
  function vote_post (line 82) | async fn vote_post(
  function undo_vote_comment (line 96) | async fn undo_vote_comment(
  function undo_vote_post (line 106) | async fn undo_vote_post(

FILE: crates/apub/activities/src/voting/undo_vote.rs
  method new (line 22) | pub(in crate::voting) fn new(
  type DataType (line 40) | type DataType = LemmyContext;
  type Error (line 41) | type Error = LemmyError;
  method id (line 43) | fn id(&self) -> &Url {
  method actor (line 47) | fn actor(&self) -> &Url {
  method verify (line 51) | async fn verify(&self, context: &Data<LemmyContext>) -> LemmyResult<()> {
  method receive (line 60) | async fn receive(self, context: &Data<LemmyContext>) -> LemmyResult<()> {

FILE: crates/apub/activities/src/voting/vote.rs
  method new (line 23) | pub(in crate::voting) fn new(
  type DataType (line 42) | type DataType = LemmyContext;
  type Error (line 43) | type Error = LemmyError;
  method id (line 45) | fn id(&self) -> &Url {
  method actor (line 49) | fn actor(&self) -> &Url {
  method verify (line 53) | async fn verify(&self, context: &Data<LemmyContext>) -> LemmyResult<()> {
  method receive (line 60) | async fn receive(self, context: &Data<LemmyContext>) -> LemmyResult<()> {

FILE: crates/apub/apub/src/collections/community_featured.rs
  type ApubCommunityFeatured (line 19) | pub(crate) struct ApubCommunityFeatured(());
  type Owner (line 23) | type Owner = ApubCommunity;
  type DataType (line 24) | type DataType = LemmyContext;
  type Kind (line 25) | type Kind = GroupFeatured;
  type Error (line 26) | type Error = LemmyError;
  method read_local (line 28) | async fn read_local(
  method verify (line 48) | async fn verify(
  method from_json (line 57) | async fn from_json(

FILE: crates/apub/apub/src/collections/community_follower.rs
  type ApubCommunityFollower (line 16) | pub(crate) struct ApubCommunityFollower(());
  type Owner (line 20) | type Owner = ApubCommunity;
  type DataType (line 21) | type DataType = LemmyContext;
  type Kind (line 22) | type Kind = GroupFollowers;
  type Error (line 23) | type Error = LemmyError;
  method read_local (line 25) | async fn read_local(
  method verify (line 41) | async fn verify(
  method from_json (line 50) | async fn from_json(

FILE: crates/apub/apub/src/collections/community_moderators.rs
  type ApubCommunityModerators (line 17) | pub(crate) struct ApubCommunityModerators(());
  type Owner (line 21) | type Owner = ApubCommunity;
  type DataType (line 22) | type DataType = LemmyContext;
  type Kind (line 23) | type Kind = GroupModerators;
  type Error (line 24) | type Error = LemmyError;
  method read_local (line 26) | async fn read_local(owner: &Self::Owner, data: &Data<Self::DataType>) ->...
  method verify (line 39) | async fn verify(
  method from_json (line 48) | async fn from_json(
  function handle_community_moderators (line 60) | pub(super) async fn handle_community_moderators(
  function test_parse_lemmy_community_moderators (line 118) | async fn test_parse_lemmy_community_moderators() -> LemmyResult<()> {

FILE: crates/apub/apub/src/collections/community_outbox.rs
  type ApubCommunityOutbox (line 27) | pub(crate) struct ApubCommunityOutbox(());
  type Owner (line 31) | type Owner = ApubCommunity;
  type DataType (line 32) | type DataType = LemmyContext;
  type Kind (line 33) | type Kind = GroupOutbox;
  type Error (line 34) | type Error = LemmyError;
  method read_local (line 36) | async fn read_local(owner: &Self::Owner, data: &Data<Self::DataType>) ->...
  method verify (line 82) | async fn verify(
  method from_json (line 91) | async fn from_json(

FILE: crates/apub/apub/src/collections/mod.rs
  function fetch_community_collections (line 30) | pub fn fetch_community_collections(
  method new_response (line 70) | pub(crate) async fn new_response(
  method new_empty_response (line 88) | pub(crate) fn new_empty_response(id: String) -> LemmyResult<HttpResponse> {

FILE: crates/apub/apub/src/http/comment.rs
  type CommentQuery (line 19) | pub(crate) struct CommentQuery {
  function get_comment (line 23) | async fn get_comment(
  function get_apub_comment (line 38) | pub(crate) async fn get_apub_comment(
  function get_apub_comment_context (line 47) | pub(crate) async fn get_apub_comment_context(

FILE: crates/apub/apub/src/http/community.rs
  type CommunityPath (line 45) | pub(crate) struct CommunityPath {
  type CommunityIsFollowerQuery (line 50) | pub(crate) struct CommunityIsFollowerQuery {
  function get_apub_community_http (line 55) | pub(crate) async fn get_apub_community_http(
  function get_apub_community_followers (line 71) | pub(crate) async fn get_apub_community_followers(
  function check_is_follower (line 89) | async fn check_is_follower(
  function get_apub_community_outbox (line 124) | pub(crate) async fn get_apub_community_outbox(
  function get_apub_community_moderators (line 139) | pub(crate) async fn get_apub_community_moderators(
  function get_apub_community_featured (line 154) | pub(crate) async fn get_apub_community_featured(
  type MultiCommunityQuery (line 170) | pub(crate) struct MultiCommunityQuery {
  function get_apub_person_multi_community (line 174) | pub(crate) async fn get_apub_person_multi_community(
  function get_apub_person_multi_community_follows (line 187) | pub(crate) async fn get_apub_person_multi_community_follows(
  type CommunityTagPath (line 201) | pub(crate) struct CommunityTagPath {
  function get_apub_community_tag_http (line 207) | pub(crate) async fn get_apub_community_tag_http(
  function init (line 249) | async fn init(
  function decode_response (line 275) | async fn decode_response<T: DeserializeOwned>(res: HttpResponse) -> Lemm...
  function test_get_community (line 283) | async fn test_get_community() -> LemmyResult<()> {
  function test_get_deleted_community (line 322) | async fn test_get_deleted_community() -> LemmyResult<()> {
  function test_get_local_only_community (line 352) | async fn test_get_local_only_community() -> LemmyResult<()> {
  function test_outbox_deleted_user (line 378) | async fn test_outbox_deleted_user() -> LemmyResult<()> {

FILE: crates/apub/apub/src/http/mod.rs
  constant INCOMING_ACTIVITY_TIMEOUT (line 42) | const INCOMING_ACTIVITY_TIMEOUT: Duration = Duration::from_secs(9);
  function shared_inbox (line 44) | pub async fn shared_inbox(
  type Dummy (line 62) | struct Dummy;
    method hook (line 65) | async fn hook(
  type ActivityQuery (line 88) | struct ActivityQuery {
  function get_activity (line 94) | async fn get_activity(
  function check_community_fetchable (line 117) | fn check_community_fetchable(community: &Community) -> LemmyResult<()> {
  function check_community_content_fetchable (line 125) | async fn check_community_content_fetchable(
  function get_instance_id (line 162) | pub(in crate::http) fn get_instance_id(s: &SiteOrMultiOrCommunityOrUser)...

FILE: crates/apub/apub/src/http/person.rs
  type PersonQuery (line 14) | pub(crate) struct PersonQuery {
  function get_apub_person_http (line 19) | pub(crate) async fn get_apub_person_http(
  function get_apub_person_outbox (line 33) | pub(crate) async fn get_apub_person_outbox(

FILE: crates/apub/apub/src/http/post.rs
  type PostQuery (line 19) | pub(crate) struct PostQuery {
  function get_post (line 23) | async fn get_post(
  function get_apub_post (line 39) | pub(crate) async fn get_apub_post(
  function get_apub_post_context (line 48) | pub(crate) async fn get_apub_post_context(

FILE: crates/apub/apub/src/http/routes.rs
  function config (line 25) | pub fn config(cfg: &mut web::ServiceConfig) {
  type InboxRequestGuard (line 88) | struct InboxRequestGuard;
  method check (line 91) | fn check(&self, ctx: &GuardContext) -> bool {

FILE: crates/apub/apub/src/http/site.rs
  function get_apub_site_http (line 9) | pub(crate) async fn get_apub_site_http(context: Data<LemmyContext>) -> L...
  function get_apub_site_outbox (line 15) | pub(crate) async fn get_apub_site_outbox(context: Data<LemmyContext>) ->...

FILE: crates/apub/apub/src/lib.rs
  constant FEDERATION_HTTP_FETCH_LIMIT (line 17) | pub const FEDERATION_HTTP_FETCH_LIMIT: u32 = 100;
  type VerifyUrlData (line 20) | pub struct VerifyUrlData(pub ActualDbPool);
  method verify (line 24) | async fn verify(&self, url: &Url) -> Result<(), ActivityPubError> {
  function is_new_instance (line 51) | async fn is_new_instance(context: &LemmyContext) -> LemmyResult<bool> {

FILE: crates/apub/apub/src/protocol/collections/group_featured.rs
  type GroupFeatured (line 8) | pub struct GroupFeatured {

FILE: crates/apub/apub/src/protocol/collections/group_followers.rs
  type GroupFollowers (line 7) | pub(crate) struct GroupFollowers {

FILE: crates/apub/apub/src/protocol/collections/group_moderators.rs
  type GroupModerators (line 11) | pub struct GroupModerators {

FILE: crates/apub/apub/src/protocol/collections/group_outbox.rs
  type GroupOutbox (line 8) | pub struct GroupOutbox {

FILE: crates/apub/apub/src/protocol/collections/mod.rs
  function test_parse_lemmy_collections (line 22) | fn test_parse_lemmy_collections() -> LemmyResult<()> {
  function test_parse_mastodon_collections (line 34) | fn test_parse_mastodon_collections() -> LemmyResult<()> {

FILE: crates/apub/apub/src/protocol/collections/url_collection.rs
  type UrlCollection (line 7) | pub(crate) struct UrlCollection {

FILE: crates/apub/objects/src/objects/comment.rs
  type ApubComment (line 55) | pub struct ApubComment(pub Comment);
    method from (line 65) | fn from(c: Comment) -> Self {
  type Target (line 58) | type Target = Comment;
  method deref (line 59) | fn deref(&self) -> &Self::Target {
  type DataType (line 72) | type DataType = LemmyContext;
  type Kind (line 73) | type Kind = Note;
  type Error (line 74) | type Error = LemmyError;
  method id (line 76) | fn id(&self) -> &Url {
  method read_from_id (line 80) | async fn read_from_id(
  method delete (line 91) | async fn delete(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
  method is_deleted (line 102) | fn is_deleted(&self) -> bool {
  method into_json (line 106) | async fn into_json(self, context: &Data<Self::DataType>) -> LemmyResult<...
  method verify (line 153) | async fn verify(
  method from_json (line 199) | async fn from_json(note: Note, context: &Data<LemmyContext>) -> LemmyRes...
  function prepare_comment_test (line 264) | async fn prepare_comment_test(
  function test_parse_lemmy_comment (line 280) | pub(crate) async fn test_parse_lemmy_comment() -> LemmyResult<()> {
  function test_parse_pleroma_comment (line 305) | async fn test_parse_pleroma_comment() -> LemmyResult<()> {
  function test_html_to_markdown_sanitize (line 332) | async fn test_html_to_markdown_sanitize() {

FILE: crates/apub/objects/src/objects/community.rs
  type ApubCommunity (line 59) | pub struct ApubCommunity(pub Community);
    method from (line 69) | fn from(c: Community) -> Self {
  type Target (line 62) | type Target = Community;
  method deref (line 63) | fn deref(&self) -> &Self::Target {
  type DataType (line 76) | type DataType = LemmyContext;
  type Kind (line 77) | type Kind = Group;
  type Error (line 78) | type Error = LemmyError;
  method id (line 80) | fn id(&self) -> &Url {
  method last_refreshed_at (line 84) | fn last_refreshed_at(&self) -> Option<DateTime<Utc>> {
  method read_from_id (line 88) | async fn read_from_id(
  method delete (line 99) | async fn delete(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
  method is_deleted (line 108) | fn is_deleted(&self) -> bool {
  method into_json (line 112) | async fn into_json(self, data: &Data<Self::DataType>) -> LemmyResult<Gro...
  method verify (line 152) | async fn verify(
  method from_json (line 166) | async fn from_json(group: Group, context: &Data<Self::DataType>) -> Lemm...
  method public_key_pem (line 270) | fn public_key_pem(&self) -> &str {
  method private_key_pem (line 274) | fn private_key_pem(&self) -> Option<String> {
  method inbox (line 278) | fn inbox(&self) -> Url {
  method shared_inbox (line 282) | fn shared_inbox(&self) -> Option<Url> {
  method actor_type (line 288) | fn actor_type(&self) -> ActorType {
  function test_parse_lemmy_community (line 303) | async fn test_parse_lemmy_community() -> LemmyResult<()> {

FILE: crates/apub/objects/src/objects/instance.rs
  type ApubSite (line 45) | pub struct ApubSite(pub Site);
    method from (line 55) | fn from(s: Site) -> Self {
  type Target (line 48) | type Target = Site;
  method deref (line 49) | fn deref(&self) -> &Self::Target {
  type DataType (line 62) | type DataType = LemmyContext;
  type Kind (line 63) | type Kind = Instance;
  type Error (line 64) | type Error = LemmyError;
  method id (line 66) | fn id(&self) -> &Url {
  method last_refreshed_at (line 70) | fn last_refreshed_at(&self) -> Option<DateTime<Utc>> {
  method read_from_id (line 74) | async fn read_from_id(object_id: Url, data: &Data<Self::DataType>) -> Le...
  method delete (line 82) | async fn delete(&self, _data: &Data<Self::DataType>) -> LemmyResult<()> {
  method into_json (line 86) | async fn into_json(self, data: &Data<Self::DataType>) -> LemmyResult<Sel...
  method verify (line 113) | async fn verify(
  method from_json (line 125) | async fn from_json(apub: Self::Kind, context: &Data<Self::DataType>) -> ...
  method public_key_pem (line 171) | fn public_key_pem(&self) -> &str {
  method private_key_pem (line 175) | fn private_key_pem(&self) -> Option<String> {
  method inbox (line 179) | fn inbox(&self) -> Url {
  method actor_type (line 184) | fn actor_type(&self) -> ActorType {
  function fetch_instance_actor_for_object (line 190) | pub(crate) async fn fetch_instance_actor_for_object<T: Into<Url> + Clone>(
  function test_parse_lemmy_instance (line 226) | async fn test_parse_lemmy_instance() -> LemmyResult<()> {

FILE: crates/apub/objects/src/objects/mod.rs
  type PostOrComment (line 20) | pub type PostOrComment = Either<ApubPost, ApubComment>;
  type SearchableObjects (line 22) | pub type SearchableObjects = Either<Either<PostOrComment, UserOrCommunit...
  type ReportableObjects (line 24) | pub type ReportableObjects = Either<PostOrComment, ApubCommunity>;
  type UserOrCommunity (line 26) | pub type UserOrCommunity = Either<ApubPerson, ApubCommunity>;
  type SiteOrMultiOrCommunityOrUser (line 28) | pub type SiteOrMultiOrCommunityOrUser =
  type CommunityOrMulti (line 31) | pub type CommunityOrMulti = Either<ApubCommunity, ApubMultiCommunity>;
  type UserOrCommunityOrMulti (line 33) | pub type UserOrCommunityOrMulti = Either<ApubPerson, CommunityOrMulti>;

FILE: crates/apub/objects/src/objects/multi_community.rs
  type ApubMultiCommunity (line 55) | pub struct ApubMultiCommunity(MultiCommunity);
    method from (line 66) | fn from(m: MultiCommunity) -> Self {
  type Target (line 58) | type Target = MultiCommunity;
  method deref (line 60) | fn deref(&self) -> &Self::Target {
  type DataType (line 73) | type DataType = LemmyContext;
  type Kind (line 74) | type Kind = Feed;
  type Error (line 75) | type Error = LemmyError;
  method id (line 77) | fn id(&self) -> &Url {
  method last_refreshed_at (line 81) | fn last_refreshed_at(&self) -> Option<DateTime<Utc>> {
  method read_from_id (line 85) | async fn read_from_id(
  method delete (line 96) | async fn delete(&self, _context: &Data<Self::DataType>) -> LemmyResult<(...
  method is_deleted (line 100) | fn is_deleted(&self) -> bool {
  method into_json (line 104) | async fn into_json(self, context: &Data<Self::DataType>) -> LemmyResult<...
  method verify (line 125) | async fn verify(
  method from_json (line 137) | async fn from_json(json: Self::Kind, context: &Data<LemmyContext>) -> Le...
  method public_key_pem (line 194) | fn public_key_pem(&self) -> &str {
  method private_key_pem (line 198) | fn private_key_pem(&self) -> Option<String> {
  method inbox (line 202) | fn inbox(&self) -> Url {
  method shared_inbox (line 206) | fn shared_inbox(&self) -> Option<Url> {
  method actor_type (line 212) | fn actor_type(&self) -> ActorType {

FILE: crates/apub/objects/src/objects/multi_community_collection.rs
  type ApubFeedCollection (line 27) | pub struct ApubFeedCollection;
  type DataType (line 31) | type DataType = LemmyContext;
  type Kind (line 32) | type Kind = FeedCollection;
  type Owner (line 33) | type Owner = ApubMultiCommunity;
  type Error (line 34) | type Error = LemmyError;
  method read_local (line 36) | async fn read_local(
  method verify (line 49) | async fn verify(
  method from_json (line 58) | async fn from_json(

FILE: crates/apub/objects/src/objects/person.rs
  type ApubPerson (line 45) | pub struct ApubPerson(pub DbPerson);
    method from (line 55) | fn from(p: DbPerson) -> Self {
  type Target (line 48) | type Target = DbPerson;
  method deref (line 49) | fn deref(&self) -> &Self::Target {
  type DataType (line 62) | type DataType = LemmyContext;
  type Kind (line 63) | type Kind = Person;
  type Error (line 64) | type Error = LemmyError;
  method id (line 66) | fn id(&self) -> &Url {
  method last_refreshed_at (line 70) | fn last_refreshed_at(&self) -> Option<DateTime<Utc>> {
  method read_from_id (line 74) | async fn read_from_id(
  method delete (line 85) | async fn delete(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
  method is_deleted (line 94) | fn is_deleted(&self) -> bool {
  method into_json (line 98) | async fn into_json(self, _context: &Data<Self::DataType>) -> LemmyResult...
  method verify (line 125) | async fn verify(
  method from_json (line 137) | async fn from_json(person: Person, context: &Data<Self::DataType>) -> Le...
  method public_key_pem (line 185) | fn public_key_pem(&self) -> &str {
  method private_key_pem (line 189) | fn private_key_pem(&self) -> Option<String> {
  method inbox (line 193) | fn inbox(&self) -> Url {
  method shared_inbox (line 197) | fn shared_inbox(&self) -> Option<Url> {
  method actor_type (line 203) | fn actor_type(&self) -> ActorType {
  function test_parse_lemmy_person (line 222) | async fn test_parse_lemmy_person() -> LemmyResult<()> {
  function test_parse_pleroma_person (line 238) | async fn test_parse_pleroma_person() -> LemmyResult<()> {

FILE: crates/apub/objects/src/objects/post.rs
  constant MAX_TITLE_LENGTH (line 66) | const MAX_TITLE_LENGTH: usize = 200;
  type ApubPost (line 69) | pub struct ApubPost(pub Post);
    method from (line 79) | fn from(p: Post) -> Self {
  type Target (line 72) | type Target = Post;
  method deref (line 73) | fn deref(&self) -> &Self::Target {
  type DataType (line 86) | type DataType = LemmyContext;
  type Kind (line 87) | type Kind = Page;
  type Error (line 88) | type Error = LemmyError;
  method id (line 90) | fn id(&self) -> &Url {
  method read_from_id (line 94) | async fn read_from_id(
  method delete (line 105) | async fn delete(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
  method is_deleted (line 116) | fn is_deleted(&self) -> bool {
  method into_json (line 122) | async fn into_json(self, context: &Data<Self::DataType>) -> LemmyResult<...
  method verify (line 184) | async fn verify(
  method from_json (line 210) | async fn from_json(page: Page, context: &Data<Self::DataType>) -> LemmyR...
  function update_apub_post_tags (line 331) | pub async fn update_apub_post_tags(
  function post_nsfw (line 352) | pub async fn post_nsfw(
  function test_parse_lemmy_post (line 391) | async fn test_parse_lemmy_post() -> LemmyResult<()> {
  function test_convert_mastodon_post_title (line 417) | async fn test_convert_mastodon_post_title() -> LemmyResult<()> {

FILE: crates/apub/objects/src/objects/private_message.rs
  type ApubPrivateMessage (line 45) | pub struct ApubPrivateMessage(pub DbPrivateMessage);
    method from (line 55) | fn from(pm: DbPrivateMessage) -> Self {
  type Target (line 48) | type Target = DbPrivateMessage;
  method deref (line 49) | fn deref(&self) -> &Self::Target {
  type DataType (line 62) | type DataType = LemmyContext;
  type Kind (line 63) | type Kind = PrivateMessage;
  type Error (line 64) | type Error = LemmyError;
  method id (line 66) | fn id(&self) -> &Url {
  method read_from_id (line 70) | async fn read_from_id(
  method delete (line 81) | async fn delete(&self, _context: &Data<Self::DataType>) -> LemmyResult<(...
  method is_deleted (line 86) | fn is_deleted(&self) -> bool {
  method into_json (line 90) | async fn into_json(self, context: &Data<Self::DataType>) -> LemmyResult<...
  method verify (line 122) | async fn verify(
  method from_json (line 137) | async fn from_json(
  function prepare_comment_test (line 192) | async fn prepare_comment_test(
  function test_parse_lemmy_pm (line 210) | async fn test_parse_lemmy_pm() -> LemmyResult<()> {
  function test_parse_pleroma_pm (line 234) | async fn test_parse_pleroma_pm() -> LemmyResult<()> {

FILE: crates/apub/objects/src/protocol/group.rs
  type Group (line 24) | pub struct Group {

FILE: crates/apub/objects/src/protocol/instance.rs
  type Instance (line 18) | pub struct Instance {

FILE: crates/apub/objects/src/protocol/mod.rs
  function test_parse_objects_lemmy (line 25) | fn test_parse_objects_lemmy() -> LemmyResult<()> {
  function test_parse_objects_pleroma (line 37) | fn test_parse_objects_pleroma() -> LemmyResult<()> {
  function test_parse_objects_smithereen (line 44) | fn test_parse_objects_smithereen() -> LemmyResult<()> {
  function test_parse_objects_mastodon (line 51) | fn test_parse_objects_mastodon() -> LemmyResult<()> {
  function test_parse_objects_lotide (line 60) | fn test_parse_objects_lotide() -> LemmyResult<()> {
  function test_parse_object_friendica (line 70) | fn test_parse_object_friendica() -> LemmyResult<()> {
  function test_parse_object_gnusocial (line 81) | fn test_parse_object_gnusocial() -> LemmyResult<()> {
  function test_parse_object_peertube (line 90) | fn test_parse_object_peertube() -> LemmyResult<()> {
  function test_parse_object_mobilizon (line 99) | fn test_parse_object_mobilizon() -> LemmyResult<()> {
  function test_parse_object_discourse (line 107) | fn test_parse_object_discourse() -> LemmyResult<()> {
  function test_parse_object_nodebb (line 115) | fn test_parse_object_nodebb() -> LemmyResult<()> {
  function test_parse_object_wordpress (line 123) | fn test_parse_object_wordpress() -> LemmyResult<()> {
  function test_parse_object_mbin (line 132) | fn test_parse_object_mbin() -> LemmyResult<()> {

FILE: crates/apub/objects/src/protocol/multi_community.rs
  type Feed (line 20) | pub struct Feed {
  type FeedType (line 42) | pub enum FeedType {
  type FeedCollection (line 49) | pub struct FeedCollection {

FILE: crates/apub/objects/src/protocol/note.rs
  type Note (line 36) | pub struct Note {
    method get_parents (line 64) | pub async fn get_parents(
  method community (line 106) | async fn community(&self, context: &Data<LemmyContext>) -> LemmyResult<A...

FILE: crates/apub/objects/src/protocol/page.rs
  type PageType (line 36) | pub enum PageType {
  type Page (line 47) | pub struct Page {
    method creator (line 163) | pub fn creator(&self) -> LemmyResult<ObjectId<ApubPerson>> {
  type Link (line 84) | pub struct Link {
  type Image (line 92) | pub struct Image {
  type Document (line 102) | pub struct Document {
  type Attachment (line 113) | pub enum Attachment {
    method url (line 120) | pub(crate) fn url(self) -> Url {
    method alt_text (line 131) | pub(crate) fn alt_text(self) -> Option<String> {
    method as_markdown (line 139) | pub(crate) async fn as_markdown(&self, context: &Data<LemmyContext>) -...
    method new (line 177) | pub(crate) fn new(url: Url, media_type: Option<String>, alt_text: Opti...
  type DataType (line 198) | type DataType = LemmyContext;
  type Error (line 199) | type Error = LemmyError;
  method id (line 200) | fn id(&self) -> &Url {
  method actor (line 204) | fn actor(&self) -> &Url {
  method verify (line 208) | async fn verify(&self, data: &Data<Self::DataType>) -> LemmyResult<()> {
  method receive (line 211) | async fn receive(self, data: &Data<Self::DataType>) -> LemmyResult<()> {
  method community (line 218) | async fn community(&self, context: &Data<LemmyContext>) -> LemmyResult<A...
  function deserialize_not_present (line 256) | fn deserialize_not_present<'de, D>(deserializer: D) -> Result<Option<Str...
  function test_not_parsing_note_as_page (line 272) | fn test_not_parsing_note_as_page() {

FILE: crates/apub/objects/src/protocol/person.rs
  type UserTypes (line 18) | pub enum UserTypes {
  type Person (line 27) | pub struct Person {

FILE: crates/apub/objects/src/protocol/private_message.rs
  type PrivateMessage (line 19) | pub struct PrivateMessage {
  type PrivateMessageType (line 36) | pub enum PrivateMessageType {

FILE: crates/apub/objects/src/protocol/tags.rs
  type ApubTag (line 17) | pub enum ApubTag {
    method community_tag_id (line 25) | pub(crate) fn community_tag_id(&self) -> Option<&Url> {
    method mention_id (line 31) | pub fn mention_id(&self) -> Option<&ObjectId<ApubPerson>> {
  type Mention (line 40) | pub struct Mention {
  type Hashtag (line 48) | pub struct Hashtag {
  type HashtagType (line 56) | pub enum HashtagType {
  type CommunityTagType (line 64) | enum CommunityTagType {
  type ApubCommunityTag (line 72) | pub struct ApubCommunityTag {
    method to_json (line 83) | pub fn to_json(tag: CommunityTag) -> Self {
    method to_insert_form (line 94) | pub fn to_insert_form(&self, community_id: CommunityId) -> CommunityTa...

FILE: crates/apub/objects/src/utils/functions.rs
  function read_from_string_or_source (line 33) | pub fn read_from_string_or_source(
  function read_from_string_or_source_opt (line 50) | pub fn read_from_string_or_source_opt(
  type LocalSiteData (line 61) | pub struct LocalSiteData {
  function local_site_data_cached (line 67) | pub async fn local_site_data_cached(pool: &mut DbPool<'_>) -> LemmyResul...
  function check_apub_id_valid_with_strictness (line 101) | pub async fn check_apub_id_valid_with_strictness(
  function check_apub_id_valid (line 148) | pub fn check_apub_id_valid(apub_id: &Url, local_site_data: &LocalSiteDat...
  type GetActorType (line 184) | pub trait GetActorType {
    method actor_type (line 185) | fn actor_type(&self) -> ActorType;
    method actor_type (line 189) | fn actor_type(&self) -> ActorType {
  function generate_to (line 198) | pub fn generate_to(community: &Community) -> LemmyResult<Vec<Url>> {
  function verify_person_in_community (line 212) | pub async fn verify_person_in_community(
  function verify_person_in_site_or_community (line 224) | pub async fn verify_person_in_site_or_community(
  function verify_is_public (line 239) | pub fn verify_is_public(to: &[Url], cc: &[Url]) -> LemmyResult<()> {
  function verify_visibility (line 249) | pub fn verify_visibility(to: &[Url], cc: &[Url], community: &ApubCommuni...
  function append_attachments_to_comment (line 259) | pub async fn append_attachments_to_comment(
  function community_visibility (line 276) | pub fn community_visibility(group: &Group) -> CommunityVisibility {
  function context_url (line 287) | pub fn context_url(id: &Url) -> String {
  function verify_mod_action (line 300) | pub async fn verify_mod_action(

FILE: crates/apub/objects/src/utils/markdown_links.rs
  function markdown_rewrite_remote_links_opt (line 9) | pub async fn markdown_rewrite_remote_links_opt(
  function markdown_rewrite_remote_links (line 25) | pub async fn markdown_rewrite_remote_links(
  function to_local_url (line 49) | pub(crate) async fn to_local_url(url: &str, context: &Data<LemmyContext>...
  function test_markdown_rewrite_remote_links (line 86) | async fn test_markdown_rewrite_remote_links() -> LemmyResult<()> {

FILE: crates/apub/objects/src/utils/mentions.rs
  type MentionsAndAddresses (line 20) | pub(crate) struct MentionsAndAddresses {
  function collect_non_local_mentions (line 28) | pub(crate) async fn collect_non_local_mentions(
  function get_comment_parent_creator (line 82) | pub(crate) async fn get_comment_parent_creator(

FILE: crates/apub/objects/src/utils/protocol.rs
  type Source (line 22) | pub struct Source {
    method new (line 28) | pub(crate) fn new(content: String) -> Self {
  type InCommunity (line 36) | pub trait InCommunity {
    method community (line 37) | fn community(
  type ImageObject (line 45) | pub struct ImageObject {
    method new (line 52) | pub(crate) fn new(url: DbUrl) -> Self {
  type AttributedTo (line 62) | pub enum AttributedTo {
    method url (line 82) | pub fn url(self) -> Option<DbUrl> {
  type PersonOrGroupType (line 68) | pub enum PersonOrGroupType {
  type AttributedToPeertube (line 75) | pub struct AttributedToPeertube {
  type PersonOrGroupModerators (line 91) | pub struct PersonOrGroupModerators(Url);
    method from (line 102) | fn from(value: DbUrl) -> Self {
    method creator (line 108) | pub(crate) fn creator(&self) -> ObjectId<ApubPerson> {
    method moderators (line 112) | pub fn moderators(&self) -> Url {
  type Target (line 94) | type Target = Url;
  method deref (line 96) | fn deref(&self) -> &Self::Target {
  type LanguageTag (line 120) | pub(crate) struct LanguageTag {
    method new_single (line 135) | pub(crate) async fn new_single(
    method new_multiple (line 152) | pub(crate) async fn new_multiple(
    method to_language_id_single (line 172) | pub(crate) async fn to_language_id_single(
    method to_language_id_multiple (line 179) | pub(crate) async fn to_language_id_multiple(
  method default (line 126) | fn default() -> Self {
  type Endpoints (line 196) | pub struct Endpoints {
  type Id (line 200) | pub trait Id {
    method id (line 201) | fn id(&self) -> &Url;
    method id (line 205) | fn id(&self) -> &Url {

FILE: crates/apub/objects/src/utils/test.rs
  function file_to_json_object (line 13) | pub fn file_to_json_object<T: DeserializeOwned>(path: &str) -> LemmyResu...
  function test_json (line 19) | pub fn test_json<T: DeserializeOwned>(path: &str) -> LemmyResult<WithCon...
  function test_parse_lemmy_item (line 25) | pub fn test_parse_lemmy_item<T: Serialize + DeserializeOwned + std::fmt:...
  function parse_lemmy_instance (line 38) | pub(crate) async fn parse_lemmy_instance(context: &Data<LemmyContext>) -...
  function parse_lemmy_person (line 47) | pub async fn parse_lemmy_person(
  function parse_lemmy_community (line 59) | pub async fn parse_lemmy_community(context: &Data<LemmyContext>) -> Lemm...

FILE: crates/apub/send/src/inboxes.rs
  type DataSource (line 44) | pub trait DataSource: Send + Sync {
    method read_site_from_instance_id (line 45) | async fn read_site_from_instance_id(&self, instance_id: InstanceId) ->...
    method get_instance_followed_community_inboxes (line 46) | async fn get_instance_followed_community_inboxes(
    method read_site_from_instance_id (line 63) | async fn read_site_from_instance_id(&self, instance_id: InstanceId) ->...
    method get_instance_followed_community_inboxes (line 67) | async fn get_instance_followed_community_inboxes(
  type DbDataSource (line 52) | pub struct DbDataSource {
    method new (line 57) | pub fn new(pool: ActualDbPool) -> Self {
  type CommunityInboxCollector (line 81) | pub(crate) struct CommunityInboxCollector<T: DataSource> {
  type RealCommunityInboxCollector (line 96) | pub type RealCommunityInboxCollector = CommunityInboxCollector<DbDataSou...
  function new_real (line 99) | pub fn new_real(
  function new (line 106) | pub fn new(
  function get_inbox_urls (line 126) | pub async fn get_inbox_urls(&mut self, activity: &SentActivity) -> Lemmy...
  function update_communities (line 169) | pub async fn update_communities(&mut self) -> LemmyResult<()> {
  function get_communities (line 198) | async fn get_communities(
  function setup_collector (line 247) | fn setup_collector() -> CommunityInboxCollector<MockDataSource> {
  function test_get_inbox_urls_empty (line 255) | async fn test_get_inbox_urls_empty() -> LemmyResult<()> {
  function test_get_inbox_urls_send_all_instances (line 277) | async fn test_get_inbox_urls_send_all_instances() -> LemmyResult<()> {
  function test_get_inbox_urls_community_followers (line 324) | async fn test_get_inbox_urls_community_followers() -> LemmyResult<()> {
  function test_get_inbox_urls_send_inboxes (line 364) | async fn test_get_inbox_urls_send_inboxes() -> LemmyResult<()> {
  function test_get_inbox_urls_combined (line 397) | async fn test_get_inbox_urls_combined() -> LemmyResult<()> {
  function test_update_communities (line 463) | async fn test_update_communities() -> LemmyResult<()> {
  function test_get_inbox_urls_no_duplicates (line 514) | async fn test_get_inbox_urls_no_duplicates() -> LemmyResult<()> {

FILE: crates/apub/send/src/lib.rs
  type Opts (line 31) | pub struct Opts {
  type SendManager (line 38) | pub struct SendManager {
    method new (line 48) | fn new(
    method run (line 71) | pub fn run(
    method do_loop (line 100) | async fn do_loop(&mut self, cancel: CancellationToken) -> LemmyResult<...
    method cancel (line 172) | pub async fn cancel(self) -> LemmyResult<()> {
  type TestData (line 216) | struct TestData {
    method init (line 222) | async fn init(process_count: i32, process_index: i32) -> LemmyResult<S...
    method run (line 256) | async fn run(&mut self) -> LemmyResult<()> {
    method cleanup (line 268) | async fn cleanup(self) -> LemmyResult<()> {
  function test_send_manager (line 278) | async fn test_send_manager() -> LemmyResult<()> {
  function test_send_manager_processes (line 294) | async fn test_send_manager_processes() -> LemmyResult<()> {
  function test_send_manager_blocked (line 319) | async fn test_send_manager_blocked() -> LemmyResult<()> {
  function test_send_manager_allowed (line 341) | async fn test_send_manager_allowed() -> LemmyResult<()> {
  function test_send_manager_dead (line 362) | async fn test_send_manager_dead() -> LemmyResult<()> {

FILE: crates/apub/send/src/send.rs
  type SendSuccessInfo (line 25) | pub(crate) struct SendSuccessInfo {
  method eq (line 33) | fn eq(&self, other: &Self) -> bool {
  method partial_cmp (line 40) | fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
  method cmp (line 45) | fn cmp(&self, other: &Self) -> std::cmp::Ordering {
  type SendActivityResult (line 66) | pub(crate) enum SendActivityResult {
  type SendRetryTask (line 74) | pub(crate) struct SendRetryTask<'a> {
  function send_retry_loop (line 99) | pub async fn send_retry_loop(self) -> Result<()> {
  type DummyActivity (line 161) | struct DummyActivity {
  type DataType (line 170) | type DataType = LemmyContext;
  type Error (line 172) | type Error = LemmyError;
  method id (line 174) | fn id(&self) -> &Url {
  method actor (line 178) | fn actor(&self) -> &Url {
  method verify (line 182) | async fn verify(&self, _context: &Data<Self::DataType>) -> LemmyResult<(...
  method receive (line 186) | async fn receive(self, _context: &Data<LemmyContext>) -> LemmyResult<()> {

FILE: crates/apub/send/src/stats.rs
  function receive_print_stats (line 13) | pub(crate) async fn receive_print_stats(
  function print_stats (line 40) | async fn print_stats(
  function print_stats_with_error (line 50) | async fn print_stats_with_error(

FILE: crates/apub/send/src/util.rs
  type CancellableTask (line 83) | pub struct CancellableTask {
    method spawn (line 89) | pub fn spawn<F, R>(
    method cancel (line 128) | pub async fn cancel(self) -> Result<(), anyhow::Error> {
  function get_actor_cached (line 135) | pub(crate) async fn get_actor_cached(
  type CachedActivityInfo (line 177) | type CachedActivityInfo = Option<Arc<SentActivity>>;
  function get_activity_cached (line 182) | pub(crate) async fn get_activity_cached(
  function get_latest_activity_id (line 197) | pub(crate) async fn get_latest_activity_id(pool: &mut DbPool<'_>) -> Res...
  type FederationQueueStateWithDomain (line 220) | pub(crate) struct FederationQueueStateWithDomain {

FILE: crates/apub/send/src/worker.rs
  constant MAX_SUCCESSFULS (line 43) | const MAX_SUCCESSFULS: usize = 1000;
  constant MIN_ACTIVITY_SEND_RESULTS_TO_HANDLE (line 47) | const MIN_ACTIVITY_SEND_RESULTS_TO_HANDLE: usize = 4;
  constant MIN_ACTIVITY_SEND_RESULTS_TO_HANDLE (line 49) | const MIN_ACTIVITY_SEND_RESULTS_TO_HANDLE: usize = 0;
  type InstanceWorker (line 61) | pub(crate) struct InstanceWorker {
    method init_and_loop (line 84) | pub(crate) async fn init_and_loop(
    method loop_until_stopped (line 120) | async fn loop_until_stopped(&mut self) -> LemmyResult<()> {
    method initial_fail_sleep (line 201) | async fn initial_fail_sleep(&mut self) -> Result<()> {
    method get_last_sent_id (line 231) | async fn get_last_sent_id(&mut self) -> Result<ActivityId> {
    method handle_send_results (line 250) | async fn handle_send_results(&mut self) -> Result<(), anyhow::Error> {
    method mark_instance_alive (line 296) | async fn mark_instance_alive(&mut self) -> Result<()> {
    method pop_successfuls_and_write (line 318) | async fn pop_successfuls_and_write(&mut self, force_write: bool) -> Re...
    method spawn_send_if_needed (line 358) | async fn spawn_send_if_needed(&mut self, activity_id: ActivityId) -> L...
    method save_and_send_state (line 432) | async fn save_and_send_state(&mut self) -> Result<()> {
    method pool (line 445) | fn pool(&self) -> DbPool<'_> {
  type Data (line 481) | struct Data {
    method init (line 495) | async fn init() -> LemmyResult<Self> {
    method cleanup (line 549) | async fn cleanup(&mut self) -> LemmyResult<()> {
  method setup (line 566) | async fn setup() -> Data {
  method teardown (line 569) | async fn teardown(mut self) {
  function test_stats (line 578) | async fn test_stats(data: &mut Data) -> LemmyResult<()> {
  function test_send_40 (line 618) | async fn test_send_40(data: &mut Data) -> LemmyResult<()> {
  function test_send_15_20_30 (line 644) | async fn test_send_15_20_30(data: &mut Data) -> LemmyResult<()> {
  function test_update_instance (line 671) | async fn test_update_instance(data: &mut Data) -> LemmyResult<()> {
  function test_errors (line 689) | async fn test_errors(data: &mut Data) -> LemmyResult<()> {
  function wait_receive (line 720) | async fn wait_receive(
  function listen_activities (line 734) | fn listen_activities(
  function send_activity (line 772) | async fn send_activity(
  function compare_sent_with_receive (line 806) | async fn compare_sent_with_receive(data: &mut Data, mut sent: Vec<SentAc...

FILE: crates/db_schema/src/impls/activity.rs
  method create (line 15) | pub async fn create(pool: &mut DbPool<'_>, form: SentActivityForm) -> Le...
  method read_from_apub_id (line 25) | pub async fn read_from_apub_id(pool: &mut DbPool<'_>, object_id: &DbUrl)...
  method read (line 34) | pub async fn read(pool: &mut DbPool<'_>, object_id: ActivityId) -> Lemmy...
  method create (line 46) | pub async fn create(pool: &mut DbPool<'_>, ap_id_: &DbUrl) -> LemmyResul...
  function receive_activity_duplicate (line 78) | async fn receive_activity_duplicate() -> LemmyResult<()> {
  function sent_activity_write_read (line 93) | async fn sent_activity_write_read() -> LemmyResult<()> {

FILE: crates/db_schema/src/impls/actor_language.rs
  constant UNDETERMINED_ID (line 34) | pub const UNDETERMINED_ID: LanguageId = LanguageId(0);
  method read (line 37) | pub async fn read(
  method update (line 55) | pub async fn update(
  method read_local_raw (line 107) | pub async fn read_local_raw(pool: &mut DbPool<'_>) -> LemmyResult<Vec<La...
  method read (line 119) | pub async fn read(pool: &mut DbPool<'_>, for_site_id: SiteId) -> LemmyRe...
  method update (line 131) | pub async fn update(
  method is_allowed_community_language (line 187) | async fn is_allowed_community_language(
  method limit_languages (line 212) | async fn limit_languages(
  method read (line 238) | pub async fn read(
  method update (line 257) | pub async fn update(
  function validate_post_language (line 311) | pub async fn validate_post_language(
  function convert_update_languages (line 323) | async fn convert_update_languages(
  function convert_read_languages (line 342) | async fn convert_read_languages(
  function test_langs1 (line 385) | async fn test_langs1(pool: &mut DbPool<'_>) -> LemmyResult<Vec<LanguageI...
  function test_langs2 (line 392) | async fn test_langs2(pool: &mut DbPool<'_>) -> LemmyResult<Vec<LanguageI...
  function test_convert_update_languages (line 401) | async fn test_convert_update_languages() -> LemmyResult<()> {
  function test_convert_read_languages (line 419) | async fn test_convert_read_languages() -> LemmyResult<()> {
  function test_site_languages (line 440) | async fn test_site_languages() -> LemmyResult<()> {
  function test_user_languages (line 463) | async fn test_user_languages() -> LemmyResult<()> {
  function test_community_languages (line 495) | async fn test_community_languages() -> LemmyResult<()> {
  function test_validate_post_language (line 550) | async fn test_validate_post_language() -> LemmyResult<()> {

FILE: crates/db_schema/src/impls/comment.rs
  method permadelete_for_creator (line 45) | pub async fn permadelete_for_creator(
  method update_removed_for_creator (line 62) | pub async fn update_removed_for_creator(
  method creator_comments_in_community (line 79) | async fn creator_comments_in_community(
  method creator_comments_in_instance (line 97) | async fn creator_comments_in_instance(
  method update_removed_for_creator_and_community (line 116) | pub async fn update_removed_for_creator_and_community(
  method update_removed_for_creator_and_instance (line 139) | pub async fn update_removed_for_creator_and_instance(
  method create (line 161) | pub async fn create(
  method insert_apub (line 169) | pub async fn insert_apub(
  method read_from_apub_id (line 196) | pub async fn read_from_apub_id(
  method parent_comment_id (line 209) | pub fn parent_comment_id(&self) -> Option<CommentId> {
  method update_hot_rank (line 220) | pub async fn update_hot_rank(pool: &mut DbPool<'_>, comment_id: CommentI...
  method local_url (line 229) | pub fn local_url(&self, settings: &Settings) -> LemmyResult<Url> {
  method set_not_pending (line 235) | pub async fn set_not_pending(&self, pool: &mut DbPool<'_>) -> LemmyResul...
  method update_locked_for_comment_and_children (line 247) | pub async fn update_locked_for_comment_and_children(
  method update_removed_for_comment_and_children (line 260) | pub async fn update_removed_for_comment_and_children(
  method update_comment_and_children (line 275) | async fn update_comment_and_children(
  method update_removed_for_post (line 290) | pub async fn update_removed_for_post(
  method read_ap_ids_for_post (line 307) | pub async fn read_ap_ids_for_post(
  type InsertForm (line 326) | type InsertForm = CommentInsertForm;
  type UpdateForm (line 327) | type UpdateForm = CommentUpdateForm;
  type IdType (line 328) | type IdType = CommentId;
  method create (line 331) | async fn create(_pool: &mut DbPool<'_>, _comment_form: &Self::InsertForm...
  method update (line 335) | async fn update(
  type Form (line 350) | type Form = CommentLikeForm;
  type IdType (line 351) | type IdType = CommentId;
  method like (line 353) | async fn like(pool: &mut DbPool<'_>, form: &Self::Form) -> LemmyResult<S...
  method remove_all_likes (line 367) | async fn remove_all_likes(
  method remove_likes_in_community (line 381) | async fn remove_likes_in_community(
  type Form (line 401) | type Form = CommentSavedForm;
  method save (line 402) | async fn save(pool: &mut DbPool<'_>, form: &Self::Form) -> LemmyResult<S...
  method unsave (line 414) | async fn unsave(pool: &mut DbPool<'_>, form: &Self::Form) -> LemmyResult...
  method read (line 425) | pub async fn read(
  function test_crud (line 464) | async fn test_crud() -> LemmyResult<()> {
  function test_aggregates (line 578) | async fn test_aggregates() -> LemmyResult<()> {
  function test_update_children (line 675) | async fn test_update_children() -> LemmyResult<()> {
  function test_remove_post_children (line 742) | async fn test_remove_post_children() -> LemmyResult<()> {

FILE: crates/db_schema/src/impls/comment_report.rs
  type Form (line 24) | type Form = CommentReportForm;
  type IdType (line 25) | type IdType = CommentReportId;
  type ObjectIdType (line 26) | type ObjectIdType = CommentId;
  method report (line 31) | async fn report(pool: &mut DbPool<'_>, form: &Self::Form) -> LemmyResult...
  method update_resolved (line 45) | async fn update_resolved(
  method resolve_apub (line 63) | async fn resolve_apub(
  method resolve_all_for_object (line 87) | async fn resolve_all_for_object(
  method resolve_all_for_thread (line 106) | pub async fn resolve_all_for_thread(
  method resolve_all_for_post (line 129) | pub async fn resolve_all_for_post(

FILE: crates/db_schema/src/impls/community.rs
  type InsertForm (line 55) | type InsertForm = CommunityInsertForm;
  type UpdateForm (line 56) | type UpdateForm = CommunityUpdateForm;
  type IdType (line 57) | type IdType = CommunityId;
  method create (line 59) | async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Lemmy...
  method update (line 74) | async fn update(
  method join (line 89) | pub async fn join(pool: &mut DbPool<'_>, form: &CommunityModeratorForm) ...
  method leave (line 105) | pub async fn leave(
  type CollectionType (line 119) | pub enum CollectionType {
  method insert_apub (line 125) | pub async fn insert_apub(
  method get_by_collection_url (line 156) | pub async fn get_by_collection_url(
  method set_featured_posts (line 181) | pub async fn set_featured_posts(
  method get_random_community_id (line 202) | pub async fn get_random_community_id(
  method hide_removed_and_deleted (line 266) | pub fn hide_removed_and_deleted() -> _ {
  method update_federated_followers (line 272) | pub async fn update_federated_followers(
  method read (line 287) | pub async fn read(
  method delete_mods_for_community (line 301) | pub async fn delete_mods_for_community(
  method leave_mod_team_for_all_communities (line 314) | pub async fn leave_mod_team_for_all_communities(
  method get_person_moderated_communities (line 326) | pub async fn get_person_moderated_communities(
  method check_accept_activity_in_community (line 345) | pub async fn check_accept_activity_in_community(
  method approve_private_community_follower (line 368) | pub async fn approve_private_community_follower(
  method fetch_largest_subscribed_community (line 389) | pub async fn fetch_largest_subscribed_community(
  method update_notification_state (line 417) | pub async fn update_notification_state(
  method list_subscribers (line 443) | pub async fn list_subscribers(
  type Form (line 474) | type Form = CommunityPersonBanForm;
  method ban (line 475) | async fn ban(pool: &mut DbPool<'_>, form: &Self::Form) -> LemmyResult<Se...
  method unban (line 491) | async fn unban(pool: &mut DbPool<'_>, form: &Self::Form) -> LemmyResult<...
  type Form (line 503) | type Form = CommunityFollowerForm;
  type IdType (line 504) | type IdType = CommunityId;
  method follow (line 506) | async fn follow(pool: &mut DbPool<'_>, form: &Self::Form) -> LemmyResult...
  method follow_accepted (line 521) | async fn follow_accepted(
  method unfollow (line 538) | async fn unfollow(
  type Form (line 555) | type Form = CommunityBlockForm;
  type ObjectIdType (line 556) | type ObjectIdType = CommunityId;
  type ObjectType (line 557) | type ObjectType = Community;
  method block (line 559) | async fn block(pool: &mut DbPool<'_>, form: &Self::Form) -> LemmyResult<...
  method unblock (line 574) | async fn unblock(
  method read_block (line 589) | async fn read_block(
  method read_blocks_for_person (line 606) | async fn read_blocks_for_person(
  method read_from_apub_id (line 626) | async fn read_from_apub_id(
  method read_from_name (line 639) | async fn read_from_name(
  method actor_url (line 665) | fn actor_url(&self, settings: &Settings) -> LemmyResult<Url> {
  method generate_local_actor_url (line 675) | fn generate_local_actor_url(name: &str, settings: &Settings) -> LemmyRes...
  function test_crud (line 711) | async fn test_crud() -> LemmyResult<()> {
  function test_aggregates (line 862) | async fn test_aggregates() -> LemmyResult<()> {

FILE: crates/db_schema/src/impls/community_community_follow.rs
  method follow (line 13) | pub async fn follow(
  method unfollow (line 29) | pub async fn unfollow(

FILE: crates/db_schema/src/impls/community_report.rs
  type Form (line 19) | type Form = CommunityReportForm;
  type IdType (line 20) | type IdType = CommunityReportId;
  type ObjectIdType (line 21) | type ObjectIdType = CommunityId;
  method report (line 26) | async fn report(pool: &mut DbPool<'_>, form: &Self::Form) -> LemmyResult...
  method update_resolved (line 40) | async fn update_resolved(
  method resolve_apub (line 58) | async fn resolve_apub(
  method resolve_all_for_object (line 82) | async fn resolve_all_for_object(

FILE: crates/db_schema/src/impls/community_tag.rs
  type InsertForm (line 38) | type InsertForm = CommunityTagInsertForm;
  type UpdateForm (line 39) | type UpdateForm = CommunityTagUpdateForm;
  type IdType (line 40) | type IdType = CommunityTagId;
  method create (line 42) | async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Lemmy...
  method update (line 51) | async fn update(
  method read_for_community (line 66) | pub async fn read_for_community(
  method update_many (line 79) | pub async fn update_many(
  method read_for_post (line 127) | pub async fn read_for_post(
  method read_apub (line 142) | pub async fn read_apub(pool: &mut DbPool<'_>, ap_id: &DbUrl) -> LemmyRes...
  method from_sql (line 155) | fn from_sql(bytes: PgValue) -> diesel::deserialize::Result<Self> {
  method from_nullable_sql (line 159) | fn from_nullable_sql(
  method to_sql (line 170) | fn to_sql(&self, out: &mut diesel::serialize::Output<Pg>) -> diesel::ser...
  method update (line 177) | pub async fn update(

FILE: crates/db_schema/src/impls/custom_emoji.rs
  type InsertForm (line 21) | type InsertForm = CustomEmojiInsertForm;
  type UpdateForm (line 22) | type UpdateForm = CustomEmojiUpdateForm;
  type IdType (line 23) | type IdType = CustomEmojiId;
  method create (line 25) | async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Lemmy...
  method update (line 34) | async fn update(
  method create_from_keywords (line 49) | pub async fn create_from_keywords(
  method create (line 65) | pub async fn create(
  method delete (line 76) | pub async fn delete(pool: &mut DbPool<'_>, emoji_id: CustomEmojiId) -> L...

FILE: crates/db_schema/src/impls/email_verification.rs
  method create (line 15) | pub async fn create(pool: &mut DbPool<'_>, form: &EmailVerificationForm)...
  method read_for_token (line 24) | pub async fn read_for_token(pool: &mut DbPool<'_>, token: &str) -> Lemmy...
  method delete_old_tokens_for_local_user (line 33) | pub async fn delete_old_tokens_for_local_user(

FILE: crates/db_schema/src/impls/federation_allowlist.rs
  method allow (line 9) | pub async fn allow(pool: &mut DbPool<'_>, form: &FederationAllowListForm...
  method unallow (line 17) | pub async fn unallow(pool: &mut DbPool<'_>, instance_id_: InstanceId) ->...
  function test_allowlist_insert_and_clear (line 37) | async fn test_allowlist_insert_and_clear() -> LemmyResult<()> {

FILE: crates/db_schema/src/impls/federation_blocklist.rs
  method block (line 9) | pub async fn block(pool: &mut DbPool<'_>, form: &FederationBlockListForm...
  method unblock (line 17) | pub async fn unblock(pool: &mut DbPool<'_>, instance_id_: InstanceId) ->...

FILE: crates/db_schema/src/impls/federation_queue_state.rs
  method load (line 10) | pub async fn load(pool: &mut DbPool<'_>, instance_id: InstanceId) -> Lem...
  method upsert (line 28) | pub async fn upsert(pool: &mut DbPool<'_>, state: &FederationQueueState)...

FILE: crates/db_schema/src/impls/images.rs
  method create (line 29) | pub async fn create(
  method validate_by_alias_and_user (line 53) | pub async fn validate_by_alias_and_user(
  method delete_by_alias (line 73) | pub async fn delete_by_alias(pool: &mut DbPool<'_>, alias: &str) -> Lemm...
  method delete_by_aliases (line 82) | pub async fn delete_by_aliases(pool: &mut DbPool<'_>, aliases: &[String]...
  method create (line 92) | pub async fn create(pool: &mut DbPool<'_>, links: Vec<Url>) -> LemmyResu...
  method validate (line 106) | pub async fn validate(pool: &mut DbPool<'_>, link_: DbUrl) -> LemmyResul...
  method create (line 120) | pub async fn create(pool: &mut DbPool<'_>, form: &ImageDetailsInsertForm...

FILE: crates/db_schema/src/impls/instance.rs
  method read_or_create (line 47) | pub async fn read_or_create(pool: &mut DbPool<'_>, domain_: &str) -> Lem...
  method read (line 80) | pub async fn read(pool: &mut DbPool<'_>, instance_id: InstanceId) -> Lem...
  method update (line 89) | pub async fn update(
  method delete (line 102) | pub async fn delete(pool: &mut DbPool<'_>, instance_id: InstanceId) -> L...
  method read_all (line 110) | pub async fn read_all(pool: &mut DbPool<'_>) -> LemmyResult<Vec<Instance...
  method delete_all (line 120) | pub async fn delete_all(pool: &mut DbPool<'_>) -> LemmyResult<usize> {
  method allowlist (line 131) | pub async fn allowlist(pool: &mut DbPool<'_>) -> LemmyResult<Vec<Self>> {
  method blocklist (line 141) | pub async fn blocklist(pool: &mut DbPool<'_>) -> LemmyResult<Vec<Self>> {
  method read_federated_with_blocked_and_dead (line 153) | pub async fn read_federated_with_blocked_and_dead(
  method block_communities (line 193) | pub async fn block_communities(
  method unblock_communities (line 209) | pub async fn unblock_communities(
  method read_communities_block (line 222) | pub async fn read_communities_block(
  method read_communities_block_for_person (line 238) | pub async fn read_communities_block_for_person(
  method block_persons (line 254) | pub async fn block_persons(
  method unblock_persons (line 270) | pub async fn unblock_persons(
  method read_persons_block (line 283) | pub async fn read_persons_block(
  method read_persons_block_for_person (line 299) | pub async fn read_persons_block_for_person(
  method check_ban (line 315) | pub async fn check_ban(
  type Form (line 338) | type Form = InstanceBanForm;
  method ban (line 339) | async fn ban(pool: &mut DbPool<'_>, form: &Self::Form) -> LemmyResult<Se...
  method unban (line 352) | async fn unban(pool: &mut DbPool<'_>, form: &Self::Form) -> LemmyResult<...

FILE: crates/db_schema/src/impls/keyword_block.rs
  method read (line 12) | pub async fn read(
  method update (line 25) | pub async fn update(

FILE: crates/db_schema/src/impls/language.rs
  method read_all (line 16) | pub async fn read_all(pool: &mut DbPool<'_>) -> LemmyResult<Vec<Self>> {
  method read_from_id (line 33) | pub async fn read_from_id(pool: &mut DbPool<'_>, id_: LanguageId) -> Lem...
  method read_id_from_code (line 43) | pub async fn read_id_from_code(pool: &mut DbPool<'_>, code_: &str) -> Le...
  function test_languages (line 68) | async fn test_languages() -> LemmyResult<()> {

FILE: crates/db_schema/src/impls/local_site.rs
  method create (line 9) | pub async fn create(pool: &mut DbPool<'_>, form: &LocalSiteInsertForm) -...
  method update (line 18) | pub async fn update(pool: &mut DbPool<'_>, form: &LocalSiteUpdateForm) -...
  method delete (line 27) | pub async fn delete(pool: &mut DbPool<'_>) -> LemmyResult<usize> {
  function read_local_site (line 59) | async fn read_local_site(pool: &mut DbPool<'_>) -> LemmyResult<LocalSite> {
  function prepare_site_with_community (line 67) | async fn prepare_site_with_community(
  function test_aggregates (line 89) | async fn test_aggregates() -> LemmyResult<()> {
  function test_soft_delete (line 159) | async fn test_soft_delete() -> LemmyResult<()> {

FILE: crates/db_schema/src/impls/local_site_rate_limit.rs
  method read (line 16) | pub async fn read(pool: &mut DbPool<'_>) -> LemmyResult<Option<Self>> {
  method create (line 25) | pub async fn create(
  method update (line 36) | pub async fn update(
  method is_empty (line 54) | fn is_empty(&self) -> bool {

FILE: crates/db_schema/src/impls/local_site_url_blocklist.rs
  method replace (line 9) | pub async fn replace(pool: &mut DbPool<'_>, url_blocklist: Vec<String>) ...
  method clear (line 36) | async fn clear(conn: &mut AsyncPgConnection) -> LemmyResult<usize> {
  method get_all (line 43) | pub async fn get_all(pool: &mut DbPool<'_>) -> LemmyResult<Vec<Self>> {

FILE: crates/db_schema/src/impls/local_user.rs
  method create (line 35) | pub async fn create(
  method update (line 58) | pub async fn update(
  method delete (line 76) | pub async fn delete(pool: &mut DbPool<'_>, id: LocalUserId) -> LemmyResu...
  method update_password (line 84) | pub async fn update_password(
  method set_all_users_email_verified (line 99) | pub async fn set_all_users_email_verified(pool: &mut DbPool<'_>) -> Lemm...
  method set_all_users_registration_applications_accepted (line 108) | pub async fn set_all_users_registration_applications_accepted(
  method delete_old_denied_local_users (line 119) | pub async fn delete_old_denied_local_users(pool: &mut DbPool<'_>) -> Lem...
  method check_is_email_taken (line 147) | pub async fn check_is_email_taken(pool: &mut DbPool<'_>, email: &str) ->...
  method export_backup (line 160) | pub async fn export_backup(
  method is_higher_admin_check (line 247) | pub async fn is_higher_admin_check(
  method is_higher_mod_or_admin_check (line 276) | pub async fn is_higher_mod_or_admin_check(
  type LocalUserOptionHelper (line 315) | pub trait LocalUserOptionHelper {
    method person_id (line 316) | fn person_id(&self) -> Option<PersonId>;
    method local_user_id (line 317) | fn local_user_id(&self) -> Option<LocalUserId>;
    method show_bot_accounts (line 318) | fn show_bot_accounts(&self) -> bool;
    method show_read_posts (line 319) | fn show_read_posts(&self) -> bool;
    method is_admin (line 320) | fn is_admin(&self) -> bool;
    method show_nsfw (line 321) | fn show_nsfw(&self, site: &Site) -> bool;
    method hide_media (line 322) | fn hide_media(&self) -> bool;
    method visible_communities_only (line 323) | fn visible_communities_only<Q>(&self, query: Q) -> Q
    method person_id (line 332) | fn person_id(&self) -> Option<PersonId> {
    method local_user_id (line 336) | fn local_user_id(&self) -> Option<LocalUserId> {
    method show_bot_accounts (line 340) | fn show_bot_accounts(&self) -> bool {
    method show_read_posts (line 344) | fn show_read_posts(&self) -> bool {
    method is_admin (line 348) | fn is_admin(&self) -> bool {
    method show_nsfw (line 352) | fn show_nsfw(&self, site: &Site) -> bool {
    method hide_media (line 358) | fn hide_media(&self) -> bool {
    method visible_communities_only (line 363) | fn visible_communities_only<Q>(&self, query: Q) -> Q
  method test_form (line 379) | pub fn test_form(person_id: PersonId) -> Self {
  method test_form_admin (line 383) | pub fn test_form_admin(person_id: PersonId) -> Self {
  type UserBackupLists (line 391) | pub struct UserBackupLists {
  function test_admin_higher_check (line 414) | async fn test_admin_higher_check() -> LemmyResult<()> {
  function test_email_taken (line 453) | async fn test_email_taken() -> LemmyResult<()> {

FILE: crates/db_schema/src/impls/login_token.rs
  method create (line 13) | pub async fn create(pool: &mut DbPool<'_>, form: LoginTokenCreateForm) -...
  method validate (line 23) | pub async fn validate(
  method list (line 38) | pub async fn list(pool: &mut DbPool<'_>, user_id_: LocalUserId) -> Lemmy...
  method invalidate (line 49) | pub async fn invalidate(pool: &mut DbPool<'_>, token_: &str) -> LemmyRes...
  method invalidate_all (line 58) | pub async fn invalidate_all(pool: &mut DbPool<'_>, user_id_: LocalUserId...

FILE: crates/db_schema/src/impls/modlog.rs
  method create (line 20) | pub async fn create<'a>(
  function admin_ban (line 34) | pub fn admin_ban(
  function admin_add (line 49) | pub fn admin_add(mod_person: &Person, target_person_id: PersonId, added:...
  function mod_remove_post (line 56) | pub fn mod_remove_post(
  function mod_remove_comment (line 72) | pub fn mod_remove_comment(
  function mod_lock_comment (line 90) | pub fn mod_lock_comment(
  function mod_lock_post (line 106) | pub fn mod_lock_post(
  function mod_create_comment_warning (line 120) | pub fn mod_create_comment_warning(
  function mod_create_post_warning (line 135) | pub fn mod_create_post_warning(mod_person_id: PersonId, post: &Post, rea...
  function admin_remove_community (line 144) | pub fn admin_remove_community(
  function mod_change_community_visibility (line 160) | pub fn mod_change_community_visibility(
  function mod_ban_from_community (line 173) | pub fn mod_ban_from_community(
  function mod_add_to_community (line 189) | pub fn mod_add_to_community(
  function mod_transfer_community (line 201) | pub fn mod_transfer_community(
  function admin_allow_instance (line 212) | pub fn admin_allow_instance(
  function admin_block_instance (line 224) | pub fn admin_block_instance(
  function admin_purge_comment (line 236) | pub fn admin_purge_comment(
  function admin_purge_post (line 250) | pub fn admin_purge_post(
  function admin_purge_community (line 261) | pub fn admin_purge_community(mod_person_id: PersonId, reason: &'a str) -...
  function admin_purge_person (line 267) | pub fn admin_purge_person(mod_person_id: PersonId, reason: &'a str) -> S...
  function mod_feature_post_community (line 273) | pub fn mod_feature_post_community(mod_person_id: PersonId, post: &Post, ...
  function admin_feature_post_site (line 284) | pub fn admin_feature_post_site(mod_person: &Person, post: &Post, feature...

FILE: crates/db_schema/src/impls/multi_community.rs
  constant MULTI_COMMUNITY_ENTRY_LIMIT (line 50) | const MULTI_COMMUNITY_ENTRY_LIMIT: i8 = 50;
  type InsertForm (line 53) | type InsertForm = MultiCommunityInsertForm;
  type UpdateForm (line 54) | type UpdateForm = MultiCommunityUpdateForm;
  type IdType (line 55) | type IdType = MultiCommunityId;
  method create (line 57) | async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Lemmy...
  method update (line 67) | async fn update(
  method upsert (line 83) | pub async fn upsert(pool: &mut DbPool<'_>, form: &MultiCommunityInsertFo...
  method follow (line 96) | pub async fn follow(
  method unfollow (line 115) | pub async fn unfollow(
  method follower_inboxes (line 133) | pub async fn follower_inboxes(
  method update_entries (line 151) | pub async fn update_entries(
  method read_community_ap_ids (line 210) | pub async fn read_community_ap_ids(
  method read_from_apub_id (line 232) | async fn read_from_apub_id(
  method read_from_name (line 245) | async fn read_from_name(
  method actor_url (line 271) | fn actor_url(&self, settings: &Settings) -> LemmyResult<Url> {
  method generate_local_actor_url (line 281) | fn generate_local_actor_url(name: &str, settings: &Settings) -> LemmyRes...
  method create (line 288) | pub async fn create(pool: &mut DbPool<'_>, form: &MultiCommunityEntryFor...
  method delete (line 298) | pub async fn delete(pool: &mut DbPool<'_>, form: &MultiCommunityEntryFor...
  method check_entry_limit (line 312) | pub async fn check_entry_limit(
  method community_used_in_multiple (line 331) | pub async fn community_used_in_multiple(
  type Data (line 363) | struct Data {
  function setup (line 370) | async fn setup(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
  function test_counts (line 400) | async fn test_counts() -> LemmyResult<()> {
  function test_multi_community_apub (line 458) | async fn test_multi_community_apub() -> LemmyResult<()> {

FILE: crates/db_schema/src/impls/notification.rs
  method create (line 17) | pub async fn create(
  method mark_read_by_comment_and_recipient (line 30) | pub async fn mark_read_by_comment_and_recipient(
  method mark_read_by_post_and_recipient (line 48) | pub async fn mark_read_by_post_and_recipient(
  method mark_all_as_read (line 66) | pub async fn mark_all_as_read(
  method mark_read_by_id_and_person (line 82) | pub async fn mark_read_by_id_and_person(
  method delete (line 101) | pub async fn delete(pool: &mut DbPool<'_>, id: NotificationId) -> LemmyR...

FILE: crates/db_schema/src/impls/oauth_account.rs
  method create (line 12) | pub async fn create(pool: &mut DbPool<'_>, form: &OAuthAccountInsertForm...
  method delete_user_accounts (line 21) | pub async fn delete_user_accounts(

FILE: crates/db_schema/src/impls/oauth_provider.rs
  type InsertForm (line 20) | type InsertForm = OAuthProviderInsertForm;
  type UpdateForm (line 21) | type UpdateForm = OAuthProviderUpdateForm;
  type IdType (line 22) | type IdType = OAuthProviderId;
  method create (line 24) | async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Lemmy...
  method update (line 33) | async fn update(
  method get_all (line 48) | pub async fn get_all(pool: &mut DbPool<'_>) -> LemmyResult<Vec<Self>> {
  method convert_providers_to_public (line 58) | pub fn convert_providers_to_public(
  method get_all_public (line 75) | pub async fn get_all_public(pool: &mut DbPool<'_>) -> LemmyResult<Vec<Pu...

FILE: crates/db_schema/src/impls/password_reset_request.rs
  method create (line 18) | pub async fn create(
  method read_and_delete (line 35) | pub async fn read_and_delete(pool: &mut DbPool<'_>, token_: &str) -> Lem...
  function test_password_reset (line 62) | async fn test_password_reset() -> LemmyResult<()> {

FILE: crates/db_schema/src/impls/person.rs
  type InsertForm (line 44) | type InsertForm = PersonInsertForm;
  type UpdateForm (line 45) | type UpdateForm = PersonUpdateForm;
  type IdType (line 46) | type IdType = PersonId;
  method read (line 49) | async fn read(pool: &mut DbPool<'_>, person_id: PersonId) -> LemmyResult...
  method create (line 59) | async fn create(pool: &mut DbPool<'_>, form: &PersonInsertForm) -> Lemmy...
  method update (line 67) | async fn update(
  method upsert (line 86) | pub async fn upsert(pool: &mut DbPool<'_>, form: &PersonInsertForm) -> L...
  method delete_account (line 98) | pub async fn delete_account(
  method check_username_taken (line 143) | pub async fn check_username_taken(pool: &mut DbPool<'_>, username: &str)...
  method test_form (line 158) | pub fn test_form(instance_id: InstanceId, name: &str) -> Self {
  method read_from_apub_id (line 164) | async fn read_from_apub_id(
  method read_from_name (line 177) | async fn read_from_name(
  method actor_url (line 203) | fn actor_url(&self, settings: &Settings) -> LemmyResult<Url> {
  method generate_local_actor_url (line 213) | fn generate_local_actor_url(name: &str, settings: &Settings) -> LemmyRes...
  type Form (line 220) | type Form = PersonFollowerForm;
  type IdType (line 221) | type IdType = PersonId;
  method follow (line 223) | async fn follow(pool: &mut DbPool<'_>, form: &PersonFollowerForm) -> Lem...
  method follow_accepted (line 237) | async fn follow_accepted(_: &mut DbPool<'_>, _: CommunityId, _: PersonId...
  method unfollow (line 241) | async fn unfollow(
  type Form (line 257) | type Form = PersonBlockForm;
  type ObjectIdType (line 258) | type ObjectIdType = PersonId;
  type ObjectType (line 259) | type ObjectType = Person;
  method block (line 261) | async fn block(pool: &mut DbPool<'_>, form: &Self::Form) -> LemmyResult<...
  method unblock (line 274) | async fn unblock(pool: &mut DbPool<'_>, form: &Self::Form) -> LemmyResul...
  method read_block (line 283) | async fn read_block(
  method read_blocks_for_person (line 300) | async fn read_blocks_for_person(
  method follower_inboxes (line 324) | pub async fn follower_inboxes(
  method note (line 340) | pub async fn note(pool: &mut DbPool<'_>, form: &PersonNoteForm) -> Lemmy...
  method delete_note (line 353) | pub async fn delete_note(
  method like (line 367) | pub async fn like(
  function test_crud (line 434) | async fn test_crud() -> LemmyResult<()> {
  function follow (line 486) | async fn follow() -> LemmyResult<()> {
  function test_aggregates (line 513) | async fn test_aggregates() -> LemmyResult<()> {
  function person_vote_counts (line 640) | async fn person_vote_counts() -> LemmyResult<()> {

FILE: crates/db_schema/src/impls/post.rs
  type InsertForm (line 53) | type InsertForm = PostInsertForm;
  type UpdateForm (line 54) | type UpdateForm = PostUpdateForm;
  type IdType (line 55) | type IdType = PostId;
  method create (line 57) | async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Lemmy...
  method update (line 66) | async fn update(
  method read (line 78) | async fn read(pool: &mut DbPool<'_>, id: PostId) -> LemmyResult<Self> {
  method insert_apub (line 89) | pub async fn insert_apub(
  method list_featured_for_community (line 106) | pub async fn list_featured_for_community(
  method list_for_sitemap (line 123) | pub async fn list_for_sitemap(
  method permadelete_for_creator (line 140) | pub async fn permadelete_for_creator(
  method creator_post_ids_in_community (line 159) | async fn creator_post_ids_in_community(
  method creator_post_ids_in_instance (line 177) | async fn creator_post_ids_in_instance(
  method update_removed_for_creator_and_community (line 194) | pub async fn update_removed_for_creator_and_community(
  method update_removed_for_creator_and_instance (line 211) | pub async fn update_removed_for_creator_and_instance(
  method update_removed_for_creator (line 229) | pub async fn update_removed_for_creator(
  method is_post_creator (line 244) | pub fn is_post_creator(person_id: PersonId, post_creator_id: PersonId) -...
  method read_from_apub_id (line 248) | pub async fn read_from_apub_id(
  method delete_from_apub_id (line 262) | pub async fn delete_from_apub_id(
  method user_scheduled_post_count (line 276) | pub async fn user_scheduled_post_count(
  method update_ranks (line 299) | pub async fn update_ranks(pool: &mut DbPool<'_>, post_id: PostId) -> Lem...
  method local_url (line 330) | pub fn local_url(&self, settings: &Settings) -> LemmyResult<Url> {
  method set_not_pending (line 336) | pub async fn set_not_pending(&self, pool: &mut DbPool<'_>) -> LemmyResul...
  type Form (line 349) | type Form = PostLikeForm;
  type IdType (line 350) | type IdType = PostId;
  method like (line 352) | async fn like(pool: &mut DbPool<'_>, form: &Self::Form) -> LemmyResult<S...
  method remove_all_likes (line 366) | async fn remove_all_likes(
  method remove_likes_in_community (line 380) | async fn remove_likes_in_community(
  type Form (line 399) | type Form = PostSavedForm;
  method save (line 400) | async fn save(pool: &mut DbPool<'_>, form: &Self::Form) -> LemmyResult<S...
  method unsave (line 412) | async fn unsave(pool: &mut DbPool<'_>, form: &Self::Form) -> LemmyResult...
  method mark_as_unread (line 423) | pub async fn mark_as_unread(
  method mark_as_read (line 442) | pub async fn mark_as_read(
  method hide (line 466) | pub async fn hide(pool: &mut DbPool<'_>, form: &PostHideForm) -> LemmyRe...
  method unhide (line 479) | pub async fn unhide(pool: &mut DbPool<'_>, form: &PostHideForm) -> Lemmy...
  method update_read_comments (line 495) | pub async fn update_read_comments(
  method read (line 513) | pub async fn read(
  method update_notification_state (line 527) | pub async fn update_notification_state(
  method list_subscribers (line 550) | pub async fn list_subscribers(
  function test_crud (line 590) | async fn test_crud() -> LemmyResult<()> {
  function test_aggregates (line 730) | async fn test_aggregates() -> LemmyResult<()> {
  function test_aggregates_soft_delete (line 835) | async fn test_aggregates_soft_delete() -> LemmyResult<()> {

FILE: crates/db_schema/src/impls/post_report.rs
  type Form (line 19) | type Form = PostReportForm;
  type IdType (line 20) | type IdType = PostReportId;
  type ObjectIdType (line 21) | type ObjectIdType = PostId;
  method report (line 23) | async fn report(pool: &mut DbPool<'_>, form: &Self::Form) -> LemmyResult...
  method update_resolved (line 32) | async fn update_resolved(
  method resolve_apub (line 50) | async fn resolve_apub(
  method resolve_all_for_object (line 74) | async fn resolve_all_for_object(
  function init (line 105) | async fn init(pool: &mut DbPool<'_>) -> LemmyResult<(Person, PostReport)> {
  function test_resolve_post_report (line 134) | async fn test_resolve_post_report() -> LemmyResult<()> {
  function test_resolve_all_post_reports (line 154) | async fn test_resolve_all_post_reports() -> LemmyResult<()> {

FILE: crates/db_schema/src/impls/private_message.rs
  type InsertForm (line 26) | type InsertForm = PrivateMessageInsertForm;
  type UpdateForm (line 27) | type UpdateForm = PrivateMessageUpdateForm;
  type IdType (line 28) | type IdType = PrivateMessageId;
  method create (line 30) | async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Lemmy...
  method update (line 39) | async fn update(
  method insert_apub (line 54) | pub async fn insert_apub(
  method read_from_apub_id (line 73) | pub async fn read_from_apub_id(
  method local_url (line 85) | pub fn local_url(&self, settings: &Settings) -> LemmyResult<DbUrl> {
  method update_removed_for_creator (line 90) | pub async fn update_removed_for_creator(
  method clear_deleted_by_recipient (line 107) | pub fn clear_deleted_by_recipient(&mut self, my_person: Option<&Person>) {
  function test_crud (line 130) | async fn test_crud() -> LemmyResult<()> {

FILE: crates/db_schema/src/impls/private_message_report.rs
  type Form (line 18) | type Form = PrivateMessageReportForm;
  type IdType (line 19) | type IdType = PrivateMessageReportId;
  type ObjectIdType (line 20) | type ObjectIdType = PrivateMessageId;
  method report (line 22) | async fn report(pool: &mut DbPool<'_>, form: &Self::Form) -> LemmyResult...
  method update_resolved (line 31) | async fn update_resolved(
  method resolve_apub (line 48) | async fn resolve_apub(
  method resolve_all_for_object (line 58) | async fn resolve_all_for_object(

FILE: crates/db_schema/src/impls/registration_application.rs
  type InsertForm (line 19) | type InsertForm = RegistrationApplicationInsertForm;
  type UpdateForm (line 20) | type UpdateForm = RegistrationApplicationUpdateForm;
  type IdType (line 21) | type IdType = RegistrationApplicationId;
  method create (line 23) | async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Lemmy...
  method update (line 32) | async fn update(
  method find_by_local_user_id (line 47) | pub async fn find_by_local_user_id(
  method last_updated (line 60) | pub async fn last_updated(pool: &mut DbPool<'_>) -> LemmyResult<Self> {
  method updated_published_duration (line 73) | pub fn updated_published_duration(&self) -> Option<i64> {
  method is_unread (line 81) | pub fn is_unread() -> _ {

FILE: crates/db_schema/src/impls/secret.rs
  method init (line 10) | pub async fn init(pool: &mut DbPool<'_>) -> LemmyResult<Secret> {
  method read_secrets (line 14) | async fn read_secrets(pool: &mut DbPool<'_>) -> LemmyResult<Self> {

FILE: crates/db_schema/src/impls/site.rs
  type InsertForm (line 21) | type InsertForm = SiteInsertForm;
  type UpdateForm (line 22) | type UpdateForm = SiteUpdateForm;
  type IdType (line 23) | type IdType = SiteId;
  method read (line 26) | async fn read(_pool: &mut DbPool<'_>, _site_id: SiteId) -> LemmyResult<S...
  method create (line 30) | async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Lemmy...
  method update (line 54) | async fn update(
  method read_from_instance_id (line 69) | pub async fn read_from_instance_id(
  method read_from_apub_id (line 80) | pub async fn read_from_apub_id(
  method read_remote_sites (line 94) | pub async fn read_remote_sites(pool: &mut DbPool<'_>) -> LemmyResult<Vec...
  method instance_ap_id_from_url (line 106) | pub fn instance_ap_id_from_url(mut url: Url) -> Url {

FILE: crates/db_schema/src/impls/tagline.rs
  type InsertForm (line 25) | type InsertForm = TaglineInsertForm;
  type UpdateForm (line 26) | type UpdateForm = TaglineUpdateForm;
  type IdType (line 27) | type IdType = TaglineId;
  method create (line 29) | async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Lemmy...
  method update (line 38) | async fn update(
  type PaginatedType (line 53) | type PaginatedType = Tagline;
  method to_cursor (line 55) | fn to_cursor(&self) -> CursorData {
  method from_cursor (line 59) | async fn from_cursor(
  method list (line 68) | pub async fn list(
  method get_random (line 88) | pub async fn get_random(pool: &mut DbPool<'_>) -> LemmyResult<Self> {

FILE: crates/db_schema/src/lib.rs
  type SearchSortType (line 38) | pub enum SearchSortType {
  type CommunitySortType (line 50) | pub enum CommunitySortType {
  type LocalUserSortType (line 72) | pub enum LocalUserSortType {
  type MultiCommunitySortType (line 82) | pub enum MultiCommunitySortType {
  type MultiCommunityListingType (line 98) | pub enum MultiCommunityListingType {
  type SearchType (line 115) | pub enum SearchType {
  type NotificationTypeFilter (line 132) | pub enum NotificationTypeFilter {
  type ModlogKindFilter (line 146) | pub enum ModlogKindFilter {
  type PersonContentType (line 158) | pub enum PersonContentType {
  type ReportType (line 169) | pub enum ReportType {
  type PostFeatureType (line 184) | pub enum PostFeatureType {
  type LikeType (line 199) | pub enum LikeType {
  type Person1AliasAllColumnsTuple (line 215) | pub type Person1AliasAllColumnsTuple = (
  type Person2AliasAllColumnsTuple (line 242) | pub type Person2AliasAllColumnsTuple = (
  type MyInstancePersonsActionsAllColumnsTuple (line 269) | pub type MyInstancePersonsActionsAllColumnsTuple = (

FILE: crates/db_schema/src/newtypes.rs
  type PostId (line 11) | pub struct PostId(pub i32);
    method fmt (line 14) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  type CommentId (line 24) | pub struct CommentId(pub i32);
    method fmt (line 27) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  type PostOrCommentId (line 32) | pub enum PostOrCommentId {
  type CommunityId (line 42) | pub struct CommunityId(pub i32);
  type LocalUserId (line 49) | pub struct LocalUserId(pub i32);
  type PrivateMessageId (line 56) | pub struct PrivateMessageId(pub i32);
    method fmt (line 59) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  type NotificationId (line 68) | pub struct NotificationId(pub i32);
  type CommentReportId (line 75) | pub struct CommentReportId(pub i32);
  type CommunityReportId (line 82) | pub struct CommunityReportId(pub i32);
  type PostReportId (line 89) | pub struct PostReportId(pub i32);
  type PrivateMessageReportId (line 96) | pub struct PrivateMessageReportId(pub i32);
  type SiteId (line 103) | pub struct SiteId(pub i32);
  type LanguageId (line 110) | pub struct LanguageId(pub i32);
  type ActivityId (line 118) | pub struct ActivityId(pub i64);
  type LocalSiteId (line 125) | pub struct LocalSiteId(i32);
  type CustomEmojiId (line 132) | pub struct CustomEmojiId(i32);
  type TaglineId (line 139) | pub struct TaglineId(pub i32);
  type RegistrationApplicationId (line 146) | pub struct RegistrationApplicationId(pub i32);
  type OAuthProviderId (line 153) | pub struct OAuthProviderId(pub i32);
  type LtreeDef (line 159) | pub struct LtreeDef(pub String);
  type ReportCombinedId (line 164) | pub struct ReportCombinedId(i32);
  type PersonContentCombinedId (line 169) | pub struct PersonContentCombinedId(i32);
  type PersonSavedCombinedId (line 174) | pub struct PersonSavedCombinedId(i32);
  type PersonLikedCombinedId (line 179) | pub struct PersonLikedCombinedId(i32);
  type SearchCombinedId (line 184) | pub struct SearchCombinedId(i32);
  type ModlogId (line 190) | pub struct ModlogId(pub i32);
  type MultiCommunityId (line 196) | pub struct MultiCommunityId(pub i32);
  type CommunityTagId (line 203) | pub struct CommunityTagId(pub i32);

FILE: crates/db_schema/src/source/activity.rs
  type ActivitySendTargets (line 15) | pub struct ActivitySendTargets {
    method empty (line 26) | pub fn empty() -> ActivitySendTargets {
    method to_inbox (line 29) | pub fn to_inbox(url: Url) -> ActivitySendTargets {
    method to_local_community_followers (line 34) | pub fn to_local_community_followers(id: CommunityId) -> ActivitySendTa...
    method to_all_instances (line 39) | pub fn to_all_instances() -> ActivitySendTargets {
    method set_all_instances (line 44) | pub fn set_all_instances(&mut self) {
    method add_inbox (line 48) | pub fn add_inbox(&mut self, inbox: Url) {
    method add_inboxes (line 51) | pub fn add_inboxes(&mut self, inboxes: Vec<DbUrl>) {
  type SentActivity (line 60) | pub struct SentActivity {
  type SentActivityForm (line 75) | pub struct SentActivityForm {
  type ReceivedActivity (line 91) | pub struct ReceivedActivity {

FILE: crates/db_schema/src/source/actor_language.rs
  type LocalUserLanguage (line 11) | pub struct LocalUserLanguage {
  type LocalUserLanguageForm (line 19) | pub struct LocalUserLanguageForm {
  type CommunityLanguage (line 32) | pub struct CommunityLanguage {
  type CommunityLanguageForm (line 40) | pub struct CommunityLanguageForm {
  type SiteLanguage (line 53) | pub struct SiteLanguage {
  type SiteLanguageForm (line 61) | pub struct SiteLanguageForm {

FILE: crates/db_schema/src/source/combined/person_content.rs
  type PersonContentCombined (line 21) | pub struct PersonContentCombined {

FILE: crates/db_schema/src/source/combined/person_liked.rs
  type PersonLikedCombined (line 21) | pub struct PersonLikedCombined {

FILE: crates/db_schema/src/source/combined/person_saved.rs
  type PersonSavedCombined (line 21) | pub struct PersonSavedCombined {

FILE: crates/db_schema/src/source/combined/report.rs
  type ReportCombined (line 26) | pub struct ReportCombined {

FILE: crates/db_schema/src/source/combined/search.rs
  type SearchCombined (line 21) | pub struct SearchCombined {

FILE: crates/db_schema/src/source/comment.rs
  type Comment (line 28) | pub struct Comment {
  type CommentInsertForm (line 75) | pub struct CommentInsertForm {
  type CommentUpdateForm (line 104) | pub struct CommentUpdateForm {
  type CommentActions (line 131) | pub struct CommentActions {
  type CommentLikeForm (line 150) | pub struct CommentLikeForm {
    method new (line 159) | pub fn new(comment_id: CommentId, person_id: PersonId, is_upvote: Opti...
  type CommentSavedForm (line 178) | pub struct CommentSavedForm {

FILE: crates/db_schema/src/source/comment_report.rs
  type CommentReport (line 21) | pub struct CommentReport {
  type CommentReportForm (line 37) | pub struct CommentReportForm {

FILE: crates/db_schema/src/source/community.rs
  type Community (line 29) | pub struct Community {
  type CommunityInsertForm (line 102) | pub struct CommunityInsertForm {
  type CommunityUpdateForm (line 152) | pub struct CommunityUpdateForm {
  type CommunityActions (line 193) | pub struct CommunityActions {
  type CommunityModeratorForm (line 219) | pub struct CommunityModeratorForm {
  type CommunityPersonBanForm (line 229) | pub struct CommunityPersonBanForm {
  type CommunityFollowerForm (line 241) | pub struct CommunityFollowerForm {
  type CommunityBlockForm (line 254) | pub struct CommunityBlockForm {

FILE: crates/db_schema/src/source/community_community_follow.rs
  type CommunityCommunityFollow (line 8) | pub struct CommunityCommunityFollow {

FILE: crates/db_schema/src/source/community_report.rs
  type CommunityReport (line 25) | pub struct CommunityReport {
  type CommunityReportForm (line 45) | pub struct CommunityReportForm {

FILE: crates/db_schema/src/source/community_tag.rs
  type CommunityTag (line 21) | pub struct CommunityTag {
  type CommunityTagInsertForm (line 38) | pub struct CommunityTagInsertForm {
  type CommunityTagUpdateForm (line 51) | pub struct CommunityTagUpdateForm {
  type CommunityTagsView (line 68) | pub struct CommunityTagsView(pub Vec<CommunityTag>);
  type PostCommunityTag (line 85) | pub struct PostCommunityTag {
  type PostCommunityTagForm (line 94) | pub struct PostCommunityTagForm {

FILE: crates/db_schema/src/source/custom_emoji.rs
  type CustomEmoji (line 17) | pub struct CustomEmoji {
  type CustomEmojiInsertForm (line 30) | pub struct CustomEmojiInsertForm {
  type CustomEmojiUpdateForm (line 40) | pub struct CustomEmojiUpdateForm {

FILE: crates/db_schema/src/source/custom_emoji_keyword.rs
  type CustomEmojiKeyword (line 21) | pub struct CustomEmojiKeyword {
  type CustomEmojiKeywordInsertForm (line 29) | pub struct CustomEmojiKeywordInsertForm {

FILE: crates/db_schema/src/source/email_verification.rs
  type EmailVerification (line 10) | pub struct EmailVerification {
  type EmailVerificationForm (line 20) | pub struct EmailVerificationForm {

FILE: crates/db_schema/src/source/federation_allowlist.rs
  type FederationAllowList (line 22) | pub struct FederationAllowList {
  type FederationAllowListForm (line 32) | pub struct FederationAllowListForm {

FILE: crates/db_schema/src/source/federation_blocklist.rs
  type FederationBlockList (line 22) | pub struct FederationBlockList {
  type FederationBlockListForm (line 33) | pub struct FederationBlockListForm {

FILE: crates/db_schema/src/source/federation_queue_state.rs
  type FederationQueueState (line 19) | pub struct FederationQueueState {

FILE: crates/db_schema/src/source/images.rs
  type LocalImage (line 27) | pub struct LocalImage {
  type LocalImageForm (line 38) | pub struct LocalImageForm {
  type RemoteImage (line 52) | pub struct RemoteImage {
  type ImageDetails (line 65) | pub struct ImageDetails {
  type ImageDetailsInsertForm (line 76) | pub struct ImageDetailsInsertForm {

FILE: crates/db_schema/src/source/instance.rs
  type Instance (line 25) | pub struct Instance {
  type InstanceForm (line 40) | pub struct InstanceForm {
  type InstanceActions (line 64) | pub struct InstanceActions {
  type InstanceCommunitiesBlockForm (line 82) | pub struct InstanceCommunitiesBlockForm {
  type InstancePersonsBlockForm (line 92) | pub struct InstancePersonsBlockForm {
  type InstanceBanForm (line 102) | pub struct InstanceBanForm {

FILE: crates/db_schema/src/source/keyword_block.rs
  type LocalUserKeywordBlock (line 11) | pub struct LocalUserKeywordBlock {
  type LocalUserKeywordBlockForm (line 18) | pub struct LocalUserKeywordBlockForm {

FILE: crates/db_schema/src/source/language.rs
  type Language (line 13) | pub struct Language {

FILE: crates/db_schema/src/source/local_site.rs
  type LocalSite (line 29) | pub struct LocalSite {
  type LocalSiteInsertForm (line 121) | pub struct LocalSiteInsertForm {
  type LocalSiteUpdateForm (line 200) | pub struct LocalSiteUpdateForm {

FILE: crates/db_schema/src/source/local_site_rate_limit.rs
  type LocalSiteRateLimit (line 21) | pub struct LocalSiteRateLimit {
  type LocalSiteRateLimitInsertForm (line 44) | pub struct LocalSiteRateLimitInsertForm {
  type LocalSiteRateLimitUpdateForm (line 79) | pub struct LocalSiteRateLimitUpdateForm {

FILE: crates/db_schema/src/source/local_site_url_blocklist.rs
  type LocalSiteUrlBlocklist (line 14) | pub struct LocalSiteUrlBlocklist {
  type LocalSiteUrlBlocklistForm (line 24) | pub struct LocalSiteUrlBlocklistForm {

FILE: crates/db_schema/src/source/local_user.rs
  type LocalUser (line 22) | pub struct LocalUser {
  type LocalUserInsertForm (line 86) | pub struct LocalUserInsertForm {
  type LocalUserUpdateForm (line 158) | pub struct LocalUserUpdateForm {

FILE: crates/db_schema/src/source/login_token.rs
  type LoginToken (line 18) | pub struct LoginToken {
  type LoginTokenCreateForm (line 33) | pub struct LoginTokenCreateForm {

FILE: crates/db_schema/src/source/mod.rs
  function placeholder_apub_url (line 52) | fn placeholder_apub_url() -> DbUrl {

FILE: crates/db_schema/src/source/modlog.rs
  type Modlog (line 20) | pub struct Modlog {
  type ModlogInsertForm (line 45) | pub struct ModlogInsertForm<'a> {

FILE: crates/db_schema/src/source/multi_community.rs
  type MultiCommunity (line 30) | pub struct MultiCommunity {
  type MultiCommunityInsertForm (line 62) | pub struct MultiCommunityInsertForm {
  type MultiCommunityUpdateForm (line 90) | pub struct MultiCommunityUpdateForm {
  type MultiCommunityFollow (line 104) | pub struct MultiCommunityFollow {
  type MultiCommunityFollowForm (line 113) | pub struct MultiCommunityFollowForm {
  type MultiCommunityEntry (line 130) | pub struct MultiCommunityEntry {
  type MultiCommunityEntryForm (line 138) | pub struct MultiCommunityEntryForm {

FILE: crates/db_schema/src/source/notification.rs
  type Notification (line 23) | pub struct Notification {
  type NotificationInsertForm (line 39) | pub struct NotificationInsertForm {
    method new_post (line 54) | pub fn new_post(post: &Post, recipient_id: PersonId, kind: Notificatio...
    method new_comment (line 60) | pub fn new_comment(comment: &Comment, recipient_id: PersonId, kind: No...
    method new_private_message (line 66) | pub fn new_private_message(private_message: &PrivateMessage) -> Self {
    method new_mod_action (line 76) | pub fn new_mod_action(modlog_id: ModlogId, recipient_id: PersonId, cre...

FILE: crates/db_schema/src/source/oauth_account.rs
  type OAuthAccount (line 16) | pub struct OAuthAccount {
  type OAuthAccountInsertForm (line 27) | pub struct OAuthAccountInsertForm {

FILE: crates/db_schema/src/source/oauth_provider.rs
  type AdminOAuthProvider (line 17) | pub struct AdminOAuthProvider {
  type PublicOAuthProvider (line 67) | pub struct PublicOAuthProvider {
  type OAuthProviderInsertForm (line 88) | pub struct OAuthProviderInsertForm {
  type OAuthProviderUpdateForm (line 107) | pub struct OAuthProviderUpdateForm {

FILE: crates/db_schema/src/source/password_reset_request.rs
  type PasswordResetRequest (line 11) | pub struct PasswordResetRequest {
  type PasswordResetRequestForm (line 20) | pub struct PasswordResetRequestForm {

FILE: crates/db_schema/src/source/person.rs
  type Person (line 24) | pub struct Person {
  type PersonInsertForm (line 67) | pub struct PersonInsertForm {
  type PersonUpdateForm (line 104) | pub struct PersonUpdateForm {
  type PersonActions (line 133) | pub struct PersonActions {
  type PersonFollowerForm (line 159) | pub struct PersonFollowerForm {
  type PersonBlockForm (line 170) | pub struct PersonBlockForm {
  type PersonNoteForm (line 180) | pub struct PersonNoteForm {

FILE: crates/db_schema/src/source/post.rs
  type Post (line 25) | pub struct Post {
  type PostInsertForm (line 97) | pub struct PostInsertForm {
  type PostUpdateForm (line 152) | pub struct PostUpdateForm {
  type PostActions (line 191) | pub struct PostActions {
  type PostLikeForm (line 217) | pub struct PostLikeForm {
    method new (line 226) | pub fn new(post_id: PostId, person_id: PersonId, is_upvote: Option<boo...
  type PostSavedForm (line 245) | pub struct PostSavedForm {
  type PostReadForm (line 255) | pub(crate) struct PostReadForm {
  type PostReadCommentsForm (line 265) | pub struct PostReadCommentsForm {
  type PostHideForm (line 276) | pub struct PostHideForm {

FILE: crates/db_schema/src/source/post_report.rs
  type PostReport (line 22) | pub struct PostReport {
  type PostReportForm (line 43) | pub struct PostReportForm {

FILE: crates/db_schema/src/source/private_message.rs
  type PrivateMessage (line 25) | pub struct PrivateMessage {
  type PrivateMessageInsertForm (line 45) | pub struct PrivateMessageInsertForm {
  type PrivateMessageUpdateForm (line 64) | pub struct PrivateMessageUpdateForm {

FILE: crates/db_schema/src/source/private_message_report.rs
  type PrivateMessageReport (line 24) | pub struct PrivateMessageReport {
  type PrivateMessageReportForm (line 40) | pub struct PrivateMessageReportForm {

FILE: crates/db_schema/src/source/registration_application.rs
  type RegistrationApplication (line 21) | pub struct RegistrationApplication {
  type RegistrationApplicationInsertForm (line 33) | pub struct RegistrationApplicationInsertForm {
  type RegistrationApplicationUpdateForm (line 40) | pub struct RegistrationApplicationUpdateForm {

FILE: crates/db_schema/src/source/secret.rs
  type Secret (line 9) | pub struct Secret {

FILE: crates/db_schema/src/source/site.rs
  type Site (line 19) | pub struct Site {
  type SiteInsertForm (line 51) | pub struct SiteInsertForm {
  type SiteUpdateForm (line 83) | pub struct SiteUpdateForm {

FILE: crates/db_schema/src/source/tagline.rs
  type Tagline (line 20) | pub struct Tagline {
  type TaglineInsertForm (line 30) | pub struct TaglineInsertForm {
  type TaglineUpdateForm (line 37) | pub struct TaglineUpdateForm {

FILE: crates/db_schema/src/test_data.rs
  type TestData (line 11) | pub struct TestData {
    method create (line 19) | pub async fn create(pool: &mut DbPool<'_>) -> LemmyResult<Self> {
    method delete (line 45) | pub async fn delete(self, pool: &mut DbPool<'_>) -> LemmyResult<()> {

FILE: crates/db_schema/src/traits.rs
  type Followable (line 9) | pub trait Followable: Sized {
    method follow (line 12) | fn follow(
    method follow_accepted (line 16) | fn follow_accepted(
    method unfollow (line 21) | fn unfollow(
  type Likeable (line 28) | pub trait Likeable: Sized {
    method like (line 31) | fn like(
    method remove_all_likes (line 36) | fn remove_all_likes(
    method remove_likes_in_community (line 41) | fn remove_likes_in_community(
  type Bannable (line 48) | pub trait Bannable: Sized {
    method ban (line 50) | fn ban(
    method unban (line 54) | fn unban(
  type Saveable (line 60) | pub trait Saveable: Sized {
    method save (line 62) | fn save(
    method unsave (line 66) | fn unsave(
  type Blockable (line 72) | pub trait Blockable: Sized {
    method block (line 76) | fn block(
    method unblock (line 80) | fn unblock(
    method read_block (line 84) | fn read_block(
    method read_blocks_for_person (line 90) | fn read_blocks_for_person(
  type Reportable (line 97) | pub trait Reportable: Sized {
    method report (line 101) | fn report(
    method update_resolved (line 105) | fn update_resolved(
    method resolve_apub (line 111) | fn resolve_apub(
    method resolve_all_for_object (line 117) | fn resolve_all_for_object(
  type ApubActor (line 124) | pub trait ApubActor: Sized {
    method read_from_apub_id (line 125) | fn read_from_apub_id(
    method read_from_name (line 132) | fn read_from_name(
    method generate_local_actor_url (line 139) | fn generate_local_actor_url(name: &str, settings: &Settings) -> LemmyR...
    method actor_url (line 140) | fn actor_url(&self, settings: &Settings) -> LemmyResult<Url>;
  type InternalToCombinedView (line 143) | pub trait InternalToCombinedView {
    method map_to_enum (line 147) | fn map_to_enum(self) -> Option<Self::CombinedView>;

FILE: crates/db_schema/src/utils/mod.rs
  constant FETCH_LIMIT_DEFAULT (line 10) | const FETCH_LIMIT_DEFAULT: i64 = 20;
  constant FETCH_LIMIT_MAX (line 11) | pub const FETCH_LIMIT_MAX: usize = 50;
  constant SITEMAP_LIMIT (line 12) | pub const SITEMAP_LIMIT: i64 = 50000;
  constant SITEMAP_DAYS (line 13) | pub const SITEMAP_DAYS: TimeDelta = TimeDelta::days(31);
  constant RANK_DEFAULT (line 14) | pub const RANK_DEFAULT: f32 = 0.0001;
  constant DELETED_REPLACEMENT_TEXT (line 15) | pub const DELETED_REPLACEMENT_TEXT: &str = "*Permanently Deleted*";
  function limit_fetch (line 17) | pub fn limit_fetch(limit: Option<i64>, no_limit: Option<bool>) -> LemmyR...
  function limit_fetch_check (line 28) | pub fn limit_fetch_check(limit: i64) -> LemmyResult<i64> {
  function format_actor_url (line 36) | pub(crate) fn format_actor_url(

FILE: crates/db_schema/src/utils/queries/filters.rs
  function filter_blocked (line 25) | pub fn filter_blocked() -> _ {
  type IsSubscribedType (line 38) | type IsSubscribedType =
  function filter_is_subscribed (line 41) | pub fn filter_is_subscribed() -> IsSubscribedType {
  type IsNotUnlistedType (line 45) | type IsNotUnlistedType =
  function filter_not_unlisted_or_is_subscribed (line 49) | pub fn filter_not_unlisted_or_is_subscribed() -> _ {
  function filter_suggested_communities (line 56) | pub fn filter_suggested_communities() -> _ {

FILE: crates/db_schema/src/utils/queries/selects.rs
  function creator_is_admin (line 43) | pub fn creator_is_admin() -> _ {
  function local_user_is_admin (line 52) | pub fn local_user_is_admin() -> _ {
  function comment_creator_is_admin (line 58) | pub fn comment_creator_is_admin() -> _ {
  function post_creator_is_admin (line 69) | pub fn post_creator_is_admin() -> _ {
  function creator_is_moderator (line 80) | pub fn creator_is_moderator() -> _ {
  function creator_banned_from_community (line 88) | pub fn creator_banned_from_community() -> _ {
  function creator_ban_expires_from_community (line 96) | pub fn creator_ban_expires_from_community() -> _ {
  function creator_local_banned (line 104) | fn creator_local_banned() -> _ {
  function creator_local_ban_expires (line 112) | fn creator_local_ban_expires() -> _ {
  function creator_community_instance_banned (line 120) | fn creator_community_instance_banned() -> _ {
  function creator_community_instance_ban_expires (line 128) | fn creator_community_instance_ban_expires() -> _ {
  function creator_home_banned (line 136) | pub fn creator_home_banned() -> _ {
  function creator_home_ban_expires (line 145) | pub fn creator_home_ban_expires() -> _ {
  function creator_local_home_banned (line 155) | pub fn creator_local_home_banned() -> _ {
  type CreatorLocalHomeBanExpiresType (line 159) | pub type CreatorLocalHomeBanExpiresType = coalesce_2_nullable<
  function creator_local_home_ban_expires (line 165) | pub fn creator_local_home_ban_expires() -> CreatorLocalHomeBanExpiresType {
  function creator_local_home_community_banned (line 174) | pub fn creator_local_home_community_banned() -> _ {
  type CreatorLocalHomeCommunityBanExpiresType (line 180) | pub type CreatorLocalHomeCommunityBanExpiresType = coalesce_3_nullable<
  function creator_local_home_community_ban_expires (line 187) | pub fn creator_local_home_community_ban_expires() -> CreatorLocalHomeCom...
  function am_higher_mod (line 196) | fn am_higher_mod() -> _ {
  function local_user_can_mod (line 217) | pub fn local_user_can_mod() -> _ {
  function local_user_can_mod_post (line 223) | pub fn local_user_can_mod_post() -> _ {
  function local_user_can_mod_comment (line 229) | pub fn local_user_can_mod_comment() -> _ {
  function local_user_community_can_mod (line 235) | pub fn local_user_community_can_mod() -> _ {
  function comment_select_remove_deletes (line 246) | pub fn comment_select_remove_deletes() -> _ {
  function post_select_remove_deletes (line 288) | pub fn post_select_remove_deletes() -> _ {
  function post_community_tags_fragment (line 345) | pub fn post_community_tags_fragment() -> _ {
  function community_tags_fragment (line 358) | pub fn community_tags_fragment() -> _ {
  function person1_select (line 374) | pub fn person1_select() -> Person1AliasAllColumnsTuple {
  function person2_select (line 379) | pub fn person2_select() -> Person2AliasAllColumnsTuple {

FILE: crates/db_schema_file/src/enums.rs
  type PostSortType (line 17) | pub enum PostSortType {
  type CommentSortType (line 41) | pub enum CommentSortType {
  type ListingType (line 61) | pub enum ListingType {
  type RegistrationMode (line 86) | pub enum RegistrationMode {
  type PostListingMode (line 107) | pub enum PostListingMode {
  type CommunityVisibility (line 128) | pub enum CommunityVisibility {
    method can_federate (line 144) | pub fn can_federate(&self) -> bool {
    method can_view_without_login (line 148) | pub fn can_view_without_login(&self) -> bool {
  type FederationMode (line 165) | pub enum FederationMode {
  type ImageMode (line 186) | pub enum ImageMode {
  type ActorType (line 213) | pub enum ActorType {
  type CommunityFollowerState (line 230) | pub enum CommunityFollowerState {
  type TagColor (line 247) | pub enum TagColor {
  type VoteShow (line 272) | pub enum VoteShow {
  type PostNotificationsMode (line 290) | pub enum PostNotificationsMode {
  type CommunityNotificationsMode (line 308) | pub enum CommunityNotificationsMode {
  type NotificationType (line 327) | pub enum NotificationType {
  type ModlogKind (line 348) | pub enum ModlogKind {

FILE: crates/db_schema_file/src/joins.rs
  function creator_local_user_admin_join (line 31) | pub fn creator_local_user_admin_join() -> _ {
  function community_join (line 40) | pub fn community_join() -> _ {
  function creator_home_instance_actions_join (line 44) | pub fn creator_home_instance_actions_join() -> _ {
  function creator_community_instance_actions_join (line 57) | pub fn creator_community_instance_actions_join() -> _ {
  function creator_local_instance_actions_join (line 74) | pub fn creator_local_instance_actions_join(local_instance_id: InstanceId...
  function my_instance_communities_actions_join (line 89) | pub fn my_instance_communities_actions_join(my_person_id: Option<PersonI...
  function my_instance_persons_actions_join (line 99) | pub fn my_instance_persons_actions_join(my_person_id: Option<PersonId>) ...
  function my_instance_persons_actions_join_1 (line 110) | pub fn my_instance_persons_actions_join_1(my_person_id: Option<PersonId>...
  function image_details_join (line 125) | pub fn image_details_join() -> _ {
  function my_community_actions_join (line 130) | pub fn my_community_actions_join(my_person_id: Option<PersonId>) -> _ {
  function my_post_actions_join (line 139) | pub fn my_post_actions_join(my_person_id: Option<PersonId>) -> _ {
  function my_comment_actions_join (line 148) | pub fn my_comment_actions_join(my_person_id: Option<PersonId>) -> _ {
  function my_person_actions_join (line 157) | pub fn my_person_actions_join(my_person_id: Option<PersonId>) -> _ {
  function my_local_user_admin_join (line 166) | pub fn my_local_user_admin_join(my_person_id: Option<PersonId>) -> _ {
  function my_multi_community_follower_join (line 176) | pub fn my_multi_community_follower_join(my_person_id: Option<PersonId>) ...
  function creator_community_actions_join (line 189) | pub fn creator_community_actions_join() -> _ {

FILE: crates/db_schema_file/src/lib.rs
  type PersonId (line 34) | pub struct PersonId(pub i32);
  type InstanceId (line 43) | pub struct InstanceId(pub i32);
    method inner (line 46) | pub fn inner(self) -> i32 {

FILE: crates/db_schema_file/src/schema.rs
  type ActorTypeEnum (line 6) | pub struct ActorTypeEnum;
  type CommentSortTypeEnum (line 10) | pub struct CommentSortTypeEnum;
  type CommunityFollowerState (line 14) | pub struct CommunityFollowerState;
  type CommunityNotificationsModeEnum (line 18) | pub struct CommunityNotificationsModeEnum;
  type CommunityVisibility (line 22) | pub struct CommunityVisibility;
  type FederationModeEnum (line 26) | pub struct FederationModeEnum;
  type ImageModeEnum (line 30) | pub struct ImageModeEnum;
  type ListingTypeEnum (line 34) | pub struct ListingTypeEnum;
  type Ltree (line 38) | pub struct Ltree;
  type ModlogKind (line 42) | pub struct ModlogKind;
  type NotificationTypeEnum (line 46) | pub struct NotificationTypeEnum;
  type PostListingModeEnum (line 50) | pub struct PostListingModeEnum;
  type PostNotificationsModeEnum (line 54) | pub struct PostNotificationsModeEnum;
  type PostSortTypeEnum (line 58) | pub struct PostSortTypeEnum;
  type RegistrationModeEnum (line 62) | pub struct RegistrationModeEnum;
  type TagColorEnum (line 66) | pub struct TagColorEnum;
  type VoteShowEnum (line 70) | pub struct VoteShowEnum;

FILE: crates/db_schema_file/src/table_impls.rs
  type Key (line 10) | type Key = (comment_actions::person_id, comment_actions::comment_id);
  type AdditionalIgnoredColumns (line 11) | type AdditionalIgnoredColumns = ();
  type Key (line 15) | type Key = (
  type AdditionalIgnoredColumns (line 19) | type AdditionalIgnoredColumns = ();
  type Key (line 23) | type Key = (instance_actions::person_id, instance_actions::instance_id);
  type AdditionalIgnoredColumns (line 24) | type AdditionalIgnoredColumns = ();
  type Key (line 28) | type Key = (person_actions::person_id, person_actions::target_id);
  type AdditionalIgnoredColumns (line 29) | type AdditionalIgnoredColumns = ();
  type Key (line 33) | type Key = (post_actions::person_id, post_actions::post_id);
  type AdditionalIgnoredColumns (line 34) | type AdditionalIgnoredColumns = ();

FILE: crates/db_views/comment/src/api.rs
  type CommentResponse (line 13) | pub struct CommentResponse {
  type CreateComment (line 22) | pub struct CreateComment {
  type CreateCommentLike (line 33) | pub struct CreateCommentLike {
  type DeleteComment (line 44) | pub struct DeleteComment {
  type DistinguishComment (line 54) | pub struct DistinguishComment {
  type GetComment (line 64) | pub struct GetComment {
  type GetComments (line 73) | pub struct GetComments {
  type ListCommentLikes (line 93) | pub struct ListCommentLikes {
  type LockComment (line 104) | pub struct LockComment {
  type PurgeComment (line 115) | pub struct PurgeComment {
  type RemoveComment (line 125) | pub struct RemoveComment {
  type SaveComment (line 138) | pub struct SaveComment {
  type EditComment (line 148) | pub struct EditComment {
  type CreateCommentWarning (line 159) | pub struct CreateCommentWarning {

FILE: crates/db_views/comment/src/impls.rs
  type PaginatedType (line 65) | type PaginatedType = Comment;
  method to_cursor (line 66) | fn to_cursor(&self) -> CursorData {
  method from_cursor (line 70) | async fn from_cursor(
  method joins (line 80) | fn joins(my_person_id: Option<PersonId>, local_instance_id: InstanceId) ...
  method read (line 111) | pub async fn read(
  method map_to_slim (line 144) | pub fn map_to_slim(self) -> CommentSlimView {
  type CommentQuery (line 160) | pub struct CommentQuery<'a> {
  function list (line 174) | pub async fn list(
  type Data (line 366) | struct Data {
  function init_data (line 379) | async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
  function test_crud (line 496) | async fn test_crud() -> LemmyResult<()> {
  function test_comment_tree (line 552) | async fn test_comment_tree() -> LemmyResult<()> {
  function test_languages (line 631) | async fn test_languages() -> LemmyResult<()> {
  function test_distinguished_first (line 690) | async fn test_distinguished_first() -> LemmyResult<()> {
  function test_creator_is_moderator (line 715) | async fn test_creator_is_moderator() -> LemmyResult<()> {
  function test_creator_is_admin (line 744) | async fn test_creator_is_admin() -> LemmyResult<()> {
  function cleanup (line 767) | async fn cleanup(data: Data, pool: &mut DbPool<'_>) -> LemmyResult<()> {
  function local_only_instance (line 780) | async fn local_only_instance() -> LemmyResult<()> {
  function comment_listing_local_user_banned_from_community (line 828) | async fn comment_listing_local_user_banned_from_community() -> LemmyResu...
  function comment_listing_local_user_not_banned_from_community (line 871) | async fn comment_listing_local_user_not_banned_from_community() -> Lemmy...
  function comment_listings_hide_nsfw (line 891) | async fn comment_listings_hide_nsfw() -> LemmyResult<()> {
  function comment_listing_private_community (line 920) | async fn comment_listing_private_community() -> LemmyResult<()> {
  function comment_removed (line 1013) | async fn comment_removed() -> LemmyResult<()> {

FILE: crates/db_views/comment/src/lib.rs
  type CommentView (line 39) | pub struct CommentView {
  type CommentSlimView (line 116) | pub struct CommentSlimView {

FILE: crates/db_views/community/src/api.rs
  type AddModToCommunity (line 22) | pub struct AddModToCommunity {
  type AddModToCommunityResponse (line 32) | pub struct AddModToCommunityResponse {
  type ApproveCommunityPendingFollower (line 39) | pub struct ApproveCommunityPendingFollower {
  type BanFromCommunity (line 50) | pub struct BanFromCommunity {
  type BlockCommunity (line 68) | pub struct BlockCommunity {
  type CommunityIdQuery (line 78) | pub struct CommunityIdQuery {
  type CommunityResponse (line 86) | pub struct CommunityResponse {
  type CreateCommunity (line 96) | pub struct CreateCommunity {
  type DeleteCommunity (line 122) | pub struct DeleteCommunity {
  type EditCommunity (line 132) | pub struct EditCommunity {
  type FollowCommunity (line 152) | pub struct FollowCommunity {
  type GetCommunity (line 163) | pub struct GetCommunity {
  type GetCommunityResponse (line 174) | pub struct GetCommunityResponse {
  type GetRandomCommunity (line 186) | pub struct GetRandomCommunity {
  type HideCommunity (line 196) | pub struct HideCommunity {
  type ListCommunities (line 207) | pub struct ListCommunities {
  type PurgeCommunity (line 223) | pub struct PurgeCommunity {
  type RemoveCommunity (line 233) | pub struct RemoveCommunity {
  type TransferCommunity (line 243) | pub struct TransferCommunity {
  type CreateMultiCommunity (line 251) | pub struct CreateMultiCommunity {
  type EditMultiCommunity (line 261) | pub struct EditMultiCommunity {
  type CreateOrDeleteMultiCommunityEntry (line 272) | pub struct CreateOrDeleteMultiCommunityEntry {
  type ListMultiCommunities (line 280) | pub struct ListMultiCommunities {
  type GetMultiCommunity (line 294) | pub struct GetMultiCommunity {
  type GetMultiCommunityResponse (line 302) | pub struct GetMultiCommunityResponse {
  type MultiCommunityResponse (line 310) | pub struct MultiCommunityResponse {
  type FollowMultiCommunity (line 317) | pub struct FollowMultiCommunity {
  type EditCommunityNotifications (line 326) | pub struct EditCommunityNotifications {
  type CreateCommunityTag (line 336) | pub struct CreateCommunityTag {
  type EditCommunityTag (line 349) | pub struct EditCommunityTag {
  type DeleteCommunityTag (line 361) | pub struct DeleteCommunityTag {

FILE: crates/db_views/community/src/impls.rs
  method joins (line 61) | fn joins(person_id: Option<PersonId>) -> _ {
  method read (line 73) | pub async fn read(
  type PaginatedType (line 102) | type PaginatedType = Community;
  method to_cursor (line 103) | fn to_cursor(&self) -> CursorData {
  method from_cursor (line 107) | async fn from_cursor(
  type CommunityQuery (line 116) | pub struct CommunityQuery<'a> {
  function list (line 128) | pub async fn list(
  method joins (line 223) | fn joins(person_id: Option<PersonId>) -> _ {
  method read (line 232) | pub async fn read(
  type PaginatedType (line 249) | type PaginatedType = MultiCommunity;
  method to_cursor (line 250) | fn to_cursor(&self) -> CursorData {
  method from_cursor (line 254) | async fn from_cursor(
  type MultiCommunityQuery (line 263) | pub struct MultiCommunityQuery {
    method list (line 275) | pub async fn list(self, pool: &mut DbPool<'_>) -> LemmyResult<PagedRes...
  type Data (line 377) | struct Data {
  function init_data (line 384) | async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
  function cleanup (line 456) | async fn cleanup(data: Data, pool: &mut DbPool<'_>) -> LemmyResult<()> {
  function follow_state (line 468) | async fn follow_state() -> LemmyResult<()> {
  function local_only_community (line 540) | async fn local_only_community() -> LemmyResult<()> {
  function community_sort_name (line 585) | async fn community_sort_name() -> LemmyResult<()> {
  function can_mod (line 615) | async fn can_mod() -> LemmyResult<()> {
  function test_multi_community_list (line 662) | async fn test_multi_community_list() -> LemmyResult<()> {

FILE: crates/db_views/community/src/lib.rs
  type CommunityView (line 31) | pub struct CommunityView {
  type MultiCommunityView (line 56) | pub struct MultiCommunityView {

FILE: crates/db_views/community_follower/src/impls.rs
  method joins (line 28) | fn joins() -> _ {
  method get_instance_followed_community_inboxes (line 36) | pub async fn get_instance_followed_community_inboxes(
  method count_community_followers (line 62) | pub async fn count_community_followers(
  method for_person (line 76) | pub async fn for_person(pool: &mut DbPool<'_>, person_id: PersonId) -> L...
  method is_follower (line 93) | pub async fn is_follower(

FILE: crates/db_views/community_follower/src/lib.rs
  type CommunityFollowerView (line 17) | pub struct CommunityFollowerView {
  type PendingFollow (line 30) | pub struct PendingFollow {

FILE: crates/db_views/community_follower_approval/src/api.rs
  type ListCommunityPendingFollows (line 9) | pub struct ListCommunityPendingFollows {

FILE: crates/db_views/community_follower_approval/src/impls.rs
  method joins (line 47) | fn joins() -> _ {
  method list_approval_required (line 71) | pub async fn list_approval_required(
  method count_approval_required (line 155) | pub async fn count_approval_required(
  method check_private_community_action (line 174) | pub async fn check_private_community_action(
  method check_has_followers_from_instance (line 194) | pub async fn check_has_followers_from_instance(
  type PaginatedType (line 215) | type PaginatedType = CommunityActions;
  method to_cursor (line 217) | fn to_cursor(&self) -> CursorData {
  method from_cursor (line 221) | async fn from_cursor(
  function test_has_followers_from_instance (line 255) | async fn test_has_followers_from_instance() -> LemmyResult<()> {
  function test_pending_followers (line 324) | async fn test_pending_followers() -> LemmyResult<()> {

FILE: crates/db_views/community_follower_approval/src/lib.rs
  type PendingFollowerView (line 18) | pub struct PendingFollowerView {

FILE: crates/db_views/community_moderator/src/impls.rs
  method joins (line 26) | fn joins() -> _ {
  method check_is_community_moderator (line 33) | pub async fn check_is_community_moderator(
  method is_community_moderator_of_any (line 50) | pub async fn is_community_moderator_of_any(
  method for_community (line 64) | pub async fn for_community(
  method top_mod_for_community (line 78) | pub async fn top_mod_for_community(
  method for_person (line 93) | pub async fn for_person(
  method get_community_first_mods (line 126) | pub async fn get_community_first_mods(pool: &mut DbPool<'_>) -> LemmyRes...
  method check (line 144) | pub async fn check(

FILE: crates/db_views/community_moderator/src/lib.rs
  type CommunityModeratorView (line 15) | pub struct CommunityModeratorView {
  type CommunityPersonBanView (line 26) | pub struct CommunityPersonBanView {

FILE: crates/db_views/custom_emoji/src/api.rs
  type CreateCustomEmoji (line 11) | pub struct CreateCustomEmoji {
  type CustomEmojiResponse (line 23) | pub struct CustomEmojiResponse {
  type DeleteCustomEmoji (line 31) | pub struct DeleteCustomEmoji {
  type EditCustomEmoji (line 39) | pub struct EditCustomEmoji {
  type ListCustomEmojis (line 53) | pub struct ListCustomEmojis {
  type ListCustomEmojisResponse (line 61) | pub struct ListCustomEmojisResponse {

FILE: crates/db_views/custom_emoji/src/impls.rs
  type SelectionType (line 13) | type SelectionType = (
  function selection (line 18) | fn selection() -> SelectionType {
  type CustomEmojiTuple (line 24) | type CustomEmojiTuple = (CustomEmoji, Option<CustomEmojiKeyword>);
  method joins (line 29) | fn joins() -> _ {
  method get (line 35) | pub async fn get(pool: &mut DbPool<'_>, emoji_id: CustomEmojiId) -> Lemm...
  method list (line 52) | pub async fn list(pool: &mut DbPool<'_>, category: &Option<String>) -> L...
  method from_tuple_to_vec (line 71) | fn from_tuple_to_vec(items: Vec<CustomEmojiTuple>) -> Vec<Self> {

FILE: crates/db_views/custom_emoji/src/lib.rs
  type CustomEmojiView (line 19) | pub struct CustomEmojiView {

FILE: crates/db_views/local_image/src/api.rs
  type DeleteImageParams (line 9) | pub struct DeleteImageParams {
  type ImageGetParams (line 17) | pub struct ImageGetParams {
  type ImageProxyParams (line 26) | pub struct ImageProxyParams {
  type ListMedia (line 37) | pub struct ListMedia {
  type UploadImageResponse (line 46) | pub struct UploadImageResponse {

FILE: crates/db_views/local_image/src/impls.rs
  method joins (line 27) | fn joins() -> _ {
  method get_all_paged_by_person_id (line 33) | pub async fn get_all_paged_by_person_id(
  method get_all_by_person_id (line 60) | pub async fn get_all_by_person_id(
  method get_all_paged (line 73) | pub async fn get_all_paged(
  type PaginatedType (line 97) | type PaginatedType = LocalImage;
  method to_cursor (line 98) | fn to_cursor(&self) -> CursorData {
  method from_cursor (line 103) | async fn from_cursor(

FILE: crates/db_views/local_image/src/lib.rs
  type LocalImageView (line 18) | pub struct LocalImageView {

FILE: crates/db_views/local_user/src/api.rs
  type AdminListUsers (line 10) | pub struct AdminListUsers {

FILE: crates/db_views/local_user/src/impls.rs
  method joins (line 47) | fn joins() -> _ {
  method read (line 53) | pub async fn read(pool: &mut DbPool<'_>, local_user_id: LocalUserId) -> ...
  method read_person (line 63) | pub async fn read_person(pool: &mut DbPool<'_>, person_id: PersonId) -> ...
  method read_from_name (line 73) | pub async fn read_from_name(pool: &mut DbPool<'_>, name: &str) -> LemmyR...
  method find_by_email_or_name (line 83) | pub async fn find_by_email_or_name(
  method find_by_email (line 100) | pub async fn find_by_email(pool: &mut DbPool<'_>, from_email: &str) -> L...
  method find_by_oauth_id (line 110) | pub async fn find_by_oauth_id(
  method list_admins_with_emails (line 126) | pub async fn list_admins_with_emails(pool: &mut DbPool<'_>) -> LemmyResu...
  method create_test_user (line 137) | pub async fn create_test_user(
  type LocalUserQuery (line 162) | pub struct LocalUserQuery {
    method list (line 171) | pub async fn list(self, pool: &mut DbPool<'_>) -> LemmyResult<PagedRes...
  type Error (line 217) | type Error = LemmyError;
  type Future (line 218) | type Future = Ready<Result<Self, Self::Error>>;
  method from_request (line 220) | fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Futu...
  type PaginatedType (line 229) | type PaginatedType = Person;
  method to_cursor (line 231) | fn to_cursor(&self) -> CursorData {
  method from_cursor (line 235) | async fn from_cursor(
  type Data (line 265) | struct Data {
  function init_data (line 269) | async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
  function cleanup (line 283) | async fn cleanup(data: Data, pool: &mut DbPool<'_>) -> LemmyResult<()> {
  function list_banned (line 290) | async fn list_banned() -> LemmyResult<()> {

FILE: crates/db_views/local_user/src/lib.rs
  type LocalUserView (line 20) | pub struct LocalUserView {

FILE: crates/db_views/modlog/src/api.rs
  type GetModlog (line 15) | pub struct GetModlog {

FILE: crates/db_views/modlog/src/impls.rs
  method joins (line 49) | fn joins(my_person_id: Option<PersonId>) -> _ {
  type PaginatedType (line 75) | type PaginatedType = Modlog;
  method to_cursor (line 76) | fn to_cursor(&self) -> CursorData {
  method from_cursor (line 80) | async fn from_cursor(
  type ModlogQuery (line 96) | pub struct ModlogQuery<'a> {
  function list (line 113) | pub async fn list(self, pool: &mut DbPool<'_>) -> LemmyResult<PagedRespo...
  method hide_mod_name (line 197) | pub fn hide_mod_name(self, hide_modlog_names: bool) -> Self {
  type Data (line 230) | struct Data {
  function init_data (line 243) | async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
  function cleanup (line 300) | async fn cleanup(data: Data, pool: &mut DbPool<'_>) -> LemmyResult<()> {
  function admin_types (line 308) | async fn admin_types() -> LemmyResult<()> {
  function mod_types (line 460) | async fn mod_types() -> LemmyResult<()> {
  function hide_modlog_names (line 855) | async fn hide_modlog_names() -> LemmyResult<()> {
  function individual_modlog_is_not_bulk (line 896) | async fn individual_modlog_is_not_bulk() -> LemmyResult<()> {
  function bulk_modlog_has_parent_id (line 922) | async fn bulk_modlog_has_parent_id() -> LemmyResult<()> {
  function bulk_action_parent_id_isolation (line 1006) | async fn bulk_action_parent_id_isolation() -> LemmyResult<()> {

FILE: crates/db_views/modlog/src/lib.rs
  type ModlogView (line 28) | pub struct ModlogView {

FILE: crates/db_views/notification/src/api.rs
  type MarkNotificationAsRead (line 8) | pub struct MarkNotificationAsRead {

FILE: crates/db_views/notification/src/impls.rs
  method get_unread_count (line 42) | pub async fn get_unread_count(
  method read (line 73) | pub async fn read(
  type PaginatedType (line 93) | type PaginatedType = Notification;
  method to_cursor (line 95) | fn to_cursor(&self) -> CursorData {
  method from_cursor (line 99) | async fn from_cursor(
  type NotificationQuery (line 114) | pub struct NotificationQuery {
    method list (line 126) | pub fn list(
  function map_to_enum (line 204) | fn map_to_enum(

FILE: crates/db_views/notification/src/lib.rs
  type NotificationViewInternal (line 55) | struct NotificationViewInternal {
  type NotificationView (line 111) | pub struct NotificationView {
  type NotificationData (line 120) | pub enum NotificationData {
  type ListNotifications (line 132) | pub struct ListNotifications {

FILE: crates/db_views/notification/src/tests.rs
  type Data (line 24) | struct Data {
  function init_data (line 29) | async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
  function cleanup (line 41) | async fn cleanup(data: Data, pool: &mut DbPool<'_>) -> LemmyResult<()> {
  function test_private_message (line 48) | async fn test_private_message() -> LemmyResult<()> {
  function test_post (line 80) | async fn test_post() -> LemmyResult<()> {
  function test_modlog (line 151) | async fn test_modlog() -> LemmyResult<()> {

FILE: crates/db_views/notification_sql/src/lib.rs
  function notification_joins (line 31) | pub fn notification_joins(person_id: PersonId, instance_id: InstanceId) ...

FILE: crates/db_views/person/src/api.rs
  type AddAdmin (line 13) | pub struct AddAdmin {
  type AddAdminResponse (line 22) | pub struct AddAdminResponse {
  type BanPerson (line 31) | pub struct BanPerson {
  type BlockPerson (line 48) | pub struct BlockPerson {
  type PersonResponse (line 57) | pub struct PersonResponse {
  type GetPersonDetails (line 68) | pub struct GetPersonDetails {
  type GetPersonDetailsResponse (line 79) | pub struct GetPersonDetailsResponse {
  type PurgePerson (line 91) | pub struct PurgePerson {
  type NotePerson (line 102) | pub struct NotePerson {

FILE: crates/db_views/person/src/impls.rs
  type PaginatedType (line 23) | type PaginatedType = Person;
  method to_cursor (line 25) | fn to_cursor(&self) -> CursorData {
  method from_cursor (line 29) | async fn from_cursor(
  method joins (line 39) | fn joins(my_person_id: Option<PersonId>, local_instance_id: InstanceId) ...
  method read (line 51) | pub async fn read(
  method list_admins (line 74) | pub async fn list_admins(
  type Data (line 116) | struct Data {
  function init_data (line 122) | async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
  function cleanup (line 147) | async fn cleanup(data: Data, pool: &mut DbPool<'_>) -> LemmyResult<()> {
  function exclude_deleted (line 154) | async fn exclude_deleted() -> LemmyResult<()> {
  function list_admins (line 181) | async fn list_admins() -> LemmyResult<()> {
  function note (line 215) | async fn note() -> LemmyResult<()> {

FILE: crates/db_views/person/src/lib.rs
  type PersonView (line 26) | pub struct PersonView {

FILE: crates/db_views/person_content_combined/src/api.rs
  type ListPersonHidden (line 10) | pub struct ListPersonHidden {
  type ListPersonRead (line 20) | pub struct ListPersonRead {

FILE: crates/db_views/person_content_combined/src/impls.rs
  type PostCommentCombinedViewWrapper (line 59) | struct PostCommentCombinedViewWrapper(PostCommentCombinedView);
  type PaginatedType (line 62) | type PaginatedType = PersonContentCombined;
  method to_cursor (line 64) | fn to_cursor(&self) -> CursorData {
  method from_cursor (line 72) | async fn from_cursor(
  type PersonContentCombinedQuery (line 95) | pub struct PersonContentCombinedQuery {
    method joins (line 109) | fn joins(my_person_id: Option<PersonId>, local_instance_id: InstanceId...
    method list (line 147) | pub async fn list(
  type Data (line 252) | struct Data {
  function init_data (line 266) | async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
  function cleanup (line 353) | async fn cleanup(data: Data, pool: &mut DbPool<'_>) -> LemmyResult<()> {
  function combined (line 361) | async fn combined() -> LemmyResult<()> {
  function private_community (line 430) | async fn private_community() -> LemmyResult<()> {

FILE: crates/db_views/person_content_combined/src/lib.rs
  type ListPersonContent (line 20) | pub struct ListPersonContent {

FILE: crates/db_views/person_liked_combined/src/impls.rs
  type PersonLikedCombinedQuery (line 57) | pub struct PersonLikedCombinedQuery {
    method joins (line 104) | pub(crate) fn joins(my_person_id: PersonId, local_instance_id: Instanc...
    method list (line 145) | pub async fn list(
  type PostCommentCombinedViewWrapper (line 67) | struct PostCommentCombinedViewWrapper(PostCommentCombinedView);
  type PaginatedType (line 70) | type PaginatedType = PersonLikedCombined;
  method to_cursor (line 72) | fn to_cursor(&self) -> CursorData {
  method from_cursor (line 80) | async fn from_cursor(
  type Data (line 238) | struct Data {
  function init_data (line 248) | async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
  function cleanup (line 305) | async fn cleanup(data: Data, pool: &mut DbPool<'_>) -> LemmyResult<()> {
  function test_combined (line 313) | async fn test_combined() -> LemmyResult<()> {

FILE: crates/db_views/person_liked_combined/src/lib.rs
  type ListPersonLiked (line 16) | pub struct ListPersonLiked {

FILE: crates/db_views/person_saved_combined/src/impls.rs
  type PersonSavedCombinedQuery (line 55) | pub struct PersonSavedCombinedQuery {
    method joins (line 101) | fn joins(my_person_id: PersonId, local_instance_id: InstanceId) -> _ {
    method list (line 142) | pub async fn list(
  type PostCommentCombinedViewWrapper (line 64) | struct PostCommentCombinedViewWrapper(PostCommentCombinedView);
  type PaginatedType (line 67) | type PaginatedType = PersonSavedCombined;
  method to_cursor (line 69) | fn to_cursor(&self) -> CursorData {
  method from_cursor (line 77) | async fn from_cursor(
  t
Condensed preview — 1431 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (4,349K chars).
[
  {
    "path": ".gitattributes",
    "chars": 80,
    "preview": "# Normalize EOL for all files that Git considers text files.\n* text=auto eol=lf\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "chars": 115,
    "preview": "* @Nutomic @dessalines @phiresky @dullbananas\ncrates/apub/ @Nutomic\nmigrations/ @dessalines @phiresky @dullbananas\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 84,
    "preview": "# These are supported funding model platforms\n\npatreon: dessalines\nliberapay: Lemmy\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/BUG_REPORT.yml",
    "chars": 2497,
    "preview": "name: \"\\U0001F41E Bug Report\"\ndescription: Create a report to help us improve lemmy\ntitle: \"[Bug]: \"\nlabels: [\"bug\", \"tr"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml",
    "chars": 2162,
    "preview": "name: \"\\U0001F680 Feature request\"\ndescription: Suggest an idea for improving Lemmy\nlabels: [\"enhancement\"]\nbody:\n  - ty"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/QUESTION.yml",
    "chars": 604,
    "preview": "name: \"? Question\"\ndescription: General questions about Lemmy\ntitle: \"Question: \"\nlabels: [\"question\", \"triage\"]\nbody:\n "
  },
  {
    "path": ".github/SECURITY.md",
    "chars": 155,
    "preview": "# Security Policy\n\n## Reporting a Vulnerability\n\nUse [Github's security advisory issue system](https://github.com/LemmyN"
  },
  {
    "path": ".gitignore",
    "chars": 516,
    "preview": "# local ansible configuration\nansible/inventory\nansible/passwords/\n\n# docker build files\ndocker/lemmy_mine.hjson\ndocker/"
  },
  {
    "path": ".gitmodules",
    "chars": 154,
    "preview": "[submodule \"crates/utils/translations\"]\n\tpath = crates/email/translations\n\turl = https://github.com/LemmyNet/lemmy-trans"
  },
  {
    "path": ".rustfmt.toml",
    "chars": 163,
    "preview": "tab_spaces = 2\nedition = \"2024\"\nimports_layout = \"HorizontalVertical\"\nimports_granularity = \"Crate\"\ngroup_imports = \"One"
  },
  {
    "path": ".woodpecker.yml",
    "chars": 11155,
    "preview": "# TODO: The when: platform conditionals aren't working currently\n# See https://github.com/woodpecker-ci/woodpecker/issue"
  },
  {
    "path": "Cargo.toml",
    "chars": 9919,
    "preview": "[workspace.package]\nversion = \"1.0.0-test-arm-qemu.0\"\nedition = \"2024\"\ndescription = \"A link aggregator for the fedivers"
  },
  {
    "path": "LICENSE",
    "chars": 34523,
    "preview": "                    GNU AFFERO GENERAL PUBLIC LICENSE\n                       Version 3, 19 November 2007\n\n Copyright (C)"
  },
  {
    "path": "README.md",
    "chars": 8522,
    "preview": "<div align=\"center\">\n\n[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/LemmyNet/lemmy.svg)](https://gith"
  },
  {
    "path": "api_tests/.npmrc",
    "chars": 29,
    "preview": "package-manager-strict=false\n"
  },
  {
    "path": "api_tests/.prettierrc.json",
    "chars": 45,
    "preview": "{\n  \"arrowParens\": \"avoid\",\n  \"semi\": true\n}\n"
  },
  {
    "path": "api_tests/eslint.config.mjs",
    "chars": 1387,
    "preview": "import pluginJs from \"@eslint/js\";\nimport tseslint from \"typescript-eslint\";\n\nexport default [\n  pluginJs.configs.recomm"
  },
  {
    "path": "api_tests/jest.config.js",
    "chars": 70,
    "preview": "module.exports = {\n  preset: \"ts-jest\",\n  testEnvironment: \"node\",\n};\n"
  },
  {
    "path": "api_tests/package.json",
    "chars": 1907,
    "preview": "{\n  \"name\": \"api_tests\",\n  \"version\": \"0.0.1\",\n  \"description\": \"API tests for lemmy backend\",\n  \"main\": \"index.js\",\n  \""
  },
  {
    "path": "api_tests/pnpm-workspace.yaml",
    "chars": 41,
    "preview": "onlyBuiltDependencies:\n  - unrs-resolver\n"
  },
  {
    "path": "api_tests/prepare-drone-federation-test.sh",
    "chars": 4414,
    "preview": "#!/usr/bin/env bash\n# IMPORTANT NOTE: this script does not use the normal LEMMY_DATABASE_URL format\n#   it is expected t"
  },
  {
    "path": "api_tests/run-federation-test.sh",
    "chars": 533,
    "preview": "#!/usr/bin/env bash\nset -e\n\nexport LEMMY_DATABASE_URL=postgres://lemmy:password@localhost:5432\npushd ..\ncargo build\nrm t"
  },
  {
    "path": "api_tests/src/apiv3.spec.ts",
    "chars": 1643,
    "preview": "jest.setTimeout(180000);\n\nimport {\n  LemmyHttp,\n  Login,\n  CreatePost,\n  ResolveObject,\n} from \"lemmy-js-client-019\";\nim"
  },
  {
    "path": "api_tests/src/comment.spec.ts",
    "chars": 35303,
    "preview": "jest.setTimeout(180000);\n\nimport { PostResponse } from \"lemmy-js-client/dist/types/PostResponse\";\nimport {\n  alpha,\n  be"
  },
  {
    "path": "api_tests/src/community.spec.ts",
    "chars": 27520,
    "preview": "jest.setTimeout(120000);\n\nimport { AddModToCommunity } from \"lemmy-js-client/dist/types/AddModToCommunity\";\nimport {\n  a"
  },
  {
    "path": "api_tests/src/follow.spec.ts",
    "chars": 3697,
    "preview": "jest.setTimeout(120000);\n\nimport {\n  alpha,\n  setupLogins,\n  resolveBetaCommunity,\n  followCommunity,\n  waitUntil,\n  bet"
  },
  {
    "path": "api_tests/src/image.spec.ts",
    "chars": 11073,
    "preview": "jest.setTimeout(120000);\n\nimport {\n  UploadImage,\n  PurgePerson,\n  PurgePost,\n  DeleteImageParams,\n} from \"lemmy-js-clie"
  },
  {
    "path": "api_tests/src/post.spec.ts",
    "chars": 33181,
    "preview": "jest.setTimeout(120000);\n\nimport { CommunityView } from \"lemmy-js-client/dist/types/CommunityView\";\nimport {\n  alpha,\n  "
  },
  {
    "path": "api_tests/src/private_comm.spec.ts",
    "chars": 12230,
    "preview": "jest.setTimeout(120000);\n\nimport { FollowCommunity, LemmyError, LemmyHttp } from \"lemmy-js-client\";\nimport {\n  alpha,\n  "
  },
  {
    "path": "api_tests/src/private_message.spec.ts",
    "chars": 4716,
    "preview": "jest.setTimeout(120000);\nimport { LemmyError, PrivateMessageView } from \"lemmy-js-client\";\nimport {\n  alpha,\n  beta,\n  s"
  },
  {
    "path": "api_tests/src/shared.ts",
    "chars": 26942,
    "preview": "import {\n  ApproveCommunityPendingFollower,\n  BlockCommunity,\n  CommunityId,\n  CommunityVisibility,\n  CreatePrivateMessa"
  },
  {
    "path": "api_tests/src/speed.spec.ts",
    "chars": 15565,
    "preview": "// This is meant to be used with an already-filled / production db with lots of history.\n// Requires env vars:\n//\n// LEM"
  },
  {
    "path": "api_tests/src/tags.spec.ts",
    "chars": 6851,
    "preview": "jest.setTimeout(120000);\n\nimport {\n  alpha,\n  beta,\n  setupLogins,\n  createCommunity,\n  unfollows,\n  randomString,\n  fol"
  },
  {
    "path": "api_tests/src/user.spec.ts",
    "chars": 12756,
    "preview": "jest.setTimeout(120000);\n\nimport { PersonView } from \"lemmy-js-client/dist/types/PersonView\";\nimport {\n  alpha,\n  beta,\n"
  },
  {
    "path": "api_tests/tsconfig.json",
    "chars": 360,
    "preview": "{\n  \"compilerOptions\": {\n    \"declaration\": true,\n    \"declarationDir\": \"./dist\",\n    \"module\": \"CommonJS\",\n    \"noImpli"
  },
  {
    "path": "cliff.toml",
    "chars": 2966,
    "preview": "# git-cliff ~ configuration file\n# https://git-cliff.org/docs/configuration\n\n[remote.github]\nowner = \"LemmyNet\"\nrepo = \""
  },
  {
    "path": "config/config.hjson",
    "chars": 165,
    "preview": "# See the documentation for available config fields and descriptions:\n# https://join-lemmy.org/docs/en/administration/co"
  },
  {
    "path": "config/defaults.hjson",
    "chars": 4002,
    "preview": "{\n  # settings related to the postgresql database\n  database: {\n    # Configure the database by specifying URI pointing "
  },
  {
    "path": "crates/api/api/Cargo.toml",
    "chars": 2993,
    "preview": "[package]\nname = \"lemmy_api\"\npublish = false\nversion.workspace = true\nedition.workspace = true\ndescription.workspace = t"
  },
  {
    "path": "crates/api/api/src/comment/distinguish.rs",
    "chars": 1965,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  context::LemmyContext,\n  se"
  },
  {
    "path": "crates/api/api/src/comment/like.rs",
    "chars": 2937,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  build_response::build_comme"
  },
  {
    "path": "crates/api/api/src/comment/list_comment_likes.rs",
    "chars": 1106,
    "preview": "use actix_web::web::{Data, Json, Query};\nuse lemmy_api_utils::{context::LemmyContext, utils::is_mod_or_admin};\nuse lemmy"
  },
  {
    "path": "crates/api/api/src/comment/lock.rs",
    "chars": 1933,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  build_response::build_comme"
  },
  {
    "path": "crates/api/api/src/comment/mod.rs",
    "chars": 108,
    "preview": "pub mod distinguish;\npub mod like;\npub mod list_comment_likes;\npub mod lock;\npub mod save;\npub mod warning;\n"
  },
  {
    "path": "crates/api/api/src/comment/save.rs",
    "chars": 1179,
    "preview": "use actix_web::web::{Data, Json};\nuse lemmy_api_utils::{context::LemmyContext, utils::check_local_user_valid};\nuse lemmy"
  },
  {
    "path": "crates/api/api/src/comment/warning.rs",
    "chars": 1561,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  context::LemmyContext,\n  no"
  },
  {
    "path": "crates/api/api/src/community/add_mod.rs",
    "chars": 3703,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse diesel_async::scoped_futures::ScopedFutureExt;\nu"
  },
  {
    "path": "crates/api/api/src/community/ban.rs",
    "chars": 3976,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse diesel_async::scoped_futures::ScopedFutureExt;\nu"
  },
  {
    "path": "crates/api/api/src/community/block.rs",
    "chars": 2222,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse diesel_async::scoped_futures::ScopedFutureExt;\nu"
  },
  {
    "path": "crates/api/api/src/community/follow.rs",
    "chars": 1259,
    "preview": "use crate::community::do_follow_community;\nuse activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy"
  },
  {
    "path": "crates/api/api/src/community/mod.rs",
    "chars": 2224,
    "preview": "use activitypub_federation::config::Data;\nuse lemmy_api_utils::{\n  context::LemmyContext,\n  send_activity::{ActivityChan"
  },
  {
    "path": "crates/api/api/src/community/multi_community_follow.rs",
    "chars": 1826,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  context::LemmyContext,\n  se"
  },
  {
    "path": "crates/api/api/src/community/pending_follows/approve.rs",
    "chars": 1409,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  context::LemmyContext,\n  se"
  },
  {
    "path": "crates/api/api/src/community/pending_follows/list.rs",
    "chars": 1052,
    "preview": "use actix_web::web::{Data, Json, Query};\nuse lemmy_api_utils::{context::LemmyContext, utils::check_community_mod_of_any_"
  },
  {
    "path": "crates/api/api/src/community/pending_follows/mod.rs",
    "chars": 31,
    "preview": "pub mod approve;\npub mod list;\n"
  },
  {
    "path": "crates/api/api/src/community/random.rs",
    "chars": 1516,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::{Json, Query};\nuse lemmy_api_utils::{\n  context::LemmyCont"
  },
  {
    "path": "crates/api/api/src/community/tag.rs",
    "chars": 3991,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse chrono::Utc;\nuse lemmy_api_utils::{\n  context::L"
  },
  {
    "path": "crates/api/api/src/community/transfer.rs",
    "chars": 3487,
    "preview": "use actix_web::web::{Data, Json};\nuse anyhow::Context;\nuse diesel_async::scoped_futures::ScopedFutureExt;\nuse lemmy_api_"
  },
  {
    "path": "crates/api/api/src/community/update_notifications.rs",
    "chars": 1396,
    "preview": "use crate::community::do_follow_community;\nuse activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy"
  },
  {
    "path": "crates/api/api/src/federation/fetcher.rs",
    "chars": 3595,
    "preview": "use crate::federation::ApubPerson;\nuse activitypub_federation::{\n  config::Data,\n  fetch::webfinger::webfinger_resolve_a"
  },
  {
    "path": "crates/api/api/src/federation/list_comments.rs",
    "chars": 3251,
    "preview": "use crate::federation::{\n  comment_sort_type_with_default,\n  fetch_limit_with_default,\n  fetcher::resolve_community_iden"
  },
  {
    "path": "crates/api/api/src/federation/list_person_content.rs",
    "chars": 1420,
    "preview": "use crate::federation::fetcher::resolve_person_identifier;\nuse activitypub_federation::config::Data;\nuse actix_web::web:"
  },
  {
    "path": "crates/api/api/src/federation/list_posts.rs",
    "chars": 3275,
    "preview": "use crate::federation::{\n  fetch_limit_with_default,\n  fetcher::{resolve_community_identifier, resolve_multi_community_i"
  },
  {
    "path": "crates/api/api/src/federation/mod.rs",
    "chars": 2847,
    "preview": "use lemmy_apub_objects::objects::person::ApubPerson;\nuse lemmy_db_schema::{\n  newtypes::CommunityId,\n  source::{local_si"
  },
  {
    "path": "crates/api/api/src/federation/read_community.rs",
    "chars": 2020,
    "preview": "use crate::federation::fetcher::resolve_community_identifier;\nuse activitypub_federation::config::Data;\nuse actix_web::w"
  },
  {
    "path": "crates/api/api/src/federation/read_multi_community.rs",
    "chars": 1311,
    "preview": "use crate::federation::fetcher::resolve_multi_community_identifier;\nuse activitypub_federation::config::Data;\nuse actix_"
  },
  {
    "path": "crates/api/api/src/federation/read_person.rs",
    "chars": 2255,
    "preview": "use crate::federation::fetcher::resolve_person_identifier;\nuse activitypub_federation::config::Data;\nuse actix_web::web:"
  },
  {
    "path": "crates/api/api/src/federation/resolve_object.rs",
    "chars": 7426,
    "preview": "use activitypub_federation::{\n  config::Data,\n  fetch::{object_id::ObjectId, webfinger::webfinger_resolve_actor},\n};\nuse"
  },
  {
    "path": "crates/api/api/src/federation/search.rs",
    "chars": 2060,
    "preview": "use crate::federation::{\n  fetcher::resolve_community_identifier,\n  resolve_object::resolve_object_internal,\n};\nuse acti"
  },
  {
    "path": "crates/api/api/src/federation/user_settings_backup.rs",
    "chars": 15484,
    "preview": "use activitypub_federation::{config::Data, fetch::object_id::ObjectId, traits::Object};\nuse actix_web::web::Json;\nuse fu"
  },
  {
    "path": "crates/api/api/src/lib.rs",
    "chars": 2783,
    "preview": "use lemmy_api_utils::{context::LemmyContext, utils::is_mod_or_admin_opt};\nuse lemmy_db_schema::newtypes::CommunityId;\nus"
  },
  {
    "path": "crates/api/api/src/local_user/add_admin.rs",
    "chars": 1963,
    "preview": "use actix_web::web::{Data, Json};\nuse lemmy_api_utils::{context::LemmyContext, notify::notify_mod_action, utils::is_admi"
  },
  {
    "path": "crates/api/api/src/local_user/ban_person.rs",
    "chars": 2771,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  context::LemmyContext,\n  no"
  },
  {
    "path": "crates/api/api/src/local_user/block.rs",
    "chars": 1565,
    "preview": "use actix_web::web::{Data, Json};\nuse lemmy_api_utils::{context::LemmyContext, utils::check_local_user_valid};\nuse lemmy"
  },
  {
    "path": "crates/api/api/src/local_user/change_password.rs",
    "chars": 1729,
    "preview": "use actix_web::{\n  HttpRequest,\n  web::{Data, Json},\n};\nuse bcrypt::verify;\nuse lemmy_api_utils::{\n  claims::Claims,\n  c"
  },
  {
    "path": "crates/api/api/src/local_user/change_password_after_reset.rs",
    "chars": 1197,
    "preview": "use actix_web::web::{Data, Json};\nuse lemmy_api_utils::{context::LemmyContext, utils::password_length_check};\nuse lemmy_"
  },
  {
    "path": "crates/api/api/src/local_user/donation_dialog_shown.rs",
    "chars": 691,
    "preview": "use actix_web::web::{Data, Json};\nuse chrono::Utc;\nuse lemmy_api_utils::context::LemmyContext;\nuse lemmy_db_schema::sour"
  },
  {
    "path": "crates/api/api/src/local_user/export_data.rs",
    "chars": 3029,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::context::LemmyContext;\nuse lemm"
  },
  {
    "path": "crates/api/api/src/local_user/generate_totp_secret.rs",
    "chars": 1464,
    "preview": "use crate::{build_totp_2fa, generate_totp_2fa_secret};\nuse activitypub_federation::config::Data;\nuse actix_web::web::Jso"
  },
  {
    "path": "crates/api/api/src/local_user/get_captcha.rs",
    "chars": 717,
    "preview": "use actix_web::{\n  HttpResponse,\n  HttpResponseBuilder,\n  http::{\n    StatusCode,\n    header::{CacheControl, CacheDirect"
  },
  {
    "path": "crates/api/api/src/local_user/list_hidden.rs",
    "chars": 723,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::{Json, Query};\nuse lemmy_api_utils::context::LemmyContext;"
  },
  {
    "path": "crates/api/api/src/local_user/list_liked.rs",
    "chars": 874,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::{Json, Query};\nuse lemmy_api_utils::context::LemmyContext;"
  },
  {
    "path": "crates/api/api/src/local_user/list_logins.rs",
    "chars": 539,
    "preview": "use actix_web::web::{Data, Json};\nuse lemmy_api_utils::context::LemmyContext;\nuse lemmy_db_schema::source::login_token::"
  },
  {
    "path": "crates/api/api/src/local_user/list_media.rs",
    "chars": 654,
    "preview": "use actix_web::web::{Data, Json, Query};\nuse lemmy_api_utils::context::LemmyContext;\nuse lemmy_db_views_local_image::{Lo"
  },
  {
    "path": "crates/api/api/src/local_user/list_read.rs",
    "chars": 711,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::{Json, Query};\nuse lemmy_api_utils::context::LemmyContext;"
  },
  {
    "path": "crates/api/api/src/local_user/list_saved.rs",
    "chars": 1065,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::{Json, Query};\nuse lemmy_api_utils::{context::LemmyContext"
  },
  {
    "path": "crates/api/api/src/local_user/login.rs",
    "chars": 1827,
    "preview": "use crate::check_totp_2fa_valid;\nuse actix_web::{\n  HttpRequest,\n  web::{Data, Json},\n};\nuse bcrypt::verify;\nuse lemmy_a"
  },
  {
    "path": "crates/api/api/src/local_user/logout.rs",
    "chars": 861,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::{HttpRequest, HttpResponse, cookie::Cookie};\nuse lemmy_api_util"
  },
  {
    "path": "crates/api/api/src/local_user/mod.rs",
    "chars": 615,
    "preview": "pub mod add_admin;\npub mod ban_person;\npub mod block;\npub mod change_password;\npub mod change_password_after_reset;\npub "
  },
  {
    "path": "crates/api/api/src/local_user/note_person.rs",
    "chars": 1951,
    "preview": "use actix_web::web::{Data, Json};\nuse lemmy_api_utils::{\n  context::LemmyContext,\n  utils::{check_local_user_valid, get_"
  },
  {
    "path": "crates/api/api/src/local_user/notifications/list.rs",
    "chars": 1068,
    "preview": "use crate::hide_modlog_names;\nuse actix_web::web::{Data, Json, Query};\nuse lemmy_api_utils::context::LemmyContext;\nuse l"
  },
  {
    "path": "crates/api/api/src/local_user/notifications/mark_all_read.rs",
    "chars": 546,
    "preview": "use actix_web::web::{Data, Json};\nuse lemmy_api_utils::context::LemmyContext;\nuse lemmy_db_schema::source::notification:"
  },
  {
    "path": "crates/api/api/src/local_user/notifications/mark_notification_read.rs",
    "chars": 717,
    "preview": "use actix_web::web::{Data, Json};\nuse lemmy_api_utils::context::LemmyContext;\nuse lemmy_db_schema::source::notification:"
  },
  {
    "path": "crates/api/api/src/local_user/notifications/mod.rs",
    "chars": 69,
    "preview": "pub mod list;\npub mod mark_all_read;\npub mod mark_notification_read;\n"
  },
  {
    "path": "crates/api/api/src/local_user/resend_verification_email.rs",
    "chars": 968,
    "preview": "use actix_web::web::{Data, Json};\nuse lemmy_api_utils::{context::LemmyContext, utils::check_local_user_valid};\nuse lemmy"
  },
  {
    "path": "crates/api/api/src/local_user/reset_password.rs",
    "chars": 1286,
    "preview": "use actix_web::web::{Data, Json};\nuse lemmy_api_utils::{\n  context::LemmyContext,\n  utils::{check_email_verified, check_"
  },
  {
    "path": "crates/api/api/src/local_user/save_settings.rs",
    "chars": 6091,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  context::LemmyContext,\n  ut"
  },
  {
    "path": "crates/api/api/src/local_user/unread_counts.rs",
    "chars": 2130,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  context::LemmyContext,\n  ut"
  },
  {
    "path": "crates/api/api/src/local_user/update_totp.rs",
    "chars": 1509,
    "preview": "use crate::check_totp_2fa_valid;\nuse actix_web::web::{Data, Json};\nuse lemmy_api_utils::{context::LemmyContext, utils::c"
  },
  {
    "path": "crates/api/api/src/local_user/user_block_instance.rs",
    "chars": 1992,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{context::LemmyContext, utils::"
  },
  {
    "path": "crates/api/api/src/local_user/validate_auth.rs",
    "chars": 783,
    "preview": "use actix_web::{\n  HttpRequest,\n  web::{Data, Json},\n};\nuse lemmy_api_utils::{\n  context::LemmyContext,\n  utils::{local_"
  },
  {
    "path": "crates/api/api/src/local_user/verify_email.rs",
    "chars": 2045,
    "preview": "use actix_web::web::{Data, Json};\nuse lemmy_api_utils::{context::LemmyContext, utils::check_local_user_valid};\nuse lemmy"
  },
  {
    "path": "crates/api/api/src/post/feature.rs",
    "chars": 2162,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  build_response::build_post_"
  },
  {
    "path": "crates/api/api/src/post/get_link_metadata.rs",
    "chars": 746,
    "preview": "use actix_web::web::{Data, Json, Query};\nuse lemmy_api_utils::{context::LemmyContext, request::fetch_link_metadata};\nuse"
  },
  {
    "path": "crates/api/api/src/post/hide.rs",
    "chars": 1136,
    "preview": "use actix_web::web::{Data, Json};\nuse lemmy_api_utils::{context::LemmyContext, utils::check_local_user_valid};\nuse lemmy"
  },
  {
    "path": "crates/api/api/src/post/like.rs",
    "chars": 2920,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  build_response::build_post_"
  },
  {
    "path": "crates/api/api/src/post/list_post_likes.rs",
    "chars": 950,
    "preview": "use actix_web::web::{Data, Json, Query};\nuse lemmy_api_utils::{context::LemmyContext, utils::is_mod_or_admin};\nuse lemmy"
  },
  {
    "path": "crates/api/api/src/post/lock.rs",
    "chars": 1912,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  build_response::build_post_"
  },
  {
    "path": "crates/api/api/src/post/mark_many_read.rs",
    "chars": 934,
    "preview": "use actix_web::web::{Data, Json};\nuse lemmy_api_utils::context::LemmyContext;\nuse lemmy_db_schema::source::post::PostAct"
  },
  {
    "path": "crates/api/api/src/post/mark_read.rs",
    "chars": 1037,
    "preview": "use actix_web::web::{Data, Json};\nuse lemmy_api_utils::context::LemmyContext;\nuse lemmy_db_schema::source::post::PostAct"
  },
  {
    "path": "crates/api/api/src/post/mod.rs",
    "chars": 235,
    "preview": "pub mod feature;\npub mod get_link_metadata;\npub mod hide;\npub mod like;\npub mod list_post_likes;\npub mod lock;\npub mod m"
  },
  {
    "path": "crates/api/api/src/post/mod_update.rs",
    "chars": 2163,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse chrono::Utc;\nuse lemmy_api_utils::{\n  build_resp"
  },
  {
    "path": "crates/api/api/src/post/save.rs",
    "chars": 1244,
    "preview": "use actix_web::web::{Data, Json};\nuse lemmy_api_utils::{context::LemmyContext, utils::check_local_user_valid};\nuse lemmy"
  },
  {
    "path": "crates/api/api/src/post/update_notifications.rs",
    "chars": 1371,
    "preview": "use crate::community::do_follow_community;\nuse activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy"
  },
  {
    "path": "crates/api/api/src/post/warning.rs",
    "chars": 1451,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  build_response::build_post_"
  },
  {
    "path": "crates/api/api/src/reports/comment_report/create.rs",
    "chars": 3117,
    "preview": "use crate::check_report_reason;\nuse activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse either::Either;\n"
  },
  {
    "path": "crates/api/api/src/reports/comment_report/mod.rs",
    "chars": 33,
    "preview": "pub mod create;\npub mod resolve;\n"
  },
  {
    "path": "crates/api/api/src/reports/comment_report/resolve.rs",
    "chars": 1812,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse either::Either;\nuse lemmy_api_utils::{\n  context"
  },
  {
    "path": "crates/api/api/src/reports/community_report/create.rs",
    "chars": 3060,
    "preview": "use crate::check_report_reason;\nuse activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse either::Either;\n"
  },
  {
    "path": "crates/api/api/src/reports/community_report/mod.rs",
    "chars": 33,
    "preview": "pub mod create;\npub mod resolve;\n"
  },
  {
    "path": "crates/api/api/src/reports/community_report/resolve.rs",
    "chars": 1597,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse either::Either;\nuse lemmy_api_utils::{\n  context"
  },
  {
    "path": "crates/api/api/src/reports/mod.rs",
    "chars": 128,
    "preview": "pub mod comment_report;\npub mod community_report;\npub mod post_report;\npub mod private_message_report;\npub mod report_co"
  },
  {
    "path": "crates/api/api/src/reports/post_report/create.rs",
    "chars": 3004,
    "preview": "use crate::check_report_reason;\nuse activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse either::Either;\n"
  },
  {
    "path": "crates/api/api/src/reports/post_report/mod.rs",
    "chars": 33,
    "preview": "pub mod create;\npub mod resolve;\n"
  },
  {
    "path": "crates/api/api/src/reports/post_report/resolve.rs",
    "chars": 1715,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse either::Either;\nuse lemmy_api_utils::{\n  context"
  },
  {
    "path": "crates/api/api/src/reports/private_message_report/create.rs",
    "chars": 2501,
    "preview": "use crate::check_report_reason;\nuse actix_web::web::{Data, Json};\nuse lemmy_api_utils::{\n  context::LemmyContext,\n  plug"
  },
  {
    "path": "crates/api/api/src/reports/private_message_report/mod.rs",
    "chars": 33,
    "preview": "pub mod create;\npub mod resolve;\n"
  },
  {
    "path": "crates/api/api/src/reports/private_message_report/resolve.rs",
    "chars": 1070,
    "preview": "use actix_web::web::{Data, Json};\nuse lemmy_api_utils::{context::LemmyContext, utils::is_admin};\nuse lemmy_db_schema::{s"
  },
  {
    "path": "crates/api/api/src/reports/report_combined/list.rs",
    "chars": 1347,
    "preview": "use actix_web::web::{Data, Json, Query};\nuse lemmy_api_utils::{context::LemmyContext, utils::check_community_mod_of_any_"
  },
  {
    "path": "crates/api/api/src/reports/report_combined/mod.rs",
    "chars": 14,
    "preview": "pub mod list;\n"
  },
  {
    "path": "crates/api/api/src/site/admin_allow_instance.rs",
    "chars": 1515,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{context::LemmyContext, utils::"
  },
  {
    "path": "crates/api/api/src/site/admin_block_instance.rs",
    "chars": 1614,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  context::LemmyContext,\n  ut"
  },
  {
    "path": "crates/api/api/src/site/admin_list_users.rs",
    "chars": 748,
    "preview": "use actix_web::web::{Data, Json, Query};\nuse lemmy_api_utils::{context::LemmyContext, utils::is_admin};\nuse lemmy_db_vie"
  },
  {
    "path": "crates/api/api/src/site/federated_instances.rs",
    "chars": 575,
    "preview": "use actix_web::web::{Data, Json, Query};\nuse lemmy_api_utils::context::LemmyContext;\nuse lemmy_db_views_site::{Federated"
  },
  {
    "path": "crates/api/api/src/site/list_all_media.rs",
    "chars": 686,
    "preview": "use actix_web::web::{Data, Json, Query};\nuse lemmy_api_utils::{context::LemmyContext, utils::is_admin};\nuse lemmy_db_vie"
  },
  {
    "path": "crates/api/api/src/site/mod.rs",
    "chars": 206,
    "preview": "pub mod admin_allow_instance;\npub mod admin_block_instance;\npub mod admin_list_users;\npub mod federated_instances;\npub m"
  },
  {
    "path": "crates/api/api/src/site/mod_log.rs",
    "chars": 13702,
    "preview": "use crate::hide_modlog_names;\nuse actix_web::web::{Data, Json, Query};\nuse lemmy_api_utils::{context::LemmyContext, util"
  },
  {
    "path": "crates/api/api/src/site/purge/comment.rs",
    "chars": 1960,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  context::LemmyContext,\n  se"
  },
  {
    "path": "crates/api/api/src/site/purge/community.rs",
    "chars": 1908,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  context::LemmyContext,\n  se"
  },
  {
    "path": "crates/api/api/src/site/purge/mod.rs",
    "chars": 66,
    "preview": "pub mod comment;\npub mod community;\npub mod person;\npub mod post;\n"
  },
  {
    "path": "crates/api/api/src/site/purge/person.rs",
    "chars": 2002,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  context::LemmyContext,\n  se"
  },
  {
    "path": "crates/api/api/src/site/purge/post.rs",
    "chars": 1664,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  context::LemmyContext,\n  se"
  },
  {
    "path": "crates/api/api/src/site/registration_applications/approve.rs",
    "chars": 2899,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse chrono::Utc;\nuse diesel_async::scoped_futures::S"
  },
  {
    "path": "crates/api/api/src/site/registration_applications/get.rs",
    "chars": 914,
    "preview": "use actix_web::web::{Data, Json, Query};\nuse lemmy_api_utils::{context::LemmyContext, utils::is_admin};\nuse lemmy_db_vie"
  },
  {
    "path": "crates/api/api/src/site/registration_applications/list.rs",
    "chars": 1223,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::{Json, Query};\nuse lemmy_api_utils::{context::LemmyContext"
  },
  {
    "path": "crates/api/api/src/site/registration_applications/mod.rs",
    "chars": 68,
    "preview": "pub mod approve;\npub mod get;\npub mod list;\n#[cfg(test)]\nmod tests;\n"
  },
  {
    "path": "crates/api/api/src/site/registration_applications/tests.rs",
    "chars": 11047,
    "preview": "use crate::{\n  local_user::unread_counts::get_unread_counts,\n  site::registration_applications::{\n    approve::approve_r"
  },
  {
    "path": "crates/api/api/src/sitemap.rs",
    "chars": 3902,
    "preview": "use actix_web::{\n  HttpResponse,\n  http::header::{self, CacheDirective},\n  web::Data,\n};\nuse lemmy_api_utils::{context::"
  },
  {
    "path": "crates/api/api_common/Cargo.toml",
    "chars": 2513,
    "preview": "[package]\nname = \"lemmy_api_common\"\nversion.workspace = true\nedition.workspace = true\ndescription.workspace = true\nlicen"
  },
  {
    "path": "crates/api/api_common/README.md",
    "chars": 1586,
    "preview": "# lemmy_api_common\n\nThis crate provides all the data types which are necessary to build a client for [Lemmy](https://joi"
  },
  {
    "path": "crates/api/api_common/src/account.rs",
    "chars": 901,
    "preview": "pub use lemmy_db_views_person_content_combined::api::{ListPersonHidden, ListPersonRead};\npub use lemmy_db_views_person_l"
  },
  {
    "path": "crates/api/api_common/src/comment.rs",
    "chars": 571,
    "preview": "pub use lemmy_db_schema::{\n  newtypes::CommentId,\n  source::comment::{Comment, CommentActions, CommentInsertForm},\n};\npu"
  },
  {
    "path": "crates/api/api_common/src/community.rs",
    "chars": 1731,
    "preview": "pub use lemmy_db_schema::{\n  newtypes::{CommunityId, CommunityTagId, MultiCommunityId},\n  source::{\n    community::{Comm"
  },
  {
    "path": "crates/api/api_common/src/custom_emoji.rs",
    "chars": 357,
    "preview": "pub use lemmy_db_schema::{\n  newtypes::CustomEmojiId,\n  source::{custom_emoji::CustomEmoji, custom_emoji_keyword::Custom"
  },
  {
    "path": "crates/api/api_common/src/error.rs",
    "chars": 65,
    "preview": "pub use lemmy_utils::error::{LemmyErrorType, UntranslatedError};\n"
  },
  {
    "path": "crates/api/api_common/src/federation.rs",
    "chars": 625,
    "preview": "pub use lemmy_db_schema::{\n  newtypes::ActivityId,\n  source::{\n    federation_allowlist::FederationAllowList,\n    federa"
  },
  {
    "path": "crates/api/api_common/src/language.rs",
    "chars": 77,
    "preview": "pub use lemmy_db_schema::{newtypes::LanguageId, source::language::Language};\n"
  },
  {
    "path": "crates/api/api_common/src/lib.rs",
    "chars": 596,
    "preview": "pub mod account;\npub mod comment;\npub mod community;\npub mod custom_emoji;\npub mod error;\npub mod federation;\npub mod la"
  },
  {
    "path": "crates/api/api_common/src/media.rs",
    "chars": 235,
    "preview": "pub use lemmy_db_schema::source::images::{ImageDetails, LocalImage, RemoteImage};\npub use lemmy_db_views_local_image::{\n"
  },
  {
    "path": "crates/api/api_common/src/modlog.rs",
    "chars": 118,
    "preview": "pub use lemmy_db_schema::{newtypes::ModlogId, source::modlog::Modlog};\npub use lemmy_db_views_modlog::api::GetModlog;\n"
  },
  {
    "path": "crates/api/api_common/src/notification.rs",
    "chars": 236,
    "preview": "pub use lemmy_db_schema::{\n  NotificationTypeFilter,\n  newtypes::NotificationId,\n  source::notification::Notification,\n}"
  },
  {
    "path": "crates/api/api_common/src/oauth.rs",
    "chars": 303,
    "preview": "pub use lemmy_db_schema::{\n  newtypes::OAuthProviderId,\n  source::{\n    oauth_account::OAuthAccount,\n    oauth_provider:"
  },
  {
    "path": "crates/api/api_common/src/person.rs",
    "chars": 995,
    "preview": "pub use lemmy_db_schema::{\n  PersonContentType,\n  newtypes::LocalUserId,\n  source::{\n    local_user::LocalUser,\n    pers"
  },
  {
    "path": "crates/api/api_common/src/plugin.rs",
    "chars": 50,
    "preview": "pub use lemmy_db_views_site::api::PluginMetadata;\n"
  },
  {
    "path": "crates/api/api_common/src/post.rs",
    "chars": 881,
    "preview": "pub use lemmy_db_schema::{\n  PostFeatureType,\n  newtypes::PostId,\n  source::post::{Post, PostActions, PostInsertForm, Po"
  },
  {
    "path": "crates/api/api_common/src/private_message.rs",
    "chars": 338,
    "preview": "pub use lemmy_db_schema::{newtypes::PrivateMessageId, source::private_message::PrivateMessage};\npub use lemmy_db_views_p"
  },
  {
    "path": "crates/api/api_common/src/report.rs",
    "chars": 820,
    "preview": "pub use lemmy_db_schema::{\n  ReportType,\n  newtypes::{CommentReportId, CommunityReportId, PostReportId, PrivateMessageRe"
  },
  {
    "path": "crates/api/api_common/src/search.rs",
    "chars": 359,
    "preview": "pub use lemmy_db_schema::{\n  CommunitySortType,\n  LikeType,\n  PersonContentType,\n  SearchSortType,\n  SearchType,\n  newty"
  },
  {
    "path": "crates/api/api_common/src/site.rs",
    "chars": 767,
    "preview": "pub use lemmy_db_schema::{\n  newtypes::{LocalSiteId, SiteId},\n  source::{\n    local_site::LocalSite,\n    local_site_rate"
  },
  {
    "path": "crates/api/api_common/src/tagline.rs",
    "chars": 250,
    "preview": "pub use lemmy_db_schema::{newtypes::TaglineId, source::tagline::Tagline};\npub use lemmy_db_views_site::api::{ListTagline"
  },
  {
    "path": "crates/api/api_crud/Cargo.toml",
    "chars": 2209,
    "preview": "[package]\nname = \"lemmy_api_crud\"\npublish = false\nversion.workspace = true\nedition.workspace = true\ndescription.workspac"
  },
  {
    "path": "crates/api/api_crud/src/comment/create.rs",
    "chars": 5301,
    "preview": "use crate::community_use_pending;\nuse activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_util"
  },
  {
    "path": "crates/api/api_crud/src/comment/delete.rs",
    "chars": 2069,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  build_response::build_comme"
  },
  {
    "path": "crates/api/api_crud/src/comment/mod.rs",
    "chars": 78,
    "preview": "pub mod create;\npub mod delete;\npub mod read;\npub mod remove;\npub mod update;\n"
  },
  {
    "path": "crates/api/api_crud/src/comment/read.rs",
    "chars": 856,
    "preview": "use actix_web::web::{Data, Json, Query};\nuse lemmy_api_utils::{\n  build_response::build_comment_response,\n  context::Lem"
  },
  {
    "path": "crates/api/api_crud/src/comment/remove.rs",
    "chars": 4059,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  build_response::build_comme"
  },
  {
    "path": "crates/api/api_crud/src/comment/update.rs",
    "chars": 3022,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse chrono::Utc;\nuse lemmy_api_utils::{\n  build_resp"
  },
  {
    "path": "crates/api/api_crud/src/community/create.rs",
    "chars": 5115,
    "preview": "use activitypub_federation::{config::Data, http_signatures::generate_actor_keypair};\nuse actix_web::web::Json;\nuse lemmy"
  },
  {
    "path": "crates/api/api_crud/src/community/delete.rs",
    "chars": 1762,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  build_response::build_commu"
  },
  {
    "path": "crates/api/api_crud/src/community/list.rs",
    "chars": 1327,
    "preview": "use actix_web::web::{Data, Json, Query};\nuse lemmy_api_utils::{context::LemmyContext, utils::check_private_instance};\nus"
  },
  {
    "path": "crates/api/api_crud/src/community/mod.rs",
    "chars": 78,
    "preview": "pub mod create;\npub mod delete;\npub mod list;\npub mod remove;\npub mod update;\n"
  },
  {
    "path": "crates/api/api_crud/src/community/remove.rs",
    "chars": 2337,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  build_response::build_commu"
  },
  {
    "path": "crates/api/api_crud/src/community/update.rs",
    "chars": 4310,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse chrono::Utc;\nuse lemmy_api_utils::{\n  build_resp"
  },
  {
    "path": "crates/api/api_crud/src/custom_emoji/create.rs",
    "chars": 1271,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{context::LemmyContext, utils::"
  },
  {
    "path": "crates/api/api_crud/src/custom_emoji/delete.rs",
    "chars": 759,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{context::LemmyContext, utils::"
  },
  {
    "path": "crates/api/api_crud/src/custom_emoji/list.rs",
    "chars": 541,
    "preview": "use actix_web::web::{Data, Json, Query};\nuse lemmy_api_utils::context::LemmyContext;\nuse lemmy_db_views_custom_emoji::{\n"
  },
  {
    "path": "crates/api/api_crud/src/custom_emoji/mod.rs",
    "chars": 62,
    "preview": "pub mod create;\npub mod delete;\npub mod list;\npub mod update;\n"
  },
  {
    "path": "crates/api/api_crud/src/custom_emoji/update.rs",
    "chars": 1474,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{context::LemmyContext, utils::"
  },
  {
    "path": "crates/api/api_crud/src/lib.rs",
    "chars": 717,
    "preview": "use lemmy_api_utils::context::LemmyContext;\nuse lemmy_db_schema::source::community::{Community, CommunityActions};\n\npub "
  },
  {
    "path": "crates/api/api_crud/src/multi_community/create.rs",
    "chars": 3176,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{\n  context::LemmyContext,\n  ut"
  },
  {
    "path": "crates/api/api_crud/src/multi_community/create_entry.rs",
    "chars": 2592,
    "preview": "use super::{check_multi_community_creator, send_federation_update};\nuse activitypub_federation::config::Data;\nuse actix_"
  },
  {
    "path": "crates/api/api_crud/src/multi_community/delete_entry.rs",
    "chars": 2087,
    "preview": "use super::{check_multi_community_creator, send_federation_update};\nuse activitypub_federation::config::Data;\nuse actix_"
  },
  {
    "path": "crates/api/api_crud/src/multi_community/list.rs",
    "chars": 977,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::{Json, Query};\nuse lemmy_api_utils::context::LemmyContext;"
  },
  {
    "path": "crates/api/api_crud/src/multi_community/mod.rs",
    "chars": 1066,
    "preview": "use activitypub_federation::config::Data;\nuse lemmy_api_utils::{\n  context::LemmyContext,\n  send_activity::{ActivityChan"
  },
  {
    "path": "crates/api/api_crud/src/multi_community/update.rs",
    "chars": 2696,
    "preview": "use super::{check_multi_community_creator, send_federation_update};\nuse activitypub_federation::config::Data;\nuse actix_"
  },
  {
    "path": "crates/api/api_crud/src/oauth_provider/create.rs",
    "chars": 1537,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{context::LemmyContext, utils::"
  },
  {
    "path": "crates/api/api_crud/src/oauth_provider/delete.rs",
    "chars": 751,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse lemmy_api_utils::{context::LemmyContext, utils::"
  },
  {
    "path": "crates/api/api_crud/src/oauth_provider/mod.rs",
    "chars": 48,
    "preview": "pub mod create;\npub mod delete;\npub mod update;\n"
  },
  {
    "path": "crates/api/api_crud/src/oauth_provider/update.rs",
    "chars": 1878,
    "preview": "use activitypub_federation::config::Data;\nuse actix_web::web::Json;\nuse chrono::Utc;\nuse lemmy_api_utils::{context::Lemm"
  },
  {
    "path": "crates/api/api_crud/src/post/create.rs",
    "chars": 5096,
    "preview": "use super::convert_published_time;\nuse crate::community_use_pending;\nuse activitypub_federation::config::Data;\nuse actix"
  }
]

// ... and 1231 more files (download for full content)

About this extraction

This page contains the full source code of the LemmyNet/lemmy GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 1431 files (3.9 MB), approximately 1.1M tokens, and a symbol index with 4492 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!