Merge branch 'main' into mk.absturztau.be

This commit is contained in:
Puniko 2022-12-18 14:43:12 +01:00
commit 3900d2f716
326 changed files with 2060 additions and 3384 deletions

View file

@ -133,3 +133,10 @@ redis:
#allowedPrivateNetworks: [ #allowedPrivateNetworks: [
# '127.0.0.1/32' # '127.0.0.1/32'
#] #]
# images used on error screens. You can use absolute or relative URLs.
# If you use relative URLs, be aware that the URL may be used on different pages/paths, so the path component should be absolute.
#images:
# info: /twemoji/1f440.svg
# notFound: /twemoji/2049.svg
# error: /twemoji/1f480.svg

View file

@ -1,6 +1,6 @@
.autogen .autogen
.vscode
.config .config
.woodpecker
Dockerfile Dockerfile
build/ build/
built/ built/

View file

@ -2,9 +2,10 @@ root = true
[*] [*]
indent_style = tab indent_style = tab
indent_size = 2 indent_size = 4
charset = utf-8 charset = utf-8
insert_final_newline = true insert_final_newline = true
[*.yml] [*.yml]
indent_style = space indent_style = space
indent_size = 2

6
.gitattributes vendored
View file

@ -1,7 +1 @@
*.svg -diff -text *.svg -diff -text
*.psd -diff -text
*.ai -diff -text
*.mqo -diff -text
*.glb -diff -text
*.blend -diff -text
*.afdesign -diff -text

2
.gitignore vendored
View file

@ -1,6 +1,6 @@
# Visual Studio Code # Visual Studio Code
/.vscode /.vscode
!/.vscode/extensions.json /.vsls.json
# Intelij-IDEA # Intelij-IDEA
/.idea /.idea

View file

@ -1,8 +0,0 @@
{
"recommendations": [
"editorconfig.editorconfig",
"dbaeumer.vscode-eslint",
"Vue.volar",
"Vue.vscode-typescript-vue-plugin"
]
}

View file

@ -1,4 +0,0 @@
{
"$schema": "http://json.schemastore.org/vsls",
"gitignore": "exclude"
}

22
.woodpecker/lint-sw.yml Normal file
View file

@ -0,0 +1,22 @@
clone:
git:
image: woodpeckerci/plugin-git
settings:
depth: 1 # CI does not need commit history
recursive: true
pipeline:
install:
when:
event:
- pull_request
image: node:18.6.0
commands:
- yarn install
lint:
when:
event:
- pull_request
image: node:18.6.0
commands:
- yarn workspace sw run lint

View file

@ -316,8 +316,8 @@ This does not apply when using the Composition API since reactivation is manual.
If you import json in TypeScript, the json file will be spit out together with the TypeScript file into the dist directory when compiling with tsc. This behavior may cause unintentional rewriting of files, so when importing json files, be sure to check whether the files are allowed to be rewritten or not. If you do not want the file to be rewritten, you should make sure that the file can be rewritten by importing the json file. If you do not want the file to be rewritten, use functions such as `fs.readFileSync` to read the file instead of importing it. If you import json in TypeScript, the json file will be spit out together with the TypeScript file into the dist directory when compiling with tsc. This behavior may cause unintentional rewriting of files, so when importing json files, be sure to check whether the files are allowed to be rewritten or not. If you do not want the file to be rewritten, you should make sure that the file can be rewritten by importing the json file. If you do not want the file to be rewritten, use functions such as `fs.readFileSync` to read the file instead of importing it.
### Component style definitions do not have a `margin` ### Component style definitions do not have a `margin`
Setting the `margin` of a component may be confusing. ~~Setting the `margin` of a component may be confusing. Instead, it should always be the user of a component that sets a `margin`.~~
Instead, it should always be the user of a component that sets a `margin`. This was a philosophy used previously. Hoever it now seems a better idea to add a default margin to the top level element of a component which can be easily overwritten on the usage of that component with a `style` attribute.
### Do not use the word "follow" in HTML class names ### Do not use the word "follow" in HTML class names
This has caused things to be blocked by an ad blocker in the past. This has caused things to be blocked by an ad blocker in the past.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 317 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

42
docs/oauth.md Normal file
View file

