Compare commits

...

172 Commits

Author SHA1 Message Date
Lhcfl a856523119 fix: add slashquote in MkRenoteButton 2024-04-22 09:09:39 +08:00
Lhcfl 83e3f96ced Merge branch 'develop' of https://firefish.dev/firefish/firefish into feat/slash-quote 2024-04-22 09:01:19 +08:00
naskya 9acd130a22
chore (backend): update meta cache every 5 mins 2024-04-22 08:57:00 +09:00
naskya 0c1e7cdd72
refactor (backend): port should-block-instance to backend-rs 2024-04-22 08:31:28 +09:00
naskya cbd15fb2ca Merge branch 'redis' into 'develop'
Make Redis accessible from backend-rs


See merge request firefish/firefish!10753
2024-04-21 22:23:29 +00:00
naskya a6498b0491 Merge branch 'feat/alt_warning' into 'develop'
feat(client): attachment without description opened when choose add alt

Co-authored-by: 老周部落 <laozhoubuluo@gmail.com>

See merge request firefish/firefish!10699
2024-04-21 22:20:45 +00:00
naskya 9ced0d96ad
chore (client): don't make a new post as soon as you add descriptions 2024-04-22 07:20:07 +09:00
naskya 9a4988eaad
chore (client): fix type errors 2024-04-22 07:14:56 +09:00
naskya fbdc068115
locale: update en-US.yml 2024-04-22 07:09:54 +09:00
naskya 23ec206aee
Merge branch 'develop' into feat/alt_warning 2024-04-22 06:59:58 +09:00
naskya 07444ae7c1
Merge branch 'develop' into redis 2024-04-22 06:42:53 +09:00
naskya 455ecdf743 Merge branch 'docs/add_dependencies' into 'develop'
docs: add minimum dependencies

Co-authored-by: 老周部落 <laozhoubuluo@gmail.com>

See merge request firefish/firefish!10703
2024-04-21 21:40:34 +00:00
naskya d98c564ead
docs: move the dependencies section to the top 2024-04-22 06:39:20 +09:00
naskya 56aac15a6b
docs (minor): paraphrase a bit 2024-04-22 06:32:07 +09:00
naskya 280dddf464 Merge branch 'fix/download-url-agent' into 'develop'
fix: download-url should use proxy bypass hosts

Co-authored-by: 老周部落 <laozhoubuluo@gmail.com>

See merge request firefish/firefish!10739
2024-04-21 21:27:55 +00:00
naskya 1347c6ff04
Merge branch 'develop' into redis 2024-04-22 06:23:17 +09:00
naskya b3cc01c440 Merge branch 'feat/show-MkRemoteCaution-in-history' into 'develop'
feat: show MkRemoteCaution in note history page

Co-authored-by: Lhcfl <Lhcfl@outlook.com>

See merge request firefish/firefish!10743
2024-04-21 21:23:02 +00:00
naskya ebaefb9697
chore (minor, client): remove redundant attribute 2024-04-22 06:02:08 +09:00
naskya d9982a0b6a
Merge branch 'develop' into feat/show-MkRemoteCaution-in-history 2024-04-22 06:01:19 +09:00
naskya 0cb2e94d99 Merge branch 'fix/feed' into 'develop'
fix: notes in rss feed do not display HTML

Co-authored-by: Lhcfl <Lhcfl@outlook.com>

See merge request firefish/firefish!10744
2024-04-21 21:00:18 +00:00
naskya d1817d9a22 Merge branch 'feat/antenna_limit' into 'develop'
feat: antenna limit

Co-authored-by: 老周部落 <laozhoubuluo@gmail.com>

Closes #10894

See merge request firefish/firefish!10740
2024-04-21 20:58:09 +00:00
naskya c9de5f6095
docs: update api-changes.md 2024-04-22 05:56:46 +09:00
naskya c4658801aa
chore: regenerate entities 2024-04-22 05:54:32 +09:00
naskya a107d8c1ec
fix (backend): update import 2024-04-22 05:52:56 +09:00
naskya 4c91e8e37f
Merge branch 'develop' into feat/antenna_limit 2024-04-22 05:51:22 +09:00
naskya 0c9dc92f07
fix (backend-rs): use hostname for Redis key prefix and host for Redis streams
I suspect this is a bug, but I keep this behavior for compatibility for now
2024-04-22 05:16:14 +09:00
naskya 9fef36e80c
chore (backend): add comment 2024-04-22 01:56:34 +09:00
naskya b4ae877462
chore: format 2024-04-22 01:54:44 +09:00
naskya 2a30b4a536
Revert "refactor (backend): it turns out that sending the entire note object was redundant"
This reverts commit 3b65ebcb3e.
2024-04-22 01:47:56 +09:00
naskya 3039458c4c
chore (backend-rs): config::server::CONFIG -> config::CONFIG 2024-04-22 00:36:06 +09:00
naskya 574d3b3fe5
chore (backend-rs): in the current implementation we need to call to_string() anyway
There's room for refactoring
2024-04-22 00:30:59 +09:00
naskya 137d0fe3e5
chore (backend-rs): make variable names clearer 2024-04-22 00:29:37 +09:00
naskya 5c6f1c818a
chore (backend-rs): clean redundant match expression 2024-04-22 00:21:10 +09:00
naskya 2d8f4b945f
chore (backend-rs): remove unneeded serialize derivation for now 2024-04-22 00:17:33 +09:00
naskya 77e6479a67
chore (backend-rs): separate one-to-one/group chat stream types 2024-04-22 00:14:19 +09:00
naskya ec940bb068
chore (backend-rs): publish -> publish_to_stream 2024-04-21 22:43:09 +09:00
naskya 9b91035a79
chore (backend-rs): remove unneeded reference 2024-04-21 22:40:58 +09:00
naskya ce672f4edd
dev: add cargo test to pnpm scripts
mocha test has been unmaintained for a long time and is very broken :(
2024-04-21 22:36:05 +09:00
naskya 2fa0ca355d
Merge branch 'develop' into redis 2024-04-21 22:25:50 +09:00
naskya 131b3686d4 Merge branch 'feat/drive-file-usage-hints' into 'develop'
feat: Add usageHint field to DriveFile

Co-authored-by: yumeko <yumeko@mainichi.social>

See merge request firefish/firefish!10750
2024-04-21 12:58:37 +00:00
naskya 6b008c651a
chore (backend): remove (technically) incorrect TypeORM decorator field 2024-04-21 11:09:18 +09:00
naskya d2dbfb37c7
chore (backend): reflect entity changes to the schema and repository 2024-04-21 10:59:02 +09:00
naskya 96481f1353
chore: update downgrade.sql 2024-04-21 10:48:31 +09:00
naskya c936102a4c
chore (backend-rs): regenerate entities and index.js/d.ts 2024-04-21 10:45:47 +09:00
naskya 43570a54aa
chore: format 2024-04-21 10:44:54 +09:00
naskya 4d34e14dd8
Merge branch 'develop' into feat/drive-file-usage-hints 2024-04-21 10:42:25 +09:00
naskya 28f7ac1acd
fix (backend): typo 2024-04-21 10:31:00 +09:00
naskya 9f3396af21
chore (backend): translate Japanese comments into English 2024-04-21 10:30:13 +09:00
naskya dac4043dd9
v20240421 2024-04-21 10:09:45 +09:00
naskya d1e898c0d0
docs: update changelog 2024-04-21 09:32:05 +09:00
mei23 dc02a07774
fix (backend): add Cache-Control to Bull Dashboard 2024-04-21 09:29:00 +09:00
naskya 2760e7feee
chore (minor): use ** in lieu of Math.pow 2024-04-21 06:40:53 +09:00
naskya 488323cc8e
chore: format 2024-04-21 05:57:05 +09:00
naskya 3b65ebcb3e
refactor (backend): it turns out that sending the entire note object was redundant 2024-04-21 05:55:45 +09:00
naskya 6349705fb2
test (backend-rs): add db connection tests 2024-04-21 00:48:03 +09:00
naskya b08175fb83
Merge branch 'develop' into redis 2024-04-20 23:15:58 +09:00
naskya a2699e6687
chore (backend): fix imports 2024-04-20 23:04:12 +09:00
naskya 77ded03330
Merge branch 'develop' into redis 2024-04-20 10:17:11 +09:00
naskya dd3ad89b64 Merge branch 'refactor/types' into 'develop'
revert unnecessary MaybeRef in components

Co-authored-by: Lhcfl <Lhcfl@outlook.com>

See merge request firefish/firefish!10751
2024-04-20 01:07:25 +00:00
naskya 4fb2cab617 Merge branch 'fix/emoji-picker' into 'develop'
fix: use settings from reactionPicker for non-reaction emoji picker

Co-authored-by: Lhcfl <Lhcfl@outlook.com>

Closes #10905

See merge request firefish/firefish!10752
2024-04-20 01:06:53 +00:00
naskya 2b0668dacd
fix (backend-rs): Redis streaming 2024-04-20 09:54:02 +09:00
naskya f13df7e202
chore (backend-rs): make entities deserializable 2024-04-20 09:27:58 +09:00
naskya f33c7c6c94
fix (backend): host and hostname was messed up 2024-04-20 08:48:48 +09:00
naskya d41b462a89
fix (backend): fix redis key prefix 2024-04-20 07:43:09 +09:00
naskya ccbd6178e4
refactor (backend): port add-note-to-antenna to backend-rs
I hit this bug: https://github.com/napi-rs/napi-rs/issues/2060
2024-04-20 07:18:39 +09:00
naskya f486caf244
fix (backend-rs): use correct Redis key prefix 2024-04-20 06:53:45 +09:00
naskya b017f9ce94
fix (backend-rs): use cache server if present 2024-04-20 06:53:34 +09:00
naskya b157cbe79a
chore (backend-rs): make entities serializable 2024-04-20 04:41:47 +09:00
naskya 5c4a773ecf
chore (backend): qualify Node.js builtin modules 2024-04-20 03:09:18 +09:00
naskya ccb17977c3
chore (minor, backend): use type import 2024-04-20 03:08:35 +09:00
naskya def62ff1ce
chore (minor, backend): remove unused import 2024-04-20 03:04:34 +09:00
naskya 56038b174d
fix (backend): correct import path 2024-04-20 03:01:13 +09:00
naskya 037b7950a2
refactor (backend): clean the booting process a bit 2024-04-20 02:58:39 +09:00
naskya e82a07c03d
dev (backend-rs): make backend-rs accessible to Redis 2024-04-20 02:47:32 +09:00
naskya e60898b4b0
refactor (backend-rs): separate postgresql connector from database/mod.rs 2024-04-20 02:46:44 +09:00
naskya 3b89a8bfa6
refactor (backend): port config loader to backend-rs completely 2024-04-20 02:46:37 +09:00
Lhcfl 207855b0e8 fix: use settings from reactionPicker for non-reaction emoji picker 2024-04-20 01:05:30 +08:00
Lhcfl 781c98dda7 revert unnecessary `.value` for MkLink 2024-04-20 00:18:36 +08:00
Lhcfl ab221c98a7 revert unnecessary MaybeRef in components 2024-04-20 00:05:37 +08:00
yumeko 6c46bb56fd
Switch DriveFile's usageHint field to an enum type 2024-04-19 18:24:48 +03:00
naskya 1be5373dfc
chore (backend-rs): make exported enum compatible w/ TypeScript's string enum 2024-04-19 21:59:35 +09:00
yumeko 968657d26e
Run format 2024-04-19 07:54:11 +03:00
yumeko 913de651db
When updating (remote) user avatar/banner, clear usageHint for the previous drivefile, if any 2024-04-19 07:25:42 +03:00
yumeko 4aeb0d95cc
Add DriveFile usageHint field to rust model as well 2024-04-19 07:03:09 +03:00
yumeko c0f93de94b
Set file usage hints on local avatar/banner uploads as well + export "valid" values as type 2024-04-19 06:29:28 +03:00
yumeko 4823abd3a9
Add usageHint field to DriveFile, and fill accordingly when operating on Persons 2024-04-19 03:41:36 +03:00
naskya c6e2776298
chore (backend): remove a horrible and unused function 2024-04-19 03:42:49 +09:00
naskya 4b7724ed1f Merge branch 'cw-text' into 'develop'
Increase CW character limit

Closes #10876

See merge request firefish/firefish!10746
2024-04-17 20:47:40 +00:00
naskya 9d87679800
chore: lint 2024-04-18 05:34:23 +09:00
naskya 78092cd4be
dev (client): update eslint rules 2024-04-18 05:32:42 +09:00
naskya ff08d044b5
chore: format 2024-04-18 05:22:54 +09:00
naskya bce88ec199 Merge branch 'refactor/types' into 'develop'
Refactor/types

Co-authored-by: Lhcfl <Lhcfl@outlook.com>

See merge request firefish/firefish!10737
2024-04-17 20:21:52 +00:00
naskya 1b076c96d7
Merge branch 'develop' into refactor/types 2024-04-18 05:10:20 +09:00
naskya c19c439ac1
fix (backend): add hasPoll to packed note 2024-04-18 05:08:14 +09:00
naskya cc452da6c5
Merge branch 'develop' into refactor/types 2024-04-18 05:03:32 +09:00
naskya 30969ad817
refactor (backend): port get-note-summary to backend-rs
I removed trim() as it wasn't strictly neccessary
2024-04-18 05:02:00 +09:00
naskya 8337863ed3
chore: format 2024-04-18 05:01:49 +09:00
naskya 6a94d1b65d Merge branch 'fix/server-stats-disable' into 'develop'
Fix check for whether stats are disabled in meta in server machine stats job

Co-authored-by: yumeko <yumeko@mainichi.social>

See merge request firefish/firefish!10748
2024-04-17 18:20:35 +00:00
naskya c471aa30ae Merge branch 'fix/pinned-user-null' into 'develop'
Fix internal error in api/pinned-users if one or more name fails to resolve

Co-authored-by: yumeko <yumeko@mainichi.social>

See merge request firefish/firefish!10747
2024-04-17 18:19:17 +00:00
yumeko a411f4e4d9 Fix internal error in api/pinned-users if one or more name fails to resolve 2024-04-17 18:19:17 +00:00
naskya 22f4278ab5
meta: update issue/merge request templates 2024-04-17 23:14:43 +09:00
naskya ec7578e78e
docs: specify max-old-space-size in example config files 2024-04-17 19:49:02 +09:00
naskya adaaae1583
Merge branch 'develop' into refactor/types 2024-04-17 19:07:43 +09:00
naskya 8489066130
fix (client): list layout on mobile 2024-04-17 19:06:29 +09:00
naskya 17fb05430e
fix (backend, Mastodon API): add 'meta.original' field to media attachments
addresses https://github.com/whitescent/Mastify/pull/102
2024-04-17 17:46:23 +09:00
yumeko bf3c0717b9 Fix check for whether stats are disabled in meta in server machine stats job 2024-04-16 15:29:18 +00:00
naskya 082948bfe0
Merge branch 'develop' into refactor/types 2024-04-16 22:29:04 +09:00
Hosted Weblate 86f2e32c66
Merge branch 'origin/develop' into Weblate 2024-04-16 05:02:06 +02:00
Gary O'Regan Kelly 7af2cca2d4
locale: update translations (French)
Currently translated at 100.0% (1920 of 1920 strings)

Translation: Firefish/locales
Translate-URL: https://hosted.weblate.org/projects/firefish/locales/fr/
2024-04-16 05:01:56 +02:00
naskya 07384a4f0f
feat (backend): increase CW character limit (close #10876) 2024-04-16 09:14:44 +09:00
naskya 77a2bcfc4b
chore: remove unused items from example config file 2024-04-16 09:01:12 +09:00
naskya fd333250c9
chore (backend): set proxyRemoteFiles to true by default (close #9426) 2024-04-16 08:56:05 +09:00
naskya 38192052c9
meta: update issue/merge request templates 2024-04-16 05:40:27 +09:00
naskya 80b80277e2
fix (pug): random MOTD not showing 2024-04-16 01:50:42 +09:00
naskya 71c158fbd3
refactor (backend): port env.ts to backend-rs 2024-04-15 17:28:20 +09:00
Lhcfl 241c824ab5 fix: use better `]]>` replacer 2024-04-14 16:44:12 +08:00
Lhcfl 54d9916fec fix: rss feed no HTML 2024-04-14 16:34:33 +08:00
Lhcfl f0a50bc288 feat: show MkRemoteCaution in note history page 2024-04-14 13:59:27 +08:00
Lhcfl 8a62bf90f5 fix: MkMenu.vue 2024-04-14 03:42:30 +08:00
Lhcfl cee3a13f51 fix types 2024-04-14 03:15:31 +08:00
Lhcfl 1a6ba246f2 add other FormInput 2024-04-13 23:21:31 +08:00
Lhcfl 16880b1231 fix types 2024-04-13 23:08:58 +08:00
Lhcfl 3e43819ba1 rewrite MkFormDialog 2024-04-13 23:08:46 +08:00
Lhcfl bb9a58ce34 Merge branch 'develop' of https://firefish.dev/firefish/firefish into refactor/types 2024-04-13 20:08:41 +08:00
Lhcfl baba86a203 Downgrade vue-tsc
new versions of vue-tsc have perfomance issues:
see https://github.com/vuejs/language-tools/issues/4223
2024-04-13 17:55:40 +08:00
Lhcfl f95e2d1c51 Merge branch 'develop' of https://firefish.dev/firefish/firefish into refactor/types 2024-04-13 15:39:44 +08:00
Lhcfl 2b88ef18a5 fix type errors of components 2024-04-13 15:37:23 +08:00
老周部落 5eff4da27b
feat: antenna limit 2024-04-13 10:02:32 +08:00
老周部落 f44a2937d4
fix: download-url should use proxy bypass hosts 2024-04-13 09:00:08 +08:00
Lhcfl 393ab2590d fix type errors of components 2024-04-12 22:02:03 +08:00
Lhcfl f422842aef use Number.parseInt 2024-04-12 16:55:34 +08:00
Lhcfl 695cb452bc chore: Temporarily disable organizeImports 2024-04-12 16:50:07 +08:00
Lhcfl e4927c9b9b fix types of components 2024-04-12 16:37:32 +08:00
Lhcfl ea6ef881c2 fix types of components 2024-04-12 14:08:20 +08:00
Lhcfl 2bf51abc12 fix type of MkModalPageWindow 2024-04-12 11:31:11 +08:00
Lhcfl 5da03666b2 fix types of component 2024-04-12 11:16:26 +08:00
Lhcfl f3b189a70c refactor: rewrite MkMediaCaption 2024-04-12 09:46:04 +08:00
Lhcfl 95b91c6396 chore: remove unused type imports 2024-04-12 09:40:34 +08:00
Lhcfl 9c75dd0b26 refactor: define more cleared type of os.ts 2024-04-12 09:33:27 +08:00
Lhcfl 38668c4c11 fix type errors 2024-04-12 01:32:04 +08:00
Lhcfl e6b7eca775 fix type errors of components 2024-04-12 01:12:18 +08:00
Lhcfl 8e28f0e97c Merge branch 'develop' of https://firefish.dev/firefish/firefish into refactor/types 2024-04-12 00:23:21 +08:00
Lhcfl d8b4eb6f5e fix: gallery posts not show & fix types 2024-04-12 00:22:49 +08:00
Lhcfl ef94ba1474 refactor: fix type errrors of some components 2024-04-12 00:20:51 +08:00
Lhcfl c4a093209f fix type of MkEmojiPicker 2024-04-11 18:00:37 +08:00
Lhcfl db37eb4ad1 refactor: rewrite MkFolder 2024-04-11 17:29:07 +08:00
Lhcfl 3716e7f74c fix: expose toggleContent for it was a method 2024-04-11 17:11:48 +08:00
Lhcfl 7a4e6334f1 fix type error 2024-04-11 17:01:37 +08:00
Lhcfl 783f5481bb remove unnecessary assertion 2024-04-11 16:58:58 +08:00
Lhcfl 3ddd68097a fix type errors 2024-04-11 00:48:35 +08:00
Lhcfl f275fc9cdf refactor: fix type errors of MkCropperDialog 2024-04-11 00:14:36 +08:00
Lhcfl 18ba024cbb chore: format 2024-04-11 00:00:54 +08:00
Lhcfl 43aeec32ce fix types error of MkContextMenu 2024-04-10 23:36:42 +08:00
Lhcfl 909125e519 refactor: rewrite MkContainer using composition api 2024-04-10 23:35:14 +08:00
Lhcfl 124b2244d6 fix type errors of MkCode & MkModalWindow 2024-04-10 22:50:30 +08:00
Lhcfl 0b7ab1b90d fix type errors of MkChatPreview 2024-04-10 22:45:01 +08:00
Lhcfl 6982843716 fix: channel editor cannot remove channel banner 2024-04-10 22:25:45 +08:00
Lhcfl 17a945b8b1 fix type errors of channel 2024-04-10 22:25:11 +08:00
Lhcfl f7f7959ba6 refactor: fix waring for MkCaptcha 2024-04-10 22:24:16 +08:00
Lhcfl c1155f169a fix type warnings of MkCaptcha 2024-04-10 20:42:48 +08:00
Lhcfl b59186f093 fix type errors of MkButton 2024-04-10 20:41:31 +08:00
Lhcfl 1a1d817772 fix type errors of MkAvatars 2024-04-10 20:37:34 +08:00
Lhcfl 73537ec6fa fix type errors of MkAutoComplete 2024-04-10 20:36:20 +08:00
Lhcfl 6ac6a4cfa9 refactor: fix type errors of MkAnnouncements 2024-04-10 20:10:43 +08:00
Lhcfl b6baded2e3 refactor: fix MkAcct type 2024-04-10 17:58:02 +08:00
Lhcfl 23145c61af refactor: fix type of MkAbuseReport 2024-04-10 17:55:52 +08:00
Lhcfl 268b7aeb3f refactor: Fix type errors of mfm.ts 2024-04-10 17:16:25 +08:00
老周部落 46bf02cdd5
chore: format 2024-03-31 06:44:00 +08:00
老周部落 f346d2e2f6
feat: add showAddFileDescriptionAtFirstPost and allow cancel adding alt-text midway 2024-03-31 06:42:33 +08:00
naskya 2267e90d3b
refactor (client): await asynchronous processes, remove duplicate code 2024-03-31 06:41:20 +08:00
老周部落 db0bd21edc
feat(client): attachment without description opened when choose add alt 2024-03-31 06:41:07 +08:00
老周部落 de4da3c1fd
docs: add minimum dependencies 2024-03-19 22:51:05 +08:00
409 changed files with 4117 additions and 2419 deletions

View File

@ -178,19 +178,13 @@ logLevel: [
# Media Proxy
#mediaProxy: https://example.com/proxy
# Proxy remote files (default: false)
# Proxy remote files (default: true)
#proxyRemoteFiles: true
#allowedPrivateNetworks: [
# '127.0.0.1/32'
#]
# TWA
#twa:
# nameSpace: android_app
# packageName: tld.domain.twa
# sha256CertFingerprints: ['AB:CD:EF']
# Upload or download file size limits (bytes)
#maxFileSize: 262144000

View File

@ -3,30 +3,47 @@
🔒 Found a security vulnerability? [Please disclose it responsibly.](https://firefish.dev/firefish/firefish/-/blob/develop/SECURITY.md)
🤝 By submitting this issue, you agree to follow our [Contribution Guidelines.](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md) -->
**What happened?** _(Please give us a brief description of what happened.)_
## What happened? <!-- Please give us a brief description of what happened. -->
**What did you expect to happen?** _(Please give us a brief description of what you expected to happen.)_
**Version** _(What version of firefish is your instance running? You can find this by clicking your instance's logo at the bottom left and then clicking instance information.)_
## What did you expect to happen? <!-- Please give us a brief description of what you expected to happen. -->
**Instance** _(What instance of firefish are you using?)_
**What type of issue is this?** _(If this happens on your device and has to do with the user interface, it's client-side. If this happens on either with the API or the backend, or you got a server-side error in the client, it's server-side.)_
## Version <!-- What version of firefish is your instance running? You can find this by clicking your instance's logo at the bottom left and then clicking instance information. -->
**What browser are you using? (Client-side issues only)**
**What operating system are you using? (Client-side issues only)**
## What type of issue is this? <!-- If this happens on your device and has to do with the user interface, it's client-side. If this happens on either with the API or the backend, or you got a server-side error in the client, it's server-side. -->
**How do you deploy Firefish on your server? (Server-side issues only)**
- [ ] server-side
- [ ] client-side
- [ ] not sure
**What operating system are you using? (Server-side issues only)**
<details>
**Relevant log output** _(Please copy and paste any relevant log output. You can find your log by inspecting the page, and going to the "console" tab. This will be automatically formatted into code, so no need for backticks.)_
### Instance <!-- What instance of firefish are you using? -->
**Contribution Guidelines**
### What browser are you using? (client-side issues only)
### What operating system are you using? (client-side issues only)
### How do you deploy Firefish on your server? (server-side issues only)
### What operating system are you using? (Server-side issues only)
### Relevant log output <!-- Please copy and paste any relevant log output. You can find your log by inspecting the page, and going to the "console" tab. -->
</details>
## Contribution Guidelines
By submitting this issue, you agree to follow our [Contribution Guidelines](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md)
- [ ] I agree to follow this project's Contribution Guidelines
- [ ] I have searched the issue tracker for similar issues, and this is not a duplicate.
**Are you willing to fix this bug?** (optional)
## Are you willing to fix this bug? (optional)
- [ ] Yes. I will fix this bug and open a merge request if the change is agreed upon.

View File

@ -3,18 +3,22 @@
🔒 Found a security vulnerability? [Please disclose it responsibly.](https://firefish.dev/firefish/firefish/-/blob/develop/SECURITY.md)
🤝 By submitting this feature request, you agree to follow our [Contribution Guidelines.](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md) -->
**What feature would you like implemented?** _(Please give us a brief description of what you'd like.)_
## What feature would you like implemented? <!-- Please give us a brief description of what you'd like. -->
**Why should we add this feature?** _(Please give us a brief description of why your feature is important.)_
**Version** _(What version of firefish is your instance running? You can find this by clicking your instance's logo at the bottom left and then clicking instance information.)_
## Why should we add this feature? <!-- Please give us a brief description of why your feature is important. -->
**Instance** _(What instance of firefish are you using?)_
**Contribution Guidelines**
## Version <!-- What version of firefish is your instance running? You can find this by clicking your instance's logo at the bottom left and then clicking instance information. -->
## Instance <!-- What instance of firefish are you using? -->
## Contribution Guidelines
By submitting this issue, you agree to follow our [Contribution Guidelines](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md)
- [ ] I agree to follow this project's Contribution Guidelines
- [ ] I have searched the issue tracker for similar requests, and this is not a duplicate.
**Are you willing to implement this feature?** (optional)
## Are you willing to implement this feature? (optional)
- [ ] Yes. I will implement this feature and open a merge request if the change is agreed upon.

View File

@ -1,8 +1,9 @@
<!-- Thanks for taking the time to make Firefish better! It's not required, but please consider using [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) when making your commits. If you use VSCode, please use the [Conventional Commits extension](https://marketplace.visualstudio.com/items?itemName=vivaxy.vscode-conventional-commits). -->
**What does this PR do?** _(Please give us a brief description of what this PR does.)_
## What does this PR do? <!-- Please give us a brief description of what this PR does. -->
**Contribution Guidelines**
## Contribution Guidelines
By submitting this merge request, you agree to follow our [Contribution Guidelines](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md)
- [ ] This change is reviewed in an issue / This is a minor bug fix
- [ ] I agree to follow this project's Contribution Guidelines

63
Cargo.lock generated
View File

@ -220,12 +220,14 @@ dependencies = [
"parse-display",
"pretty_assertions",
"rand",
"redis",
"regex",
"schemars",
"sea-orm",
"serde",
"serde_json",
"serde_yaml",
"strum 0.26.2",
"thiserror",
"tokio",
"url",
@ -524,6 +526,16 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "combine"
version = "4.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
dependencies = [
"bytes",
"memchr",
]
[[package]]
name = "const-oid"
version = "0.9.6"
@ -1858,6 +1870,21 @@ dependencies = [
"getrandom",
]
[[package]]
name = "redis"
version = "0.25.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6472825949c09872e8f2c50bde59fcefc17748b6be5c90fd67cd8b4daca73bfd"
dependencies = [
"combine",
"itoa",
"percent-encoding",
"ryu",
"sha1_smol",
"socket2",
"url",
]
[[package]]
name = "redox_syscall"
version = "0.4.1"
@ -2070,6 +2097,12 @@ dependencies = [
"untrusted",
]
[[package]]
name = "rustversion"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47"
[[package]]
name = "ryu"
version = "1.0.17"
@ -2150,7 +2183,7 @@ dependencies = [
"serde",
"serde_json",
"sqlx",
"strum",
"strum 0.25.0",
"thiserror",
"time",
"tracing",
@ -2295,6 +2328,12 @@ dependencies = [
"digest",
]
[[package]]
name = "sha1_smol"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
[[package]]
name = "sha2"
version = "0.10.8"
@ -2676,6 +2715,28 @@ version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
[[package]]
name = "strum"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946"
dependencies = [
"heck 0.4.1",
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.58",
]
[[package]]
name = "subtle"
version = "2.5.0"

View File

@ -26,12 +26,14 @@ pretty_assertions = "1.4.0"
proc-macro2 = "1.0.79"
quote = "1.0.36"
rand = "0.8.5"
redis = "0.25.3"
regex = "1.10.4"
schemars = "0.8.16"
sea-orm = "0.12.15"
serde = "1.0.197"
serde_json = "1.0.115"
serde_yaml = "0.9.34"
strum = "0.26.2"
syn = "2.0.58"
thiserror = "1.0.58"
tokio = "1.37.0"

View File

@ -1,7 +1,7 @@
{
"$schema": "https://biomejs.dev/schemas/1.6.4/schema.json",
"organizeImports": {
"enabled": true
"enabled": false
},
"linter": {
"enabled": true,
@ -21,7 +21,8 @@
"useImportType": "warn",
"useShorthandFunctionType": "warn",
"useTemplate": "warn",
"noNonNullAssertion": "off"
"noNonNullAssertion": "off",
"useNodejsImportProtocol": "off"
}
}
}

View File

@ -42,6 +42,8 @@ cargo --version
### PostgreSQL and PGroonga
Firefish requires PostgreSQL v12 or later. We recommend that you install v12.x for the same reason as Node.js.
PostgreSQL install instructions can be found at [this page](https://www.postgresql.org/download/).
```sh

View File

@ -17,6 +17,7 @@ services:
# - web
environment:
NODE_ENV: production
NODE_OPTIONS: --max-old-space-size=3072
volumes:
- ./custom:/firefish/custom:ro
- ./files:/firefish/files

View File

@ -2,6 +2,10 @@
Breaking changes are indicated by the :warning: icon.
## Unreleased
- Added `antennaLimit` field to the response of `meta` and `admin/meta`, and the request of `admin/update-meta` (optional).
## v20240413
- :warning: Removed `patrons` endpoint.

View File

@ -5,6 +5,10 @@ Critical security updates are indicated by the :warning: icon.
- Server administrators should check [notice-for-admins.md](./notice-for-admins.md) as well.
- Third-party client/bot developers may want to check [api-change.md](./api-change.md) as well.
## [v20240421](https://firefish.dev/firefish/firefish/-/merge_requests/10756/commits)
- Fix bugs
## [v20240413](https://firefish.dev/firefish/firefish/-/merge_requests/10741/commits)
- Add "Media" tab to user page

View File

@ -1,6 +1,8 @@
BEGIN;
DELETE FROM "migrations" WHERE name IN (
'AddDriveFileUsage1713451569342',
'ConvertCwVarcharToText1713225866247',
'FixChatFileConstraint1712855579316',
'DropTimeZone1712425488543',
'ExpandNoteEdit1711936358554',
@ -22,6 +24,15 @@ DELETE FROM "migrations" WHERE name IN (
'RemoveNativeUtilsMigration1705877093218'
);
-- AddDriveFileUsage
ALTER TABLE "drive_file" DROP COLUMN "usageHint";
DROP TYPE "drive_file_usage_hint_enum";
-- convert-cw-varchar-to-text
DROP INDEX "IDX_8e3bbbeb3df04d1a8105da4c8f";
ALTER TABLE "note" ALTER COLUMN "cw" TYPE character varying(512);
CREATE INDEX "IDX_8e3bbbeb3df04d1a8105da4c8f" ON "note" USING "pgroonga" ("cw" pgroonga_varchar_full_text_search_ops_v2);
-- fix-chat-file-constraint
ALTER TABLE "messaging_message" DROP CONSTRAINT "FK_535def119223ac05ad3fa9ef64b";
ALTER TABLE "messaging_message" ADD CONSTRAINT "FK_535def119223ac05ad3fa9ef64b" FOREIGN KEY ("fileId") REFERENCES "drive_file"("id") ON DELETE CASCADE ON UPDATE NO ACTION;

View File

@ -1,9 +1,36 @@
# Install Firefish
This document shows an example procedure for installing Firefish on Debian 12. Note that there is much room for customizing the server setup; this document merely demonstrates a simple installation.
Firefish depends on the following software.
## Runtime dependencies
- At least [NodeJS](https://nodejs.org/en/) v18.17.0 (v20/v21 recommended)
- At least [PostgreSQL](https://www.postgresql.org/) v12 (v16 recommended) with [PGroonga](https://pgroonga.github.io/) extension
- At least [Redis](https://redis.io/) v7
- Web Proxy (one of the following)
- Caddy (recommended)
- Nginx (recommended)
- Apache
- [FFmpeg](https://ffmpeg.org/) for video transcoding (**optional**)
- Caching server (**optional**, one of the following)
- [DragonflyDB](https://www.dragonflydb.io/)
- [KeyDB](https://keydb.dev/)
- Another [Redis](https://redis.io/) server
## Build dependencies
- At least [Rust](https://www.rust-lang.org/) v1.74
- C/C++ compiler & build tools
- `build-essential` on Debian/Ubuntu Linux
- `base-devel` on Arch Linux
- [Python 3](https://www.python.org/)
This document shows an example procedure for installing these dependencies and Firefish on Debian 12. Note that there is much room for customizing the server setup; this document merely demonstrates a simple installation.
If you want to use the pre-built container image, please refer to [`install-container.md`](./install-container.md).
If you do not prepare your environment as document, be sure to meet the minimum dependencies given at the bottom of the page.
Make sure that you can use the `sudo` command before proceeding.
## 1. Install dependencies
@ -154,7 +181,7 @@ sudo apt install ffmpeg
1. Build
```sh
pnpm install --frozen-lockfile
NODE_ENV=production pnpm run build
NODE_ENV=production NODE_OPTIONS='--max-old-space-size=3072' pnpm run build
```
1. Execute database migrations
```sh
@ -242,6 +269,7 @@ In this instruction, we use [Caddy](https://caddyserver.com/) to make the Firefi
WorkingDirectory=/home/firefish/firefish
Environment="NODE_ENV=production"
Environment="npm_config_cache=/tmp"
Environment="NODE_OPTIONS=--max-old-space-size=3072"
# uncomment the following line if you use jemalloc (note that the path varies on different environments)
# Environment="LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2"
StandardOutput=journal

View File

@ -394,6 +394,7 @@ enableRegistration: "Enable new user registration"
invite: "Invite"
driveCapacityPerLocalAccount: "Drive capacity per local user"
driveCapacityPerRemoteAccount: "Drive capacity per remote user"
antennaLimit: "The maximum number of antennas that each user can create"
inMb: "In megabytes"
iconUrl: "Icon URL"
bannerUrl: "Banner image URL"
@ -1226,6 +1227,8 @@ publishTimelinesDescription: "If enabled, the Local and Global timelines will be
on {url} even when signed out."
noAltTextWarning: "Some attached file(s) have no description. Did you forget to write?"
showNoAltTextWarning: "Show a warning if you attempt to post files without a description"
showAddFileDescriptionAtFirstPost: "Automatically open a form to write a description when you
attempt to post files without a description"
_emojiModPerm:
unauthorized: "None"

View File

@ -2318,3 +2318,4 @@ markLocalFilesNsfwByDefaultDescription: Indépendamment de ce réglage, les util
peuvent supprimer le drapeau « sensible » (NSFW) eux-mêmes. Les fichiers existants
ne sont pas affectés.
noteEditHistory: Historique des publications
media: Multimédia

View File

@ -340,6 +340,7 @@ invite: "邀请"
driveCapacityPerLocalAccount: "每个本地用户的网盘容量"
driveCapacityPerRemoteAccount: "每个远程用户的网盘容量"
inMb: "以兆字节 (MegaByte) 为单位"
antennaLimit: "每个用户最多可以创建的天线数量"
iconUrl: "图标 URL"
bannerUrl: "横幅图 URL"
backgroundImageUrl: "背景图 URL"
@ -2053,6 +2054,7 @@ searchRangeDescription: "如果您要过滤时间段,请按以下格式输入
messagingUnencryptedInfo: "Firefish 上的聊天没有经过端到端加密,请不要在聊天中分享您的敏感信息。"
noAltTextWarning: 有些附件没有描述。您是否忘记写描述了?
showNoAltTextWarning: 当您尝试发布没有描述的帖子附件时显示警告
showAddFileDescriptionAtFirstPost: 当您首次尝试发布没有描述的帖子附件时自动弹出添加描述页面
autocorrectNoteLanguage: 当帖子语言不符合自动检测的结果的时候显示警告
incorrectLanguageWarning: "看上去您帖子使用的语言是{detected},但您选择的语言是{current}。\n要改为以{detected}发帖吗?"
noteEditHistory: "帖子编辑历史"

View File

@ -1,6 +1,6 @@
{
"name": "firefish",
"version": "20240413",
"version": "20240421",
"repository": {
"type": "git",
"url": "https://firefish.dev/firefish/firefish.git"
@ -26,7 +26,9 @@
"debug": "pnpm run build:debug && pnpm run start",
"build:debug": "pnpm run clean && pnpm node ./scripts/dev-build.mjs && pnpm run gulp",
"mocha": "pnpm --filter backend run mocha",
"test": "pnpm run mocha",
"test": "pnpm run test:ts && pnpm run test:rs",
"test:ts": "pnpm run mocha",
"test:rs": "cargo test",
"format": "pnpm run format:ts; pnpm run format:rs",
"format:ts": "pnpm -r --parallel run format",
"format:rs": "cargo fmt --all --",

View File

@ -30,12 +30,14 @@ jsonschema = { workspace = true }
once_cell = { workspace = true }
parse-display = { workspace = true }
rand = { workspace = true }
redis = { workspace = true }
regex = { workspace = true }
schemars = { workspace = true, features = ["chrono"] }
sea-orm = { workspace = true, features = ["sqlx-postgres", "runtime-tokio-rustls"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
serde_yaml = { workspace = true }
strum = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["full"] }
url = { workspace = true }

View File

@ -6,6 +6,7 @@ SRC += $(call recursive_wildcard, src, *)
.PHONY: regenerate-entities
regenerate-entities:
rm --recursive --force src/model/entity
sea-orm-cli generate entity \
--output-dir='src/model/entity' \
--database-url='postgres://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@localhost:25432/$(POSTGRES_DB)' \
@ -16,8 +17,9 @@ regenerate-entities:
jsname=$$(printf '%s\n' "$${base%.*}" | perl -pe 's/(^|_)./uc($$&)/ge;s/_//g'); \
attribute=$$(printf 'cfg_attr(feature = "napi", napi_derive::napi(object, js_name = "%s", use_nullable = true))' "$${jsname}"); \
sed -i "s/NAPI_EXTRA_ATTR_PLACEHOLDER/$${attribute}/" "$${file}"; \
sed -i 's/#\[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)\]/#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]\n#[serde(rename_all = "camelCase")]/' "$${file}"; \
done
sed -i 's/#\[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)\]/#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]\n#[cfg_attr(not(feature = "napi"), derive(Clone))]\n#[cfg_attr(feature = "napi", napi_derive::napi)]/' \
sed -i 's/#\[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum)\]/#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize)]\n#[serde(rename_all = "camelCase")]\n#[cfg_attr(not(feature = "napi"), derive(Clone))]\n#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]/' \
src/model/entity/sea_orm_active_enums.rs
cargo fmt --all --

View File

@ -3,6 +3,16 @@
/* auto-generated by NAPI-RS */
export interface EnvConfig {
onlyQueue: boolean
onlyServer: boolean
noDaemons: boolean
disableClustering: boolean
verbose: boolean
withLogTime: boolean
slow: boolean
}
export function loadEnv(): EnvConfig
export interface ServerConfig {
url: string
port: number
@ -19,7 +29,7 @@ export interface ServerConfig {
/** `NapiValue` is not implemented for `u64` */
maxFileSize?: number
accessLog?: string
clusterLimits?: WorkerConfig
clusterLimits?: WorkerConfigInternal
cuid?: IdConfig
outgoingAddress?: string
deliverJobConcurrency?: number
@ -60,13 +70,17 @@ export interface RedisConfig {
pass?: string
tls?: TlsConfig
db: number
prefix: string
prefix?: string
}
export interface TlsConfig {
host: string
rejectUnauthorized: boolean
}
export interface WorkerConfig {
web: number
queue: number
}
export interface WorkerConfigInternal {
web?: number
queue?: number
}
@ -111,14 +125,91 @@ export interface ObjectStorageConfig {
setPublicReadOnUpload?: boolean
s3ForcePathStyle?: boolean
}
export function readServerConfig(): ServerConfig
export interface Config {
url: string
port: number
bind?: string
disableHsts?: boolean
db: DbConfig
redis: RedisConfig
cacheServer?: RedisConfig
proxy?: string
proxySmtp?: string
proxyBypassHosts?: Array<string>
allowedPrivateNetworks?: Array<string>
maxFileSize?: number
accessLog?: string
clusterLimits: WorkerConfig
cuid?: IdConfig
outgoingAddress?: string
deliverJobConcurrency?: number
inboxJobConcurrency?: number
deliverJobPerSec?: number
inboxJobPerSec?: number
deliverJobMaxAttempts?: number
inboxJobMaxAttempts?: number
logLevel?: Array<string>
syslog?: SysLogConfig
proxyRemoteFiles?: boolean
mediaProxy?: string
summalyProxyUrl?: string
reservedUsernames?: Array<string>
maxUserSignups?: number
isManagedHosting?: boolean
maxNoteLength?: number
maxCaptionLength?: number
deepl?: DeepLConfig
libreTranslate?: LibreTranslateConfig
email?: EmailConfig
objectStorage?: ObjectStorageConfig
version: string
host: string
hostname: string
redisKeyPrefix: string
scheme: string
wsScheme: string
apiUrl: string
wsUrl: string
authUrl: string
driveUrl: string
userAgent: string
clientEntry: Manifest
}
export interface Manifest {
file: string
name: string
src: string
isEntry: boolean
isDynamicEntry: boolean
imports: Array<string>
dynamicImports: Array<string>
css: Array<string>
assets: Array<string>
}
export function loadConfig(): Config
export interface Acct {
username: string
host: string | null
}
export function stringToAcct(acct: string): Acct
export function acctToString(acct: Acct): string
export interface NoteLike {
/**
* @param host punycoded instance host
* @returns whether the given host should be blocked
*/
export function isBlockedServer(host: string): Promise<boolean>
/**
* @param host punycoded instance host
* @returns whether the given host should be limited
*/
export function isSilencedServer(host: string): Promise<boolean>
/**
* @param host punycoded instance host
* @returns whether the given host is allowlisted (this is always true if private mode is disabled)
*/
export function isAllowedServer(host: string): Promise<boolean>
/** TODO: handle name collisions better */
export interface NoteLikeForCheckWordMute {
fileIds: Array<string>
userId: string | null
text: string | null
@ -126,7 +217,7 @@ export interface NoteLike {
renoteId: string | null
replyId: string | null
}
export function checkWordMute(note: NoteLike, mutedWordLists: Array<Array<string>>, mutedPatterns: Array<string>): Promise<boolean>
export function checkWordMute(note: NoteLikeForCheckWordMute, mutedWordLists: Array<Array<string>>, mutedPatterns: Array<string>): Promise<boolean>
export function getFullApAccount(username: string, host?: string | undefined | null): string
export function isSelfHost(host?: string | undefined | null): boolean
export function isSameOrigin(uri: string): boolean
@ -137,6 +228,14 @@ export function sqlLikeEscape(src: string): string
export function safeForSql(src: string): boolean
/** Convert milliseconds to a human readable string */
export function formatMilliseconds(milliseconds: number): string
/** TODO: handle name collisions better */
export interface NoteLikeForGetNoteSummary {
fileIds: Array<string>
text: string | null
cw: string | null
hasPoll: boolean
}
export function getNoteSummary(note: NoteLikeForGetNoteSummary): string
export function toMastodonId(firefishId: string): string | null
export function fromMastodonId(mastodonId: string): string | null
export function fetchMeta(useCache: boolean): Promise<Meta>
@ -329,6 +428,7 @@ export interface DriveFile {
webpublicType: string | null
requestHeaders: Json | null
requestIp: string | null
usageHint: DriveFileUsageHintEnum | null
}
export interface DriveFolder {
id: string
@ -534,6 +634,7 @@ export interface Meta {
donationLink: string | null
moreUrls: Json
markLocalFilesNsfwByDefault: boolean
antennaLimit: number
}
export interface Migrations {
id: number
@ -753,81 +854,85 @@ export interface ReplyMuting {
muteeId: string
muterId: string
}
export const enum AntennaSrcEnum {
All = 0,
Group = 1,
Home = 2,
Instances = 3,
List = 4,
Users = 5
export enum AntennaSrcEnum {
All = 'all',
Group = 'group',
Home = 'home',
Instances = 'instances',
List = 'list',
Users = 'users'
}
export const enum MutedNoteReasonEnum {
Manual = 0,
Other = 1,
Spam = 2,
Word = 3
export enum DriveFileUsageHintEnum {
UserAvatar = 'userAvatar',
UserBanner = 'userBanner'
}
export const enum NoteVisibilityEnum {
Followers = 0,
Hidden = 1,
Home = 2,
Public = 3,
Specified = 4
export enum MutedNoteReasonEnum {
Manual = 'manual',
Other = 'other',
Spam = 'spam',
Word = 'word'
}
export const enum NotificationTypeEnum {
App = 0,
Follow = 1,
FollowRequestAccepted = 2,
GroupInvited = 3,
Mention = 4,
PollEnded = 5,
PollVote = 6,
Quote = 7,
Reaction = 8,
ReceiveFollowRequest = 9,
Renote = 10,
Reply = 11
export enum NoteVisibilityEnum {
Followers = 'followers',
Hidden = 'hidden',
Home = 'home',
Public = 'public',
Specified = 'specified'
}
export const enum PageVisibilityEnum {
Followers = 0,
Public = 1,
Specified = 2
export enum NotificationTypeEnum {
App = 'app',
Follow = 'follow',
FollowRequestAccepted = 'followRequestAccepted',
GroupInvited = 'groupInvited',
Mention = 'mention',
PollEnded = 'pollEnded',
PollVote = 'pollVote',
Quote = 'quote',
Reaction = 'reaction',
ReceiveFollowRequest = 'receiveFollowRequest',
Renote = 'renote',
Reply = 'reply'
}
export const enum PollNotevisibilityEnum {
Followers = 0,
Home = 1,
Public = 2,
Specified = 3
export enum PageVisibilityEnum {
Followers = 'followers',
Public = 'public',
Specified = 'specified'
}
export const enum RelayStatusEnum {
Accepted = 0,
Rejected = 1,
Requesting = 2
export enum PollNotevisibilityEnum {
Followers = 'followers',
Home = 'home',
Public = 'public',
Specified = 'specified'
}
export const enum UserEmojimodpermEnum {
Add = 0,
Full = 1,
Mod = 2,
Unauthorized = 3
export enum RelayStatusEnum {
Accepted = 'accepted',
Rejected = 'rejected',
Requesting = 'requesting'
}
export const enum UserProfileFfvisibilityEnum {
Followers = 0,
Private = 1,
Public = 2
export enum UserEmojimodpermEnum {
Add = 'add',
Full = 'full',
Mod = 'mod',
Unauthorized = 'unauthorized'
}
export const enum UserProfileMutingnotificationtypesEnum {
App = 0,
Follow = 1,
FollowRequestAccepted = 2,
GroupInvited = 3,
Mention = 4,
PollEnded = 5,
PollVote = 6,
Quote = 7,
Reaction = 8,
ReceiveFollowRequest = 9,
Renote = 10,
Reply = 11
export enum UserProfileFfvisibilityEnum {
Followers = 'followers',
Private = 'private',
Public = 'public'
}
export enum UserProfileMutingnotificationtypesEnum {
App = 'app',
Follow = 'follow',
FollowRequestAccepted = 'followRequestAccepted',
GroupInvited = 'groupInvited',
Mention = 'mention',
PollEnded = 'pollEnded',
PollVote = 'pollVote',
Quote = 'quote',
Reaction = 'reaction',
ReceiveFollowRequest = 'receiveFollowRequest',
Renote = 'renote',
Reply = 'reply'
}
export interface Signin {
id: string
@ -1014,6 +1119,7 @@ export interface Webhook {
latestSentAt: Date | null
latestStatus: number | null
}
export function addNoteToAntenna(antennaId: string, note: Note): void
/** Initializes Cuid2 generator. Must be called before any [create_id]. */
export function initIdGenerator(length: number, fingerprint: string): void
export function getTimestamp(id: string): number

View File

@ -310,11 +310,15 @@ if (!nativeBinding) {
throw new Error(`Failed to load native binding`)
}
const { readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding
const { loadEnv, loadConfig, stringToAcct, acctToString, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getNoteSummary, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, AntennaSrcEnum, DriveFileUsageHintEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, addNoteToAntenna, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding
module.exports.readServerConfig = readServerConfig
module.exports.loadEnv = loadEnv
module.exports.loadConfig = loadConfig
module.exports.stringToAcct = stringToAcct
module.exports.acctToString = acctToString
module.exports.isBlockedServer = isBlockedServer
module.exports.isSilencedServer = isSilencedServer
module.exports.isAllowedServer = isAllowedServer
module.exports.checkWordMute = checkWordMute
module.exports.getFullApAccount = getFullApAccount
module.exports.isSelfHost = isSelfHost
@ -325,6 +329,7 @@ module.exports.isUnicodeEmoji = isUnicodeEmoji
module.exports.sqlLikeEscape = sqlLikeEscape
module.exports.safeForSql = safeForSql
module.exports.formatMilliseconds = formatMilliseconds
module.exports.getNoteSummary = getNoteSummary
module.exports.toMastodonId = toMastodonId
module.exports.fromMastodonId = fromMastodonId
module.exports.fetchMeta = fetchMeta
@ -337,6 +342,7 @@ module.exports.decodeReaction = decodeReaction
module.exports.countReactions = countReactions
module.exports.toDbReaction = toDbReaction
module.exports.AntennaSrcEnum = AntennaSrcEnum
module.exports.DriveFileUsageHintEnum = DriveFileUsageHintEnum
module.exports.MutedNoteReasonEnum = MutedNoteReasonEnum
module.exports.NoteVisibilityEnum = NoteVisibilityEnum
module.exports.NotificationTypeEnum = NotificationTypeEnum
@ -346,6 +352,7 @@ module.exports.RelayStatusEnum = RelayStatusEnum
module.exports.UserEmojimodpermEnum = UserEmojimodpermEnum
module.exports.UserProfileFfvisibilityEnum = UserProfileFfvisibilityEnum
module.exports.UserProfileMutingnotificationtypesEnum = UserProfileMutingnotificationtypesEnum
module.exports.addNoteToAntenna = addNoteToAntenna
module.exports.initIdGenerator = initIdGenerator
module.exports.getTimestamp = getTimestamp
module.exports.genId = genId

View File

@ -33,8 +33,8 @@
},
"scripts": {
"artifacts": "napi artifacts",
"build": "napi build --features napi --platform --release ./built/",
"build:debug": "napi build --features napi --platform ./built/",
"build": "napi build --features napi --no-const-enum --platform --release ./built/",
"build:debug": "napi build --features napi --no-const-enum --platform ./built/",
"prepublishOnly": "napi prepublish -t npm",
"test": "pnpm run cargo:test && pnpm run build:debug && ava",
"universal": "napi universal",

View File

@ -0,0 +1,27 @@
// FIXME: Are these options used?
#[crate::export(object)]
pub struct EnvConfig {
pub only_queue: bool,
pub only_server: bool,
pub no_daemons: bool,
pub disable_clustering: bool,
pub verbose: bool,
pub with_log_time: bool,
pub slow: bool,
}
#[crate::export]
pub fn load_env() -> EnvConfig {
let node_env = std::env::var("NODE_ENV").unwrap_or_default().to_lowercase();
let is_testing = node_env == "test";
EnvConfig {
only_queue: std::env::var("MK_ONLY_QUEUE").is_ok(),
only_server: std::env::var("MK_ONLY_SERVER").is_ok(),
no_daemons: is_testing || std::env::var("MK_NO_DAEMONS").is_ok(),
disable_clustering: is_testing || std::env::var("MK_DISABLE_CLUSTERING").is_ok(),
verbose: std::env::var("MK_VERBOSE").is_ok(),
with_log_time: std::env::var("MK_WITH_LOG_TIME").is_ok(),
slow: std::env::var("MK_SLOW").is_ok(),
}
}

View File

@ -1 +1,4 @@
pub use server::CONFIG;
pub mod environment;
pub mod server;

View File

@ -6,7 +6,7 @@ use std::fs;
#[derive(Clone, Debug, PartialEq, Deserialize)]
#[serde(rename_all = "camelCase")]
#[crate::export(object, use_nullable = false)]
pub struct ServerConfig {
struct ServerConfig {
pub url: String,
pub port: u16,
/// host to listen on
@ -25,7 +25,7 @@ pub struct ServerConfig {
/// `NapiValue` is not implemented for `u64`
pub max_file_size: Option<i64>,
pub access_log: Option<String>,
pub cluster_limits: Option<WorkerConfig>,
pub cluster_limits: Option<WorkerConfigInternal>,
pub cuid: Option<IdConfig>,
pub outgoing_address: Option<String>,
@ -82,8 +82,7 @@ pub struct RedisConfig {
pub tls: Option<TlsConfig>,
#[serde(default)]
pub db: u32,
#[serde(default)]
pub prefix: String,
pub prefix: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Deserialize)]
@ -94,10 +93,16 @@ pub struct TlsConfig {
pub reject_unauthorized: bool,
}
#[crate::export(object, use_nullable = false)]
pub struct WorkerConfig {
pub web: u32,
pub queue: u32,
}
#[derive(Clone, Debug, PartialEq, Deserialize)]
#[serde(rename_all = "camelCase")]
#[crate::export(object, use_nullable = false)]
pub struct WorkerConfig {
pub struct WorkerConfigInternal {
pub web: Option<u32>,
pub queue: Option<u32>,
}
@ -167,17 +172,207 @@ pub struct ObjectStorageConfig {
pub s3_force_path_style: Option<bool>,
}
#[crate::export]
pub fn read_server_config() -> ServerConfig {
#[crate::export(object, use_nullable = false)]
pub struct Config {
// ServerConfig (from default.yml)
pub url: String,
pub port: u16,
pub bind: Option<String>,
pub disable_hsts: Option<bool>,
pub db: DbConfig,
pub redis: RedisConfig,
pub cache_server: Option<RedisConfig>,
pub proxy: Option<String>,
pub proxy_smtp: Option<String>,
pub proxy_bypass_hosts: Option<Vec<String>>,
pub allowed_private_networks: Option<Vec<String>>,
pub max_file_size: Option<i64>,
pub access_log: Option<String>,
pub cluster_limits: WorkerConfig,
pub cuid: Option<IdConfig>,
pub outgoing_address: Option<String>,
pub deliver_job_concurrency: Option<u32>,
pub inbox_job_concurrency: Option<u32>,
pub deliver_job_per_sec: Option<u32>,
pub inbox_job_per_sec: Option<u32>,
pub deliver_job_max_attempts: Option<u32>,
pub inbox_job_max_attempts: Option<u32>,
pub log_level: Option<Vec<String>>,
pub syslog: Option<SysLogConfig>,
pub proxy_remote_files: Option<bool>,
pub media_proxy: Option<String>,
pub summaly_proxy_url: Option<String>,
pub reserved_usernames: Option<Vec<String>>,
pub max_user_signups: Option<u32>,
pub is_managed_hosting: Option<bool>,
pub max_note_length: Option<u32>,
pub max_caption_length: Option<u32>,
pub deepl: Option<DeepLConfig>,
pub libre_translate: Option<LibreTranslateConfig>,
pub email: Option<EmailConfig>,
pub object_storage: Option<ObjectStorageConfig>,
// Mixin
pub version: String,
pub host: String,
pub hostname: String,
pub redis_key_prefix: String,
pub scheme: String,
pub ws_scheme: String,
pub api_url: String,
pub ws_url: String,
pub auth_url: String,
pub drive_url: String,
pub user_agent: String,
pub client_entry: Manifest,
}
#[derive(Clone, Debug, PartialEq, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Meta {
pub version: String,
}
#[derive(Clone, Debug, PartialEq, Deserialize)]
struct ManifestJson {
#[serde(rename = "src/init.ts")]
pub init_ts: Manifest,
}
#[derive(Clone, Debug, PartialEq, Deserialize)]
#[serde(rename_all = "camelCase")]
#[crate::export(object, use_nullable = false)]
pub struct Manifest {
pub file: String,
pub name: String,
pub src: String,
pub is_entry: bool,
pub is_dynamic_entry: bool,
pub imports: Vec<String>,
pub dynamic_imports: Vec<String>,
pub css: Vec<String>,
pub assets: Vec<String>,
}
fn read_config_file() -> ServerConfig {
let cwd = env::current_dir().unwrap();
let yml = fs::File::open(cwd.join("../../.config/default.yml"))
.expect("Failed to open '.config/default.yml'");
let mut data: ServerConfig = serde_yaml::from_reader(yml).expect("Failed to parse yaml");
let mut data: ServerConfig =
serde_yaml::from_reader(yml).expect("Failed to parse .config/default.yml");
data.url = url::Url::parse(&data.url)
.expect("Config url is invalid")
.origin()
.ascii_serialization();
if data.bind.is_none() {
data.bind = std::env::var("BIND").ok()
}
data
}
pub static SERVER_CONFIG: Lazy<ServerConfig> = Lazy::new(read_server_config);
fn read_meta() -> Meta {
let cwd = env::current_dir().unwrap();
let meta_json = fs::File::open(cwd.join("../../built/meta.json"))
.expect("Failed to open 'built/meta.json'");
serde_json::from_reader(meta_json).expect("Failed to parse built/meta.json")
}
fn read_manifest() -> Manifest {
let cwd = env::current_dir().unwrap();
let manifest_json = fs::File::open(cwd.join("../../built/_client_dist_/manifest.json"))
.expect("Failed to open 'built/_client_dist_/manifest.json'");
let manifest: ManifestJson = serde_json::from_reader(manifest_json)
.expect("Failed to parse built/_client_dist_/manifest.json");
manifest.init_ts
}
#[crate::export]
fn load_config() -> Config {
let server_config = read_config_file();
let version = read_meta().version;
let manifest = read_manifest();
let url = url::Url::parse(&server_config.url).expect("Config url is invalid");
let hostname = url
.host_str()
.expect("Hostname is missing in the config url")
.to_owned();
let host = match url.port() {
Some(port) => format!("{}:{}", hostname, port),
None => hostname.clone(),
};
let scheme = url.scheme().to_owned();
let ws_scheme = scheme.replace("http", "ws");
let cluster_limits = match server_config.cluster_limits {
Some(cl) => WorkerConfig {
web: cl.web.unwrap_or(1),
queue: cl.queue.unwrap_or(1),
},
None => WorkerConfig { web: 1, queue: 1 },
};
let redis_key_prefix = if let Some(cache_server) = &server_config.cache_server {
cache_server.prefix.clone()
} else {
server_config.redis.prefix.clone()
}
.unwrap_or(hostname.clone());
Config {
url: server_config.url,
port: server_config.port,
bind: server_config.bind,
disable_hsts: server_config.disable_hsts,
db: server_config.db,
redis: server_config.redis,
cache_server: server_config.cache_server,
proxy: server_config.proxy,
proxy_smtp: server_config.proxy_smtp,
proxy_bypass_hosts: server_config.proxy_bypass_hosts,
allowed_private_networks: server_config.allowed_private_networks,
max_file_size: server_config.max_file_size,
access_log: server_config.access_log,
cluster_limits,
cuid: server_config.cuid,
outgoing_address: server_config.outgoing_address,
deliver_job_concurrency: server_config.deliver_job_concurrency,
inbox_job_concurrency: server_config.inbox_job_concurrency,
deliver_job_per_sec: server_config.deliver_job_per_sec,
inbox_job_per_sec: server_config.inbox_job_per_sec,
deliver_job_max_attempts: server_config.deliver_job_max_attempts,
inbox_job_max_attempts: server_config.inbox_job_max_attempts,
log_level: server_config.log_level,
syslog: server_config.syslog,
proxy_remote_files: server_config.proxy_remote_files,
media_proxy: server_config.media_proxy,
summaly_proxy_url: server_config.summaly_proxy_url,
reserved_usernames: server_config.reserved_usernames,
max_user_signups: server_config.max_user_signups,
is_managed_hosting: server_config.is_managed_hosting,
max_note_length: server_config.max_note_length,
max_caption_length: server_config.max_caption_length,
deepl: server_config.deepl,
libre_translate: server_config.libre_translate,
email: server_config.email,
object_storage: server_config.object_storage,
ws_url: format!("{}://{}", ws_scheme, host),
api_url: format!("{}://{}/api", scheme, host),
auth_url: format!("{}://{}/auth", scheme, host),
drive_url: format!("{}://{}/files", scheme, host),
user_agent: format!("Firefish/{} ({})", version, url),
version,
host,
hostname,
redis_key_prefix,
scheme,
ws_scheme,
client_entry: manifest,
}
}
pub static CONFIG: Lazy<Config> = Lazy::new(load_config);

View File

@ -1,34 +1,6 @@
use crate::config::server::SERVER_CONFIG;
use sea_orm::{Database, DbConn, DbErr};
pub use postgresql::db_conn;
pub use redis::key as redis_key;
pub use redis::redis_conn;
static DB_CONN: once_cell::sync::OnceCell<DbConn> = once_cell::sync::OnceCell::new();
async fn init_database() -> Result<&'static DbConn, DbErr> {
let database_uri = format!(
"postgres://{}:{}@{}:{}/{}",
SERVER_CONFIG.db.user,
urlencoding::encode(&SERVER_CONFIG.db.pass),
SERVER_CONFIG.db.host,
SERVER_CONFIG.db.port,
SERVER_CONFIG.db.db,
);
let conn = Database::connect(database_uri).await?;
Ok(DB_CONN.get_or_init(move || conn))
}
pub async fn db_conn() -> Result<&'static DbConn, DbErr> {
match DB_CONN.get() {
Some(conn) => Ok(conn),
None => init_database().await,
}
}
#[cfg(test)]
mod unit_test {
use super::db_conn;
#[tokio::test]
async fn connect_test() {
assert!(db_conn().await.is_ok());
}
}
pub mod postgresql;
pub mod redis;

View File

@ -0,0 +1,35 @@
use crate::config::CONFIG;
use sea_orm::{Database, DbConn, DbErr};
static DB_CONN: once_cell::sync::OnceCell<DbConn> = once_cell::sync::OnceCell::new();
async fn init_database() -> Result<&'static DbConn, DbErr> {
let database_uri = format!(
"postgres://{}:{}@{}:{}/{}",
CONFIG.db.user,
urlencoding::encode(&CONFIG.db.pass),
CONFIG.db.host,
CONFIG.db.port,
CONFIG.db.db,
);
let conn = Database::connect(database_uri).await?;
Ok(DB_CONN.get_or_init(move || conn))
}
pub async fn db_conn() -> Result<&'static DbConn, DbErr> {
match DB_CONN.get() {
Some(conn) => Ok(conn),
None => init_database().await,
}
}
#[cfg(test)]
mod unit_test {
use super::db_conn;
#[tokio::test]
async fn connect() {
assert!(db_conn().await.is_ok());
assert!(db_conn().await.is_ok());
}
}

View File

@ -0,0 +1,68 @@
use crate::config::CONFIG;
use redis::{Client, Connection, RedisError};
static REDIS_CLIENT: once_cell::sync::OnceCell<Client> = once_cell::sync::OnceCell::new();
fn init_redis() -> Result<Client, RedisError> {
let redis_url = {
let mut params = vec!["redis://".to_owned()];
let redis = if let Some(cache_server) = &CONFIG.cache_server {
cache_server
} else {
&CONFIG.redis
};
if let Some(user) = &redis.user {
params.push(user.to_string())
}
if let Some(pass) = &redis.pass {
params.push(format!(":{}@", pass))
}
params.push(redis.host.to_string());
params.push(format!(":{}", redis.port));
params.push(format!("/{}", redis.db));
params.concat()
};
Client::open(redis_url)
}
pub fn redis_conn() -> Result<Connection, RedisError> {
match REDIS_CLIENT.get() {
Some(client) => Ok(client.get_connection()?),
None => init_redis()?.get_connection(),
}
}
#[inline]
/// prefix redis key
pub fn key(key: impl ToString) -> String {
format!("{}:{}", CONFIG.redis_key_prefix, key.to_string())
}
#[cfg(test)]
mod unit_test {
use super::redis_conn;
use pretty_assertions::assert_eq;
use redis::Commands;
#[test]
fn connect() {
assert!(redis_conn().is_ok());
assert!(redis_conn().is_ok());
}
#[test]
fn access() {
let mut redis = redis_conn().unwrap();
let key = "CARGO_UNIT_TEST_KEY";
let value = "CARGO_UNIT_TEST_VALUE";
assert_eq!(redis.set::<&str, &str, String>(key, value).unwrap(), "OK");
assert_eq!(redis.get::<&str, String>(key).unwrap(), value);
assert_eq!(redis.del::<&str, u32>(key).unwrap(), 1);
}
}

View File

@ -4,4 +4,5 @@ pub mod config;
pub mod database;
pub mod misc;
pub mod model;
pub mod service;
pub mod util;

View File

@ -0,0 +1,49 @@
use crate::misc::meta::fetch_meta;
use sea_orm::DbErr;
/**
* @param host punycoded instance host
* @returns whether the given host should be blocked
*/
#[crate::export]
pub async fn is_blocked_server(host: &str) -> Result<bool, DbErr> {
Ok(fetch_meta(true)
.await?
.blocked_hosts
.iter()
.any(|blocked_host| {
host == blocked_host || host.ends_with(format!(".{}", blocked_host).as_str())
}))
}
/**
* @param host punycoded instance host
* @returns whether the given host should be limited
*/
#[crate::export]
pub async fn is_silenced_server(host: &str) -> Result<bool, DbErr> {
Ok(fetch_meta(true)
.await?
.silenced_hosts
.iter()
.any(|silenced_host| {
host == silenced_host || host.ends_with(format!(".{}", silenced_host).as_str())
}))
}
/**
* @param host punycoded instance host
* @returns whether the given host is allowlisted (this is always true if private mode is disabled)
*/
#[crate::export]
pub async fn is_allowed_server(host: &str) -> Result<bool, DbErr> {
let meta = fetch_meta(true).await?;
if !meta.private_mode.unwrap_or(false) {
return Ok(true);
}
if let Some(allowed_hosts) = meta.allowed_hosts {
return Ok(allowed_hosts.contains(&host.to_string()));
}
Ok(false)
}

View File

@ -4,7 +4,8 @@ use once_cell::sync::Lazy;
use regex::Regex;
use sea_orm::{prelude::*, QuerySelect};
#[crate::export(object)]
/// TODO: handle name collisions better
#[crate::export(object, js_name = "NoteLikeForCheckWordMute")]
pub struct NoteLike {
pub file_ids: Vec<String>,
pub user_id: Option<String>,

View File

@ -1,4 +1,4 @@
use crate::config::server::SERVER_CONFIG;
use crate::config::CONFIG;
#[derive(thiserror::Error, Debug)]
pub enum Error {
@ -14,21 +14,21 @@ pub enum Error {
pub fn get_full_ap_account(username: &str, host: Option<&str>) -> Result<String, Error> {
Ok(match host {
Some(host) => format!("{}@{}", username, to_puny(host)?),
None => format!("{}@{}", username, extract_host(&SERVER_CONFIG.url)?),
None => format!("{}@{}", username, extract_host(&CONFIG.url)?),
})
}
#[crate::export]
pub fn is_self_host(host: Option<&str>) -> Result<bool, Error> {
Ok(match host {
Some(host) => extract_host(&SERVER_CONFIG.url)? == to_puny(host)?,
Some(host) => extract_host(&CONFIG.url)? == to_puny(host)?,
None => true,
})
}
#[crate::export]
pub fn is_same_origin(uri: &str) -> Result<bool, Error> {
Ok(url::Url::parse(uri)?.origin().ascii_serialization() == SERVER_CONFIG.url)
Ok(url::Url::parse(uri)?.origin().ascii_serialization() == CONFIG.url)
}
#[crate::export]

View File

@ -0,0 +1,90 @@
/// TODO: handle name collisions better
#[crate::export(object, js_name = "NoteLikeForGetNoteSummary")]
pub struct NoteLike {
pub file_ids: Vec<String>,
pub text: Option<String>,
pub cw: Option<String>,
pub has_poll: bool,
}
#[crate::export]
pub fn get_note_summary(note: NoteLike) -> String {
let mut buf: Vec<String> = vec![];
if let Some(cw) = note.cw {
buf.push(cw)
} else if let Some(text) = note.text {
buf.push(text)
}
match note.file_ids.len() {
0 => (),
1 => buf.push("📎".to_string()),
n => buf.push(format!("📎 ({})", n)),
};
if note.has_poll {
buf.push("📊".to_string())
}
buf.join(" ")
}
#[cfg(test)]
mod unit_test {
use super::{get_note_summary, NoteLike};
use pretty_assertions::assert_eq;
#[test]
fn test_note_summary() {
let note = NoteLike {
file_ids: vec![],
text: Some("Hello world!".to_string()),
cw: None,
has_poll: false,
};
assert_eq!(get_note_summary(note), "Hello world!");
let note_with_cw = NoteLike {
file_ids: vec![],
text: Some("Hello world!".to_string()),
cw: Some("Content warning".to_string()),
has_poll: false,
};
assert_eq!(get_note_summary(note_with_cw), "Content warning");
let note_with_file_and_cw = NoteLike {
file_ids: vec!["9s7fmcqogiq4igin".to_string()],
text: None,
cw: Some("Selfie, no ec".to_string()),
has_poll: false,
};
assert_eq!(get_note_summary(note_with_file_and_cw), "Selfie, no ec 📎");
let note_with_files_only = NoteLike {
file_ids: vec![
"9s7fmcqogiq4igin".to_string(),
"9s7qrld5u14cey98".to_string(),
"9s7gebs5zgts4kca".to_string(),
"9s5z3e4vefqd29ee".to_string(),
],
text: None,
cw: None,
has_poll: false,
};
assert_eq!(get_note_summary(note_with_files_only), "📎 (4)");
let note_all = NoteLike {
file_ids: vec![
"9s7fmcqogiq4igin".to_string(),
"9s7qrld5u14cey98".to_string(),
"9s7gebs5zgts4kca".to_string(),
"9s5z3e4vefqd29ee".to_string(),
],
text: Some("Hello world!".to_string()),
cw: Some("Content warning".to_string()),
has_poll: true,
};
assert_eq!(get_note_summary(note_all), "Content warning 📎 (4) 📊");
}
}

View File

@ -1,9 +1,11 @@
pub mod acct;
pub mod check_server_block;
pub mod check_word_mute;
pub mod convert_host;
pub mod emoji;
pub mod escape_sql;
pub mod format_milliseconds;
pub mod get_note_summary;
pub mod mastodon_id;
pub mod meta;
pub mod nyaify;

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "abuse_user_report")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "access_token")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "ad")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "announcement")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "announcement_read")]
#[cfg_attr(
feature = "napi",

View File

@ -3,7 +3,8 @@
use super::sea_orm_active_enums::AntennaSrcEnum;
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "antenna")]
#[cfg_attr(
feature = "napi",

View File

@ -1,49 +0,0 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
#[sea_orm(table_name = "antenna_note")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub id: String,
#[sea_orm(column_name = "noteId")]
pub note_id: String,
#[sea_orm(column_name = "antennaId")]
pub antenna_id: String,
pub read: bool,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::antenna::Entity",
from = "Column::AntennaId",
to = "super::antenna::Column::Id",
on_update = "NoAction",
on_delete = "Cascade"
)]
Antenna,
#[sea_orm(
belongs_to = "super::note::Entity",
from = "Column::NoteId",
to = "super::note::Column::Id",
on_update = "NoAction",
on_delete = "Cascade"
)]
Note,
}
impl Related<super::antenna::Entity> for Entity {
fn to() -> RelationDef {
Relation::Antenna.def()
}
}
impl Related<super::note::Entity> for Entity {
fn to() -> RelationDef {
Relation::Note.def()
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "app")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "attestation_challenge")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "auth_session")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "blocking")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "channel")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "channel_following")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "channel_note_pining")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "clip")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "clip_note")]
#[cfg_attr(
feature = "napi",

View File

@ -1,8 +1,10 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.15
use super::sea_orm_active_enums::DriveFileUsageHintEnum;
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "drive_file")]
#[cfg_attr(
feature = "napi",
@ -52,6 +54,8 @@ pub struct Model {
pub request_headers: Option<Json>,
#[sea_orm(column_name = "requestIp")]
pub request_ip: Option<String>,
#[sea_orm(column_name = "usageHint")]
pub usage_hint: Option<DriveFileUsageHintEnum>,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "drive_folder")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "emoji")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "follow_request")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "following")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "gallery_like")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "gallery_post")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "hashtag")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "instance")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "messaging_message")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "meta")]
#[cfg_attr(
feature = "napi",
@ -173,6 +174,8 @@ pub struct Model {
pub more_urls: Json,
#[sea_orm(column_name = "markLocalFilesNsfwByDefault")]
pub mark_local_files_nsfw_by_default: bool,
#[sea_orm(column_name = "antennaLimit")]
pub antenna_limit: i32,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "migrations")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "moderation_log")]
#[cfg_attr(
feature = "napi",

View File

@ -3,7 +3,8 @@
use super::sea_orm_active_enums::MutedNoteReasonEnum;
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "muted_note")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "muting")]
#[cfg_attr(
feature = "napi",