@ -0,0 +1,42 @@
# 3rd party access
Foundkey supports:
- OAuth 2.0 Authorization Code grant per [RFC 6749](https://www.rfc-editor.org/rfc/rfc6749).
- OAuth Bearer Token Usage per [RFC 6750](https://www.rfc-editor.org/rfc/rfc6750).
- Proof Key for Code Exchange (PKCE) per [RFC 7636](https://www.rfc-editor.org/rfc/rfc7636).
- OAuth 2.0 Authorization Server Metadata per [RFC 8414](https://www.rfc-editor.org/rfc/rfc8414.html).
# Discovery
Because the implementation may change in the future, it is recommended that you use OAuth 2.0 Authorization Server Metadata a.k.a. OpenID Connect Discovery.
In short, this means that to discover the URLs for the grant endpoints you should request `/.well-known/oauth-authorization-server`, which is a JSON object.
From there, `authorization_endpoint` and `token_endpoint` will probably be most interesting to you.
The definitions of all data fields are to be found in [RFC 8414, section 2](https://www.rfc-editor.org/rfc/rfc8414#section-2).
# App registration
Before using the OAuth grant you need to register your application.
Currently you will need to use the pre-existing Misskey API to register, though Dynamic Client Registration may be implemented at a later point.
(You'd be able to tell from the Authorization Server Metadata, see above.)
The data you will need to know before registering is the following:
- a name for your app,
- a short description to be shown to users,
- which API permissions you need, and
- the callback URL you want to use.
There can only be 1 callback URL per registration.
Note that you can specify permissions a 2nd time in the OAuth flow.
If you do not provide permissions again in the grant flow, the default is to use all permissions you gave when registering the app.
If you do provide permissions in the grant flow, permissions that were not registered will never be granted.
A list of available permissions can be viewed on any Foundkey instance by going to the API documentation at `/api-doc`.
To register your app you need to `POST` to `/api/app/create`.
The body of the request must be a JSON object with the following keys:
- `name` (string): a name for your app,
- `description` (string): a short description to be shown to users,
- `permission` (array of permission names) which API permissions you need, and
- `callbackUrl` (string): the callback URL you want to use.
If successful (HTTP response code 200) you will receive back a JSON object containing among other things:
- `id` (string): the client ID
- `secret` (string): the client secret
With these credentials you should be able to use the Authorization Code grant to obtain authorization.

View file

@ -36,7 +36,7 @@ gulp.task('copy:client:locales', cb => {
}); });
gulp.task('build:backend:script', () => { gulp.task('build:backend:script', () => {
return gulp.src(['./packages/backend/src/server/web/boot.js', './packages/backend/src/server/web/bios.js', './packages/backend/src/server/web/cli.js']) return gulp.src(['./packages/backend/src/server/web/boot.js'])
.pipe(replace('LANGS', JSON.stringify(Object.keys(locales)))) .pipe(replace('LANGS', JSON.stringify(Object.keys(locales))))
.pipe(terser({ .pipe(terser({
toplevel: true toplevel: true
@ -45,7 +45,7 @@ gulp.task('build:backend:script', () => {
}); });
gulp.task('build:backend:style', () => { gulp.task('build:backend:style', () => {
return gulp.src(['./packages/backend/src/server/web/style.css', './packages/backend/src/server/web/bios.css', './packages/backend/src/server/web/cli.css']) return gulp.src(['./packages/backend/src/server/web/style.css'])
.pipe(cssnano({ .pipe(cssnano({
zindex: false zindex: false
})) }))

View file

@ -293,9 +293,6 @@ dayX: "{day}"
monthX: "{month}" monthX: "{month}"
yearX: "{year}" yearX: "{year}"
pages: "الصفحات" pages: "الصفحات"
integration: "التكامل"
connectService: "اتصل"
disconnectService: "اقطع الاتصال"
enableLocalTimeline: "تفعيل الخيط المحلي" enableLocalTimeline: "تفعيل الخيط المحلي"
enableGlobalTimeline: "تفعيل الخيط الزمني الشامل" enableGlobalTimeline: "تفعيل الخيط الزمني الشامل"
disablingTimelinesInfo: "سيتمكن المديرون والمشرفون من الوصول إلى كل الخيوط الزمنية\ disablingTimelinesInfo: "سيتمكن المديرون والمشرفون من الوصول إلى كل الخيوط الزمنية\
@ -402,7 +399,6 @@ normalPassword: "الكلمة السرية جيدة"
strongPassword: "الكلمة السرية قوية" strongPassword: "الكلمة السرية قوية"
passwordMatched: "التطابق صحيح!" passwordMatched: "التطابق صحيح!"
passwordNotMatched: "غير متطابقتان" passwordNotMatched: "غير متطابقتان"
signinWith: "الولوج عبر {x}"
signinFailed: "فشل الولوج، خطأ في اسم المستخدم أو كلمة المرور." signinFailed: "فشل الولوج، خطأ في اسم المستخدم أو كلمة المرور."
tapSecurityKey: "أنقر مفتاح الأمان" tapSecurityKey: "أنقر مفتاح الأمان"
or: "أو" or: "أو"

View file

@ -308,9 +308,6 @@ dayX: "{day}"
monthX: "{month}" monthX: "{month}"
yearX: "{year}" yearX: "{year}"
pages: "পৃষ্ঠা" pages: "পৃষ্ঠা"
integration: "ইন্টিগ্রেশন"
connectService: "সংযুক্ত করুন"
disconnectService: "সংযোগ বিচ্ছিন্ন করুন"
enableLocalTimeline: "স্থানীয় টাইমলাইন চালু করুন" enableLocalTimeline: "স্থানীয় টাইমলাইন চালু করুন"
enableGlobalTimeline: "গ্লোবাল টাইমলাইন চালু করুন" enableGlobalTimeline: "গ্লোবাল টাইমলাইন চালু করুন"
disablingTimelinesInfo: "আপনি এই টাইমলাইনগুলি বন্ধ করলেও প্রশাসক এবং মডারেটররা এই\ disablingTimelinesInfo: "আপনি এই টাইমলাইনগুলি বন্ধ করলেও প্রশাসক এবং মডারেটররা এই\
@ -417,7 +414,6 @@ normalPassword: "সাধারণ পাসওয়ার্ড"
strongPassword: "শক্তিশালী পাসওয়ার্ড" strongPassword: "শক্তিশালী পাসওয়ার্ড"
passwordMatched: "মিলেছে" passwordMatched: "মিলেছে"
passwordNotMatched: "মিলেনি" passwordNotMatched: "মিলেনি"
signinWith: "{x} এর সাহায্যে সাইন ইন করুন"
signinFailed: "লগ ইন করা যায়নি। আপনার ব্যবহারকারীর নাম এবং পাসওয়ার্ড চেক করুন." signinFailed: "লগ ইন করা যায়নি। আপনার ব্যবহারকারীর নাম এবং পাসওয়ার্ড চেক করুন."
tapSecurityKey: "সিকিউরিটি কী স্পর্শ করুন" tapSecurityKey: "সিকিউরিটি কী স্পর্শ করুন"
or: "অথবা" or: "অথবা"

View file

@ -277,9 +277,6 @@ dayX: "{day}"
monthX: "{month}" monthX: "{month}"
yearX: "{year}" yearX: "{year}"
pages: "Stránky" pages: "Stránky"
integration: "Integrace"
connectService: "Připojit"
disconnectService: "Odpojit"
enableLocalTimeline: "Povolit lokální čas" enableLocalTimeline: "Povolit lokální čas"
enableGlobalTimeline: "Povolit globální čas" enableGlobalTimeline: "Povolit globální čas"
enableRegistration: "Povolit registraci novým uživatelům" enableRegistration: "Povolit registraci novým uživatelům"
@ -353,7 +350,6 @@ normalPassword: "Dobré heslo"
strongPassword: "Silné heslo" strongPassword: "Silné heslo"
passwordMatched: "Hesla se schodují" passwordMatched: "Hesla se schodují"
passwordNotMatched: "Hesla se neschodují" passwordNotMatched: "Hesla se neschodují"
signinWith: "Přihlásit se s {x}"
signinFailed: "Nelze se přihlásit. Zkontrolujte prosím své uživatelské jméno a heslo." signinFailed: "Nelze se přihlásit. Zkontrolujte prosím své uživatelské jméno a heslo."
or: "Nebo" or: "Nebo"
language: "Jazyk" language: "Jazyk"

View file

@ -321,9 +321,6 @@ dayX: "{day}"
monthX: "{month}" monthX: "{month}"
yearX: "{year}" yearX: "{year}"
pages: "Seiten" pages: "Seiten"
integration: "Integration"
connectService: "Verbinden"
disconnectService: "Trennen"
enableLocalTimeline: "Lokale Chronik aktivieren" enableLocalTimeline: "Lokale Chronik aktivieren"
enableGlobalTimeline: "Globale Chronik aktivieren" enableGlobalTimeline: "Globale Chronik aktivieren"
disablingTimelinesInfo: "Administratoren und Moderatoren haben immer Zugriff auf alle\ disablingTimelinesInfo: "Administratoren und Moderatoren haben immer Zugriff auf alle\
@ -433,7 +430,6 @@ normalPassword: "Durchschnittliches Passwort"
strongPassword: "Starkes Passwort" strongPassword: "Starkes Passwort"
passwordMatched: "Stimmt überein" passwordMatched: "Stimmt überein"
passwordNotMatched: "Stimmt nicht überein" passwordNotMatched: "Stimmt nicht überein"
signinWith: "Mit {x} anmelden"
signinFailed: "Anmeldung fehlgeschlagen. Überprüfe Benutzername und Passswort." signinFailed: "Anmeldung fehlgeschlagen. Überprüfe Benutzername und Passswort."
tapSecurityKey: "Tippe deinen Sicherheitsschlüssel an" tapSecurityKey: "Tippe deinen Sicherheitsschlüssel an"
or: "Oder" or: "Oder"
@ -1373,18 +1369,6 @@ recommended: "Empfehlung"
check: "Check" check: "Check"
maxCustomEmojiPicker: Maximale Anzahl vorgeschlagener benutzerdefinierter Emoji maxCustomEmojiPicker: Maximale Anzahl vorgeschlagener benutzerdefinierter Emoji
maxUnicodeEmojiPicker: Maximale Anzahl vorgeschlagener Unicode-Emoji maxUnicodeEmojiPicker: Maximale Anzahl vorgeschlagener Unicode-Emoji
_services:
_discord:
connected: 'Discord: @{username}#{discriminator} wurde mit Foundkey-Account @{mkUsername}
verknüpft!'
disconnected: Discord-Verknüpfung wurde entfernt.
_twitter:
connected: Twitter-Account @{twitterUserName} wurde mit Foundkey-Account @{userName}
verknüpft!
disconnected: Twitter-Verknüpfung wurde entfernt.
_github:
connected: GitHub-Account @{login} wurde mit Foundkey-Account @{userName} verknüpft!
disconnected: GitHub-Verknüpfung wurde entfernt.
documentation: Dokumentation documentation: Dokumentation
signinHistoryExpires: Frühere Login-Versuche werden aus Datenschutzgründen nach 60 signinHistoryExpires: Frühere Login-Versuche werden aus Datenschutzgründen nach 60
Tagen automatisch gelöscht. Tagen automatisch gelöscht.

View file

@ -96,6 +96,8 @@ unfollow: "Unfollow"
followRequestPending: "Follow request pending" followRequestPending: "Follow request pending"
renote: "Renote" renote: "Renote"
unrenote: "Take back renote" unrenote: "Take back renote"
unrenoteAll: "Take back all renotes"
unrenoteAllConfirm: "Are you sure that you want to take back all renotes of this note?"
quote: "Quote" quote: "Quote"
pinnedNote: "Pinned note" pinnedNote: "Pinned note"
you: "You" you: "You"
@ -187,7 +189,7 @@ clearCachedFiles: "Clear cache"
clearCachedFilesConfirm: "Are you sure that you want to delete all cached remote files?" clearCachedFilesConfirm: "Are you sure that you want to delete all cached remote files?"
blockedInstances: "Blocked Instances" blockedInstances: "Blocked Instances"
blockedInstancesDescription: "List the hostnames of the instances that you want to\ blockedInstancesDescription: "List the hostnames of the instances that you want to\
\ block. Listed instances will no longer be able to communicate with this instance. Non-ASCII domain names must be encoded in punycode. You can use an asterisk (*) as a placeholder for zero or more character(s)." \ block. Listed instances will no longer be able to communicate with this instance. Non-ASCII domain names must be encoded in punycode. Subdomains of the listed instances will also be blocked."
muteAndBlock: "Mutes and Blocks" muteAndBlock: "Mutes and Blocks"
mutedUsers: "Muted users" mutedUsers: "Muted users"
blockedUsers: "Blocked users" blockedUsers: "Blocked users"
@ -311,9 +313,6 @@ dayX: "{day}"
monthX: "{month}" monthX: "{month}"
yearX: "{year}" yearX: "{year}"
pages: "Pages" pages: "Pages"
integration: "Integration"
connectService: "Connect"
disconnectService: "Disconnect"
enableLocalTimeline: "Enable local timeline" enableLocalTimeline: "Enable local timeline"
enableGlobalTimeline: "Enable global timeline" enableGlobalTimeline: "Enable global timeline"
disablingTimelinesInfo: "Adminstrators and Moderators will always have access to all\ disablingTimelinesInfo: "Adminstrators and Moderators will always have access to all\
@ -420,7 +419,6 @@ normalPassword: "Average password"
strongPassword: "Strong password" strongPassword: "Strong password"
passwordMatched: "Matches" passwordMatched: "Matches"
passwordNotMatched: "Does not match" passwordNotMatched: "Does not match"
signinWith: "Sign in with {x}"
signinFailed: "Unable to sign in. The entered username or password is incorrect." signinFailed: "Unable to sign in. The entered username or password is incorrect."
tapSecurityKey: "Tap your security key" tapSecurityKey: "Tap your security key"
or: "Or" or: "Or"
@ -829,6 +827,10 @@ setTag: "Set tag"
addTag: "Add tag" addTag: "Add tag"
removeTag: "Remove tag" removeTag: "Remove tag"
externalCssSnippets: "Some CSS snippets for your inspiration (not managed by FoundKey)" externalCssSnippets: "Some CSS snippets for your inspiration (not managed by FoundKey)"
oauthErrorGoBack: "An error happened while trying to authenticate a 3rd party app.\
\ Please go back and try again."
appAuthorization: "App authorization"
noPermissionsRequested: "(No permissions requested.)"
_emailUnavailable: _emailUnavailable:
used: "This email address is already being used" used: "This email address is already being used"
format: "The format of this email address is invalid" format: "The format of this email address is invalid"
@ -1079,38 +1081,37 @@ _2fa:
\ authentication via hardware security keys that support FIDO2 to further secure\ \ authentication via hardware security keys that support FIDO2 to further secure\
\ your account." \ your account."
_permissions: _permissions:
"read:account": "View your account information" "read:account": "Read account information"
"write:account": "Edit your account information" "write:account": "Edit account information"
"read:blocks": "View your list of blocked users" "read:blocks": "Read which users are blocked"
"write:blocks": "Edit your list of blocked users" "write:blocks": "Block and unblock users"
"read:drive": "Access your Drive files and folders" "read:drive": "List files and folders in the drive"
"write:drive": "Edit or delete your Drive files and folders" "write:drive": "Create, change and delete files in the drive"
"read:favorites": "View your list of favorites" "read:favorites": "List favourited notes"
"write:favorites": "Edit your list of favorites" "write:favorites": "Favorite and unfavorite notes"
"read:following": "View information on who you follow" "read:following": "List followed and following users"
"write:following": "Follow or unfollow other accounts" "write:following": "Follow and unfollow other users"
"read:messaging": "View your chats" "read:messaging": "View chat messages and history"
"write:messaging": "Compose or delete chat messages" "write:messaging": "Create and delete chat messages"
"read:mutes": "View your list of muted users" "read:mutes": "List users which are muted or whose renotes are muted"
"write:mutes": "Edit your list of muted users" "write:mutes": "Mute and unmute users or their renotes"
"write:notes": "Compose or delete notes" "write:notes": "Create and delete notes"
"read:notifications": "View your notifications" "read:notifications": "Read notifications"
"write:notifications": "Manage your notifications" "write:notifications": "Mark notifications as read and create custom notifications"
"read:reactions": "View your reactions" "write:reactions": "Create and delete reactions"
"write:reactions": "Edit your reactions" "write:votes": "Vote in polls"
"write:votes": "Vote on a poll" "read:pages": "List and read pages"
"read:pages": "View your pages" "write:pages": "Create, change and delete pages"
"write:pages": "Edit or delete your pages" "read:page-likes": "List and read page likes"
"read:page-likes": "View your likes on pages" "write:page-likes": "Like and unlike pages"
"write:page-likes": "Edit your likes on pages" "read:user-groups": "List and view joined, owned and invited to groups"
"read:user-groups": "View your user groups" "write:user-groups": "Create, modify, delete, transfer, join and leave groups. Invite and ban others from groups. Accept and reject group invitations."
"write:user-groups": "Edit or delete your user groups" "read:channels": "List and read followed and joined channels"
"read:channels": "View your channels" "write:channels": "Create, modify, follow and unfollow channels"
"write:channels": "Edit your channels" "read:gallery": "List and read gallery posts"
"read:gallery": "View your gallery" "write:gallery": "Create, modify and delete gallery posts"
"write:gallery": "Edit your gallery" "read:gallery-likes": "List and read gallery post likes"
"read:gallery-likes": "View your list of liked gallery posts" "write:gallery-likes": "Like and unlike gallery posts"
"write:gallery-likes": "Edit your list of liked gallery posts"
_auth: _auth:
shareAccess: "Would you like to authorize \"{name}\" to access this account?" shareAccess: "Would you like to authorize \"{name}\" to access this account?"
shareAccessAsk: "Are you sure you want to authorize this application to access your\ shareAccessAsk: "Are you sure you want to authorize this application to access your\
@ -1342,16 +1343,6 @@ _deck:
list: "List" list: "List"
mentions: "Mentions" mentions: "Mentions"
direct: "Direct notes" direct: "Direct notes"
_services:
_discord:
connected: "Discord: @{username}#{discriminator} connected to FoundKey: @{mkUsername}!"
disconnected: "Discord linkage has been removed."
_twitter:
connected: "Twitter: @{twitterUserName} connected to FoundKey: @{userName}!"
disconnected: "Twitter linkage has been removed."
_github:
connected: "GitHub: @{login} connected to FoundKey: @{userName}!"
disconnected: "GitHub linkage has been removed."
_translationService: _translationService:
_deepl: _deepl:
authKey: "DeepL Auth Key" authKey: "DeepL Auth Key"

View file

@ -311,9 +311,6 @@ dayX: "Día {day}"
monthX: "Mes {month}" monthX: "Mes {month}"
yearX: "Año {year}" yearX: "Año {year}"
pages: "Páginas" pages: "Páginas"
integration: "Integración"
connectService: "Conectar"
disconnectService: "Desconectar"
enableLocalTimeline: "Habilitar linea de tiempo local" enableLocalTimeline: "Habilitar linea de tiempo local"
enableGlobalTimeline: "Habilitar linea de tiempo global" enableGlobalTimeline: "Habilitar linea de tiempo global"
disablingTimelinesInfo: "Aunque se desactiven estas lineas de tiempo, por conveniencia\ disablingTimelinesInfo: "Aunque se desactiven estas lineas de tiempo, por conveniencia\
@ -420,7 +417,6 @@ normalPassword: "Buena contraseña"
strongPassword: "Muy buena contraseña" strongPassword: "Muy buena contraseña"
passwordMatched: "Correcto" passwordMatched: "Correcto"
passwordNotMatched: "Las contraseñas no son las mismas" passwordNotMatched: "Las contraseñas no son las mismas"
signinWith: "Inicie sesión con {x}"
signinFailed: "Autenticación fallida. Asegúrate de haber usado el nombre de usuario\ signinFailed: "Autenticación fallida. Asegúrate de haber usado el nombre de usuario\
\ y contraseña correctos." \ y contraseña correctos."
tapSecurityKey: "Toque la clave de seguridad" tapSecurityKey: "Toque la clave de seguridad"

View file

@ -311,9 +311,6 @@ dayX: "{day}"
monthX: "{month}" monthX: "{month}"
yearX: "{year}" yearX: "{year}"
pages: "Pages" pages: "Pages"
integration: "Intégrations"
connectService: "Connexion"
disconnectService: "Déconnexion"
enableLocalTimeline: "Activer le fil local" enableLocalTimeline: "Activer le fil local"
enableGlobalTimeline: "Activer le fil global" enableGlobalTimeline: "Activer le fil global"
disablingTimelinesInfo: "Même si vous désactivez ces fils, les administrateur·rice·s\ disablingTimelinesInfo: "Même si vous désactivez ces fils, les administrateur·rice·s\
@ -423,7 +420,6 @@ normalPassword: "Mot de passe acceptable"
strongPassword: "Mot de passe fort" strongPassword: "Mot de passe fort"
passwordMatched: "Les mots de passe correspondent" passwordMatched: "Les mots de passe correspondent"
passwordNotMatched: "Les mots de passe ne correspondent pas" passwordNotMatched: "Les mots de passe ne correspondent pas"
signinWith: "Se connecter avec {x}"
signinFailed: "Échec dauthentification. Veuillez vérifier que votre nom dutilisateur\ signinFailed: "Échec dauthentification. Veuillez vérifier que votre nom dutilisateur\
\ et mot de passe sont corrects." \ et mot de passe sont corrects."
tapSecurityKey: "Appuyez sur votre clé de sécurité" tapSecurityKey: "Appuyez sur votre clé de sécurité"
@ -1331,18 +1327,6 @@ _deck:
list: "Listes" list: "Listes"
mentions: "Mentions" mentions: "Mentions"
direct: "Direct" direct: "Direct"
_services:
_discord:
connected: '@{username}#{discriminator} sur Discord est connecté à @{mkUsername}
sur FoundKey !'
disconnected: La liaison avec Discord à été supprimée.
_twitter:
connected: '@{twitterUserName} sur Twitter est connecté à @{userName} sur FoundKey
!'
disconnected: La liaison avec Twitter à été supprimée.
_github:
disconnected: La liaison avec Github à été supprimée.
connected: '@{login} sur Github est connecté à @{userName} sur FoundKey !'
exportAll: Tout exporter exportAll: Tout exporter
stopActivityDeliveryDescription: L'activité locale ne sera pas envoyé à cette instance. stopActivityDeliveryDescription: L'activité locale ne sera pas envoyé à cette instance.
La réception de l'activité continuera de fonctionner comme avant. La réception de l'activité continuera de fonctionner comme avant.

View file

@ -310,9 +310,6 @@ dayX: "{day}"
monthX: "{month}" monthX: "{month}"
yearX: "{year}" yearX: "{year}"
pages: "Halaman" pages: "Halaman"
integration: "Integrasi"
connectService: "Sambungkan"
disconnectService: "Putuskan"
enableLocalTimeline: "Nyalakan linimasa lokal" enableLocalTimeline: "Nyalakan linimasa lokal"
enableGlobalTimeline: "Nyalakan linimasa global" enableGlobalTimeline: "Nyalakan linimasa global"
disablingTimelinesInfo: "Admin dan Moderator akan selalu memiliki akses ke semua linimasa\ disablingTimelinesInfo: "Admin dan Moderator akan selalu memiliki akses ke semua linimasa\
@ -419,7 +416,6 @@ normalPassword: "Kata sandi baik"
strongPassword: "Kata sandi kuat" strongPassword: "Kata sandi kuat"
passwordMatched: "Kata sandi sama" passwordMatched: "Kata sandi sama"
passwordNotMatched: "Kata sandi tidak sama" passwordNotMatched: "Kata sandi tidak sama"
signinWith: "Masuk dengan {x}"
signinFailed: "Tidak dapat masuk. Nama pengguna atau kata sandi yang kamu masukkan\ signinFailed: "Tidak dapat masuk. Nama pengguna atau kata sandi yang kamu masukkan\
\ salah." \ salah."
tapSecurityKey: "Ketuk kunci keamanan kamu" tapSecurityKey: "Ketuk kunci keamanan kamu"

View file

@ -304,9 +304,6 @@ dayX: "{day}"
monthX: "{month}" monthX: "{month}"
yearX: "{year}" yearX: "{year}"
pages: "Pagine" pages: "Pagine"
integration: "App collegate"
connectService: "Connessione"
disconnectService: "Disconnessione "
enableLocalTimeline: "Abilita Timeline locale" enableLocalTimeline: "Abilita Timeline locale"
enableGlobalTimeline: "Abilita Timeline federata" enableGlobalTimeline: "Abilita Timeline federata"
disablingTimelinesInfo: "Anche se disabiliti queste timeline, gli amministratori e\ disablingTimelinesInfo: "Anche se disabiliti queste timeline, gli amministratori e\
@ -413,7 +410,6 @@ normalPassword: "Password buona"
strongPassword: "Password forte" strongPassword: "Password forte"
passwordMatched: "Corretta" passwordMatched: "Corretta"
passwordNotMatched: "Le password non corrispondono." passwordNotMatched: "Le password non corrispondono."
signinWith: "Accedi con {x}"
signinFailed: "Autenticazione non riuscita. Controlla la tua password e nome utente." signinFailed: "Autenticazione non riuscita. Controlla la tua password e nome utente."
tapSecurityKey: "Premi la chiave di sicurezza" tapSecurityKey: "Premi la chiave di sicurezza"
or: "oppure" or: "oppure"

View file

@ -286,9 +286,6 @@ dayX: "{day}日"
monthX: "{month}月" monthX: "{month}月"
yearX: "{year}年" yearX: "{year}年"
pages: "ページ" pages: "ページ"
integration: "連携"
connectService: "接続する"
disconnectService: "切断する"
enableLocalTimeline: "ローカルタイムラインを有効にする" enableLocalTimeline: "ローカルタイムラインを有効にする"
enableGlobalTimeline: "グローバルタイムラインを有効にする" enableGlobalTimeline: "グローバルタイムラインを有効にする"
disablingTimelinesInfo: "これらのタイムラインを無効化しても、利便性のため管理者およびモデレーターは引き続き利用することができます。" disablingTimelinesInfo: "これらのタイムラインを無効化しても、利便性のため管理者およびモデレーターは引き続き利用することができます。"
@ -392,7 +389,6 @@ normalPassword: "普通のパスワード"
strongPassword: "強いパスワード" strongPassword: "強いパスワード"
passwordMatched: "一致しました" passwordMatched: "一致しました"
passwordNotMatched: "一致していません" passwordNotMatched: "一致していません"
signinWith: "{x}でログイン"
signinFailed: "ログインできませんでした。ユーザー名とパスワードを確認してください。" signinFailed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
tapSecurityKey: "セキュリティキーにタッチ" tapSecurityKey: "セキュリティキーにタッチ"
or: "もしくは" or: "もしくは"
@ -1273,13 +1269,3 @@ _deck:
list: "リスト" list: "リスト"
mentions: "あなた宛て" mentions: "あなた宛て"
direct: "ダイレクト" direct: "ダイレクト"
_services:
_discord:
connected: "Discord: @{username}#{discriminator} を、FoundKey: @{mkUsername} に接続しました!"
disconnected: "Discordの連携を解除しました :v:"
_twitter:
connected: "Twitter: @{twitterUserName} を、FoundKey: @{userName} に接続しました!"
disconnected: "Twitterの連携を解除しました :v:"
_github:
connected: "GitHub: @{login} を、FoundKey: @{userName} に接続しました!"
disconnected: "GitHubの連携を解除しました :v:"

View file

@ -288,7 +288,6 @@ dayX: "{day}日"
monthX: "{month}月" monthX: "{month}月"
yearX: "{year}年" yearX: "{year}年"
pages: "ページ" pages: "ページ"
integration: "連携"
enableLocalTimeline: "ローカルタイムラインを使えるようにする" enableLocalTimeline: "ローカルタイムラインを使えるようにする"
enableGlobalTimeline: "グローバルタイムラインを使えるようにする" enableGlobalTimeline: "グローバルタイムラインを使えるようにする"
disablingTimelinesInfo: "ここらへんのタイムラインを使えんようにしてしもても、管理者とモデレーターは使えるままになってるで、そうやなかったら不便やからな。" disablingTimelinesInfo: "ここらへんのタイムラインを使えんようにしてしもても、管理者とモデレーターは使えるままになってるで、そうやなかったら不便やからな。"
@ -391,7 +390,6 @@ normalPassword: "普通のパスワード"
strongPassword: "ええ感じのパスワード" strongPassword: "ええ感じのパスワード"
passwordMatched: "よし!一致や!" passwordMatched: "よし!一致や!"
passwordNotMatched: "一致しとらんで?" passwordNotMatched: "一致しとらんで?"
signinWith: "{x}でログイン"
or: "それか" or: "それか"
language: "言語" language: "言語"
uiLanguage: "UIの表示言語" uiLanguage: "UIの表示言語"

View file

@ -39,7 +39,6 @@ userList: "Tibdarin"
securityKey: "Tasarutt n tɣellist" securityKey: "Tasarutt n tɣellist"
securityKeyName: "Isem n tsarutt" securityKeyName: "Isem n tsarutt"
signinRequired: "Ttxil jerred" signinRequired: "Ttxil jerred"
signinWith: "Tuqqna s {x}"
tapSecurityKey: "Sekcem tasarutt-ik·im n tɣellist" tapSecurityKey: "Sekcem tasarutt-ik·im n tɣellist"
uiLanguage: "Tutlayt n wegrudem" uiLanguage: "Tutlayt n wegrudem"
plugins: "Izegrar" plugins: "Izegrar"

View file

@ -315,9 +315,6 @@ dayX: "{day}일"
monthX: "{month}월" monthX: "{month}월"
yearX: "{year}년" yearX: "{year}년"
pages: "페이지" pages: "페이지"
integration: "연동"
connectService: "계정 연동"
disconnectService: "계정 연동 해제"
enableLocalTimeline: "로컬 타임라인 활성화" enableLocalTimeline: "로컬 타임라인 활성화"
enableGlobalTimeline: "글로벌 타임라인 활성화" enableGlobalTimeline: "글로벌 타임라인 활성화"
disablingTimelinesInfo: "특정 타임라인을 비활성화하더라도 관리자 및 모더레이터는 계속 사용할 수 있습니다." disablingTimelinesInfo: "특정 타임라인을 비활성화하더라도 관리자 및 모더레이터는 계속 사용할 수 있습니다."
@ -438,7 +435,6 @@ normalPassword: "좋은 비밀번호"
strongPassword: "강한 비밀번호" strongPassword: "강한 비밀번호"
passwordMatched: "일치합니다" passwordMatched: "일치합니다"
passwordNotMatched: "일치하지 않습니다" passwordNotMatched: "일치하지 않습니다"
signinWith: "{x}로 로그인"
signinFailed: "로그인할 수 없습니다. 사용자명과 비밀번호를 확인하여 주십시오." signinFailed: "로그인할 수 없습니다. 사용자명과 비밀번호를 확인하여 주십시오."
tapSecurityKey: "보안 키를 터치" tapSecurityKey: "보안 키를 터치"
or: "혹은" or: "혹은"

View file

@ -298,9 +298,6 @@ dayX: "{day}"
monthX: "{month}" monthX: "{month}"
yearX: "{year}" yearX: "{year}"
pages: "Strony" pages: "Strony"
integration: "Integracja"
connectService: "Połącz"
disconnectService: "Rozłącz"
enableLocalTimeline: "Włącz lokalną oś czasu" enableLocalTimeline: "Włącz lokalną oś czasu"
enableGlobalTimeline: "Włącz globalną oś czasu" enableGlobalTimeline: "Włącz globalną oś czasu"
disablingTimelinesInfo: "Administratorzy i moderatorzy będą zawsze mieć dostęp do\ disablingTimelinesInfo: "Administratorzy i moderatorzy będą zawsze mieć dostęp do\
@ -407,7 +404,6 @@ normalPassword: "Dobre hasło"
strongPassword: "Silne hasło" strongPassword: "Silne hasło"
passwordMatched: "Pasuje" passwordMatched: "Pasuje"
passwordNotMatched: "Hasła nie pasują do siebie" passwordNotMatched: "Hasła nie pasują do siebie"
signinWith: "Zaloguj się z {x}"
signinFailed: "Nie udało się zalogować. Wprowadzona nazwa użytkownika lub hasło są\ signinFailed: "Nie udało się zalogować. Wprowadzona nazwa użytkownika lub hasło są\
\ nieprawidłowe." \ nieprawidłowe."
tapSecurityKey: "Wybierz swój klucz bezpieczeństwa" tapSecurityKey: "Wybierz swój klucz bezpieczeństwa"

View file

@ -311,9 +311,6 @@ dayX: "{day}"
monthX: "{month}" monthX: "{month}"
yearX: "{year}" yearX: "{year}"
pages: "Pagini" pages: "Pagini"
integration: "Integrare"
connectService: "Conectează"
disconnectService: "Deconectează"
enableLocalTimeline: "Activează cronologia locală" enableLocalTimeline: "Activează cronologia locală"
enableGlobalTimeline: "Activeaza cronologia globală" enableGlobalTimeline: "Activeaza cronologia globală"
disablingTimelinesInfo: "Administratorii și Moderatorii vor avea mereu access la toate\ disablingTimelinesInfo: "Administratorii și Moderatorii vor avea mereu access la toate\
@ -420,7 +417,6 @@ normalPassword: "Parolă medie"
strongPassword: "Parolă puternică" strongPassword: "Parolă puternică"
passwordMatched: "Se potrivește!" passwordMatched: "Se potrivește!"
passwordNotMatched: "Nu se potrivește" passwordNotMatched: "Nu se potrivește"
signinWith: "Autentifică-te cu {x}"
signinFailed: "Nu se poate autentifica. Numele de utilizator sau parola introduse\ signinFailed: "Nu se poate autentifica. Numele de utilizator sau parola introduse\
\ sunt incorecte." \ sunt incorecte."
tapSecurityKey: "Apasă pe cheia ta de securitate." tapSecurityKey: "Apasă pe cheia ta de securitate."

View file

@ -304,9 +304,6 @@ dayX: "{day} день"
monthX: "{month} месяц" monthX: "{month} месяц"
yearX: "{year} год" yearX: "{year} год"
pages: "Страницы" pages: "Страницы"
integration: "Интеграция"
connectService: "Подключиться"
disconnectService: "Отключиться"
enableLocalTimeline: "Включить локальную ленту" enableLocalTimeline: "Включить локальную ленту"
enableGlobalTimeline: "Включить глобальную ленту" enableGlobalTimeline: "Включить глобальную ленту"
disablingTimelinesInfo: "У администраторов и модераторов есть доступ ко всем лентам,\ disablingTimelinesInfo: "У администраторов и модераторов есть доступ ко всем лентам,\
@ -415,7 +412,6 @@ normalPassword: "Годный пароль"
strongPassword: "Надёжный пароль" strongPassword: "Надёжный пароль"
passwordMatched: "Совпали" passwordMatched: "Совпали"
passwordNotMatched: "Не совпадают" passwordNotMatched: "Не совпадают"
signinWith: "Использовать {x} для входа"
signinFailed: "Невозможно войти в систему. Введенное вами имя пользователя или пароль\ signinFailed: "Невозможно войти в систему. Введенное вами имя пользователя или пароль\
\ неверны." \ неверны."
tapSecurityKey: "Нажмите на свой электронный ключ" tapSecurityKey: "Нажмите на свой электронный ключ"

View file

@ -305,9 +305,6 @@ dayX: "{day}"
monthX: "{month}" monthX: "{month}"
yearX: "{year}" yearX: "{year}"
pages: "Stránky" pages: "Stránky"
integration: "Integrácia"
connectService: "Pripojiť"
disconnectService: "Odpojiť"
enableLocalTimeline: "Povoliť lokálnu časovú os" enableLocalTimeline: "Povoliť lokálnu časovú os"
enableGlobalTimeline: "Povoliť globálnu časovú os" enableGlobalTimeline: "Povoliť globálnu časovú os"
disablingTimelinesInfo: "Administrátori a moderátori majú vždy prístup ku všetkým\ disablingTimelinesInfo: "Administrátori a moderátori majú vždy prístup ku všetkým\
@ -414,7 +411,6 @@ normalPassword: "Dobré heslo"
strongPassword: "Silné heslo" strongPassword: "Silné heslo"
passwordMatched: "Heslá sú rovnaké" passwordMatched: "Heslá sú rovnaké"
passwordNotMatched: "Heslá nie sú rovnaké" passwordNotMatched: "Heslá nie sú rovnaké"
signinWith: "Prihlásiť sa použitím {x}"
signinFailed: "Nedá sa prihlásiť. Skontrolujte prosím meno používateľa a heslo." signinFailed: "Nedá sa prihlásiť. Skontrolujte prosím meno používateľa a heslo."
tapSecurityKey: "Ťuknite na bezpečnostný kľúč" tapSecurityKey: "Ťuknite na bezpečnostný kľúč"
or: "Alebo" or: "Alebo"

View file

@ -305,9 +305,6 @@ dayX: "{day}"
monthX: "{month}" monthX: "{month}"
yearX: "{year}" yearX: "{year}"
pages: "Сторінки" pages: "Сторінки"
integration: "Інтеграція"
connectService: "Під’єднати"
disconnectService: "Відключитися"
enableLocalTimeline: "Увімкнути локальну стрічку" enableLocalTimeline: "Увімкнути локальну стрічку"
enableGlobalTimeline: "Увімкнути глобальну стрічку" enableGlobalTimeline: "Увімкнути глобальну стрічку"
disablingTimelinesInfo: "Адміністратори та модератори завжди мають доступ до всіх\ disablingTimelinesInfo: "Адміністратори та модератори завжди мають доступ до всіх\
@ -414,7 +411,6 @@ normalPassword: "Достатній пароль"
strongPassword: "Міцний пароль" strongPassword: "Міцний пароль"
passwordMatched: "Все вірно" passwordMatched: "Все вірно"
passwordNotMatched: "Паролі не співпадають" passwordNotMatched: "Паролі не співпадають"
signinWith: "Увійти за допомогою {x}"
signinFailed: "Не вдалося увійти. Введені ім’я користувача або пароль неправильнi." signinFailed: "Не вдалося увійти. Введені ім’я користувача або пароль неправильнi."
tapSecurityKey: "Торкніться ключа безпеки" tapSecurityKey: "Торкніться ключа безпеки"
or: "або" or: "або"

View file

@ -305,9 +305,6 @@ dayX: "{day}"
monthX: "{month}" monthX: "{month}"
yearX: "{year}" yearX: "{year}"
pages: "Trang" pages: "Trang"
integration: "Tương tác"
connectService: "Kết nối"
disconnectService: "Ngắt kết nối"
enableLocalTimeline: "Bật bảng tin máy chủ" enableLocalTimeline: "Bật bảng tin máy chủ"
enableGlobalTimeline: "Bật bảng tin liên hợp" enableGlobalTimeline: "Bật bảng tin liên hợp"
disablingTimelinesInfo: "Quản trị viên và Kiểm duyệt viên luôn có quyền truy cập mọi\ disablingTimelinesInfo: "Quản trị viên và Kiểm duyệt viên luôn có quyền truy cập mọi\
@ -415,7 +412,6 @@ normalPassword: "Mật khẩu tạm được"
strongPassword: "Mật khẩu mạnh" strongPassword: "Mật khẩu mạnh"
passwordMatched: "Trùng khớp" passwordMatched: "Trùng khớp"
passwordNotMatched: "Không trùng khớp" passwordNotMatched: "Không trùng khớp"
signinWith: "Đăng nhập bằng {x}"
signinFailed: "Không thể đăng nhập. Vui lòng kiểm tra tên người dùng và mật khẩu của\ signinFailed: "Không thể đăng nhập. Vui lòng kiểm tra tên người dùng và mật khẩu của\
\ bạn." \ bạn."
tapSecurityKey: "Nhấn mã bảo mật của bạn" tapSecurityKey: "Nhấn mã bảo mật của bạn"

View file

@ -284,9 +284,6 @@ dayX: "{day}日"
monthX: "{month}月" monthX: "{month}月"
yearX: "{year}年" yearX: "{year}年"
pages: "页面" pages: "页面"
integration: "关联"
connectService: "连接"
disconnectService: "断开连接"
enableLocalTimeline: "启用本地时间线功能" enableLocalTimeline: "启用本地时间线功能"
enableGlobalTimeline: "启用全局时间线" enableGlobalTimeline: "启用全局时间线"
disablingTimelinesInfo: "即使时间线功能被禁用,出于方便,管理员和数据图表也可以继续使用。" disablingTimelinesInfo: "即使时间线功能被禁用,出于方便,管理员和数据图表也可以继续使用。"
@ -390,7 +387,6 @@ normalPassword: "密码强度:中等"
strongPassword: "密码强度:强" strongPassword: "密码强度:强"
passwordMatched: "密码一致" passwordMatched: "密码一致"
passwordNotMatched: "密码不一致" passwordNotMatched: "密码不一致"
signinWith: "以{x}登录"
signinFailed: "无法登录,请检查您的用户名和密码是否正确。" signinFailed: "无法登录,请检查您的用户名和密码是否正确。"
tapSecurityKey: "轻触硬件安全密钥" tapSecurityKey: "轻触硬件安全密钥"
or: "或者" or: "或者"

View file

@ -284,9 +284,6 @@ dayX: "{day}日"
monthX: "{month}月" monthX: "{month}月"
yearX: "{year}年" yearX: "{year}年"
pages: "頁面" pages: "頁面"
integration: "整合"
connectService: "己連結"
disconnectService: "己斷開 "
enableLocalTimeline: "開啟本地時間軸" enableLocalTimeline: "開啟本地時間軸"
enableGlobalTimeline: "啟用公開時間軸" enableGlobalTimeline: "啟用公開時間軸"
disablingTimelinesInfo: "即使您關閉了時間線功能,管理員和協調人仍可以繼續使用,以方便您。" disablingTimelinesInfo: "即使您關閉了時間線功能,管理員和協調人仍可以繼續使用,以方便您。"
@ -390,7 +387,6 @@ normalPassword: "密碼強度普通"
strongPassword: "密碼強度高" strongPassword: "密碼強度高"
passwordMatched: "密碼一致" passwordMatched: "密碼一致"
passwordNotMatched: "密碼不一致" passwordNotMatched: "密碼不一致"
signinWith: "以{x}登錄"
signinFailed: "登入失敗。 請檢查使用者名稱和密碼。" signinFailed: "登入失敗。 請檢查使用者名稱和密碼。"
tapSecurityKey: "點擊安全密鑰" tapSecurityKey: "點擊安全密鑰"
or: "或者" or: "或者"

View file

@ -18,7 +18,7 @@
"migrateandstart": "yarn migrate && yarn start", "migrateandstart": "yarn migrate && yarn start",
"gulp": "gulp build", "gulp": "gulp build",
"watch": "yarn dev", "watch": "yarn dev",
"dev": "node ./scripts/dev.js", "dev": "node ./scripts/dev.mjs",
"lint": "yarn workspaces foreach run lint", "lint": "yarn workspaces foreach run lint",
"cy:open": "cypress open --browser --e2e --config-file=cypress.config.ts", "cy:open": "cypress open --browser --e2e --config-file=cypress.config.ts",
"cy:run": "cypress run", "cy:run": "cypress run",
@ -26,8 +26,8 @@
"mocha": "yarn workspace backend run mocha", "mocha": "yarn workspace backend run mocha",
"test": "yarn mocha", "test": "yarn mocha",
"format": "gulp format", "format": "gulp format",
"clean": "node ./scripts/clean.js", "clean": "node ./scripts/clean.mjs",
"clean-all": "node ./scripts/clean-all.js", "clean-all": "node ./scripts/clean-all.mjs",
"cleanall": "yarn clean-all" "cleanall": "yarn clean-all"
}, },
"resolutions": { "resolutions": {
@ -46,11 +46,11 @@
"devDependencies": { "devDependencies": {
"@types/gulp": "4.0.9", "@types/gulp": "4.0.9",
"@types/gulp-rename": "2.0.1", "@types/gulp-rename": "2.0.1",
"@typescript-eslint/parser": "^5.44.0", "@typescript-eslint/parser": "^5.46.1",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"cypress": "10.3.0", "cypress": "10.3.0",
"start-server-and-test": "1.14.0", "start-server-and-test": "1.14.0",
"typescript": "^4.9.3" "typescript": "^4.9.4"
}, },
"packageManager": "yarn@3.3.0" "packageManager": "yarn@3.3.0"
} }

View file

@ -0,0 +1,33 @@
export class tokenPermissions1667653936442 {
name = 'tokenPermissions1667653936442'
async up(queryRunner) {
// Carry over the permissions from the app for tokens that have an associated app.
await queryRunner.query(`UPDATE "access_token" SET permission = (SELECT permission FROM "app" WHERE "app"."id" = "access_token"."appId") WHERE "appId" IS NOT NULL AND CARDINALITY("permission") = 0`);
// The permission column should now always be set explicitly, so the default is not needed any more.
await queryRunner.query(`ALTER TABLE "access_token" ALTER COLUMN "permission" DROP DEFAULT`);
// Drop all currently running authorization sessions. Already created tokens remain untouched.
// If you were registering an app just before upgrade started, try again later. ¯\_(ツ)_/¯
await queryRunner.query(`TRUNCATE TABLE "auth_session"`);
// Refactor scheme to allow multiple access tokens per app.
await queryRunner.query(`ALTER TABLE "auth_session" DROP CONSTRAINT "FK_c072b729d71697f959bde66ade0"`);
await queryRunner.query(`ALTER TABLE "auth_session" RENAME COLUMN "userId" TO "accessTokenId"`);
await queryRunner.query(`ALTER TABLE "auth_session" ADD CONSTRAINT "UQ_8e001e5a101c6dca37df1a76d66" UNIQUE ("accessTokenId")`);
await queryRunner.query(`ALTER TABLE "auth_session" ADD CONSTRAINT "FK_8e001e5a101c6dca37df1a76d66" FOREIGN KEY ("accessTokenId") REFERENCES "access_token"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}
async down(queryRunner) {
// Drop all currently running authorization sessions. Already created tokens remain untouched.
// If you were registering an app just before downgrade started, try again later. ¯\_(ツ)_/¯
await queryRunner.query(`TRUNCATE TABLE "auth_session"`);
await queryRunner.query(`ALTER TABLE "auth_session" DROP CONSTRAINT "FK_8e001e5a101c6dca37df1a76d66"`);
await queryRunner.query(`ALTER TABLE "auth_session" DROP CONSTRAINT "UQ_8e001e5a101c6dca37df1a76d66"`);
await queryRunner.query(`ALTER TABLE "access_token" ALTER COLUMN "permission" DROP DEFAULT`);
await queryRunner.query(`ALTER TABLE "auth_session" RENAME COLUMN "accessTokenId" TO "userId"`);
await queryRunner.query(`ALTER TABLE "auth_session" ADD CONSTRAINT "FK_c072b729d71697f959bde66ade0" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "access_token" ALTER COLUMN "permission" SET DEFAULT '{}'::varchar[]`);
await queryRunner.query(`UPDATE "access_token" SET permission = '{}'::varchar[] WHERE "appId" IS NOT NULL`);
}
}

View file

@ -0,0 +1,12 @@
export class pkce1667738304733 {
name = 'pkce1667738304733'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "auth_session" ADD "pkceChallenge" text`);
await queryRunner.query(`COMMENT ON COLUMN "auth_session"."pkceChallenge" IS 'PKCE code_challenge value, if provided (OAuth only)'`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "auth_session" DROP COLUMN "pkceChallenge"`);
}
}

View file

@ -0,0 +1,29 @@
export class removeIntegrations1670359028055 {
name = 'removeIntegrations1670359028055'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableTwitterIntegration"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "twitterConsumerKey"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "twitterConsumerSecret"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableGithubIntegration"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "githubClientId"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "githubClientSecret"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableDiscordIntegration"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "discordClientId"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "discordClientSecret"`);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "integrations"`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "user_profile" ADD "integrations" jsonb NOT NULL DEFAULT '{}'`);
await queryRunner.query(`ALTER TABLE "meta" ADD "discordClientSecret" character varying(128)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "discordClientId" character varying(128)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "enableDiscordIntegration" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`ALTER TABLE "meta" ADD "githubClientSecret" character varying(128)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "githubClientId" character varying(128)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "enableGithubIntegration" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`ALTER TABLE "meta" ADD "twitterConsumerSecret" character varying(128)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "twitterConsumerKey" character varying(128)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "enableTwitterIntegration" boolean NOT NULL DEFAULT false`);
}
}

View file

@ -7,7 +7,7 @@
"scripts": { "scripts": {
"build": "tsc -p tsconfig.json || echo done. && tsc-alias -p tsconfig.json", "build": "tsc -p tsconfig.json || echo done. && tsc-alias -p tsconfig.json",
"watch": "node watch.mjs", "watch": "node watch.mjs",
"lint": "eslint src --ext .ts", "lint": "tsc --noEmit && eslint src --ext .ts",
"mocha": "cross-env NODE_ENV=test TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT=\"./test/tsconfig.json\" mocha", "mocha": "cross-env NODE_ENV=test TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT=\"./test/tsconfig.json\" mocha",
"migrate": "npx typeorm migration:run -d ormconfig.js", "migrate": "npx typeorm migration:run -d ormconfig.js",
"start": "node --experimental-json-modules ./built/index.js", "start": "node --experimental-json-modules ./built/index.js",
@ -29,7 +29,6 @@
"ajv": "8.11.0", "ajv": "8.11.0",
"archiver": "5.3.1", "archiver": "5.3.1",
"autobind-decorator": "2.4.0", "autobind-decorator": "2.4.0",
"autwh": "0.1.0",
"aws-sdk": "2.1165.0", "aws-sdk": "2.1165.0",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"blurhash": "1.1.5", "blurhash": "1.1.5",
@ -92,7 +91,6 @@
"reflect-metadata": "0.1.13", "reflect-metadata": "0.1.13",
"rename": "1.0.4", "rename": "1.0.4",
"require-all": "3.0.0", "require-all": "3.0.0",
"rndstr": "1.0.0",
"rss-parser": "3.12.0", "rss-parser": "3.12.0",
"sanitize-html": "2.7.0", "sanitize-html": "2.7.0",
"semver": "7.3.7", "semver": "7.3.7",
@ -124,6 +122,7 @@
"@types/bcryptjs": "2.4.2", "@types/bcryptjs": "2.4.2",
"@types/bull": "3.15.8", "@types/bull": "3.15.8",
"@types/cbor": "6.0.0", "@types/cbor": "6.0.0",
"@types/color-convert": "^2.0.0",
"@types/escape-regexp": "0.0.1", "@types/escape-regexp": "0.0.1",
"@types/fluent-ffmpeg": "2.1.20", "@types/fluent-ffmpeg": "2.1.20",
"@types/is-url": "1.2.30", "@types/is-url": "1.2.30",
@ -146,7 +145,6 @@
"@types/node": "18.7.16", "@types/node": "18.7.16",
"@types/node-fetch": "3.0.3", "@types/node-fetch": "3.0.3",
"@types/nodemailer": "6.4.5", "@types/nodemailer": "6.4.5",
"@types/oauth": "^0.9.1",
"@types/pg": "^8.6.5", "@types/pg": "^8.6.5",
"@types/pug": "2.0.6", "@types/pug": "2.0.6",
"@types/punycode": "2.1.0", "@types/punycode": "2.1.0",
@ -161,20 +159,21 @@
"@types/sinon": "^10.0.13", "@types/sinon": "^10.0.13",
"@types/sinonjs__fake-timers": "8.1.2", "@types/sinonjs__fake-timers": "8.1.2",
"@types/speakeasy": "2.0.7", "@types/speakeasy": "2.0.7",
"@types/syslog-pro": "^1.0.0",
"@types/tinycolor2": "1.4.3", "@types/tinycolor2": "1.4.3",
"@types/tmp": "0.2.3", "@types/tmp": "0.2.3",
"@types/uuid": "8.3.4", "@types/uuid": "8.3.4",
"@types/web-push": "3.3.2", "@types/web-push": "3.3.2",
"@types/websocket": "1.0.5", "@types/websocket": "1.0.5",
"@types/ws": "8.5.3", "@types/ws": "8.5.3",
"@typescript-eslint/eslint-plugin": "^5.44.0", "@typescript-eslint/eslint-plugin": "^5.46.1",
"@typescript-eslint/parser": "^5.44.0", "@typescript-eslint/parser": "^5.46.1",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"eslint": "^8.28.0", "eslint": "^8.29.0",
"eslint-plugin-import": "^2.26.0", "eslint-plugin-import": "^2.26.0",
"execa": "6.1.0", "execa": "6.1.0",
"form-data": "^4.0.0", "form-data": "^4.0.0",
"sinon": "^14.0.2", "sinon": "^14.0.2",
"typescript": "^4.9.3" "typescript": "^4.9.4"
} }
} }

View file

@ -17,7 +17,7 @@ const ev = new Xev();
/** /**
* Init process * Init process
*/ */
export default async function(): Promise<void> { export async function boot(): Promise<void> {
process.title = `FoundKey (${cluster.isPrimary ? 'master' : 'worker'})`; process.title = `FoundKey (${cluster.isPrimary ? 'master' : 'worker'})`;
if (cluster.isPrimary || envOption.disableClustering) { if (cluster.isPrimary || envOption.disableClustering) {

View file

@ -153,7 +153,7 @@ async function spawnWorkers(clusterLimits: Required<Config['clusterLimits']>): P
bootLogger.info(`Starting ${total} workers...`); bootLogger.info(`Starting ${total} workers...`);
await Promise.all(workers.map(mode => spawnWorker(mode))); await Promise.all(workers.map(mode => spawnWorker(mode)));
bootLogger.succ(`All workers started`); bootLogger.succ('All workers started');
} }
function spawnWorker(mode: 'web' | 'queue'): Promise<void> { function spawnWorker(mode: 'web' | 'queue'): Promise<void> {

View file

@ -38,6 +38,12 @@ export default function load(): Config {
config.port = config.port || parseInt(process.env.PORT || '', 10); config.port = config.port || parseInt(process.env.PORT || '', 10);
config.images = Object.assign({
info: '/twemoji/1f440.svg',
notFound: '/twemoji/2049.svg',
error: '/twemoji/1f480.svg',
}, config.images ?? {});
if (!config.maxNoteTextLength) config.maxNoteTextLength = 3000; if (!config.maxNoteTextLength) config.maxNoteTextLength = 3000;
mixin.version = meta.version; mixin.version = meta.version;

View file

@ -59,7 +59,7 @@ export type Source = {
deliverJobMaxAttempts?: number; deliverJobMaxAttempts?: number;
inboxJobMaxAttempts?: number; inboxJobMaxAttempts?: number;
syslog: { syslog?: {
host: string; host: string;
port: number; port: number;
}; };
@ -67,6 +67,12 @@ export type Source = {
mediaProxy?: string; mediaProxy?: string;
proxyRemoteFiles?: boolean; proxyRemoteFiles?: boolean;
internalStoragePath?: string; internalStoragePath?: string;
images?: {
info?: string;
notFound?: string;
error?: string;
};
}; };
/** /**

View file

@ -1,6 +1,5 @@
// https://github.com/typeorm/typeorm/issues/2400 // https://github.com/typeorm/typeorm/issues/2400
import pg from 'pg'; import pg from 'pg';
import { SECOND } from '@/const.js';
pg.types.setTypeParser(20, Number); pg.types.setTypeParser(20, Number);
@ -8,6 +7,7 @@ import { Logger, DataSource } from 'typeorm';
import * as highlight from 'cli-highlight'; import * as highlight from 'cli-highlight';
import config from '@/config/index.js'; import config from '@/config/index.js';
import { SECOND } from '@/const.js';
import { User } from '@/models/entities/user.js'; import { User } from '@/models/entities/user.js';
import { DriveFile } from '@/models/entities/drive-file.js'; import { DriveFile } from '@/models/entities/drive-file.js';
import { DriveFolder } from '@/models/entities/drive-folder.js'; import { DriveFolder } from '@/models/entities/drive-folder.js';
@ -78,33 +78,33 @@ import { redisClient } from './redis.js';
const sqlLogger = dbLogger.createSubLogger('sql', 'gray', false); const sqlLogger = dbLogger.createSubLogger('sql', 'gray', false);
class MyCustomLogger implements Logger { class MyCustomLogger implements Logger {
private highlight(sql: string) { private highlight(sql: string): string {
return highlight.highlight(sql, { return highlight.highlight(sql, {
language: 'sql', ignoreIllegals: true, language: 'sql', ignoreIllegals: true,
}); });
} }
public logQuery(query: string, parameters?: any[]) { public logQuery(query: string): void {
sqlLogger.info(this.highlight(query).substring(0, 100)); sqlLogger.info(this.highlight(query).substring(0, 100));
} }
public logQueryError(error: string, query: string, parameters?: any[]) { public logQueryError(error: string, query: string): void {
sqlLogger.error(this.highlight(query)); sqlLogger.error(this.highlight(query));
} }
public logQuerySlow(time: number, query: string, parameters?: any[]) { public logQuerySlow(time: number, query: string): void {
sqlLogger.warn(this.highlight(query)); sqlLogger.warn(this.highlight(query));
} }
public logSchemaBuild(message: string) { public logSchemaBuild(message: string): void {
sqlLogger.info(message); sqlLogger.info(message);
} }
public log(message: string) { public log(message: string): void {
sqlLogger.info(message); sqlLogger.info(message);
} }
public logMigration(message: string) { public logMigration(message: string): void {
sqlLogger.info(message); sqlLogger.info(message);
} }
} }

View file

@ -3,7 +3,7 @@
*/ */
import { EventEmitter } from 'node:events'; import { EventEmitter } from 'node:events';
import boot from '@/boot/index.js'; import { boot } from '@/boot/index.js';
Error.stackTraceLimit = Infinity; Error.stackTraceLimit = Infinity;
EventEmitter.defaultMaxListeners = 128; EventEmitter.defaultMaxListeners = 128;

View file

@ -7,6 +7,16 @@ const treeAdapter = parse5.defaultTreeAdapter;
const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/; const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/;
const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/; const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/;
function getAttr(node: TreeAdapter.Node, attr: string): string {
return node.attrs.find(({ name }) => name === attr)?.value;
}
function attrHas(node: TreeAdapter.Node, attr: string, value: string): boolean {
const attrValue = getAttr(node, attr);
if (!attrValue) return false;
return new RegExp('\\b' + value + '\\b').test(attrValue);
}
export function fromHtml(html: string, quoteUri?: string | null): string { export function fromHtml(html: string, quoteUri?: string | null): string {
const dom = parse5.parseFragment( const dom = parse5.parseFragment(
// some AP servers like Pixelfed use br tags as well as newlines // some AP servers like Pixelfed use br tags as well as newlines
@ -59,19 +69,18 @@ export function fromHtml(html: string, quoteUri?: string | null): string {
case 'a': case 'a':
{ {
const txt = getText(node); const txt = getText(node);
const rel = node.attrs.find(x => x.name === 'rel'); const href = getAttr(node, 'href');
const href = node.attrs.find(x => x.name === 'href');
// hashtags // hashtags
if (txt.startsWith('#') && href && /\btag\b/.test(rel?.value)) { if (txt.startsWith('#') && href && (attrHas(node, 'rel', 'tag') || attrHas(node, 'class', 'hashtag'))) {
text += txt; text += txt;
// mentions // mentions
} else if (txt.startsWith('@') && !(rel && rel.value.match(/^me /))) { } else if (txt.startsWith('@') && !attrHas(node, 'rel', 'me')) {
const part = txt.split('@'); const part = txt.split('@');
if (part.length === 2 && href) { if (part.length === 2 && href) {
// restore the host name part // restore the host name part
const acct = `${txt}@${(new URL(href.value)).hostname}`; const acct = `${txt}@${(new URL(href)).hostname}`;
text += acct; text += acct;
} else if (part.length === 3) { } else if (part.length === 3) {
text += txt; text += txt;
@ -85,17 +94,17 @@ export function fromHtml(html: string, quoteUri?: string | null): string {
if (!href) { if (!href) {
return txt; return txt;
} }
if (!txt || txt === href.value) { // #6383: Missing text node if (!txt || txt === href) { // #6383: Missing text node
if (href.value.match(urlRegexFull)) { if (href.match(urlRegexFull)) {
return href.value; return href;
} else { } else {
return `<${href.value}>`; return `<${href}>`;
} }
} }
if (href.value.match(urlRegex) && !href.value.match(urlRegexFull)) { if (href.match(urlRegex) && !href.match(urlRegexFull)) {
return `[${txt}](<${href.value}>)`; // #6846 return `[${txt}](<${href}>)`; // #6846
} else { } else {
return `[${txt}](${href.value})`; return `[${txt}](${href})`;
} }
}; };
@ -204,8 +213,7 @@ export function fromHtml(html: string, quoteUri?: string | null): string {
case 'span': case 'span':
{ {
const nodeClass = node.attrs.find(({ name }) => name === 'class')?.value; if (attrHas(node, 'class', 'quote-inline') && quoteUri && getText(node).trim() === `RE: ${quoteUri}`) {
if (/\bquote-inline\b/.test(nodeClass) && quoteUri && getText(node).trim() === `RE: ${quoteUri}`) {
// embedded quote thingy for backwards compatibility, don't show it // embedded quote thingy for backwards compatibility, don't show it
} else { } else {
appendChildren(node.childNodes); appendChildren(node.childNodes);

View file

@ -1,7 +1,7 @@
export class Cache<T> { export class Cache<T> {
public cache: Map<string | null, { date: number; value: T; }>; public cache: Map<string, { date: number; value: T; }>;
private lifetime: number; private lifetime: number;
public fetcher: (key: string | null) => Promise<T | undefined>; public fetcher: (key: string) => Promise<T | undefined>;
constructor(lifetime: number, fetcher: Cache<T>['fetcher']) { constructor(lifetime: number, fetcher: Cache<T>['fetcher']) {
this.cache = new Map(); this.cache = new Map();
@ -9,14 +9,14 @@ export class Cache<T> {
this.fetcher = fetcher; this.fetcher = fetcher;
} }
public set(key: string | null, value: T): void { public set(key: string, value: T): void {
this.cache.set(key, { this.cache.set(key, {
date: Date.now(), date: Date.now(),
value, value,
}); });
} }
public get(key: string | null): T | undefined { public get(key: string): T | undefined {
const cached = this.cache.get(key); const cached = this.cache.get(key);
if (cached == null) return undefined; if (cached == null) return undefined;
@ -29,7 +29,7 @@ export class Cache<T> {
return cached.value; return cached.value;
} }
public delete(key: string | null): void { public delete(key: string): void {
this.cache.delete(key); this.cache.delete(key);
} }
@ -38,7 +38,7 @@ export class Cache<T> {
* run to get the value. If the fetcher returns undefined, it is * run to get the value. If the fetcher returns undefined, it is
* returned but not cached. * returned but not cached.
*/ */
public async fetch(key: string | null): Promise<T | undefined> { public async fetch(key: string): Promise<T | undefined> {
const cached = this.get(key); const cached = this.get(key);
if (cached !== undefined) { if (cached !== undefined) {
return cached; return cached;

View file

@ -1,10 +1,9 @@
import * as crypto from 'node:crypto'; import * as crypto from 'node:crypto';
const L_CHARS = '0123456789abcdefghijklmnopqrstuvwxyz'; const L_CHARS = '0123456789abcdefghijklmnopqrstuvwxyz';
const LU_CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; const LU_CHARS = L_CHARS + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
export function secureRndstr(length = 32, useLU = true): string { export function secureRndstrCustom(length = 32, chars: string): string {
const chars = useLU ? LU_CHARS : L_CHARS;
const chars_len = chars.length; const chars_len = chars.length;
let str = ''; let str = '';
@ -19,3 +18,8 @@ export function secureRndstr(length = 32, useLU = true): string {
return str; return str;
} }
export function secureRndstr(length = 32, useLU = true): string {
const chars = useLU ? LU_CHARS : L_CHARS;
return secureRndstrCustom(length, chars);
}

View file

@ -0,0 +1,16 @@
import { fetchMeta } from '@/misc/fetch-meta.js';
import { Instance } from '@/models/entities/instance.js';
import { Meta } from '@/models/entities/meta.js';
/**
* Returns whether a specific host (punycoded) should be blocked.
*
* @param host punycoded instance host
* @param meta a Promise contatining the information from the meta table (optional)
* @returns whether the given host should be blocked
*/
export async function shouldBlockInstance(host: Instance['host'], meta: Promise<Meta> = fetchMeta()): Promise<boolean> {
const { blockedHosts } = await meta;
return blockedHosts.some(blockedHost => host === blockedHost || host.endsWith('.' + blockedHost));
}

View file

@ -2,39 +2,12 @@ import { db } from '@/db/postgre.js';
import { fetchMeta } from '@/misc/fetch-meta.js'; import { fetchMeta } from '@/misc/fetch-meta.js';
import { Instance } from '@/models/entities/instance.js'; import { Instance } from '@/models/entities/instance.js';
import { DAY } from '@/const.js'; import { DAY } from '@/const.js';
import { Meta } from '@/models/entities/meta.js'; import { shouldBlockInstance } from '@/misc/should-block-instance.js';
// Threshold from last contact after which an instance will be considered // Threshold from last contact after which an instance will be considered
// "dead" and should no longer get activities delivered to it. // "dead" and should no longer get activities delivered to it.
const deadThreshold = 7 * DAY; const deadThreshold = 7 * DAY;
/**
* Returns whether a given host matches a wildcard pattern.
* @param host punycoded instance host
* @param pattern wildcard pattern containing a punycoded instance host
* @returns whether the post matches the pattern
*/
function matchHost(host: Instance['host'], pattern: string): boolean {
// Escape all of the regex special characters. Pattern from:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
const escape = (str: string): string => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const re = new RegExp('^' + pattern.split('*').map(escape).join('.*') + '$');
return re.test(host);
}
/**
* Returns whether a specific host (punycoded) should be blocked.
*
* @param host punycoded instance host
* @param meta a Promise contatining the information from the meta table (oprional)
* @returns whether the given host should be blocked
*/
export async function shouldBlockInstance(host: string, meta: Promise<Meta> = fetchMeta()): Promise<boolean> {
const { blockedHosts } = await meta;
return blockedHosts.some(blockedHost => matchHost(host, blockedHost));
}
/** /**
* Returns the subset of hosts which should be skipped. * Returns the subset of hosts which should be skipped.
* *
@ -62,7 +35,7 @@ export async function skippedInstances(hosts: Array<Instance['host']>): Promise<
hosts.filter(host => !skipped.includes(host) && !host.includes(',')).join(','), hosts.filter(host => !skipped.includes(host) && !host.includes(',')).join(','),
], ],
) )
.then(res => res.map(row => row.host)), .then((res: Instance[]) => res.map(row => row.host)),
); );
} }

View file

@ -17,7 +17,7 @@ export class AbuseUserReport {
@Column(id()) @Column(id())
public targetUserId: User['id']; public targetUserId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -27,7 +27,7 @@ export class AbuseUserReport {
@Column(id()) @Column(id())
public reporterId: User['id']; public reporterId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -39,7 +39,7 @@ export class AbuseUserReport {
}) })
public assigneeId: User['id'] | null; public assigneeId: User['id'] | null;
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'SET NULL', onDelete: 'SET NULL',
}) })
@JoinColumn() @JoinColumn()

View file

@ -41,7 +41,7 @@ export class AccessToken {
@Column(id()) @Column(id())
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -53,7 +53,7 @@ export class AccessToken {
}) })
public appId: App['id'] | null; public appId: App['id'] | null;
@ManyToOne(type => App, { @ManyToOne(() => App, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -18,7 +18,7 @@ export class AnnouncementRead {
@Column(id()) @Column(id())
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -28,7 +28,7 @@ export class AnnouncementRead {
@Column(id()) @Column(id())
public announcementId: Announcement['id']; public announcementId: Announcement['id'];
@ManyToOne(type => Announcement, { @ManyToOne(() => Announcement, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -16,7 +16,7 @@ export class AntennaNote {
}) })
public noteId: Note['id']; public noteId: Note['id'];
@ManyToOne(type => Note, { @ManyToOne(() => Note, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -29,7 +29,7 @@ export class AntennaNote {
}) })
public antennaId: Antenna['id']; public antennaId: Antenna['id'];
@ManyToOne(type => Antenna, { @ManyToOne(() => Antenna, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -21,7 +21,7 @@ export class Antenna {
}) })
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -42,7 +42,7 @@ export class Antenna {
}) })
public userListId: UserList['id'] | null; public userListId: UserList['id'] | null;
@ManyToOne(type => UserList, { @ManyToOne(() => UserList, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -54,7 +54,7 @@ export class Antenna {
}) })
public userGroupJoiningId: UserGroupJoining['id'] | null; public userGroupJoiningId: UserGroupJoining['id'] | null;
@ManyToOne(type => UserGroupJoining, { @ManyToOne(() => UserGroupJoining, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -21,7 +21,7 @@ export class App {
}) })
public userId: User['id'] | null; public userId: User['id'] | null;
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'SET NULL', onDelete: 'SET NULL',
nullable: true, nullable: true,
}) })

View file

@ -11,7 +11,7 @@ export class AttestationChallenge {
@PrimaryColumn(id()) @PrimaryColumn(id())
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -1,6 +1,6 @@
import { Entity, PrimaryColumn, Index, Column, ManyToOne, JoinColumn } from 'typeorm'; import { Entity, PrimaryColumn, Index, Column, ManyToOne, JoinColumn } from 'typeorm';
import { id } from '../id.js'; import { id } from '../id.js';
import { User } from './user.js'; import { AccessToken } from './access-token.js';
import { App } from './app.js'; import { App } from './app.js';
@Entity() @Entity()
@ -23,21 +23,27 @@ export class AuthSession {
...id(), ...id(),
nullable: true, nullable: true,
}) })
public userId: User['id'] | null; public accessTokenId: AccessToken['id'] | null;
@ManyToOne(type => User, { @ManyToOne(() => AccessToken, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
nullable: true, nullable: true,
}) })
@JoinColumn() @JoinColumn()
public user: User | null; public accessToken: AccessToken | null;
@Column(id()) @Column(id())
public appId: App['id']; public appId: App['id'];
@ManyToOne(type => App, { @ManyToOne(() => App, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
public app: App | null; public app: App | null;
@Column('text', {
nullable: true,
comment: 'PKCE code_challenge value, if provided (OAuth only)',
})
pkceChallenge: string | null;
} }

View file

@ -21,7 +21,7 @@ export class Blocking {
}) })
public blockeeId: User['id']; public blockeeId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -34,7 +34,7 @@ export class Blocking {
}) })
public blockerId: User['id']; public blockerId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -22,7 +22,7 @@ export class ChannelFollowing {
}) })
public followeeId: Channel['id']; public followeeId: Channel['id'];
@ManyToOne(type => Channel, { @ManyToOne(() => Channel, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -35,7 +35,7 @@ export class ChannelFollowing {
}) })
public followerId: User['id']; public followerId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -18,7 +18,7 @@ export class ChannelNotePining {
@Column(id()) @Column(id())
public channelId: Channel['id']; public channelId: Channel['id'];
@ManyToOne(type => Channel, { @ManyToOne(() => Channel, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -27,7 +27,7 @@ export class ChannelNotePining {
@Column(id()) @Column(id())
public noteId: Note['id']; public noteId: Note['id'];
@ManyToOne(type => Note, { @ManyToOne(() => Note, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -28,7 +28,7 @@ export class Channel {
}) })
public userId: User['id'] | null; public userId: User['id'] | null;
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'SET NULL', onDelete: 'SET NULL',
}) })
@JoinColumn() @JoinColumn()
@ -53,7 +53,7 @@ export class Channel {
}) })
public bannerId: DriveFile['id'] | null; public bannerId: DriveFile['id'] | null;
@ManyToOne(type => DriveFile, { @ManyToOne(() => DriveFile, {
onDelete: 'SET NULL', onDelete: 'SET NULL',
}) })
@JoinColumn() @JoinColumn()

View file

@ -16,7 +16,7 @@ export class ClipNote {
}) })
public noteId: Note['id']; public noteId: Note['id'];
@ManyToOne(type => Note, { @ManyToOne(() => Note, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -29,7 +29,7 @@ export class ClipNote {
}) })
public clipId: Clip['id']; public clipId: Clip['id'];
@ManyToOne(type => Clip, { @ManyToOne(() => Clip, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -19,7 +19,7 @@ export class Clip {
}) })
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -23,7 +23,7 @@ export class DriveFile {
}) })
public userId: User['id'] | null; public userId: User['id'] | null;
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'RESTRICT', onDelete: 'RESTRICT',
}) })
@JoinColumn() @JoinColumn()
@ -144,7 +144,7 @@ export class DriveFile {
}) })
public folderId: DriveFolder['id'] | null; public folderId: DriveFolder['id'] | null;
@ManyToOne(type => DriveFolder, { @ManyToOne(() => DriveFolder, {
onDelete: 'SET NULL', onDelete: 'SET NULL',
}) })
@JoinColumn() @JoinColumn()

View file

@ -27,7 +27,7 @@ export class DriveFolder {
}) })
public userId: User['id'] | null; public userId: User['id'] | null;
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -41,7 +41,7 @@ export class DriveFolder {
}) })
public parentId: DriveFolder['id'] | null; public parentId: DriveFolder['id'] | null;
@ManyToOne(type => DriveFolder, { @ManyToOne(() => DriveFolder, {
onDelete: 'SET NULL', onDelete: 'SET NULL',
}) })
@JoinColumn() @JoinColumn()

View file

@ -20,7 +20,7 @@ export class FollowRequest {
}) })
public followeeId: User['id']; public followeeId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -33,7 +33,7 @@ export class FollowRequest {
}) })
public followerId: User['id']; public followerId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -21,7 +21,7 @@ export class Following {
}) })
public followeeId: User['id']; public followeeId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -34,7 +34,7 @@ export class Following {
}) })
public followerId: User['id']; public followerId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -16,7 +16,7 @@ export class GalleryLike {
@Column(id()) @Column(id())
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -25,7 +25,7 @@ export class GalleryLike {
@Column(id()) @Column(id())
public postId: GalleryPost['id']; public postId: GalleryPost['id'];
@ManyToOne(type => GalleryPost, { @ManyToOne(() => GalleryPost, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -37,7 +37,7 @@ export class GalleryPost {
}) })
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -22,7 +22,7 @@ export class MessagingMessage {
}) })
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -35,7 +35,7 @@ export class MessagingMessage {
}) })
public recipientId: User['id'] | null; public recipientId: User['id'] | null;
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -48,7 +48,7 @@ export class MessagingMessage {
}) })
public groupId: UserGroup['id'] | null; public groupId: UserGroup['id'] | null;
@ManyToOne(type => UserGroup, { @ManyToOne(() => UserGroup, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -81,7 +81,7 @@ export class MessagingMessage {
}) })
public fileId: DriveFile['id'] | null; public fileId: DriveFile['id'] | null;
@ManyToOne(type => DriveFile, { @ManyToOne(() => DriveFile, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -134,7 +134,7 @@ export class Meta {
}) })
public proxyAccountId: User['id'] | null; public proxyAccountId: User['id'] | null;
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'SET NULL', onDelete: 'SET NULL',
}) })
@JoinColumn() @JoinColumn()
@ -246,57 +246,6 @@ export class Meta {
}) })
public swPrivateKey: string; public swPrivateKey: string;
@Column('boolean', {
default: false,
})
public enableTwitterIntegration: boolean;
@Column('varchar', {
length: 128,
nullable: true,
})
public twitterConsumerKey: string | null;
@Column('varchar', {
length: 128,
nullable: true,
})
public twitterConsumerSecret: string | null;
@Column('boolean', {
default: false,
})
public enableGithubIntegration: boolean;
@Column('varchar', {
length: 128,
nullable: true,
})
public githubClientId: string | null;
@Column('varchar', {
length: 128,
nullable: true,
})
public githubClientSecret: string | null;
@Column('boolean', {
default: false,
})
public enableDiscordIntegration: boolean;
@Column('varchar', {
length: 128,
nullable: true,
})
public discordClientId: string | null;
@Column('varchar', {
length: 128,
nullable: true,
})
public discordClientSecret: string | null;
@Column('enum', { @Column('enum', {
enum: TranslationService, enum: TranslationService,
nullable: true, nullable: true,

View file

@ -16,7 +16,7 @@ export class ModerationLog {
@Column(id()) @Column(id())
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -17,7 +17,7 @@ export class MutedNote {
}) })
public noteId: Note['id']; public noteId: Note['id'];
@ManyToOne(type => Note, { @ManyToOne(() => Note, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -30,7 +30,7 @@ export class MutedNote {
}) })
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -27,7 +27,7 @@ export class Muting {
}) })
public muteeId: User['id']; public muteeId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -40,7 +40,7 @@ export class Muting {
}) })
public muterId: User['id']; public muterId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -18,7 +18,7 @@ export class NoteFavorite {
@Column(id()) @Column(id())
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -27,7 +27,7 @@ export class NoteFavorite {
@Column(id()) @Column(id())
public noteId: Note['id']; public noteId: Note['id'];
@ManyToOne(type => Note, { @ManyToOne(() => Note, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -19,7 +19,7 @@ export class NoteReaction {
@Column(id()) @Column(id())
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -29,7 +29,7 @@ export class NoteReaction {
@Column(id()) @Column(id())
public noteId: Note['id']; public noteId: Note['id'];
@ManyToOne(type => Note, { @ManyToOne(() => Note, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -20,7 +20,7 @@ export class NoteThreadMuting {
}) })
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -14,7 +14,7 @@ export class NoteUnread {
@Column(id()) @Column(id())
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -24,7 +24,7 @@ export class NoteUnread {
@Column(id()) @Column(id())
public noteId: Note['id']; public noteId: Note['id'];
@ManyToOne(type => Note, { @ManyToOne(() => Note, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -22,7 +22,7 @@ export class NoteWatching {
}) })
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -35,7 +35,7 @@ export class NoteWatching {
}) })
public noteId: Note['id']; public noteId: Note['id'];
@ManyToOne(type => Note, { @ManyToOne(() => Note, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -27,7 +27,7 @@ export class Note {
}) })
public replyId: Note['id'] | null; public replyId: Note['id'] | null;
@ManyToOne(type => Note, { @ManyToOne(() => Note, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -41,7 +41,7 @@ export class Note {
}) })
public renoteId: Note['id'] | null; public renoteId: Note['id'] | null;
@ManyToOne(type => Note, { @ManyToOne(() => Note, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -75,7 +75,7 @@ export class Note {
}) })
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -179,7 +179,7 @@ export class Note {
}) })
public channelId: Channel['id'] | null; public channelId: Channel['id'] | null;
@ManyToOne(type => Channel, { @ManyToOne(() => Channel, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -28,7 +28,7 @@ export class Notification {
}) })
public notifieeId: User['id']; public notifieeId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -45,7 +45,7 @@ export class Notification {
}) })
public notifierId: User['id'] | null; public notifierId: User['id'] | null;
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -89,7 +89,7 @@ export class Notification {
}) })
public noteId: Note['id'] | null; public noteId: Note['id'] | null;
@ManyToOne(type => Note, { @ManyToOne(() => Note, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -101,7 +101,7 @@ export class Notification {
}) })
public followRequestId: FollowRequest['id'] | null; public followRequestId: FollowRequest['id'] | null;
@ManyToOne(type => FollowRequest, { @ManyToOne(() => FollowRequest, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -113,7 +113,7 @@ export class Notification {
}) })
public userGroupInvitationId: UserGroupInvitation['id'] | null; public userGroupInvitationId: UserGroupInvitation['id'] | null;
@ManyToOne(type => UserGroupInvitation, { @ManyToOne(() => UserGroupInvitation, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -165,7 +165,7 @@ export class Notification {
}) })
public appAccessTokenId: AccessToken['id'] | null; public appAccessTokenId: AccessToken['id'] | null;
@ManyToOne(type => AccessToken, { @ManyToOne(() => AccessToken, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -16,7 +16,7 @@ export class PageLike {
@Column(id()) @Column(id())
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -25,7 +25,7 @@ export class PageLike {
@Column(id()) @Column(id())
public pageId: Page['id']; public pageId: Page['id'];
@ManyToOne(type => Page, { @ManyToOne(() => Page, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -57,7 +57,7 @@ export class Page {
}) })
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -69,7 +69,7 @@ export class Page {
}) })
public eyeCatchingImageId: DriveFile['id'] | null; public eyeCatchingImageId: DriveFile['id'] | null;
@ManyToOne(type => DriveFile, { @ManyToOne(() => DriveFile, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -22,7 +22,7 @@ export class PasswordResetRequest {
}) })
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -19,7 +19,7 @@ export class PollVote {
@Column(id()) @Column(id())
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -29,7 +29,7 @@ export class PollVote {
@Column(id()) @Column(id())
public noteId: Note['id']; public noteId: Note['id'];
@ManyToOne(type => Note, { @ManyToOne(() => Note, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -9,7 +9,7 @@ export class Poll {
@PrimaryColumn(id()) @PrimaryColumn(id())
public noteId: Note['id']; public noteId: Note['id'];
@OneToOne(type => Note, { @OneToOne(() => Note, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -25,7 +25,7 @@ export class RegistryItem {
}) })
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -21,7 +21,7 @@ export class RenoteMuting {
}) })
public muteeId: User['id']; public muteeId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()
@ -34,7 +34,7 @@ export class RenoteMuting {
}) })
public muterId: User['id']; public muterId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

View file

@ -16,7 +16,7 @@ export class Signin {
@Column(id()) @Column(id())
public userId: User['id']; public userId: User['id'];
@ManyToOne(type => User, { @ManyToOne(() => User, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn() @JoinColumn()

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