View File

@ -3,7 +3,8 @@
use super::sea_orm_active_enums::NoteVisibilityEnum;
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "note")]
#[cfg_attr(
feature = "napi",
@ -21,6 +22,7 @@ pub struct Model {
#[sea_orm(column_type = "Text", nullable)]
pub text: Option<String>,
pub name: Option<String>,
#[sea_orm(column_type = "Text", nullable)]
pub cw: Option<String>,
#[sea_orm(column_name = "userId")]
pub user_id: String,

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "note_edit")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "note_favorite")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "note_file")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "note_reaction")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "note_thread_muting")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "note_unread")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "note_watching")]
#[cfg_attr(
feature = "napi",

View File

@ -3,7 +3,8 @@
use super::sea_orm_active_enums::NotificationTypeEnum;
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "notification")]
#[cfg_attr(
feature = "napi",

View File

@ -3,7 +3,8 @@
use super::sea_orm_active_enums::PageVisibilityEnum;
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "page")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "page_like")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "password_reset_request")]
#[cfg_attr(
feature = "napi",

View File

@ -3,7 +3,8 @@
use super::sea_orm_active_enums::PollNotevisibilityEnum;
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "poll")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "poll_vote")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "promo_note")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "promo_read")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "registration_ticket")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "registry_item")]
#[cfg_attr(
feature = "napi",

View File

@ -3,7 +3,8 @@
use super::sea_orm_active_enums::RelayStatusEnum;
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "relay")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "renote_muting")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "reply_muting")]
#[cfg_attr(
feature = "napi",

View File

@ -2,9 +2,12 @@
use sea_orm::entity::prelude::*;
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
#[derive(
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(not(feature = "napi"), derive(Clone))]
#[cfg_attr(feature = "napi", napi_derive::napi)]
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "antenna_src_enum")]
pub enum AntennaSrcEnum {
#[sea_orm(string_value = "all")]
@ -20,9 +23,29 @@ pub enum AntennaSrcEnum {
#[sea_orm(string_value = "users")]
Users,
}
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
#[derive(
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(not(feature = "napi"), derive(Clone))]
#[cfg_attr(feature = "napi", napi_derive::napi)]
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
#[sea_orm(
rs_type = "String",
db_type = "Enum",
enum_name = "drive_file_usage_hint_enum"
)]
pub enum DriveFileUsageHintEnum {
#[sea_orm(string_value = "userAvatar")]
UserAvatar,
#[sea_orm(string_value = "userBanner")]
UserBanner,
}
#[derive(
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(not(feature = "napi"), derive(Clone))]
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
#[sea_orm(
rs_type = "String",
db_type = "Enum",
@ -38,9 +61,12 @@ pub enum MutedNoteReasonEnum {
#[sea_orm(string_value = "word")]
Word,
}
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
#[derive(
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(not(feature = "napi"), derive(Clone))]
#[cfg_attr(feature = "napi", napi_derive::napi)]
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
#[sea_orm(
rs_type = "String",
db_type = "Enum",
@ -58,9 +84,12 @@ pub enum NoteVisibilityEnum {
#[sea_orm(string_value = "specified")]
Specified,
}
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
#[derive(
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(not(feature = "napi"), derive(Clone))]
#[cfg_attr(feature = "napi", napi_derive::napi)]
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
#[sea_orm(
rs_type = "String",
db_type = "Enum",
@ -92,9 +121,12 @@ pub enum NotificationTypeEnum {
#[sea_orm(string_value = "reply")]
Reply,
}
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
#[derive(
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(not(feature = "napi"), derive(Clone))]
#[cfg_attr(feature = "napi", napi_derive::napi)]
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
#[sea_orm(
rs_type = "String",
db_type = "Enum",
@ -108,9 +140,12 @@ pub enum PageVisibilityEnum {
#[sea_orm(string_value = "specified")]
Specified,
}
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
#[derive(
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(not(feature = "napi"), derive(Clone))]
#[cfg_attr(feature = "napi", napi_derive::napi)]
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
#[sea_orm(
rs_type = "String",
db_type = "Enum",
@ -126,9 +161,12 @@ pub enum PollNotevisibilityEnum {
#[sea_orm(string_value = "specified")]
Specified,
}
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
#[derive(
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(not(feature = "napi"), derive(Clone))]
#[cfg_attr(feature = "napi", napi_derive::napi)]
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "relay_status_enum")]
pub enum RelayStatusEnum {
#[sea_orm(string_value = "accepted")]
@ -138,9 +176,12 @@ pub enum RelayStatusEnum {
#[sea_orm(string_value = "requesting")]
Requesting,
}
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
#[derive(
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(not(feature = "napi"), derive(Clone))]
#[cfg_attr(feature = "napi", napi_derive::napi)]
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
#[sea_orm(
rs_type = "String",
db_type = "Enum",
@ -156,9 +197,12 @@ pub enum UserEmojimodpermEnum {
#[sea_orm(string_value = "unauthorized")]
Unauthorized,
}
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
#[derive(
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(not(feature = "napi"), derive(Clone))]
#[cfg_attr(feature = "napi", napi_derive::napi)]
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
#[sea_orm(
rs_type = "String",
db_type = "Enum",
@ -172,9 +216,12 @@ pub enum UserProfileFfvisibilityEnum {
#[sea_orm(string_value = "public")]
Public,
}
#[derive(Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
#[derive(
Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, serde::Serialize, serde::Deserialize,
)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(not(feature = "napi"), derive(Clone))]
#[cfg_attr(feature = "napi", napi_derive::napi)]
#[cfg_attr(feature = "napi", napi_derive::napi(string_enum = "camelCase"))]
#[sea_orm(
rs_type = "String",
db_type = "Enum",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "signin")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "sw_subscription")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "used_username")]
#[cfg_attr(
feature = "napi",

View File

@ -3,7 +3,8 @@
use super::sea_orm_active_enums::UserEmojimodpermEnum;
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "user")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "user_group")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "user_group_invitation")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "user_group_invite")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "user_group_joining")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "user_ip")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "user_keypair")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "user_list")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "user_list_joining")]
#[cfg_attr(
feature = "napi",

View File

@ -2,7 +2,8 @@
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[sea_orm(table_name = "user_note_pining")]
#[cfg_attr(
feature = "napi",

Some files were not shown because too many files have changed in this diff Show More