mirror of
https://github.com/misskey-dev/misskey
synced 2025-06-29 16:22:50 +02:00
Compare commits
No commits in common. "develop" and "2025.6.1" have entirely different histories.
209 changed files with 1526 additions and 5284 deletions
23
.github/workflows/test-backend.yml
vendored
23
.github/workflows/test-backend.yml
vendored
|
@ -18,14 +18,6 @@ on:
|
||||||
- packages/misskey-js/**
|
- packages/misskey-js/**
|
||||||
- .github/workflows/test-backend.yml
|
- .github/workflows/test-backend.yml
|
||||||
- .github/misskey/test.yml
|
- .github/misskey/test.yml
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
force_ffmpeg_cache_update:
|
|
||||||
description: 'Force update ffmpeg cache'
|
|
||||||
required: false
|
|
||||||
default: false
|
|
||||||
type: boolean
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
unit:
|
unit:
|
||||||
name: Unit tests (backend)
|
name: Unit tests (backend)
|
||||||
|
@ -55,22 +47,7 @@ jobs:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.1.0
|
uses: pnpm/action-setup@v4.1.0
|
||||||
- name: Get current date
|
|
||||||
id: current-date
|
|
||||||
run: echo "today=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
|
|
||||||
- name: Setup and Restore ffmpeg/ffprobe Cache
|
|
||||||
id: cache-ffmpeg
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
/usr/local/bin/ffmpeg
|
|
||||||
/usr/local/bin/ffprobe
|
|
||||||
# daily cache
|
|
||||||
key: ${{ runner.os }}-ffmpeg-${{ steps.current-date.outputs.today }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-ffmpeg-${{ steps.current-date.outputs.today }}
|
|
||||||
- name: Install FFmpeg
|
- name: Install FFmpeg
|
||||||
if: steps.cache-ffmpeg.outputs.cache-hit != 'true' || github.event.inputs.force_ffmpeg_cache_update == true
|
|
||||||
run: |
|
run: |
|
||||||
for i in {1..3}; do
|
for i in {1..3}; do
|
||||||
echo "Attempt $i: Installing FFmpeg..."
|
echo "Attempt $i: Installing FFmpeg..."
|
||||||
|
|
22
.github/workflows/test-federation.yml
vendored
22
.github/workflows/test-federation.yml
vendored
|
@ -14,13 +14,6 @@ on:
|
||||||
- packages/backend/**
|
- packages/backend/**
|
||||||
- packages/misskey-js/**
|
- packages/misskey-js/**
|
||||||
- .github/workflows/test-federation.yml
|
- .github/workflows/test-federation.yml
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
force_ffmpeg_cache_update:
|
|
||||||
description: 'Force update ffmpeg cache'
|
|
||||||
required: false
|
|
||||||
default: false
|
|
||||||
type: boolean
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
|
@ -37,22 +30,7 @@ jobs:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.1.0
|
uses: pnpm/action-setup@v4.1.0
|
||||||
- name: Get current date
|
|
||||||
id: current-date
|
|
||||||
run: echo "today=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
|
|
||||||
- name: Setup and Restore ffmpeg/ffprobe Cache
|
|
||||||
id: cache-ffmpeg
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
/usr/local/bin/ffmpeg
|
|
||||||
/usr/local/bin/ffprobe
|
|
||||||
# daily cache
|
|
||||||
key: ${{ runner.os }}-ffmpeg-${{ steps.current-date.outputs.today }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-ffmpeg-${{ steps.current-date.outputs.today }}
|
|
||||||
- name: Install FFmpeg
|
- name: Install FFmpeg
|
||||||
if: steps.cache-ffmpeg.outputs.cache-hit != 'true' || github.event.inputs.force_ffmpeg_cache_update == true
|
|
||||||
run: |
|
run: |
|
||||||
for i in {1..3}; do
|
for i in {1..3}; do
|
||||||
echo "Attempt $i: Installing FFmpeg..."
|
echo "Attempt $i: Installing FFmpeg..."
|
||||||
|
|
31
CHANGELOG.md
31
CHANGELOG.md
|
@ -1,34 +1,3 @@
|
||||||
## 2025.6.4
|
|
||||||
|
|
||||||
### General
|
|
||||||
- Feat: ノートの下書き機能
|
|
||||||
- Feat: クリップ内でノートを検索できるように
|
|
||||||
|
|
||||||
### Client
|
|
||||||
- Feat: モデログを検索できるように
|
|
||||||
- Enhance: 設定の自動バックアップをオンにした直後に自動バックアップするように
|
|
||||||
- Enhance: ファイルアップロード前にキャプション設定を行えるように
|
|
||||||
- Enhance: ファイルアップロード時にセンシティブ設定されているか表示するように
|
|
||||||
- Enhance: ページネーション(一覧表示)の並び順を逆にできるように
|
|
||||||
- Enhance: ページネーション(一覧表示)の基準日時を指定できるように
|
|
||||||
- Fix: ファイルがドライブの既定アップロード先に指定したフォルダにアップロードされない問題を修正
|
|
||||||
|
|
||||||
### Server
|
|
||||||
- Enhance: sinceId/untilIdが指定可能なエンドポイントにおいて、sinceDate/untilDateも指定可能に
|
|
||||||
- Fix: ジョブキューのProgressの値を正しく計算する
|
|
||||||
|
|
||||||
|
|
||||||
## 2025.6.3
|
|
||||||
|
|
||||||
### Client
|
|
||||||
- Fix: キャッシュを削除しないとクライアントが使用できないことがある問題を修正
|
|
||||||
|
|
||||||
## 2025.6.2
|
|
||||||
|
|
||||||
### Client
|
|
||||||
- Fix: キャッシュを削除しないとクライアントが使用できないことがある問題を修正
|
|
||||||
- 翻訳の更新
|
|
||||||
|
|
||||||
## 2025.6.1
|
## 2025.6.1
|
||||||
|
|
||||||
### Note
|
### Note
|
||||||
|
|
|
@ -1313,7 +1313,6 @@ availableRoles: "Roles disponibles "
|
||||||
acknowledgeNotesAndEnable: "Activa'l després de comprendre els possibles perills."
|
acknowledgeNotesAndEnable: "Activa'l després de comprendre els possibles perills."
|
||||||
federationSpecified: "Aquest servidor treballa amb una federació de llistes blanques. No pot interactuar amb altres servidors que no siguin els especificats per l'administrador."
|
federationSpecified: "Aquest servidor treballa amb una federació de llistes blanques. No pot interactuar amb altres servidors que no siguin els especificats per l'administrador."
|
||||||
federationDisabled: "La unió es troba deshabilitada en aquest servidor. No es pot interactuar amb usuaris d'altres servidors."
|
federationDisabled: "La unió es troba deshabilitada en aquest servidor. No es pot interactuar amb usuaris d'altres servidors."
|
||||||
draft: "Esborrany "
|
|
||||||
confirmOnReact: "Confirmar en reaccionar"
|
confirmOnReact: "Confirmar en reaccionar"
|
||||||
reactAreYouSure: "Vols reaccionar amb \"{emoji}\"?"
|
reactAreYouSure: "Vols reaccionar amb \"{emoji}\"?"
|
||||||
markAsSensitiveConfirm: "Vols marcar aquest contingut com a sensible?"
|
markAsSensitiveConfirm: "Vols marcar aquest contingut com a sensible?"
|
||||||
|
@ -1351,7 +1350,7 @@ embed: "Incrustar"
|
||||||
settingsMigrating: "Estem migrant la teva configuració. Si us plau espera un moment... (També pots fer la migració més tard, manualment, anant a Preferències → Altres → Migrar configuració antiga)"
|
settingsMigrating: "Estem migrant la teva configuració. Si us plau espera un moment... (També pots fer la migració més tard, manualment, anant a Preferències → Altres → Migrar configuració antiga)"
|
||||||
readonly: "Només lectura"
|
readonly: "Només lectura"
|
||||||
goToDeck: "Tornar al tauler"
|
goToDeck: "Tornar al tauler"
|
||||||
federationJobs: "Treballs de federació"
|
federationJobs: "Treballs sindicats "
|
||||||
driveAboutTip: "Al Disc veure's una llista de tots els arxius que has anat pujant.<br>\nPots tornar-los a fer servir adjuntant-los a notes noves o pots adelantar-te i pujar arxius per publicar-los més tard!<br>\n<b>Tingués en compte que si esborres un arxiu també desapareixerà de tots els llocs on l'has fet servir (notes, pàgines, avatars, imatges de capçalera, etc.)</b><br>\nTambé pots crear carpetes per organitzar les."
|
driveAboutTip: "Al Disc veure's una llista de tots els arxius que has anat pujant.<br>\nPots tornar-los a fer servir adjuntant-los a notes noves o pots adelantar-te i pujar arxius per publicar-los més tard!<br>\n<b>Tingués en compte que si esborres un arxiu també desapareixerà de tots els llocs on l'has fet servir (notes, pàgines, avatars, imatges de capçalera, etc.)</b><br>\nTambé pots crear carpetes per organitzar les."
|
||||||
scrollToClose: "Desplaçar per tancar"
|
scrollToClose: "Desplaçar per tancar"
|
||||||
advice: "Consell"
|
advice: "Consell"
|
||||||
|
@ -1368,9 +1367,6 @@ redisplayAllTips: "Torna ha mostrat tots els trucs i consells"
|
||||||
hideAllTips: "Amagar tots els trucs i consells"
|
hideAllTips: "Amagar tots els trucs i consells"
|
||||||
defaultImageCompressionLevel: "Nivell de comprensió de la imatge per defecte"
|
defaultImageCompressionLevel: "Nivell de comprensió de la imatge per defecte"
|
||||||
defaultImageCompressionLevel_description: "Baixa, conserva la qualitat de la imatge però la mida de l'arxiu és més gran. <br>Alta, redueix la mida de l'arxiu però també la qualitat de la imatge."
|
defaultImageCompressionLevel_description: "Baixa, conserva la qualitat de la imatge però la mida de l'arxiu és més gran. <br>Alta, redueix la mida de l'arxiu però també la qualitat de la imatge."
|
||||||
_order:
|
|
||||||
newest: "Més recent"
|
|
||||||
oldest: "Cronològic"
|
|
||||||
_chat:
|
_chat:
|
||||||
noMessagesYet: "Encara no tens missatges "
|
noMessagesYet: "Encara no tens missatges "
|
||||||
newMessage: "Missatge nou"
|
newMessage: "Missatge nou"
|
||||||
|
@ -1997,7 +1993,6 @@ _role:
|
||||||
uploadableFileTypes: "Tipus de fitxers que en podeu pujar"
|
uploadableFileTypes: "Tipus de fitxers que en podeu pujar"
|
||||||
uploadableFileTypes_caption: "Especifica el tipus MIME. Es poden especificar diferents tipus MIME separats amb una nova línia, i es poden especificar comodins amb asteriscs (*). (Per exemple: image/*)"
|
uploadableFileTypes_caption: "Especifica el tipus MIME. Es poden especificar diferents tipus MIME separats amb una nova línia, i es poden especificar comodins amb asteriscs (*). (Per exemple: image/*)"
|
||||||
uploadableFileTypes_caption2: "Pot que no sigui possible determinar el tipus MIME d'alguns arxius. Per permetre aquests tipus d'arxius afegeix {x} a les especificacions."
|
uploadableFileTypes_caption2: "Pot que no sigui possible determinar el tipus MIME d'alguns arxius. Per permetre aquests tipus d'arxius afegeix {x} a les especificacions."
|
||||||
noteDraftLimit: "Nombre possible d'esborranys de notes al servidor"
|
|
||||||
_condition:
|
_condition:
|
||||||
roleAssignedTo: "Assignat a rols manuals"
|
roleAssignedTo: "Assignat a rols manuals"
|
||||||
isLocal: "Usuari local"
|
isLocal: "Usuari local"
|
||||||
|
@ -2157,7 +2152,6 @@ _theme:
|
||||||
install: "Instal·lar un tema"
|
install: "Instal·lar un tema"
|
||||||
manage: "Gestionar els temes "
|
manage: "Gestionar els temes "
|
||||||
code: "Codi del tema"
|
code: "Codi del tema"
|
||||||
copyThemeCode: "Copiar el codi del tema"
|
|
||||||
description: "Descripció"
|
description: "Descripció"
|
||||||
installed: "{name} Instal·lat "
|
installed: "{name} Instal·lat "
|
||||||
installedThemes: "Temes instal·lats "
|
installedThemes: "Temes instal·lats "
|
||||||
|
@ -3109,7 +3103,6 @@ _serverSetupWizard:
|
||||||
text2: "Si ho desitges, agrairíem molt la teva donació per poder seguir desenvolupant el projecte."
|
text2: "Si ho desitges, agrairíem molt la teva donació per poder seguir desenvolupant el projecte."
|
||||||
text3: "També hi ha privilegis especials per als donants!"
|
text3: "També hi ha privilegis especials per als donants!"
|
||||||
_uploader:
|
_uploader:
|
||||||
editImage: "Edició d'imatges"
|
|
||||||
compressedToX: "Comprimit a {x}"
|
compressedToX: "Comprimit a {x}"
|
||||||
savedXPercent: "{x}% d'estalvi "
|
savedXPercent: "{x}% d'estalvi "
|
||||||
abortConfirm: "Hi ha un arxiu que no s'ha pujat, vols cancel·lar?"
|
abortConfirm: "Hi ha un arxiu que no s'ha pujat, vols cancel·lar?"
|
||||||
|
@ -3176,20 +3169,3 @@ _imageEffector:
|
||||||
stripe: "Bandes"
|
stripe: "Bandes"
|
||||||
polkadot: "Lunars"
|
polkadot: "Lunars"
|
||||||
checker: "Escacs"
|
checker: "Escacs"
|
||||||
blockNoise: "Bloqueig de soroll"
|
|
||||||
tearing: "Trencament d'imatge "
|
|
||||||
drafts: "Esborrany "
|
|
||||||
_drafts:
|
|
||||||
select: "Seleccionar esborrany"
|
|
||||||
cannotCreateDraftAnymore: "S'ha sobrepassat el nombre màxim d'esborranys que es poden crear."
|
|
||||||
cannotCreateDraftOfRenote: "No es poden crear esborranys de remotes."
|
|
||||||
delete: "Esborrar esborranys"
|
|
||||||
deleteAreYouSure: "Vols esborrar els esborranys?"
|
|
||||||
noDrafts: "No hi ha esborranys"
|
|
||||||
replyTo: "Respondre a {user}"
|
|
||||||
quoteOf: "Citar les notes de {user}"
|
|
||||||
postTo: "Destinat a {channel}"
|
|
||||||
saveToDraft: "Desar com a esborrany"
|
|
||||||
restoreFromDraft: "Restaurar des dels esborranys"
|
|
||||||
restore: "Restaurar esborrany"
|
|
||||||
listDrafts: "Llistat d'esborranys"
|
|
||||||
|
|
|
@ -1347,7 +1347,7 @@ right: "Rechts"
|
||||||
bottom: "Unten"
|
bottom: "Unten"
|
||||||
top: "Oben"
|
top: "Oben"
|
||||||
embed: "Einbetten"
|
embed: "Einbetten"
|
||||||
settingsMigrating: "Deine Einstellungen werden gerade migriert. Bitte warte einen Moment... (Du kannst die Einstellungen später auch manuell migrieren, indem du zu Einstellungen → Anderes → Alte Einstellungen migrieren gehst)"
|
settingsMigrating: "Ihre Einstellungen werden gerade migriert, Bitte warten Sie einen Moment... (Sie können die Einstellungen später auch manuell migrieren, indem Sie zu Einstellungen → Sonstiges → Alte Einstellungen migrieren gehen)"
|
||||||
readonly: "Nur Lesezugriff"
|
readonly: "Nur Lesezugriff"
|
||||||
goToDeck: "Zurück zum Deck"
|
goToDeck: "Zurück zum Deck"
|
||||||
federationJobs: "Föderation Jobs"
|
federationJobs: "Föderation Jobs"
|
||||||
|
@ -1645,7 +1645,6 @@ _serverSettings:
|
||||||
allowExternalApRedirect_description: "Wenn diese Option aktiviert ist, können andere Server Inhalte von Drittanbietern über diesen Server abfragen, was jedoch zu Content-Spoofing führen kann."
|
allowExternalApRedirect_description: "Wenn diese Option aktiviert ist, können andere Server Inhalte von Drittanbietern über diesen Server abfragen, was jedoch zu Content-Spoofing führen kann."
|
||||||
userGeneratedContentsVisibilityForVisitor: "Sichtbarkeit von nutzergenerierten Inhalten für Gäste"
|
userGeneratedContentsVisibilityForVisitor: "Sichtbarkeit von nutzergenerierten Inhalten für Gäste"
|
||||||
userGeneratedContentsVisibilityForVisitor_description: "Dies ist nützlich, um zu verhindern, dass unangemessene Inhalte, die nicht gut moderiert sind, ungewollt über deinen eigenen Server im Internet veröffentlicht werden."
|
userGeneratedContentsVisibilityForVisitor_description: "Dies ist nützlich, um zu verhindern, dass unangemessene Inhalte, die nicht gut moderiert sind, ungewollt über deinen eigenen Server im Internet veröffentlicht werden."
|
||||||
userGeneratedContentsVisibilityForVisitor_description2: "Die uneingeschränkte Veröffentlichung aller Inhalte des Servers im Internet, einschließlich der vom Server empfangenen Fremdinhalte, birgt Risiken. Dies ist besonders wichtig für Betrachter, die sich des dezentralen Charakters der Inhalte nicht bewusst sind, da sie selbst fremde Inhalte fälschlicherweise als auf dem Server erstellte Inhalte wahrnehmen könnten."
|
|
||||||
_userGeneratedContentsVisibilityForVisitor:
|
_userGeneratedContentsVisibilityForVisitor:
|
||||||
all: "Alles ist öffentlich"
|
all: "Alles ist öffentlich"
|
||||||
localOnly: "Nur lokale Inhalte werden veröffentlicht, fremde Inhalte bleiben privat"
|
localOnly: "Nur lokale Inhalte werden veröffentlicht, fremde Inhalte bleiben privat"
|
||||||
|
@ -2465,8 +2464,6 @@ _visibility:
|
||||||
disableFederation: "Deföderieren"
|
disableFederation: "Deföderieren"
|
||||||
disableFederationDescription: "Nicht an andere Instanzen übertragen"
|
disableFederationDescription: "Nicht an andere Instanzen übertragen"
|
||||||
_postForm:
|
_postForm:
|
||||||
quitInspiteOfThereAreUnuploadedFilesConfirm: "Es gibt Dateien, die nicht hochgeladen wurden. Möchtest du diese verwerfen und das Formular schließen?"
|
|
||||||
uploaderTip: "Die Datei wurde noch nicht hochgeladen. Über das Dateimenü kannst du sie umbenennen, das Bild zuschneiden, ein Wasserzeichen hinzufügen, komprimieren usw. Die Datei wird automatisch hochgeladen, wenn du eine Notiz veröffentlichst."
|
|
||||||
replyPlaceholder: "Dieser Notiz antworten …"
|
replyPlaceholder: "Dieser Notiz antworten …"
|
||||||
quotePlaceholder: "Diese Notiz zitieren …"
|
quotePlaceholder: "Diese Notiz zitieren …"
|
||||||
channelPlaceholder: "In einen Kanal senden"
|
channelPlaceholder: "In einen Kanal senden"
|
||||||
|
@ -2847,12 +2844,8 @@ _dataSaver:
|
||||||
_avatar:
|
_avatar:
|
||||||
title: "Animierte Profilbilder deaktivieren"
|
title: "Animierte Profilbilder deaktivieren"
|
||||||
description: "Die Animation von Profilbildern wird angehalten. Da animierte Bilder eine größere Dateigröße haben können als normale Bilder, kann dies den Datenverkehr weiter reduzieren."
|
description: "Die Animation von Profilbildern wird angehalten. Da animierte Bilder eine größere Dateigröße haben können als normale Bilder, kann dies den Datenverkehr weiter reduzieren."
|
||||||
_urlPreviewThumbnail:
|
|
||||||
title: "URL-Vorschaubilder ausblenden"
|
|
||||||
description: "URL-Vorschaubilder werden nicht mehr geladen."
|
|
||||||
_disableUrlPreview:
|
_disableUrlPreview:
|
||||||
title: "URL-Vorschau deaktivieren"
|
title: "URL-Vorschau deaktivieren"
|
||||||
description: "Deaktiviert die URL-Vorschaufunktion. Anders als bei reinen Vorschaubildern wird dadurch das Laden der verlinkten Informationen selbst reduziert."
|
|
||||||
_code:
|
_code:
|
||||||
title: "Code-Hervorhebungen ausblenden"
|
title: "Code-Hervorhebungen ausblenden"
|
||||||
description: "Wenn Code-Hervorhebungen in MFM usw. verwendet werden, werden sie erst geladen, wenn sie angetippt werden. Die Syntaxhervorhebung erfordert das Herunterladen der Definitionsdateien für jede Programmiersprache. Es ist daher zu erwarten, dass die Deaktivierung des automatischen Ladens dieser Dateien die Menge des Datenverkehrs reduziert."
|
description: "Wenn Code-Hervorhebungen in MFM usw. verwendet werden, werden sie erst geladen, wenn sie angetippt werden. Die Syntaxhervorhebung erfordert das Herunterladen der Definitionsdateien für jede Programmiersprache. Es ist daher zu erwarten, dass die Deaktivierung des automatischen Ladens dieser Dateien die Menge des Datenverkehrs reduziert."
|
||||||
|
@ -2910,8 +2903,6 @@ _offlineScreen:
|
||||||
_urlPreviewSetting:
|
_urlPreviewSetting:
|
||||||
title: "Einstellungen der URL-Vorschau"
|
title: "Einstellungen der URL-Vorschau"
|
||||||
enable: "URL-Vorschau aktivieren"
|
enable: "URL-Vorschau aktivieren"
|
||||||
allowRedirect: "Umleitung von URL-Vorschauen erlauben"
|
|
||||||
allowRedirectDescription: "Wenn für eine URL eine Umleitung festgelegt ist, kann diese Funktion aktiviert werden, um der Umleitung zu folgen und eine Vorschau des umgeleiteten Inhalts anzuzeigen. Die Deaktivierung spart Serverressourcen, aber der Inhalt des Weiterleitungsziels wird nicht angezeigt."
|
|
||||||
timeout: "Zeitüberschreitung beim Abrufen der Vorschau (ms)"
|
timeout: "Zeitüberschreitung beim Abrufen der Vorschau (ms)"
|
||||||
timeoutDescription: "Übersteigt die für die Vorschau benötigte Zeit diesen Wert, wird keine Vorschau generiert."
|
timeoutDescription: "Übersteigt die für die Vorschau benötigte Zeit diesen Wert, wird keine Vorschau generiert."
|
||||||
maximumContentLength: "Maximale Content-Length (Bytes)"
|
maximumContentLength: "Maximale Content-Length (Bytes)"
|
||||||
|
@ -3073,11 +3064,8 @@ _serverSetupWizard:
|
||||||
single_description: "Verwende den Server alleine als deinen eigenen."
|
single_description: "Verwende den Server alleine als deinen eigenen."
|
||||||
single_youCanCreateMultipleAccounts: "Bei Bedarf können mehrere Konten eingerichtet werden, auch wenn es sich um einen Ein-Personen-Server handelt."
|
single_youCanCreateMultipleAccounts: "Bei Bedarf können mehrere Konten eingerichtet werden, auch wenn es sich um einen Ein-Personen-Server handelt."
|
||||||
group: "Gruppenserver"
|
group: "Gruppenserver"
|
||||||
group_description: "Lade andere vertrauenswürdige Benutzer ein und verwende es mit mehreren Personen."
|
|
||||||
open: "Offener Server"
|
open: "Offener Server"
|
||||||
open_description: "Registrierung für alle öffnen."
|
open_description: "Registrierung für alle öffnen."
|
||||||
openServerAdvice: "Die Aufnahme einer unbestimmten Anzahl von Nutzern birgt Risiken. Es wird empfohlen, mit einem zuverlässigen Moderationssystem zu arbeiten, um eventuell auftretende Probleme behandeln zu können."
|
|
||||||
openServerAntiSpamAdvice: "Große Sorgfalt muss auch auf die Sicherheit gelegt werden, z. B. durch die Aktivierung von Anti-Bot-Funktionen wie reCAPTCHA, um sicherzustellen, dass der Server nicht zum Verbreiten von Spam genutzt wird."
|
|
||||||
howManyUsersDoYouExpect: "Mit wie vielen Benutzern rechnest du?"
|
howManyUsersDoYouExpect: "Mit wie vielen Benutzern rechnest du?"
|
||||||
_scale:
|
_scale:
|
||||||
small: "Weniger als 100 (kleiner Maßstab)"
|
small: "Weniger als 100 (kleiner Maßstab)"
|
||||||
|
@ -3088,8 +3076,6 @@ _serverSetupWizard:
|
||||||
doYouConnectToFediverse_description1: "Bei Anschluss an ein Netz von verteilten Servern (Fediverse) können Inhalte mit anderen Servern ausgetauscht werden."
|
doYouConnectToFediverse_description1: "Bei Anschluss an ein Netz von verteilten Servern (Fediverse) können Inhalte mit anderen Servern ausgetauscht werden."
|
||||||
doYouConnectToFediverse_description2: "Die Verbindung mit dem Fediverse wird auch als „Föderation“ bezeichnet."
|
doYouConnectToFediverse_description2: "Die Verbindung mit dem Fediverse wird auch als „Föderation“ bezeichnet."
|
||||||
youCanConfigureMoreFederationSettingsLater: "Erweiterte Einstellungen, wie z. B. die Angabe von föderierbaren Servern, können später vorgenommen werden."
|
youCanConfigureMoreFederationSettingsLater: "Erweiterte Einstellungen, wie z. B. die Angabe von föderierbaren Servern, können später vorgenommen werden."
|
||||||
adminInfo: "Administrator-Informationen"
|
|
||||||
adminInfo_description: "Legt die Administrator-Informationen fest, die für den Empfang von Anfragen verwendet werden."
|
|
||||||
adminInfo_mustBeFilled: "Dies ist auf einem offenen Server oder bei aktivierter Föderation erforderlich."
|
adminInfo_mustBeFilled: "Dies ist auf einem offenen Server oder bei aktivierter Föderation erforderlich."
|
||||||
followingSettingsAreRecommended: "Die folgenden Einstellungen werden empfohlen"
|
followingSettingsAreRecommended: "Die folgenden Einstellungen werden empfohlen"
|
||||||
applyTheseSettings: "Diese Einstellungen anwenden"
|
applyTheseSettings: "Diese Einstellungen anwenden"
|
||||||
|
@ -3124,12 +3110,10 @@ _userLists:
|
||||||
watermark: "Wasserzeichen"
|
watermark: "Wasserzeichen"
|
||||||
defaultPreset: "Standard-Voreinstellungen"
|
defaultPreset: "Standard-Voreinstellungen"
|
||||||
_watermarkEditor:
|
_watermarkEditor:
|
||||||
tip: "Dem Bild kann ein Wasserzeichen, z. B. eine Quellenangabe, hinzugefügt werden."
|
|
||||||
quitWithoutSaveConfirm: "Nicht gespeicherte Änderungen verwerfen?"
|
quitWithoutSaveConfirm: "Nicht gespeicherte Änderungen verwerfen?"
|
||||||
driveFileTypeWarn: "Diese Datei wird nicht unterstützt"
|
driveFileTypeWarn: "Diese Datei wird nicht unterstützt"
|
||||||
driveFileTypeWarnDescription: "Bilddatei auswählen"
|
driveFileTypeWarnDescription: "Bilddatei auswählen"
|
||||||
title: "Wasserzeichen bearbeiten"
|
title: "Wasserzeichen bearbeiten"
|
||||||
cover: "Alles bedecken"
|
|
||||||
opacity: "Transparenz"
|
opacity: "Transparenz"
|
||||||
scale: "Größe"
|
scale: "Größe"
|
||||||
text: "Text"
|
text: "Text"
|
||||||
|
@ -3137,9 +3121,6 @@ _watermarkEditor:
|
||||||
type: "Art"
|
type: "Art"
|
||||||
image: "Bilder"
|
image: "Bilder"
|
||||||
advanced: "Fortgeschritten"
|
advanced: "Fortgeschritten"
|
||||||
stripe: "Streifen"
|
|
||||||
stripeWidth: "Linienbreite"
|
|
||||||
stripeFrequency: "Linienanzahl"
|
|
||||||
angle: "Winkel"
|
angle: "Winkel"
|
||||||
_imageEffector:
|
_imageEffector:
|
||||||
title: "Effekte"
|
title: "Effekte"
|
||||||
|
@ -3152,9 +3133,3 @@ _imageEffector:
|
||||||
invert: "Farben umkehren"
|
invert: "Farben umkehren"
|
||||||
grayscale: "Schwarzweiß"
|
grayscale: "Schwarzweiß"
|
||||||
colorAdjust: "Farbkorrektur"
|
colorAdjust: "Farbkorrektur"
|
||||||
colorClamp: "Farbkomprimierung"
|
|
||||||
colorClampAdvanced: "Farbkomprimierung (erweitert)"
|
|
||||||
distort: "Verzerrung"
|
|
||||||
stripe: "Streifen"
|
|
||||||
_drafts:
|
|
||||||
restore: "Wiederherstellen"
|
|
||||||
|
|
|
@ -327,7 +327,7 @@ dark: "Dark"
|
||||||
lightThemes: "Light themes"
|
lightThemes: "Light themes"
|
||||||
darkThemes: "Dark themes"
|
darkThemes: "Dark themes"
|
||||||
syncDeviceDarkMode: "Sync Dark Mode with your device settings"
|
syncDeviceDarkMode: "Sync Dark Mode with your device settings"
|
||||||
switchDarkModeManuallyWhenSyncEnabledConfirm: "\"{x}\" is turned on. Would you like to turn off synchronization and switch modes manually?"
|
switchDarkModeManuallyWhenSyncEnabledConfirm: "\"{x}\" is turned on, Would you like to turn off synchronization and switch modes manually?"
|
||||||
drive: "Drive"
|
drive: "Drive"
|
||||||
fileName: "Filename"
|
fileName: "Filename"
|
||||||
selectFile: "Select a file"
|
selectFile: "Select a file"
|
||||||
|
@ -1313,7 +1313,6 @@ availableRoles: "Available roles"
|
||||||
acknowledgeNotesAndEnable: "Turn on after understanding the precautions."
|
acknowledgeNotesAndEnable: "Turn on after understanding the precautions."
|
||||||
federationSpecified: "This server is operated in a whitelist federation. Interacting with servers other than those designated by the administrator is not allowed."
|
federationSpecified: "This server is operated in a whitelist federation. Interacting with servers other than those designated by the administrator is not allowed."
|
||||||
federationDisabled: "Federation is disabled on this server. You cannot interact with users on other servers."
|
federationDisabled: "Federation is disabled on this server. You cannot interact with users on other servers."
|
||||||
draft: "Drafts"
|
|
||||||
confirmOnReact: "Confirm when reacting"
|
confirmOnReact: "Confirm when reacting"
|
||||||
reactAreYouSure: "Would you like to add a \"{emoji}\" reaction?"
|
reactAreYouSure: "Would you like to add a \"{emoji}\" reaction?"
|
||||||
markAsSensitiveConfirm: "Do you want to set this media as sensitive?"
|
markAsSensitiveConfirm: "Do you want to set this media as sensitive?"
|
||||||
|
@ -1368,9 +1367,6 @@ redisplayAllTips: "Show all “Tips & Tricks” again"
|
||||||
hideAllTips: "Hide all \"Tips & Tricks\""
|
hideAllTips: "Hide all \"Tips & Tricks\""
|
||||||
defaultImageCompressionLevel: "Default image compression level"
|
defaultImageCompressionLevel: "Default image compression level"
|
||||||
defaultImageCompressionLevel_description: "High, reduces the file size but also the image quality. <br>High, reduces the file size but also the image quality."
|
defaultImageCompressionLevel_description: "High, reduces the file size but also the image quality. <br>High, reduces the file size but also the image quality."
|
||||||
_order:
|
|
||||||
newest: "Newest First"
|
|
||||||
oldest: "Oldest First"
|
|
||||||
_chat:
|
_chat:
|
||||||
noMessagesYet: "No messages yet"
|
noMessagesYet: "No messages yet"
|
||||||
newMessage: "New message"
|
newMessage: "New message"
|
||||||
|
@ -1997,7 +1993,6 @@ _role:
|
||||||
uploadableFileTypes: "Uploadable file types"
|
uploadableFileTypes: "Uploadable file types"
|
||||||
uploadableFileTypes_caption: "Specifies the allowed MIME/file types. Multiple MIME types can be specified by separating them with a new line, and wildcards can be specified with an asterisk (*). (e.g., image/*)"
|
uploadableFileTypes_caption: "Specifies the allowed MIME/file types. Multiple MIME types can be specified by separating them with a new line, and wildcards can be specified with an asterisk (*). (e.g., image/*)"
|
||||||
uploadableFileTypes_caption2: "Some files types might fail to be detected. To allow such files, add {x} to the specification."
|
uploadableFileTypes_caption2: "Some files types might fail to be detected. To allow such files, add {x} to the specification."
|
||||||
noteDraftLimit: "Number of possible drafts of server notes"
|
|
||||||
_condition:
|
_condition:
|
||||||
roleAssignedTo: "Assigned to manual roles"
|
roleAssignedTo: "Assigned to manual roles"
|
||||||
isLocal: "Local user"
|
isLocal: "Local user"
|
||||||
|
@ -2157,7 +2152,6 @@ _theme:
|
||||||
install: "Install a theme"
|
install: "Install a theme"
|
||||||
manage: "Manage themes"
|
manage: "Manage themes"
|
||||||
code: "Theme code"
|
code: "Theme code"
|
||||||
copyThemeCode: "Copy theme code"
|
|
||||||
description: "Description"
|
description: "Description"
|
||||||
installed: "{name} has been installed"
|
installed: "{name} has been installed"
|
||||||
installedThemes: "Installed themes"
|
installedThemes: "Installed themes"
|
||||||
|
@ -2471,8 +2465,6 @@ _visibility:
|
||||||
disableFederation: "Defederate"
|
disableFederation: "Defederate"
|
||||||
disableFederationDescription: "Don't transmit to other instances"
|
disableFederationDescription: "Don't transmit to other instances"
|
||||||
_postForm:
|
_postForm:
|
||||||
quitInspiteOfThereAreUnuploadedFilesConfirm: "There are files that have not been uploaded, do you want to discard them and close the form?"
|
|
||||||
uploaderTip: "The file has not yet been uploaded. From the file menu, you can rename, crop images, watermark and compress or uncompress the file. Files are automatically uploaded when you publish a note."
|
|
||||||
replyPlaceholder: "Reply to this note..."
|
replyPlaceholder: "Reply to this note..."
|
||||||
quotePlaceholder: "Quote this note..."
|
quotePlaceholder: "Quote this note..."
|
||||||
channelPlaceholder: "Post to a channel..."
|
channelPlaceholder: "Post to a channel..."
|
||||||
|
@ -3109,7 +3101,6 @@ _serverSetupWizard:
|
||||||
text2: "We would appreciate your support so that we can continue to develop this software further into the future."
|
text2: "We would appreciate your support so that we can continue to develop this software further into the future."
|
||||||
text3: "There are also special benefits for supporters!"
|
text3: "There are also special benefits for supporters!"
|
||||||
_uploader:
|
_uploader:
|
||||||
editImage: "Edit Image"
|
|
||||||
compressedToX: "Compressed to {x}"
|
compressedToX: "Compressed to {x}"
|
||||||
savedXPercent: "Saving {x}%"
|
savedXPercent: "Saving {x}%"
|
||||||
abortConfirm: "Some files have not been uploaded, do you want to abort?"
|
abortConfirm: "Some files have not been uploaded, do you want to abort?"
|
||||||
|
@ -3166,8 +3157,8 @@ _imageEffector:
|
||||||
glitch: "Glitch"
|
glitch: "Glitch"
|
||||||
mirror: "Mirror"
|
mirror: "Mirror"
|
||||||
invert: "Invert Colors"
|
invert: "Invert Colors"
|
||||||
grayscale: "Grayscale"
|
grayscale: "white-black"
|
||||||
colorAdjust: "Color Correction"
|
colorAdjust: "Colour Correction"
|
||||||
colorClamp: "Color Compression"
|
colorClamp: "Color Compression"
|
||||||
colorClampAdvanced: "Color Compression (Advanced)"
|
colorClampAdvanced: "Color Compression (Advanced)"
|
||||||
distort: "Distortion"
|
distort: "Distortion"
|
||||||
|
@ -3176,20 +3167,3 @@ _imageEffector:
|
||||||
stripe: "Stripes"
|
stripe: "Stripes"
|
||||||
polkadot: "Polkadot"
|
polkadot: "Polkadot"
|
||||||
checker: "Checker"
|
checker: "Checker"
|
||||||
blockNoise: "Block Noise"
|
|
||||||
tearing: "Tearing"
|
|
||||||
drafts: "Drafts"
|
|
||||||
_drafts:
|
|
||||||
select: "Select Draft"
|
|
||||||
cannotCreateDraftAnymore: "The number of drafts that can be created has been exceeded."
|
|
||||||
cannotCreateDraftOfRenote: "You cannot create a draft of a renote."
|
|
||||||
delete: "Delete Draft"
|
|
||||||
deleteAreYouSure: "Delete draft?"
|
|
||||||
noDrafts: "No drafts"
|
|
||||||
replyTo: "Reply to {user}"
|
|
||||||
quoteOf: "Citation to {user}'s note"
|
|
||||||
postTo: "Posting to {channel}"
|
|
||||||
saveToDraft: "Save to Draft"
|
|
||||||
restoreFromDraft: "Restore from Draft"
|
|
||||||
restore: "Restore"
|
|
||||||
listDrafts: "List of Drafts"
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ copyFileId: "Copiar ID del archivo"
|
||||||
copyFolderId: "Copiar ID de carpeta"
|
copyFolderId: "Copiar ID de carpeta"
|
||||||
copyProfileUrl: "Copiar la URL del perfil"
|
copyProfileUrl: "Copiar la URL del perfil"
|
||||||
searchUser: "Buscar un usuario"
|
searchUser: "Buscar un usuario"
|
||||||
searchThisUsersNotes: "Buscar en las notas de este usuario"
|
searchThisUsersNotes: ""
|
||||||
reply: "Responder"
|
reply: "Responder"
|
||||||
loadMore: "Ver más"
|
loadMore: "Ver más"
|
||||||
showMore: "Ver más"
|
showMore: "Ver más"
|
||||||
|
@ -125,7 +125,7 @@ renoteToOtherChannel: "Renotar a otro canal"
|
||||||
pinnedNote: "Nota fijada"
|
pinnedNote: "Nota fijada"
|
||||||
pinned: "Fijar al perfil"
|
pinned: "Fijar al perfil"
|
||||||
you: "Tú"
|
you: "Tú"
|
||||||
clickToShow: "Haz clic para verlo"
|
clickToShow: "Click para ver"
|
||||||
sensitive: "Marcado como sensible"
|
sensitive: "Marcado como sensible"
|
||||||
add: "Agregar"
|
add: "Agregar"
|
||||||
reaction: "Reacción"
|
reaction: "Reacción"
|
||||||
|
@ -168,7 +168,7 @@ customEmojis: "Emojis personalizados"
|
||||||
emoji: "Emoji"
|
emoji: "Emoji"
|
||||||
emojis: "Emoji"
|
emojis: "Emoji"
|
||||||
emojiName: "Nombre del emoji"
|
emojiName: "Nombre del emoji"
|
||||||
emojiUrl: "URL de la imagen del emoji"
|
emojiUrl: "URL de la imágen del emoji"
|
||||||
addEmoji: "Agregar emoji"
|
addEmoji: "Agregar emoji"
|
||||||
settingGuide: "Configuración sugerida"
|
settingGuide: "Configuración sugerida"
|
||||||
cacheRemoteFiles: "Mantener en cache los archivos remotos"
|
cacheRemoteFiles: "Mantener en cache los archivos remotos"
|
||||||
|
@ -848,7 +848,7 @@ info: "Información"
|
||||||
userInfo: "Información del usuario"
|
userInfo: "Información del usuario"
|
||||||
unknown: "Desconocido"
|
unknown: "Desconocido"
|
||||||
onlineStatus: "En línea"
|
onlineStatus: "En línea"
|
||||||
hideOnlineStatus: "Mostrarse como desconectado"
|
hideOnlineStatus: "mostrarse como desconectado"
|
||||||
hideOnlineStatusDescription: "Ocultar su estado en línea puede reducir la eficacia de algunas funciones, como la búsqueda"
|
hideOnlineStatusDescription: "Ocultar su estado en línea puede reducir la eficacia de algunas funciones, como la búsqueda"
|
||||||
online: "En línea"
|
online: "En línea"
|
||||||
active: "Activo"
|
active: "Activo"
|
||||||
|
@ -1313,7 +1313,6 @@ availableRoles: "Roles disponibles "
|
||||||
acknowledgeNotesAndEnable: "Activar después de comprender las precauciones"
|
acknowledgeNotesAndEnable: "Activar después de comprender las precauciones"
|
||||||
federationSpecified: "Este servidor opera en una federación de listas blancas. No puede interactuar con otros servidores que no sean los especificados por el administrador."
|
federationSpecified: "Este servidor opera en una federación de listas blancas. No puede interactuar con otros servidores que no sean los especificados por el administrador."
|
||||||
federationDisabled: "La federación está desactivada en este servidor. No puede interactuar con usuarios de otros servidores"
|
federationDisabled: "La federación está desactivada en este servidor. No puede interactuar con usuarios de otros servidores"
|
||||||
draft: "Borrador"
|
|
||||||
confirmOnReact: "Confirmar la reacción"
|
confirmOnReact: "Confirmar la reacción"
|
||||||
reactAreYouSure: "¿Quieres añadir una reacción «{emoji}»?"
|
reactAreYouSure: "¿Quieres añadir una reacción «{emoji}»?"
|
||||||
markAsSensitiveConfirm: "¿Desea establecer este medio multimedia(Imagen,vídeo...) como sensible?"
|
markAsSensitiveConfirm: "¿Desea establecer este medio multimedia(Imagen,vídeo...) como sensible?"
|
||||||
|
@ -1368,9 +1367,6 @@ redisplayAllTips: "Volver a mostrar todos \"Trucos y consejos\""
|
||||||
hideAllTips: "Ocultar todos los \"Trucos y consejos\""
|
hideAllTips: "Ocultar todos los \"Trucos y consejos\""
|
||||||
defaultImageCompressionLevel: "Nivel de compresión de la imagen por defecto"
|
defaultImageCompressionLevel: "Nivel de compresión de la imagen por defecto"
|
||||||
defaultImageCompressionLevel_description: "Baja, conserva la calidad de la imagen pero la medida del archivo es más grande. <br>Alta, reduce la medida del archivo pero también la calidad de la imagen."
|
defaultImageCompressionLevel_description: "Baja, conserva la calidad de la imagen pero la medida del archivo es más grande. <br>Alta, reduce la medida del archivo pero también la calidad de la imagen."
|
||||||
_order:
|
|
||||||
newest: "Los más recientes primero"
|
|
||||||
oldest: "Los más antiguos primero"
|
|
||||||
_chat:
|
_chat:
|
||||||
noMessagesYet: "Aún no hay mensajes"
|
noMessagesYet: "Aún no hay mensajes"
|
||||||
newMessage: "Mensajes nuevos"
|
newMessage: "Mensajes nuevos"
|
||||||
|
@ -1386,7 +1382,7 @@ _chat:
|
||||||
noInvitations: "No hay invitación."
|
noInvitations: "No hay invitación."
|
||||||
history: "Historial"
|
history: "Historial"
|
||||||
noHistory: "No hay datos en el historial"
|
noHistory: "No hay datos en el historial"
|
||||||
noRooms: "No te has unido a ninguna sala "
|
noRooms: "Sala no encontrada"
|
||||||
inviteUser: "Invitar usuarios"
|
inviteUser: "Invitar usuarios"
|
||||||
sentInvitations: "Invitaciones enviadas"
|
sentInvitations: "Invitaciones enviadas"
|
||||||
join: "Unirse"
|
join: "Unirse"
|
||||||
|
@ -1487,7 +1483,7 @@ _accountSettings:
|
||||||
makeNotesHiddenBeforeDescription: "Mientras esta función esté activada, las notas que hayan pasado la fecha y hora fijadas o hayan transcurrido el tiempo establecido sólo serán visibles para ti (se harán privadas). Si la desactivas, también se restablecerá el estado público de las notas."
|
makeNotesHiddenBeforeDescription: "Mientras esta función esté activada, las notas que hayan pasado la fecha y hora fijadas o hayan transcurrido el tiempo establecido sólo serán visibles para ti (se harán privadas). Si la desactivas, también se restablecerá el estado público de las notas."
|
||||||
mayNotEffectForFederatedNotes: "Notas federadas por un servidor remoto pueden no verse afectadas."
|
mayNotEffectForFederatedNotes: "Notas federadas por un servidor remoto pueden no verse afectadas."
|
||||||
mayNotEffectSomeSituations: "Estas restricciones son simplificadas. Pueden no aplicarse en algunas situaciones, como cuando se visualiza en un servidor remoto o durante la moderación."
|
mayNotEffectSomeSituations: "Estas restricciones son simplificadas. Pueden no aplicarse en algunas situaciones, como cuando se visualiza en un servidor remoto o durante la moderación."
|
||||||
notesHavePassedSpecifiedPeriod: "Notas publicadas durante el siguiente tiempo específico"
|
notesHavePassedSpecifiedPeriod: "Ten en cuenta que el tiempo especificado ha pasado"
|
||||||
notesOlderThanSpecifiedDateAndTime: "Notas antes de la fecha y hora especificadas"
|
notesOlderThanSpecifiedDateAndTime: "Notas antes de la fecha y hora especificadas"
|
||||||
_abuseUserReport:
|
_abuseUserReport:
|
||||||
forward: "Reenviar"
|
forward: "Reenviar"
|
||||||
|
@ -1997,7 +1993,6 @@ _role:
|
||||||
uploadableFileTypes: "Tipos de archivos que se pueden cargar."
|
uploadableFileTypes: "Tipos de archivos que se pueden cargar."
|
||||||
uploadableFileTypes_caption: "Especifica los tipos MIME/archivos permitidos. Se pueden especificar varios tipos MIME separándolos con una nueva línea, y se pueden especificar comodines con un asterisco (*). (por ejemplo, image/*)"
|
uploadableFileTypes_caption: "Especifica los tipos MIME/archivos permitidos. Se pueden especificar varios tipos MIME separándolos con una nueva línea, y se pueden especificar comodines con un asterisco (*). (por ejemplo, image/*)"
|
||||||
uploadableFileTypes_caption2: "Es posible que no se detecten algunos tipos de archivos. Para permitir estos archivos, añade {x} a la especificación."
|
uploadableFileTypes_caption2: "Es posible que no se detecten algunos tipos de archivos. Para permitir estos archivos, añade {x} a la especificación."
|
||||||
noteDraftLimit: "Número de posibles borradores de notas del servidor"
|
|
||||||
_condition:
|
_condition:
|
||||||
roleAssignedTo: "Asignado a roles manuales"
|
roleAssignedTo: "Asignado a roles manuales"
|
||||||
isLocal: "Usuario local"
|
isLocal: "Usuario local"
|
||||||
|
@ -2157,7 +2152,6 @@ _theme:
|
||||||
install: "Instalar tema"
|
install: "Instalar tema"
|
||||||
manage: "Gestor de temas"
|
manage: "Gestor de temas"
|
||||||
code: "Código del tema"
|
code: "Código del tema"
|
||||||
copyThemeCode: "Copiar el código del tema"
|
|
||||||
description: "Descripción"
|
description: "Descripción"
|
||||||
installed: "{name} ha sido instalado"
|
installed: "{name} ha sido instalado"
|
||||||
installedThemes: "Temas instalados"
|
installedThemes: "Temas instalados"
|
||||||
|
@ -2268,7 +2262,7 @@ _2fa:
|
||||||
setupCompleted: "Configuración completada"
|
setupCompleted: "Configuración completada"
|
||||||
step4: "Ahora cuando inicie sesión, ingrese el mismo token"
|
step4: "Ahora cuando inicie sesión, ingrese el mismo token"
|
||||||
securityKeyNotSupported: "Tu navegador no soporta claves de autenticación."
|
securityKeyNotSupported: "Tu navegador no soporta claves de autenticación."
|
||||||
registerTOTPBeforeKey: "Por favor. configura una aplicación de autenticación para registrar una llave de seguridad."
|
registerTOTPBeforeKey: "Please set up an authenticator app to register a security or pass key.\npor favor. configura una aplicación de autenticación para registrar una llave de seguridad."
|
||||||
securityKeyInfo: "Se puede configurar el inicio de sesión usando una clave de seguridad de hardware que soporte FIDO2 o con un certificado de huella digital o con un PIN"
|
securityKeyInfo: "Se puede configurar el inicio de sesión usando una clave de seguridad de hardware que soporte FIDO2 o con un certificado de huella digital o con un PIN"
|
||||||
registerSecurityKey: "Registrar una llave de seguridad"
|
registerSecurityKey: "Registrar una llave de seguridad"
|
||||||
securityKeyName: "Ingresa un nombre para la clave"
|
securityKeyName: "Ingresa un nombre para la clave"
|
||||||
|
@ -2908,7 +2902,7 @@ _reversi:
|
||||||
opponentHasSettingsChanged: "El oponente ha cambiado su configuración"
|
opponentHasSettingsChanged: "El oponente ha cambiado su configuración"
|
||||||
allowIrregularRules: "Reglas irregulares (completamente libre)"
|
allowIrregularRules: "Reglas irregulares (completamente libre)"
|
||||||
disallowIrregularRules: "Sin reglas irregulares "
|
disallowIrregularRules: "Sin reglas irregulares "
|
||||||
showBoardLabels: "Mostrar el número de línea y la letra de columna en el tablero de juego."
|
showBoardLabels: "Mostrar el número de línea y de columna en el tablero de juego."
|
||||||
useAvatarAsStone: "Usar los avatares de los usuarios como fichas\n"
|
useAvatarAsStone: "Usar los avatares de los usuarios como fichas\n"
|
||||||
_offlineScreen:
|
_offlineScreen:
|
||||||
title: "Fuera de línea. No se puede conectar con el servidor"
|
title: "Fuera de línea. No se puede conectar con el servidor"
|
||||||
|
@ -3109,7 +3103,6 @@ _serverSetupWizard:
|
||||||
text2: "Agradeceríamos su apoyo para que podamos seguir desarrollando este software en el futuro."
|
text2: "Agradeceríamos su apoyo para que podamos seguir desarrollando este software en el futuro."
|
||||||
text3: "También hay beneficios especiales para los donantes"
|
text3: "También hay beneficios especiales para los donantes"
|
||||||
_uploader:
|
_uploader:
|
||||||
editImage: "Editar la imagen"
|
|
||||||
compressedToX: "Comprimir a {x}"
|
compressedToX: "Comprimir a {x}"
|
||||||
savedXPercent: "Guardando {x}%"
|
savedXPercent: "Guardando {x}%"
|
||||||
abortConfirm: "Algunos archivos no se han cargado, ¿deseas cancelar?"
|
abortConfirm: "Algunos archivos no se han cargado, ¿deseas cancelar?"
|
||||||
|
@ -3176,20 +3169,3 @@ _imageEffector:
|
||||||
stripe: "Rayas"
|
stripe: "Rayas"
|
||||||
polkadot: "Lunares"
|
polkadot: "Lunares"
|
||||||
checker: "Corrector"
|
checker: "Corrector"
|
||||||
blockNoise: "Bloquear Ruido"
|
|
||||||
tearing: "Rasgado de Imagen (Tearing)"
|
|
||||||
drafts: "Borrador"
|
|
||||||
_drafts:
|
|
||||||
select: "Seleccionar borradores"
|
|
||||||
cannotCreateDraftAnymore: "Se ha superado el número de borradores que se pueden crear."
|
|
||||||
cannotCreateDraftOfRenote: "No se pueden crear borradores de renotas."
|
|
||||||
delete: "Eliminar borrador"
|
|
||||||
deleteAreYouSure: "¿Quieres borrar el borrador?"
|
|
||||||
noDrafts: "No hay borradores disponibles."
|
|
||||||
replyTo: "Responder a {user}"
|
|
||||||
quoteOf: "Citar las notas de {user}"
|
|
||||||
postTo: "Destino a {channel}"
|
|
||||||
saveToDraft: "Guardar como borrador"
|
|
||||||
restoreFromDraft: "Restaurar desde los borradores"
|
|
||||||
restore: "Restaurar"
|
|
||||||
listDrafts: "Listar los borradores"
|
|
||||||
|
|
84
locales/index.d.ts
vendored
84
locales/index.d.ts
vendored
|
@ -5270,10 +5270,6 @@ export interface Locale extends ILocale {
|
||||||
* このサーバーは連合が無効化されています。他のサーバーのユーザーとやり取りすることはできません。
|
* このサーバーは連合が無効化されています。他のサーバーのユーザーとやり取りすることはできません。
|
||||||
*/
|
*/
|
||||||
"federationDisabled": string;
|
"federationDisabled": string;
|
||||||
/**
|
|
||||||
* 下書き
|
|
||||||
*/
|
|
||||||
"draft": string;
|
|
||||||
/**
|
/**
|
||||||
* リアクションする際に確認する
|
* リアクションする際に確認する
|
||||||
*/
|
*/
|
||||||
|
@ -5493,16 +5489,6 @@ export interface Locale extends ILocale {
|
||||||
* 低くすると画質を保てますが、ファイルサイズは増加します。<br>高くするとファイルサイズを減らせますが、画質は低下します。
|
* 低くすると画質を保てますが、ファイルサイズは増加します。<br>高くするとファイルサイズを減らせますが、画質は低下します。
|
||||||
*/
|
*/
|
||||||
"defaultImageCompressionLevel_description": string;
|
"defaultImageCompressionLevel_description": string;
|
||||||
"_order": {
|
|
||||||
/**
|
|
||||||
* 新しい順
|
|
||||||
*/
|
|
||||||
"newest": string;
|
|
||||||
/**
|
|
||||||
* 古い順
|
|
||||||
*/
|
|
||||||
"oldest": string;
|
|
||||||
};
|
|
||||||
"_chat": {
|
"_chat": {
|
||||||
/**
|
/**
|
||||||
* まだメッセージはありません
|
* まだメッセージはありません
|
||||||
|
@ -7791,10 +7777,6 @@ export interface Locale extends ILocale {
|
||||||
* ファイルによっては種別を判定できないことがあります。そのようなファイルを許可する場合は {x} を指定に追加してください。
|
* ファイルによっては種別を判定できないことがあります。そのようなファイルを許可する場合は {x} を指定に追加してください。
|
||||||
*/
|
*/
|
||||||
"uploadableFileTypes_caption2": ParameterizedString<"x">;
|
"uploadableFileTypes_caption2": ParameterizedString<"x">;
|
||||||
/**
|
|
||||||
* サーバーサイドのノートの下書きの作成可能数
|
|
||||||
*/
|
|
||||||
"noteDraftLimit": string;
|
|
||||||
};
|
};
|
||||||
"_condition": {
|
"_condition": {
|
||||||
/**
|
/**
|
||||||
|
@ -8384,10 +8366,6 @@ export interface Locale extends ILocale {
|
||||||
* テーマコード
|
* テーマコード
|
||||||
*/
|
*/
|
||||||
"code": string;
|
"code": string;
|
||||||
/**
|
|
||||||
* テーマコードをコピー
|
|
||||||
*/
|
|
||||||
"copyThemeCode": string;
|
|
||||||
/**
|
/**
|
||||||
* 説明
|
* 説明
|
||||||
*/
|
*/
|
||||||
|
@ -11991,10 +11969,6 @@ export interface Locale extends ILocale {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
"_uploader": {
|
"_uploader": {
|
||||||
/**
|
|
||||||
* 画像の編集
|
|
||||||
*/
|
|
||||||
"editImage": string;
|
|
||||||
/**
|
/**
|
||||||
* {x}に圧縮
|
* {x}に圧縮
|
||||||
*/
|
*/
|
||||||
|
@ -12256,64 +12230,6 @@ export interface Locale extends ILocale {
|
||||||
"tearing": string;
|
"tearing": string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/**
|
|
||||||
* 下書き
|
|
||||||
*/
|
|
||||||
"drafts": string;
|
|
||||||
"_drafts": {
|
|
||||||
/**
|
|
||||||
* 下書きを選択
|
|
||||||
*/
|
|
||||||
"select": string;
|
|
||||||
/**
|
|
||||||
* 下書きの作成可能数を超えています。
|
|
||||||
*/
|
|
||||||
"cannotCreateDraftAnymore": string;
|
|
||||||
/**
|
|
||||||
* リノートの下書きは作成できません。
|
|
||||||
*/
|
|
||||||
"cannotCreateDraftOfRenote": string;
|
|
||||||
/**
|
|
||||||
* 下書きを削除
|
|
||||||
*/
|
|
||||||
"delete": string;
|
|
||||||
/**
|
|
||||||
* 下書きを削除しますか?
|
|
||||||
*/
|
|
||||||
"deleteAreYouSure": string;
|
|
||||||
/**
|
|
||||||
* 下書きはありません
|
|
||||||
*/
|
|
||||||
"noDrafts": string;
|
|
||||||
/**
|
|
||||||
* {user}への返信
|
|
||||||
*/
|
|
||||||
"replyTo": ParameterizedString<"user">;
|
|
||||||
/**
|
|
||||||
* {user}のノートへの引用
|
|
||||||
*/
|
|
||||||
"quoteOf": ParameterizedString<"user">;
|
|
||||||
/**
|
|
||||||
* {channel}への投稿
|
|
||||||
*/
|
|
||||||
"postTo": ParameterizedString<"channel">;
|
|
||||||
/**
|
|
||||||
* 下書きへ保存
|
|
||||||
*/
|
|
||||||
"saveToDraft": string;
|
|
||||||
/**
|
|
||||||
* 下書きから復元
|
|
||||||
*/
|
|
||||||
"restoreFromDraft": string;
|
|
||||||
/**
|
|
||||||
* 復元
|
|
||||||
*/
|
|
||||||
"restore": string;
|
|
||||||
/**
|
|
||||||
* 下書き一覧
|
|
||||||
*/
|
|
||||||
"listDrafts": string;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
declare const locales: {
|
declare const locales: {
|
||||||
[lang: string]: Locale;
|
[lang: string]: Locale;
|
||||||
|
|
|
@ -3169,5 +3169,3 @@ _imageEffector:
|
||||||
stripe: "Strisce"
|
stripe: "Strisce"
|
||||||
polkadot: "A pallini"
|
polkadot: "A pallini"
|
||||||
checker: "revisore"
|
checker: "revisore"
|
||||||
_drafts:
|
|
||||||
restore: "Ripristina"
|
|
||||||
|
|
|
@ -1313,7 +1313,6 @@ availableRoles: "利用可能なロール"
|
||||||
acknowledgeNotesAndEnable: "注意事項を理解した上でオンにします。"
|
acknowledgeNotesAndEnable: "注意事項を理解した上でオンにします。"
|
||||||
federationSpecified: "このサーバーはホワイトリスト連合で運用されています。管理者が指定したサーバー以外とやり取りすることはできません。"
|
federationSpecified: "このサーバーはホワイトリスト連合で運用されています。管理者が指定したサーバー以外とやり取りすることはできません。"
|
||||||
federationDisabled: "このサーバーは連合が無効化されています。他のサーバーのユーザーとやり取りすることはできません。"
|
federationDisabled: "このサーバーは連合が無効化されています。他のサーバーのユーザーとやり取りすることはできません。"
|
||||||
draft: "下書き"
|
|
||||||
confirmOnReact: "リアクションする際に確認する"
|
confirmOnReact: "リアクションする際に確認する"
|
||||||
reactAreYouSure: "\" {emoji} \" をリアクションしますか?"
|
reactAreYouSure: "\" {emoji} \" をリアクションしますか?"
|
||||||
markAsSensitiveConfirm: "このメディアをセンシティブとして設定しますか?"
|
markAsSensitiveConfirm: "このメディアをセンシティブとして設定しますか?"
|
||||||
|
@ -1369,10 +1368,6 @@ hideAllTips: "全ての「ヒントとコツ」を非表示"
|
||||||
defaultImageCompressionLevel: "デフォルトの画像圧縮度"
|
defaultImageCompressionLevel: "デフォルトの画像圧縮度"
|
||||||
defaultImageCompressionLevel_description: "低くすると画質を保てますが、ファイルサイズは増加します。<br>高くするとファイルサイズを減らせますが、画質は低下します。"
|
defaultImageCompressionLevel_description: "低くすると画質を保てますが、ファイルサイズは増加します。<br>高くするとファイルサイズを減らせますが、画質は低下します。"
|
||||||
|
|
||||||
_order:
|
|
||||||
newest: "新しい順"
|
|
||||||
oldest: "古い順"
|
|
||||||
|
|
||||||
_chat:
|
_chat:
|
||||||
noMessagesYet: "まだメッセージはありません"
|
noMessagesYet: "まだメッセージはありません"
|
||||||
newMessage: "新しいメッセージ"
|
newMessage: "新しいメッセージ"
|
||||||
|
@ -2018,7 +2013,6 @@ _role:
|
||||||
uploadableFileTypes: "アップロード可能なファイル種別"
|
uploadableFileTypes: "アップロード可能なファイル種別"
|
||||||
uploadableFileTypes_caption: "MIMEタイプを指定します。改行で区切って複数指定できるほか、アスタリスク(*)でワイルドカード指定できます。(例: image/*)"
|
uploadableFileTypes_caption: "MIMEタイプを指定します。改行で区切って複数指定できるほか、アスタリスク(*)でワイルドカード指定できます。(例: image/*)"
|
||||||
uploadableFileTypes_caption2: "ファイルによっては種別を判定できないことがあります。そのようなファイルを許可する場合は {x} を指定に追加してください。"
|
uploadableFileTypes_caption2: "ファイルによっては種別を判定できないことがあります。そのようなファイルを許可する場合は {x} を指定に追加してください。"
|
||||||
noteDraftLimit: "サーバーサイドのノートの下書きの作成可能数"
|
|
||||||
_condition:
|
_condition:
|
||||||
roleAssignedTo: "マニュアルロールにアサイン済み"
|
roleAssignedTo: "マニュアルロールにアサイン済み"
|
||||||
isLocal: "ローカルユーザー"
|
isLocal: "ローカルユーザー"
|
||||||
|
@ -2199,7 +2193,6 @@ _theme:
|
||||||
install: "テーマのインストール"
|
install: "テーマのインストール"
|
||||||
manage: "テーマの管理"
|
manage: "テーマの管理"
|
||||||
code: "テーマコード"
|
code: "テーマコード"
|
||||||
copyThemeCode: "テーマコードをコピー"
|
|
||||||
description: "説明"
|
description: "説明"
|
||||||
installed: "{name}をインストールしました"
|
installed: "{name}をインストールしました"
|
||||||
installedThemes: "インストールされたテーマ"
|
installedThemes: "インストールされたテーマ"
|
||||||
|
@ -3208,7 +3201,6 @@ _serverSetupWizard:
|
||||||
text3: "支援者向け特典もあります!"
|
text3: "支援者向け特典もあります!"
|
||||||
|
|
||||||
_uploader:
|
_uploader:
|
||||||
editImage: "画像の編集"
|
|
||||||
compressedToX: "{x}に圧縮"
|
compressedToX: "{x}に圧縮"
|
||||||
savedXPercent: "{x}%節約"
|
savedXPercent: "{x}%節約"
|
||||||
abortConfirm: "アップロードされていないファイルがありますが、中止しますか?"
|
abortConfirm: "アップロードされていないファイルがありますが、中止しますか?"
|
||||||
|
@ -3283,19 +3275,3 @@ _imageEffector:
|
||||||
checker: "チェッカー"
|
checker: "チェッカー"
|
||||||
blockNoise: "ブロックノイズ"
|
blockNoise: "ブロックノイズ"
|
||||||
tearing: "ティアリング"
|
tearing: "ティアリング"
|
||||||
|
|
||||||
drafts: "下書き"
|
|
||||||
_drafts:
|
|
||||||
select: "下書きを選択"
|
|
||||||
cannotCreateDraftAnymore: "下書きの作成可能数を超えています。"
|
|
||||||
cannotCreateDraftOfRenote: "リノートの下書きは作成できません。"
|
|
||||||
delete: "下書きを削除"
|
|
||||||
deleteAreYouSure: "下書きを削除しますか?"
|
|
||||||
noDrafts: "下書きはありません"
|
|
||||||
replyTo: "{user}への返信"
|
|
||||||
quoteOf: "{user}のノートへの引用"
|
|
||||||
postTo: "{channel}への投稿"
|
|
||||||
saveToDraft: "下書きへ保存"
|
|
||||||
restoreFromDraft: "下書きから復元"
|
|
||||||
restore: "復元"
|
|
||||||
listDrafts: "下書き一覧"
|
|
||||||
|
|
|
@ -1313,7 +1313,6 @@ availableRoles: "사용 가능한 역할"
|
||||||
acknowledgeNotesAndEnable: "활성화 하기 전에 주의 사항을 확인했습니다."
|
acknowledgeNotesAndEnable: "활성화 하기 전에 주의 사항을 확인했습니다."
|
||||||
federationSpecified: "이 서버는 화이트 리스트 제도로 운영 중 입니다. 정해진 리모트 서버가 아닌 경우 연합되지 않습니다."
|
federationSpecified: "이 서버는 화이트 리스트 제도로 운영 중 입니다. 정해진 리모트 서버가 아닌 경우 연합되지 않습니다."
|
||||||
federationDisabled: "이 서버는 연합을 하지 않고 있습니다. 리모트 서버 유저와 통신을 할 수 없습니다."
|
federationDisabled: "이 서버는 연합을 하지 않고 있습니다. 리모트 서버 유저와 통신을 할 수 없습니다."
|
||||||
draft: "초안"
|
|
||||||
confirmOnReact: "리액션할 때 확인"
|
confirmOnReact: "리액션할 때 확인"
|
||||||
reactAreYouSure: "\" {emoji} \"로 리액션하시겠습니까?"
|
reactAreYouSure: "\" {emoji} \"로 리액션하시겠습니까?"
|
||||||
markAsSensitiveConfirm: "이 미디어를 민감한 미디어로 설정하시겠습니까?"
|
markAsSensitiveConfirm: "이 미디어를 민감한 미디어로 설정하시겠습니까?"
|
||||||
|
@ -1368,9 +1367,6 @@ redisplayAllTips: "모든 '팁과 유용한 정보'를 재표시"
|
||||||
hideAllTips: "모든 '팁과 유용한 정보'를 비표시"
|
hideAllTips: "모든 '팁과 유용한 정보'를 비표시"
|
||||||
defaultImageCompressionLevel: "기본 이미지 압축 정도"
|
defaultImageCompressionLevel: "기본 이미지 압축 정도"
|
||||||
defaultImageCompressionLevel_description: "낮추면 화질을 유지합니다만 파일 크기는 증가합니다. <br>높이면 파일 크기를 줄일 수 있습니다만 화질은 저하됩니다."
|
defaultImageCompressionLevel_description: "낮추면 화질을 유지합니다만 파일 크기는 증가합니다. <br>높이면 파일 크기를 줄일 수 있습니다만 화질은 저하됩니다."
|
||||||
_order:
|
|
||||||
newest: "최신 순"
|
|
||||||
oldest: "오래된 순"
|
|
||||||
_chat:
|
_chat:
|
||||||
noMessagesYet: "아직 메시지가 없습니다"
|
noMessagesYet: "아직 메시지가 없습니다"
|
||||||
newMessage: "새로운 메시지"
|
newMessage: "새로운 메시지"
|
||||||
|
@ -1997,7 +1993,6 @@ _role:
|
||||||
uploadableFileTypes: "업로드 가능한 파일 유형"
|
uploadableFileTypes: "업로드 가능한 파일 유형"
|
||||||
uploadableFileTypes_caption: "MIME 유형을 "
|
uploadableFileTypes_caption: "MIME 유형을 "
|
||||||
uploadableFileTypes_caption2: "파일에 따라서는 유형을 검사하지 못하는 경우가 있습니다. 그러한 파일을 허가하는 경우에는 {x}를 지정으로 추가해주십시오."
|
uploadableFileTypes_caption2: "파일에 따라서는 유형을 검사하지 못하는 경우가 있습니다. 그러한 파일을 허가하는 경우에는 {x}를 지정으로 추가해주십시오."
|
||||||
noteDraftLimit: "서버측 노트 초안 작성 가능 수"
|
|
||||||
_condition:
|
_condition:
|
||||||
roleAssignedTo: "수동 역할에 이미 할당됨"
|
roleAssignedTo: "수동 역할에 이미 할당됨"
|
||||||
isLocal: "로컬 유저"
|
isLocal: "로컬 유저"
|
||||||
|
@ -2157,7 +2152,6 @@ _theme:
|
||||||
install: "테마 설치"
|
install: "테마 설치"
|
||||||
manage: "테마 관리"
|
manage: "테마 관리"
|
||||||
code: "테마 코드"
|
code: "테마 코드"
|
||||||
copyThemeCode: "테마 코드 복사"
|
|
||||||
description: "설명"
|
description: "설명"
|
||||||
installed: "{name} 테마가 설치되었습니다"
|
installed: "{name} 테마가 설치되었습니다"
|
||||||
installedThemes: "설치된 테마"
|
installedThemes: "설치된 테마"
|
||||||
|
@ -3109,12 +3103,11 @@ _serverSetupWizard:
|
||||||
text2: "앞으로도 계속해서 개발을 할 수 있도록 괜찮으시다면 부디 기부를 부탁드립니다."
|
text2: "앞으로도 계속해서 개발을 할 수 있도록 괜찮으시다면 부디 기부를 부탁드립니다."
|
||||||
text3: "지원자 대상 특전도 있습니다!"
|
text3: "지원자 대상 특전도 있습니다!"
|
||||||
_uploader:
|
_uploader:
|
||||||
editImage: "이미지 편집"
|
|
||||||
compressedToX: "{x}로 압축"
|
compressedToX: "{x}로 압축"
|
||||||
savedXPercent: "{x}% 절약"
|
savedXPercent: "{x}% 절약"
|
||||||
abortConfirm: "업로드되지 않은 파일이 있습니다만, 그만 두시겠습니까?"
|
abortConfirm: "업로드되지 않은 파일이 있습니다만, 그만 두시겠습니까?"
|
||||||
doneConfirm: "업로드되지 않은 파일이 있습니다만, 완료하시겠습니까?"
|
doneConfirm: "업로드되지 않은 파일이 있습니다만, 완료하시겠습니까?"
|
||||||
maxFileSizeIsX: "업로드 가능한 최대 파일 크기는 {x}입니다."
|
maxFileSizeIsX: "업오드 가능한 최대 파일 크기는 {x}입니다."
|
||||||
allowedTypes: "업로드 가능한 파일 유형"
|
allowedTypes: "업로드 가능한 파일 유형"
|
||||||
tip: "파일은 아직 업로드되지 않았습니다. 이 다이얼로그에서 업로드 전의 확인, 이름 바꾸기, 압축, 자르기 등을 하실 수 있습니다. 준비가 되셨다면 '업로드' 버튼을 클릭해 업로드를 시작하실 수 있습니다."
|
tip: "파일은 아직 업로드되지 않았습니다. 이 다이얼로그에서 업로드 전의 확인, 이름 바꾸기, 압축, 자르기 등을 하실 수 있습니다. 준비가 되셨다면 '업로드' 버튼을 클릭해 업로드를 시작하실 수 있습니다."
|
||||||
_clientPerformanceIssueTip:
|
_clientPerformanceIssueTip:
|
||||||
|
@ -3176,20 +3169,3 @@ _imageEffector:
|
||||||
stripe: "줄무늬"
|
stripe: "줄무늬"
|
||||||
polkadot: "물방울 무늬"
|
polkadot: "물방울 무늬"
|
||||||
checker: "체크 무늬"
|
checker: "체크 무늬"
|
||||||
blockNoise: "노이즈 방지"
|
|
||||||
tearing: "티어링"
|
|
||||||
drafts: "초안"
|
|
||||||
_drafts:
|
|
||||||
select: "초안 선택"
|
|
||||||
cannotCreateDraftAnymore: "초안 작성 가능 수를 초과했습니다."
|
|
||||||
cannotCreateDraftOfRenote: "리노트 초안은 작성할 수 없습니다."
|
|
||||||
delete: "초안 삭제\n"
|
|
||||||
deleteAreYouSure: "초안을 삭제하시겠습니까?"
|
|
||||||
noDrafts: "초안 없음\n"
|
|
||||||
replyTo: "{user}에 회신"
|
|
||||||
quoteOf: "{user} 노트에 인용"
|
|
||||||
postTo: "{channel}에 게시"
|
|
||||||
saveToDraft: "초안에 저장"
|
|
||||||
restoreFromDraft: "초안에서 복원\n"
|
|
||||||
restore: "복원"
|
|
||||||
listDrafts: "초안 목록"
|
|
||||||
|
|
|
@ -298,7 +298,6 @@ uploadFromUrl: "Enviar por URL"
|
||||||
uploadFromUrlDescription: "URL do arquivo que você deseja enviar"
|
uploadFromUrlDescription: "URL do arquivo que você deseja enviar"
|
||||||
uploadFromUrlRequested: "Upload solicitado"
|
uploadFromUrlRequested: "Upload solicitado"
|
||||||
uploadFromUrlMayTakeTime: "Pode levar algum tempo para que o upload seja concluído."
|
uploadFromUrlMayTakeTime: "Pode levar algum tempo para que o upload seja concluído."
|
||||||
uploadNFiles: "Enviar {n} arquivos"
|
|
||||||
explore: "Explorar"
|
explore: "Explorar"
|
||||||
messageRead: "Lida"
|
messageRead: "Lida"
|
||||||
noMoreHistory: "Não existe histórico anterior"
|
noMoreHistory: "Não existe histórico anterior"
|
||||||
|
@ -327,7 +326,6 @@ dark: "Escuro"
|
||||||
lightThemes: "Tema claro"
|
lightThemes: "Tema claro"
|
||||||
darkThemes: "Tema escuro"
|
darkThemes: "Tema escuro"
|
||||||
syncDeviceDarkMode: "Sincronize com o modo escuro do dispositivo"
|
syncDeviceDarkMode: "Sincronize com o modo escuro do dispositivo"
|
||||||
switchDarkModeManuallyWhenSyncEnabledConfirm: "\"{x}\" está ativado. Você gostaria de desligar a sincronização e alterar manualmente?"
|
|
||||||
drive: "Drive"
|
drive: "Drive"
|
||||||
fileName: "Nome do Ficheiro"
|
fileName: "Nome do Ficheiro"
|
||||||
selectFile: "Selecione os arquivos"
|
selectFile: "Selecione os arquivos"
|
||||||
|
@ -580,7 +578,6 @@ newNoteRecived: "Nova nota recebida"
|
||||||
newNote: "Nova Nota"
|
newNote: "Nova Nota"
|
||||||
sounds: "Sons"
|
sounds: "Sons"
|
||||||
sound: "Sons"
|
sound: "Sons"
|
||||||
notificationSoundSettings: "Configurações de som de notificações"
|
|
||||||
listen: "Ouvir"
|
listen: "Ouvir"
|
||||||
none: "Nenhum"
|
none: "Nenhum"
|
||||||
showInPage: "Ver na página"
|
showInPage: "Ver na página"
|
||||||
|
@ -1002,7 +999,6 @@ failedToUpload: "Falha ao enviar"
|
||||||
cannotUploadBecauseInappropriate: "Esse arquivo não pôde ser enviado porque partes dele foram detectadas como potencialmente inapropriadas."
|
cannotUploadBecauseInappropriate: "Esse arquivo não pôde ser enviado porque partes dele foram detectadas como potencialmente inapropriadas."
|
||||||
cannotUploadBecauseNoFreeSpace: "Envio falhou devido à falta de capacidade no Drive."
|
cannotUploadBecauseNoFreeSpace: "Envio falhou devido à falta de capacidade no Drive."
|
||||||
cannotUploadBecauseExceedsFileSizeLimit: "Não é possível realizar o upload deste arquivo porque ele excede o tamanho máximo permitido."
|
cannotUploadBecauseExceedsFileSizeLimit: "Não é possível realizar o upload deste arquivo porque ele excede o tamanho máximo permitido."
|
||||||
cannotUploadBecauseUnallowedFileType: "Não foi possível fazer o envio, pois o formato do arquivo não foi autorizado."
|
|
||||||
beta: "Beta"
|
beta: "Beta"
|
||||||
enableAutoSensitive: "Marcar automaticamente como conteúdo sensível"
|
enableAutoSensitive: "Marcar automaticamente como conteúdo sensível"
|
||||||
enableAutoSensitiveDescription: "Quando disponível, a marcação de mídia sensível será automaticamente atribuído ao conteúdo de mídia usando aprendizado de máquina. Mesmo que você desative essa função, em alguns servidores, isso pode ser configurado automaticamente."
|
enableAutoSensitiveDescription: "Quando disponível, a marcação de mídia sensível será automaticamente atribuído ao conteúdo de mídia usando aprendizado de máquina. Mesmo que você desative essa função, em alguns servidores, isso pode ser configurado automaticamente."
|
||||||
|
@ -1313,7 +1309,6 @@ availableRoles: "Cargos disponíveis"
|
||||||
acknowledgeNotesAndEnable: "Ative após compreender as precauções."
|
acknowledgeNotesAndEnable: "Ative após compreender as precauções."
|
||||||
federationSpecified: "Esse servidor opera com uma lista branca de federação. Interagir com servidores diferentes daqueles designados pela administração não é permitido."
|
federationSpecified: "Esse servidor opera com uma lista branca de federação. Interagir com servidores diferentes daqueles designados pela administração não é permitido."
|
||||||
federationDisabled: "Federação está desabilitada nesse servidor. Você não pode interagir com usuários de outros servidores."
|
federationDisabled: "Federação está desabilitada nesse servidor. Você não pode interagir com usuários de outros servidores."
|
||||||
draft: "Rascunhos"
|
|
||||||
confirmOnReact: "Confirmar ao reagir"
|
confirmOnReact: "Confirmar ao reagir"
|
||||||
reactAreYouSure: "Você deseja adicionar uma reação \"{emoji}\"?"
|
reactAreYouSure: "Você deseja adicionar uma reação \"{emoji}\"?"
|
||||||
markAsSensitiveConfirm: "Você deseja definir essa mídia como sensível?"
|
markAsSensitiveConfirm: "Você deseja definir essa mídia como sensível?"
|
||||||
|
@ -1331,7 +1326,6 @@ restore: "Redefinir"
|
||||||
syncBetweenDevices: "Sincronizar entre dispositivos"
|
syncBetweenDevices: "Sincronizar entre dispositivos"
|
||||||
preferenceSyncConflictTitle: "O valor configurado já existe no servidor."
|
preferenceSyncConflictTitle: "O valor configurado já existe no servidor."
|
||||||
preferenceSyncConflictText: "As preferências com a sincronização ativada irão salvar os seus valores no servidor. Porém, já existem valores no servidor. Qual conjunto de valores você deseja sobrescrever?"
|
preferenceSyncConflictText: "As preferências com a sincronização ativada irão salvar os seus valores no servidor. Porém, já existem valores no servidor. Qual conjunto de valores você deseja sobrescrever?"
|
||||||
preferenceSyncConflictChoiceMerge: "Combinar"
|
|
||||||
preferenceSyncConflictChoiceServer: "Valor configurado no servidor"
|
preferenceSyncConflictChoiceServer: "Valor configurado no servidor"
|
||||||
preferenceSyncConflictChoiceDevice: "Valor configurado no dispositivo"
|
preferenceSyncConflictChoiceDevice: "Valor configurado no dispositivo"
|
||||||
preferenceSyncConflictChoiceCancel: "Cancelar a habilitação de sincronização"
|
preferenceSyncConflictChoiceCancel: "Cancelar a habilitação de sincronização"
|
||||||
|
@ -1362,15 +1356,6 @@ emojiMute: "Silenciar emoji"
|
||||||
emojiUnmute: "Reativar emoji"
|
emojiUnmute: "Reativar emoji"
|
||||||
muteX: "Silenciar {x}"
|
muteX: "Silenciar {x}"
|
||||||
unmuteX: "Reativar {x}"
|
unmuteX: "Reativar {x}"
|
||||||
abort: "Abortar"
|
|
||||||
tip: "Dicas e Truques"
|
|
||||||
redisplayAllTips: "Mostrar todas as \"Dicas e Truques\" novamente"
|
|
||||||
hideAllTips: "Ocultas todas as \"Dicas e Truques\""
|
|
||||||
defaultImageCompressionLevel: "Nível de compressão de imagem padrão"
|
|
||||||
defaultImageCompressionLevel_description: "Alto, reduz o tamanho do arquivo mas, também, a qualidade da imagem.<br>Alto, reduz o tamanho do arquivo mas, também, a qualidade da imagem."
|
|
||||||
_order:
|
|
||||||
newest: "Priorizar Mais Novos"
|
|
||||||
oldest: "Priorizar Mais Antigos"
|
|
||||||
_chat:
|
_chat:
|
||||||
noMessagesYet: "Ainda não há mensagens"
|
noMessagesYet: "Ainda não há mensagens"
|
||||||
newMessage: "Nova mensagem"
|
newMessage: "Nova mensagem"
|
||||||
|
@ -1457,8 +1442,6 @@ _settings:
|
||||||
contentsUpdateFrequency: "Frequência da obtenção de conteúdo"
|
contentsUpdateFrequency: "Frequência da obtenção de conteúdo"
|
||||||
contentsUpdateFrequency_description: "Quanto maior o valor, mais o conteúdo atualiza. Porém, há uma diminuição do desempenho e aumento do tráfego e consumo de memória."
|
contentsUpdateFrequency_description: "Quanto maior o valor, mais o conteúdo atualiza. Porém, há uma diminuição do desempenho e aumento do tráfego e consumo de memória."
|
||||||
contentsUpdateFrequency_description2: "Quando o modo tempo-real está ativado, o conteúdo é atualizado em tempo real, ignorando essa opção."
|
contentsUpdateFrequency_description2: "Quando o modo tempo-real está ativado, o conteúdo é atualizado em tempo real, ignorando essa opção."
|
||||||
showUrlPreview: "Exibir prévia de URL"
|
|
||||||
showAvailableReactionsFirstInNote: "Exibir reações disponíveis no topo."
|
|
||||||
_chat:
|
_chat:
|
||||||
showSenderName: "Exibir nome de usuário do remetente"
|
showSenderName: "Exibir nome de usuário do remetente"
|
||||||
sendOnEnter: "Pressionar Enter para enviar"
|
sendOnEnter: "Pressionar Enter para enviar"
|
||||||
|
@ -1994,10 +1977,6 @@ _role:
|
||||||
canImportMuting: "Permitir importação de silenciamentos"
|
canImportMuting: "Permitir importação de silenciamentos"
|
||||||
canImportUserLists: "Permitir importação de listas"
|
canImportUserLists: "Permitir importação de listas"
|
||||||
chatAvailability: "Permitir Conversas"
|
chatAvailability: "Permitir Conversas"
|
||||||
uploadableFileTypes: "Tipos de arquivo enviáveis"
|
|
||||||
uploadableFileTypes_caption: "Especifica tipos MIME permitidos. Múltiplos tipos MIME podem ser especificados separando-os por linha. Curingas podem ser especificados com um asterisco (*). (exemplo, image/*)"
|
|
||||||
uploadableFileTypes_caption2: "Alguns tipos de arquivos podem não ser detectados. Para permiti-los, adicione {x} à especificação."
|
|
||||||
noteDraftLimit: "Limite de rascunhos possíveis"
|
|
||||||
_condition:
|
_condition:
|
||||||
roleAssignedTo: "Atribuído a cargos manuais"
|
roleAssignedTo: "Atribuído a cargos manuais"
|
||||||
isLocal: "Usuário local"
|
isLocal: "Usuário local"
|
||||||
|
@ -2157,7 +2136,6 @@ _theme:
|
||||||
install: "Instalar um tema"
|
install: "Instalar um tema"
|
||||||
manage: "Gerenciar temas"
|
manage: "Gerenciar temas"
|
||||||
code: "Código do tema"
|
code: "Código do tema"
|
||||||
copyThemeCode: "Copiar código do tema"
|
|
||||||
description: "Descrição"
|
description: "Descrição"
|
||||||
installed: "{name} foi instalado"
|
installed: "{name} foi instalado"
|
||||||
installedThemes: "Temas instalados"
|
installedThemes: "Temas instalados"
|
||||||
|
@ -2471,8 +2449,6 @@ _visibility:
|
||||||
disableFederation: "Defederar"
|
disableFederation: "Defederar"
|
||||||
disableFederationDescription: "Não transmitir às outras instâncias"
|
disableFederationDescription: "Não transmitir às outras instâncias"
|
||||||
_postForm:
|
_postForm:
|
||||||
quitInspiteOfThereAreUnuploadedFilesConfirm: "Há arquivos que não foram enviados, gostaria de descartá-los e fechar o editor?"
|
|
||||||
uploaderTip: "O arquivo ainda não foi enviado. No menu do arquivo, você pode renomear, cortar, adicionar uma marca d'água, comprimir ou descomprimir um arquivo. Arquivos serão enviados automaticamente ao publicar a nota."
|
|
||||||
replyPlaceholder: "Responder a essa nota..."
|
replyPlaceholder: "Responder a essa nota..."
|
||||||
quotePlaceholder: "Citar essa nota..."
|
quotePlaceholder: "Citar essa nota..."
|
||||||
channelPlaceholder: "Postar em canal..."
|
channelPlaceholder: "Postar em canal..."
|
||||||
|
@ -2853,12 +2829,6 @@ _dataSaver:
|
||||||
_avatar:
|
_avatar:
|
||||||
title: "Imagem do avatar"
|
title: "Imagem do avatar"
|
||||||
description: "Parar animação de avatares. Imagens animadas podem ter um arquivo mais pesado do que imagens normais, potencialmente levando a reduções no tráfego de dados."
|
description: "Parar animação de avatares. Imagens animadas podem ter um arquivo mais pesado do que imagens normais, potencialmente levando a reduções no tráfego de dados."
|
||||||
_urlPreviewThumbnail:
|
|
||||||
title: "Esconder miniaturas em prévias de URL"
|
|
||||||
description: "Miniaturas em prévias de URL não serão carregadas."
|
|
||||||
_disableUrlPreview:
|
|
||||||
title: "Desabilitar prévias de URL"
|
|
||||||
description: "Desabilita a função de prévias de URL. Diferente das miniaturas, essa função impede o carregamento de toda informação do link."
|
|
||||||
_code:
|
_code:
|
||||||
title: "Destaque de código"
|
title: "Destaque de código"
|
||||||
description: "Se as notações de formatação de código forem utilizadas em MFM, elas não irão carregar até serem selecionadas. Destaque de código exige baixar arquivos de alta definição para cada linguagem de programação. Logo, desabilitar o carregamento automático desses arquivos diminui a quantidade de informação comunicada."
|
description: "Se as notações de formatação de código forem utilizadas em MFM, elas não irão carregar até serem selecionadas. Destaque de código exige baixar arquivos de alta definição para cada linguagem de programação. Logo, desabilitar o carregamento automático desses arquivos diminui a quantidade de informação comunicada."
|
||||||
|
@ -2916,8 +2886,6 @@ _offlineScreen:
|
||||||
_urlPreviewSetting:
|
_urlPreviewSetting:
|
||||||
title: "Configurações da prévia de URL"
|
title: "Configurações da prévia de URL"
|
||||||
enable: "Habilitar prévia de URL"
|
enable: "Habilitar prévia de URL"
|
||||||
allowRedirect: "Permitir redirecionamentos de URL em prévias."
|
|
||||||
allowRedirectDescription: "Se um URL tem um redirecionamento, você pode habilitar essa função para segui-lo e exibir a prévia do conteúdo redirecionado. Desabilitar isso irá economizar recursos, mas o conteúdo não será exibido."
|
|
||||||
timeout: "Tempo máximo para obter a prévia (ms)"
|
timeout: "Tempo máximo para obter a prévia (ms)"
|
||||||
timeoutDescription: "Se demorar mais que esse valor para obter uma prévia, ela não será gerada."
|
timeoutDescription: "Se demorar mais que esse valor para obter uma prévia, ela não será gerada."
|
||||||
maximumContentLength: "Content-Length máximo (em bytes)"
|
maximumContentLength: "Content-Length máximo (em bytes)"
|
||||||
|
@ -3108,15 +3076,6 @@ _serverSetupWizard:
|
||||||
text1: "Misskey é software aberto desenvolvido por voluntários."
|
text1: "Misskey é software aberto desenvolvido por voluntários."
|
||||||
text2: "Nós apreciaríamos o seu apoio para podermos continuar o desenvolvimento desse software no futuro."
|
text2: "Nós apreciaríamos o seu apoio para podermos continuar o desenvolvimento desse software no futuro."
|
||||||
text3: "Também há benefícios especiais para apoiadores!"
|
text3: "Também há benefícios especiais para apoiadores!"
|
||||||
_uploader:
|
|
||||||
editImage: "Editar Imagem"
|
|
||||||
compressedToX: "Comprimido para {x}"
|
|
||||||
savedXPercent: "Salvando {x}%"
|
|
||||||
abortConfirm: "Alguns arquivos não foram enviados, deseja abortar?"
|
|
||||||
doneConfirm: "Alguns arquivos não foram enviados, deseja continuar mesmo assim?"
|
|
||||||
maxFileSizeIsX: "O tamanho máximo de arquivos enviados é {x}"
|
|
||||||
allowedTypes: "Tipos de arquivo enviáveis"
|
|
||||||
tip: "O arquivo não foi enviado. Então, esse diálogo permite que você confirme, renomeie, comprima e recorte o arquivo antes de enviar. Quando estiver pronto, você pode enviar apertando o botão \"Enviar\"."
|
|
||||||
_clientPerformanceIssueTip:
|
_clientPerformanceIssueTip:
|
||||||
title: "Dicas de desempenho"
|
title: "Dicas de desempenho"
|
||||||
makeSureDisabledAdBlocker: "Desative o seu bloqueador de anúncios"
|
makeSureDisabledAdBlocker: "Desative o seu bloqueador de anúncios"
|
||||||
|
@ -3125,20 +3084,8 @@ _clientPerformanceIssueTip:
|
||||||
makeSureDisabledCustomCss_description: "Substituir o estilo da página pode afetar o desempenho. Certifique-se que o CSS personalizado ou extensões que modifiquem o estilo da página estejam desabilitados."
|
makeSureDisabledCustomCss_description: "Substituir o estilo da página pode afetar o desempenho. Certifique-se que o CSS personalizado ou extensões que modifiquem o estilo da página estejam desabilitados."
|
||||||
makeSureDisabledAddons: "Desabilite extensões"
|
makeSureDisabledAddons: "Desabilite extensões"
|
||||||
makeSureDisabledAddons_description: "Algumas extensões podem afetar comportamentos do cliente e afetar o desempenho. Por favor, desative as extensões do seu navegador e veja se isso melhora a situação."
|
makeSureDisabledAddons_description: "Algumas extensões podem afetar comportamentos do cliente e afetar o desempenho. Por favor, desative as extensões do seu navegador e veja se isso melhora a situação."
|
||||||
_clip:
|
|
||||||
tip: "Clip é uma função que permite organização das suas notas."
|
|
||||||
_userLists:
|
|
||||||
tip: "Listas podem conter qualquer usuário que você especificar em sua criação. A lista criada aparece como uma linha do tempo exibindo usuários selecionados."
|
|
||||||
watermark: "Marca d'água"
|
|
||||||
defaultPreset: "Predefinição Padrão"
|
|
||||||
_watermarkEditor:
|
_watermarkEditor:
|
||||||
tip: "Uma marca d'água, como informação de autoria, pode ser adicionada à imagem."
|
|
||||||
quitWithoutSaveConfirm: "Descartar mudanças?"
|
|
||||||
driveFileTypeWarn: "Esse arquivo não é compatível"
|
driveFileTypeWarn: "Esse arquivo não é compatível"
|
||||||
driveFileTypeWarnDescription: "Escolha um arquivo de imagem"
|
|
||||||
title: "Editar marca d'água"
|
|
||||||
cover: "Cobrir tudo"
|
|
||||||
repeat: "Espalhar pelo conteúdo"
|
|
||||||
opacity: "Opacidade"
|
opacity: "Opacidade"
|
||||||
scale: "Tamanho"
|
scale: "Tamanho"
|
||||||
text: "Texto"
|
text: "Texto"
|
||||||
|
@ -3146,42 +3093,4 @@ _watermarkEditor:
|
||||||
type: "Tipo"
|
type: "Tipo"
|
||||||
image: "imagem"
|
image: "imagem"
|
||||||
advanced: "Avançado"
|
advanced: "Avançado"
|
||||||
stripe: "Listras"
|
|
||||||
stripeWidth: "Largura da linha"
|
|
||||||
stripeFrequency: "Número de linhas"
|
|
||||||
angle: "Ângulo"
|
angle: "Ângulo"
|
||||||
polkadot: "Bolinhas"
|
|
||||||
checker: "Xadrez"
|
|
||||||
polkadotMainDotOpacity: "Opacidade da bolinha principal"
|
|
||||||
polkadotMainDotRadius: "Raio da bolinha principal"
|
|
||||||
polkadotSubDotOpacity: "Opacidade da bolinha secundária"
|
|
||||||
polkadotSubDotRadius: "Raio das bolinhas adicionais"
|
|
||||||
polkadotSubDotDivisions: "Número de bolinhas adicionais"
|
|
||||||
_imageEffector:
|
|
||||||
title: "Efeitos"
|
|
||||||
addEffect: "Adicionar efeitos"
|
|
||||||
discardChangesConfirm: "Tem certeza que deseja sair? Há mudanças não salvas."
|
|
||||||
_fxs:
|
|
||||||
chromaticAberration: "Aberração cromática"
|
|
||||||
glitch: "Glitch"
|
|
||||||
mirror: "Espelho"
|
|
||||||
invert: "Inverter Cores"
|
|
||||||
grayscale: "Tons de Cinza"
|
|
||||||
colorAdjust: "Correção de Cores"
|
|
||||||
colorClamp: "Compressão de Cores"
|
|
||||||
colorClampAdvanced: "Compressão Avançada de Cores"
|
|
||||||
distort: "Distorção"
|
|
||||||
threshold: "Limiarização Binária"
|
|
||||||
zoomLines: "Linhas de Ação"
|
|
||||||
stripe: "Listras"
|
|
||||||
polkadot: "Bolinhas"
|
|
||||||
checker: "Xadrez"
|
|
||||||
blockNoise: "Bloquear Ruído"
|
|
||||||
tearing: "Descontinuidade"
|
|
||||||
drafts: "Rascunhos"
|
|
||||||
_drafts:
|
|
||||||
select: "Selecionar Rascunho"
|
|
||||||
cannotCreateDraftAnymore: "O número máximo de rascunhos foi excedido."
|
|
||||||
cannotCreateDraftOfRenote: "Você não pode criar o rascunho de uma repostagem."
|
|
||||||
delete: "Excluir Rascunho"
|
|
||||||
restore: "Redefinir"
|
|
||||||
|
|
|
@ -584,7 +584,6 @@ masterVolume: "ระดับเสียงหลัก"
|
||||||
notUseSound: "ไม่ใช้เสียง"
|
notUseSound: "ไม่ใช้เสียง"
|
||||||
useSoundOnlyWhenActive: "มีเสียงออกเฉพาะตอนกำลังใช้ Misskey อยู่เท่านั้น"
|
useSoundOnlyWhenActive: "มีเสียงออกเฉพาะตอนกำลังใช้ Misskey อยู่เท่านั้น"
|
||||||
details: "รายละเอียด"
|
details: "รายละเอียด"
|
||||||
renoteDetails: "รายละเอียดรีโน้ต"
|
|
||||||
chooseEmoji: "เลือกเอโมจิ"
|
chooseEmoji: "เลือกเอโมจิ"
|
||||||
unableToProcess: "ไม่สามารถดำเนินการให้เสร็จสิ้นได้"
|
unableToProcess: "ไม่สามารถดำเนินการให้เสร็จสิ้นได้"
|
||||||
recentUsed: "ใช้ล่าสุด"
|
recentUsed: "ใช้ล่าสุด"
|
||||||
|
@ -692,7 +691,6 @@ userSaysSomethingAbout: "{name} พูดอะไรบางอย่างเ
|
||||||
makeActive: "เปิดใช้งาน"
|
makeActive: "เปิดใช้งาน"
|
||||||
display: "แสดงผล"
|
display: "แสดงผล"
|
||||||
copy: "คัดลอก"
|
copy: "คัดลอก"
|
||||||
copiedToClipboard: "คัดลอกไปยังคลิปบอร์ดแล้ว"
|
|
||||||
metrics: "เมตริก"
|
metrics: "เมตริก"
|
||||||
overview: "ภาพรวม"
|
overview: "ภาพรวม"
|
||||||
logs: "ปูม"
|
logs: "ปูม"
|
||||||
|
@ -787,7 +785,6 @@ wide: "กว้าง"
|
||||||
narrow: "ชิด"
|
narrow: "ชิด"
|
||||||
reloadToApplySetting: "การตั้งค่านี้จะมีผลหลังจากโหลดหน้าซ้ำเท่านั้น ต้องการที่จะโหลดใหม่เลยไหม?"
|
reloadToApplySetting: "การตั้งค่านี้จะมีผลหลังจากโหลดหน้าซ้ำเท่านั้น ต้องการที่จะโหลดใหม่เลยไหม?"
|
||||||
needReloadToApply: "ต้องรีโหลดเพื่อให้การเปลี่ยนแปลงมีผล"
|
needReloadToApply: "ต้องรีโหลดเพื่อให้การเปลี่ยนแปลงมีผล"
|
||||||
needToRestartServerToApply: "จำเป็นต้องรีสตาร์ทเซิร์ฟเวอร์เพื่อให้การเปลี่ยนแปลงมีผล"
|
|
||||||
showTitlebar: "แสดงแถบชื่อ"
|
showTitlebar: "แสดงแถบชื่อ"
|
||||||
clearCache: "ล้างแคช"
|
clearCache: "ล้างแคช"
|
||||||
onlineUsersCount: "{n} รายกำลังออนไลน์"
|
onlineUsersCount: "{n} รายกำลังออนไลน์"
|
||||||
|
|
|
@ -1313,7 +1313,6 @@ availableRoles: "可用角色"
|
||||||
acknowledgeNotesAndEnable: "理解注意事项后再开启。"
|
acknowledgeNotesAndEnable: "理解注意事项后再开启。"
|
||||||
federationSpecified: "此服务器已开启联合白名单。只能与管理员指定的服务器通信。"
|
federationSpecified: "此服务器已开启联合白名单。只能与管理员指定的服务器通信。"
|
||||||
federationDisabled: "此服务器已禁用联合。无法与其它服务器上的用户通信。"
|
federationDisabled: "此服务器已禁用联合。无法与其它服务器上的用户通信。"
|
||||||
draft: "草稿"
|
|
||||||
confirmOnReact: "发送回应前需要确认"
|
confirmOnReact: "发送回应前需要确认"
|
||||||
reactAreYouSure: "要用「{emoji}」进行回应吗?"
|
reactAreYouSure: "要用「{emoji}」进行回应吗?"
|
||||||
markAsSensitiveConfirm: "要将此媒体标记为敏感吗?"
|
markAsSensitiveConfirm: "要将此媒体标记为敏感吗?"
|
||||||
|
@ -1368,9 +1367,6 @@ redisplayAllTips: "重新显示所有的提示和技巧"
|
||||||
hideAllTips: "隐藏所有的提示和技巧"
|
hideAllTips: "隐藏所有的提示和技巧"
|
||||||
defaultImageCompressionLevel: "默认图像压缩等级"
|
defaultImageCompressionLevel: "默认图像压缩等级"
|
||||||
defaultImageCompressionLevel_description: "较低的等级可以保持画质,但会增加文件大小。<br>较高的等级可以减少文件大小,但相对应的画质将会降低。"
|
defaultImageCompressionLevel_description: "较低的等级可以保持画质,但会增加文件大小。<br>较高的等级可以减少文件大小,但相对应的画质将会降低。"
|
||||||
_order:
|
|
||||||
newest: "从新到旧"
|
|
||||||
oldest: "从旧到新"
|
|
||||||
_chat:
|
_chat:
|
||||||
noMessagesYet: "还没有消息"
|
noMessagesYet: "还没有消息"
|
||||||
newMessage: "新消息"
|
newMessage: "新消息"
|
||||||
|
@ -1997,7 +1993,6 @@ _role:
|
||||||
uploadableFileTypes: "可上传的文件类型"
|
uploadableFileTypes: "可上传的文件类型"
|
||||||
uploadableFileTypes_caption: "指定 MIME 类型。可用换行指定多个类型,也可以用星号(*)作为通配符。(如 image/*)"
|
uploadableFileTypes_caption: "指定 MIME 类型。可用换行指定多个类型,也可以用星号(*)作为通配符。(如 image/*)"
|
||||||
uploadableFileTypes_caption2: "文件根据文件的不同,可能无法判断其类型。若要允许此类文件,请在指定中添加 {x}。"
|
uploadableFileTypes_caption2: "文件根据文件的不同,可能无法判断其类型。若要允许此类文件,请在指定中添加 {x}。"
|
||||||
noteDraftLimit: "可在服务器上创建多少草稿"
|
|
||||||
_condition:
|
_condition:
|
||||||
roleAssignedTo: "已分配给手动角色"
|
roleAssignedTo: "已分配给手动角色"
|
||||||
isLocal: "是本地用户"
|
isLocal: "是本地用户"
|
||||||
|
@ -2157,7 +2152,6 @@ _theme:
|
||||||
install: "安装主题"
|
install: "安装主题"
|
||||||
manage: "主题管理"
|
manage: "主题管理"
|
||||||
code: "主题代码"
|
code: "主题代码"
|
||||||
copyThemeCode: "复制主题代码"
|
|
||||||
description: "描述"
|
description: "描述"
|
||||||
installed: "{name} 已安装"
|
installed: "{name} 已安装"
|
||||||
installedThemes: "已安装的主题"
|
installedThemes: "已安装的主题"
|
||||||
|
@ -3109,7 +3103,6 @@ _serverSetupWizard:
|
||||||
text2: "为了今后也能继续开发,如果可以的话,请考虑一下捐助。"
|
text2: "为了今后也能继续开发,如果可以的话,请考虑一下捐助。"
|
||||||
text3: "也有面向支援者的特典!"
|
text3: "也有面向支援者的特典!"
|
||||||
_uploader:
|
_uploader:
|
||||||
editImage: "编辑图像"
|
|
||||||
compressedToX: "压缩 {x}"
|
compressedToX: "压缩 {x}"
|
||||||
savedXPercent: "节省了 {x}% 的空间"
|
savedXPercent: "节省了 {x}% 的空间"
|
||||||
abortConfirm: "还有未上传的文件,要中止吗?"
|
abortConfirm: "还有未上传的文件,要中止吗?"
|
||||||
|
@ -3176,20 +3169,3 @@ _imageEffector:
|
||||||
stripe: "条纹"
|
stripe: "条纹"
|
||||||
polkadot: "波点"
|
polkadot: "波点"
|
||||||
checker: "检查"
|
checker: "检查"
|
||||||
blockNoise: "块状噪点"
|
|
||||||
tearing: "撕裂"
|
|
||||||
drafts: "草稿"
|
|
||||||
_drafts:
|
|
||||||
select: "选择草稿"
|
|
||||||
cannotCreateDraftAnymore: "已超过可创建的草稿数量。"
|
|
||||||
cannotCreateDraftOfRenote: "无法创建转帖草稿。"
|
|
||||||
delete: "删除草稿"
|
|
||||||
deleteAreYouSure: "要删除草稿吗?"
|
|
||||||
noDrafts: "没有草稿"
|
|
||||||
replyTo: "回复给 {user}"
|
|
||||||
quoteOf: "对 {user} 帖子的引用"
|
|
||||||
postTo: "向 {channel} 的投稿"
|
|
||||||
saveToDraft: "保存到草稿"
|
|
||||||
restoreFromDraft: "从草稿恢复"
|
|
||||||
restore: "恢复"
|
|
||||||
listDrafts: "草稿一览"
|
|
||||||
|
|
|
@ -1313,7 +1313,6 @@ availableRoles: "可用角色"
|
||||||
acknowledgeNotesAndEnable: "了解注意事項後再開啟。"
|
acknowledgeNotesAndEnable: "了解注意事項後再開啟。"
|
||||||
federationSpecified: "此伺服器以白名單聯邦的方式運作。除了管理員指定的伺服器外,它無法與其他伺服器互動。"
|
federationSpecified: "此伺服器以白名單聯邦的方式運作。除了管理員指定的伺服器外,它無法與其他伺服器互動。"
|
||||||
federationDisabled: "此伺服器未開啟站台聯邦。無法與其他伺服器上的使用者互動。"
|
federationDisabled: "此伺服器未開啟站台聯邦。無法與其他伺服器上的使用者互動。"
|
||||||
draft: "草稿\n"
|
|
||||||
confirmOnReact: "在做出反應前先確認"
|
confirmOnReact: "在做出反應前先確認"
|
||||||
reactAreYouSure: "用「 {emoji} 」反應嗎?"
|
reactAreYouSure: "用「 {emoji} 」反應嗎?"
|
||||||
markAsSensitiveConfirm: "要將這個媒體設定為敏感嗎?"
|
markAsSensitiveConfirm: "要將這個媒體設定為敏感嗎?"
|
||||||
|
@ -1368,9 +1367,6 @@ redisplayAllTips: "重新顯示所有「提示與技巧」"
|
||||||
hideAllTips: "隱藏所有「提示與技巧」"
|
hideAllTips: "隱藏所有「提示與技巧」"
|
||||||
defaultImageCompressionLevel: "預設的影像壓縮程度"
|
defaultImageCompressionLevel: "預設的影像壓縮程度"
|
||||||
defaultImageCompressionLevel_description: "低的話可以保留畫質,但是會增加檔案的大小。<br>高的話可以減少檔案大小,但是會降低畫質。"
|
defaultImageCompressionLevel_description: "低的話可以保留畫質,但是會增加檔案的大小。<br>高的話可以減少檔案大小,但是會降低畫質。"
|
||||||
_order:
|
|
||||||
newest: "最新的在前"
|
|
||||||
oldest: "最舊的在前"
|
|
||||||
_chat:
|
_chat:
|
||||||
noMessagesYet: "尚無訊息"
|
noMessagesYet: "尚無訊息"
|
||||||
newMessage: "新訊息"
|
newMessage: "新訊息"
|
||||||
|
@ -1997,7 +1993,6 @@ _role:
|
||||||
uploadableFileTypes: "可上傳的檔案類型"
|
uploadableFileTypes: "可上傳的檔案類型"
|
||||||
uploadableFileTypes_caption: "請指定 MIME 類型。可以用換行區隔多個類型,也可以使用星號(*)作為萬用字元進行指定。(例如:image/*)\n"
|
uploadableFileTypes_caption: "請指定 MIME 類型。可以用換行區隔多個類型,也可以使用星號(*)作為萬用字元進行指定。(例如:image/*)\n"
|
||||||
uploadableFileTypes_caption2: "有些檔案可能無法判斷其類型。若要允許這類檔案,請在指定中加入 {x}。"
|
uploadableFileTypes_caption2: "有些檔案可能無法判斷其類型。若要允許這類檔案,請在指定中加入 {x}。"
|
||||||
noteDraftLimit: "伺服器端可建立的貼文草稿數量上限\n"
|
|
||||||
_condition:
|
_condition:
|
||||||
roleAssignedTo: "手動指派角色完成"
|
roleAssignedTo: "手動指派角色完成"
|
||||||
isLocal: "本地使用者"
|
isLocal: "本地使用者"
|
||||||
|
@ -2157,7 +2152,6 @@ _theme:
|
||||||
install: "安裝佈景主題"
|
install: "安裝佈景主題"
|
||||||
manage: "管理佈景主題"
|
manage: "管理佈景主題"
|
||||||
code: "佈景主題代碼"
|
code: "佈景主題代碼"
|
||||||
copyThemeCode: "複製主題代碼"
|
|
||||||
description: "描述"
|
description: "描述"
|
||||||
installed: "{name}已安裝"
|
installed: "{name}已安裝"
|
||||||
installedThemes: "已經安裝的佈景主題"
|
installedThemes: "已經安裝的佈景主題"
|
||||||
|
@ -3109,7 +3103,6 @@ _serverSetupWizard:
|
||||||
text2: "為了能夠繼續開發,若您願意的話,請考慮進行捐款。\n"
|
text2: "為了能夠繼續開發,若您願意的話,請考慮進行捐款。\n"
|
||||||
text3: "也有提供支援者專屬的特典!\n"
|
text3: "也有提供支援者專屬的特典!\n"
|
||||||
_uploader:
|
_uploader:
|
||||||
editImage: "編輯圖片"
|
|
||||||
compressedToX: "壓縮為 {x}"
|
compressedToX: "壓縮為 {x}"
|
||||||
savedXPercent: "節省了 {x}%"
|
savedXPercent: "節省了 {x}%"
|
||||||
abortConfirm: "有些檔案尚未上傳,您要中止嗎?"
|
abortConfirm: "有些檔案尚未上傳,您要中止嗎?"
|
||||||
|
@ -3176,20 +3169,3 @@ _imageEffector:
|
||||||
stripe: "條紋"
|
stripe: "條紋"
|
||||||
polkadot: "波卡圓點"
|
polkadot: "波卡圓點"
|
||||||
checker: "棋盤格"
|
checker: "棋盤格"
|
||||||
blockNoise: "阻擋雜訊"
|
|
||||||
tearing: "撕裂"
|
|
||||||
drafts: "草稿\n"
|
|
||||||
_drafts:
|
|
||||||
select: "選擇草槁"
|
|
||||||
cannotCreateDraftAnymore: "已超出可建立的草稿數量上限。\n"
|
|
||||||
cannotCreateDraftOfRenote: "無法建立轉發的草稿。\n"
|
|
||||||
delete: "刪除草稿"
|
|
||||||
deleteAreYouSure: "確定要刪除草稿嗎?\n"
|
|
||||||
noDrafts: "沒有草稿。\n"
|
|
||||||
replyTo: "回覆給 {user}\n"
|
|
||||||
quoteOf: "引用自 {user} 的貼文\n"
|
|
||||||
postTo: "發佈到 {channel}\n"
|
|
||||||
saveToDraft: "儲存為草稿"
|
|
||||||
restoreFromDraft: "從草稿復原\n"
|
|
||||||
restore: "還原"
|
|
||||||
listDrafts: "草稿清單"
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "2025.6.4-alpha.3",
|
"version": "2025.6.1",
|
||||||
"codename": "nasubi",
|
"codename": "nasubi",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -25,7 +25,6 @@ export default [
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
'@typescript-eslint/no-unused-vars': 'off',
|
|
||||||
'import/order': ['warn', {
|
'import/order': ['warn', {
|
||||||
groups: [
|
groups: [
|
||||||
'builtin',
|
'builtin',
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
export class CreateNoteDraft1736686850345 {
|
|
||||||
name = 'CreateNoteDraft1736686850345'
|
|
||||||
|
|
||||||
async up(queryRunner) {
|
|
||||||
await queryRunner.query(`
|
|
||||||
CREATE TABLE "note_draft" (
|
|
||||||
"id" varchar NOT NULL,
|
|
||||||
"replyId" varchar NULL,
|
|
||||||
"renoteId" varchar NULL,
|
|
||||||
"text" text NULL,
|
|
||||||
"cw" varchar(512) NULL,
|
|
||||||
"userId" varchar NOT NULL,
|
|
||||||
"localOnly" boolean DEFAULT false,
|
|
||||||
"reactionAcceptance" varchar(64) NULL,
|
|
||||||
"visibility" varchar NOT NULL,
|
|
||||||
"fileIds" varchar[] DEFAULT '{}',
|
|
||||||
"visibleUserIds" varchar[] DEFAULT '{}',
|
|
||||||
"hashtag" varchar(128) NULL,
|
|
||||||
"channelId" varchar NULL,
|
|
||||||
"hasPoll" boolean DEFAULT false,
|
|
||||||
"pollChoices" varchar(256)[] DEFAULT '{}',
|
|
||||||
"pollMultiple" boolean NULL,
|
|
||||||
"pollExpiresAt" TIMESTAMP WITH TIME ZONE NULL,
|
|
||||||
"pollExpiredAfter" bigint NULL,
|
|
||||||
PRIMARY KEY ("id")
|
|
||||||
)`);
|
|
||||||
|
|
||||||
await queryRunner.query(`
|
|
||||||
CREATE INDEX "IDX_NOTE_DRAFT_REPLY_ID" ON "note_draft" ("replyId")
|
|
||||||
`);
|
|
||||||
|
|
||||||
await queryRunner.query(`
|
|
||||||
CREATE INDEX "IDX_NOTE_DRAFT_RENOTE_ID" ON "note_draft" ("renoteId")
|
|
||||||
`);
|
|
||||||
|
|
||||||
await queryRunner.query(`
|
|
||||||
CREATE INDEX "IDX_NOTE_DRAFT_USER_ID" ON "note_draft" ("userId")
|
|
||||||
`);
|
|
||||||
|
|
||||||
await queryRunner.query(`
|
|
||||||
CREATE INDEX "IDX_NOTE_DRAFT_FILE_IDS" ON "note_draft" USING GIN ("fileIds")
|
|
||||||
`);
|
|
||||||
|
|
||||||
await queryRunner.query(`
|
|
||||||
CREATE INDEX "IDX_NOTE_DRAFT_VISIBLE_USER_IDS" ON "note_draft" USING GIN ("visibleUserIds")
|
|
||||||
`);
|
|
||||||
|
|
||||||
await queryRunner.query(`
|
|
||||||
CREATE INDEX "IDX_NOTE_DRAFT_CHANNEL_ID" ON "note_draft" ("channelId")
|
|
||||||
`);
|
|
||||||
|
|
||||||
await queryRunner.query(`
|
|
||||||
ALTER TABLE "note_draft"
|
|
||||||
ADD CONSTRAINT "FK_NOTE_DRAFT_REPLY_ID" FOREIGN KEY ("replyId") REFERENCES "note"("id") ON DELETE CASCADE
|
|
||||||
`);
|
|
||||||
|
|
||||||
await queryRunner.query(`
|
|
||||||
ALTER TABLE "note_draft"
|
|
||||||
ADD CONSTRAINT "FK_NOTE_DRAFT_RENOTE_ID" FOREIGN KEY ("renoteId") REFERENCES "note"("id") ON DELETE CASCADE
|
|
||||||
`);
|
|
||||||
|
|
||||||
await queryRunner.query(`
|
|
||||||
ALTER TABLE "note_draft"
|
|
||||||
ADD CONSTRAINT "FK_NOTE_DRAFT_USER_ID" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE
|
|
||||||
`);
|
|
||||||
|
|
||||||
await queryRunner.query(`
|
|
||||||
ALTER TABLE "note_draft"
|
|
||||||
ADD CONSTRAINT "FK_NOTE_DRAFT_CHANNEL_ID" FOREIGN KEY ("channelId") REFERENCES "channel"("id") ON DELETE CASCADE
|
|
||||||
`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async down(queryRunner) {
|
|
||||||
await queryRunner.query(`ALTER TABLE "note_draft" DROP CONSTRAINT "FK_NOTE_DRAFT_CHANNEL_ID"`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "note_draft" DROP CONSTRAINT "FK_NOTE_DRAFT_USER_ID"`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "note_draft" DROP CONSTRAINT "FK_NOTE_DRAFT_RENOTE_ID"`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "note_draft" DROP CONSTRAINT "FK_NOTE_DRAFT_REPLY_ID"`);
|
|
||||||
await queryRunner.query(`DROP INDEX "IDX_NOTE_DRAFT_CHANNEL_ID"`);
|
|
||||||
await queryRunner.query(`DROP INDEX "IDX_NOTE_DRAFT_VISIBLE_USER_IDS"`);
|
|
||||||
await queryRunner.query(`DROP INDEX "IDX_NOTE_DRAFT_FILE_IDS"`);
|
|
||||||
await queryRunner.query(`DROP INDEX "IDX_NOTE_DRAFT_USER_ID"`);
|
|
||||||
await queryRunner.query(`DROP INDEX "IDX_NOTE_DRAFT_RENOTE_ID"`);
|
|
||||||
await queryRunner.query(`DROP INDEX "IDX_NOTE_DRAFT_REPLY_ID"`);
|
|
||||||
await queryRunner.query(`DROP TABLE "note_draft"`);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -44,7 +44,6 @@ import { ModerationLogService } from './ModerationLogService.js';
|
||||||
import { NoteCreateService } from './NoteCreateService.js';
|
import { NoteCreateService } from './NoteCreateService.js';
|
||||||
import { NoteDeleteService } from './NoteDeleteService.js';
|
import { NoteDeleteService } from './NoteDeleteService.js';
|
||||||
import { NotePiningService } from './NotePiningService.js';
|
import { NotePiningService } from './NotePiningService.js';
|
||||||
import { NoteDraftService } from './NoteDraftService.js';
|
|
||||||
import { NotificationService } from './NotificationService.js';
|
import { NotificationService } from './NotificationService.js';
|
||||||
import { PollService } from './PollService.js';
|
import { PollService } from './PollService.js';
|
||||||
import { PushNotificationService } from './PushNotificationService.js';
|
import { PushNotificationService } from './PushNotificationService.js';
|
||||||
|
@ -119,7 +118,6 @@ import { RenoteMutingEntityService } from './entities/RenoteMutingEntityService.
|
||||||
import { NoteEntityService } from './entities/NoteEntityService.js';
|
import { NoteEntityService } from './entities/NoteEntityService.js';
|
||||||
import { NoteFavoriteEntityService } from './entities/NoteFavoriteEntityService.js';
|
import { NoteFavoriteEntityService } from './entities/NoteFavoriteEntityService.js';
|
||||||
import { NoteReactionEntityService } from './entities/NoteReactionEntityService.js';
|
import { NoteReactionEntityService } from './entities/NoteReactionEntityService.js';
|
||||||
import { NoteDraftEntityService } from './entities/NoteDraftEntityService.js';
|
|
||||||
import { NotificationEntityService } from './entities/NotificationEntityService.js';
|
import { NotificationEntityService } from './entities/NotificationEntityService.js';
|
||||||
import { PageEntityService } from './entities/PageEntityService.js';
|
import { PageEntityService } from './entities/PageEntityService.js';
|
||||||
import { PageLikeEntityService } from './entities/PageLikeEntityService.js';
|
import { PageLikeEntityService } from './entities/PageLikeEntityService.js';
|
||||||
|
@ -187,7 +185,6 @@ const $ModerationLogService: Provider = { provide: 'ModerationLogService', useEx
|
||||||
const $NoteCreateService: Provider = { provide: 'NoteCreateService', useExisting: NoteCreateService };
|
const $NoteCreateService: Provider = { provide: 'NoteCreateService', useExisting: NoteCreateService };
|
||||||
const $NoteDeleteService: Provider = { provide: 'NoteDeleteService', useExisting: NoteDeleteService };
|
const $NoteDeleteService: Provider = { provide: 'NoteDeleteService', useExisting: NoteDeleteService };
|
||||||
const $NotePiningService: Provider = { provide: 'NotePiningService', useExisting: NotePiningService };
|
const $NotePiningService: Provider = { provide: 'NotePiningService', useExisting: NotePiningService };
|
||||||
const $NoteDraftService: Provider = { provide: 'NoteDraftService', useExisting: NoteDraftService };
|
|
||||||
const $NotificationService: Provider = { provide: 'NotificationService', useExisting: NotificationService };
|
const $NotificationService: Provider = { provide: 'NotificationService', useExisting: NotificationService };
|
||||||
const $PollService: Provider = { provide: 'PollService', useExisting: PollService };
|
const $PollService: Provider = { provide: 'PollService', useExisting: PollService };
|
||||||
const $SystemAccountService: Provider = { provide: 'SystemAccountService', useExisting: SystemAccountService };
|
const $SystemAccountService: Provider = { provide: 'SystemAccountService', useExisting: SystemAccountService };
|
||||||
|
@ -269,7 +266,6 @@ const $RenoteMutingEntityService: Provider = { provide: 'RenoteMutingEntityServi
|
||||||
const $NoteEntityService: Provider = { provide: 'NoteEntityService', useExisting: NoteEntityService };
|
const $NoteEntityService: Provider = { provide: 'NoteEntityService', useExisting: NoteEntityService };
|
||||||
const $NoteFavoriteEntityService: Provider = { provide: 'NoteFavoriteEntityService', useExisting: NoteFavoriteEntityService };
|
const $NoteFavoriteEntityService: Provider = { provide: 'NoteFavoriteEntityService', useExisting: NoteFavoriteEntityService };
|
||||||
const $NoteReactionEntityService: Provider = { provide: 'NoteReactionEntityService', useExisting: NoteReactionEntityService };
|
const $NoteReactionEntityService: Provider = { provide: 'NoteReactionEntityService', useExisting: NoteReactionEntityService };
|
||||||
const $NoteDraftEntityService: Provider = { provide: 'NoteDraftEntityService', useExisting: NoteDraftEntityService };
|
|
||||||
const $NotificationEntityService: Provider = { provide: 'NotificationEntityService', useExisting: NotificationEntityService };
|
const $NotificationEntityService: Provider = { provide: 'NotificationEntityService', useExisting: NotificationEntityService };
|
||||||
const $PageEntityService: Provider = { provide: 'PageEntityService', useExisting: PageEntityService };
|
const $PageEntityService: Provider = { provide: 'PageEntityService', useExisting: PageEntityService };
|
||||||
const $PageLikeEntityService: Provider = { provide: 'PageLikeEntityService', useExisting: PageLikeEntityService };
|
const $PageLikeEntityService: Provider = { provide: 'PageLikeEntityService', useExisting: PageLikeEntityService };
|
||||||
|
@ -339,7 +335,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
NoteCreateService,
|
NoteCreateService,
|
||||||
NoteDeleteService,
|
NoteDeleteService,
|
||||||
NotePiningService,
|
NotePiningService,
|
||||||
NoteDraftService,
|
|
||||||
NotificationService,
|
NotificationService,
|
||||||
PollService,
|
PollService,
|
||||||
SystemAccountService,
|
SystemAccountService,
|
||||||
|
@ -421,7 +416,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
NoteEntityService,
|
NoteEntityService,
|
||||||
NoteFavoriteEntityService,
|
NoteFavoriteEntityService,
|
||||||
NoteReactionEntityService,
|
NoteReactionEntityService,
|
||||||
NoteDraftEntityService,
|
|
||||||
NotificationEntityService,
|
NotificationEntityService,
|
||||||
PageEntityService,
|
PageEntityService,
|
||||||
PageLikeEntityService,
|
PageLikeEntityService,
|
||||||
|
@ -487,7 +481,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$NoteCreateService,
|
$NoteCreateService,
|
||||||
$NoteDeleteService,
|
$NoteDeleteService,
|
||||||
$NotePiningService,
|
$NotePiningService,
|
||||||
$NoteDraftService,
|
|
||||||
$NotificationService,
|
$NotificationService,
|
||||||
$PollService,
|
$PollService,
|
||||||
$SystemAccountService,
|
$SystemAccountService,
|
||||||
|
@ -569,7 +562,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$NoteEntityService,
|
$NoteEntityService,
|
||||||
$NoteFavoriteEntityService,
|
$NoteFavoriteEntityService,
|
||||||
$NoteReactionEntityService,
|
$NoteReactionEntityService,
|
||||||
$NoteDraftEntityService,
|
|
||||||
$NotificationEntityService,
|
$NotificationEntityService,
|
||||||
$PageEntityService,
|
$PageEntityService,
|
||||||
$PageLikeEntityService,
|
$PageLikeEntityService,
|
||||||
|
@ -636,7 +628,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
NoteCreateService,
|
NoteCreateService,
|
||||||
NoteDeleteService,
|
NoteDeleteService,
|
||||||
NotePiningService,
|
NotePiningService,
|
||||||
NoteDraftService,
|
|
||||||
NotificationService,
|
NotificationService,
|
||||||
PollService,
|
PollService,
|
||||||
SystemAccountService,
|
SystemAccountService,
|
||||||
|
@ -717,7 +708,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
NoteEntityService,
|
NoteEntityService,
|
||||||
NoteFavoriteEntityService,
|
NoteFavoriteEntityService,
|
||||||
NoteReactionEntityService,
|
NoteReactionEntityService,
|
||||||
NoteDraftEntityService,
|
|
||||||
NotificationEntityService,
|
NotificationEntityService,
|
||||||
PageEntityService,
|
PageEntityService,
|
||||||
PageLikeEntityService,
|
PageLikeEntityService,
|
||||||
|
@ -783,7 +773,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$NoteCreateService,
|
$NoteCreateService,
|
||||||
$NoteDeleteService,
|
$NoteDeleteService,
|
||||||
$NotePiningService,
|
$NotePiningService,
|
||||||
$NoteDraftService,
|
|
||||||
$NotificationService,
|
$NotificationService,
|
||||||
$PollService,
|
$PollService,
|
||||||
$SystemAccountService,
|
$SystemAccountService,
|
||||||
|
@ -863,7 +852,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$NoteEntityService,
|
$NoteEntityService,
|
||||||
$NoteFavoriteEntityService,
|
$NoteFavoriteEntityService,
|
||||||
$NoteReactionEntityService,
|
$NoteReactionEntityService,
|
||||||
$NoteDraftEntityService,
|
|
||||||
$NotificationEntityService,
|
$NotificationEntityService,
|
||||||
$PageEntityService,
|
$PageEntityService,
|
||||||
$PageLikeEntityService,
|
$PageLikeEntityService,
|
||||||
|
|
|
@ -1,314 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
|
||||||
import { In } from 'typeorm';
|
|
||||||
import type { noteVisibilities, noteReactionAcceptances } from '@/types.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
|
||||||
import type { MiNoteDraft, NoteDraftsRepository, MiNote, MiDriveFile, MiChannel, UsersRepository, DriveFilesRepository, NotesRepository, BlockingsRepository, ChannelsRepository } from '@/models/_.js';
|
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
import { RoleService } from '@/core/RoleService.js';
|
|
||||||
import { IdService } from '@/core/IdService.js';
|
|
||||||
import type { MiLocalUser, MiUser } from '@/models/User.js';
|
|
||||||
import { IPoll } from '@/models/Poll.js';
|
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
|
||||||
import { isRenote, isQuote } from '@/misc/is-renote.js';
|
|
||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
|
||||||
|
|
||||||
export type NoteDraftOptions = {
|
|
||||||
replyId?: MiNote['id'] | null;
|
|
||||||
renoteId?: MiNote['id'] | null;
|
|
||||||
text?: string | null;
|
|
||||||
cw?: string | null;
|
|
||||||
localOnly?: boolean | null;
|
|
||||||
reactionAcceptance?: typeof noteReactionAcceptances[number];
|
|
||||||
visibility?: typeof noteVisibilities[number];
|
|
||||||
fileIds?: MiDriveFile['id'][];
|
|
||||||
visibleUserIds?: MiUser['id'][];
|
|
||||||
hashtag?: string;
|
|
||||||
channelId?: MiChannel['id'] | null;
|
|
||||||
poll?: (IPoll & { expiredAfter?: number | null }) | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class NoteDraftService {
|
|
||||||
constructor(
|
|
||||||
@Inject(DI.blockingsRepository)
|
|
||||||
private blockingsRepository: BlockingsRepository,
|
|
||||||
|
|
||||||
@Inject(DI.noteDraftsRepository)
|
|
||||||
private noteDraftsRepository: NoteDraftsRepository,
|
|
||||||
|
|
||||||
@Inject(DI.notesRepository)
|
|
||||||
private notesRepository: NotesRepository,
|
|
||||||
|
|
||||||
@Inject(DI.usersRepository)
|
|
||||||
private usersRepository: UsersRepository,
|
|
||||||
|
|
||||||
@Inject(DI.driveFilesRepository)
|
|
||||||
private driveFilesRepository: DriveFilesRepository,
|
|
||||||
|
|
||||||
@Inject(DI.channelsRepository)
|
|
||||||
private channelsRepository: ChannelsRepository,
|
|
||||||
|
|
||||||
private roleService: RoleService,
|
|
||||||
private idService: IdService,
|
|
||||||
private noteEntityService: NoteEntityService,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async get(me: MiLocalUser, draftId: MiNoteDraft['id']): Promise<MiNoteDraft | null> {
|
|
||||||
const draft = await this.noteDraftsRepository.findOneBy({
|
|
||||||
id: draftId,
|
|
||||||
userId: me.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
return draft;
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async create(me: MiLocalUser, data: NoteDraftOptions): Promise<MiNoteDraft> {
|
|
||||||
//#region check draft limit
|
|
||||||
|
|
||||||
const currentCount = await this.noteDraftsRepository.countBy({
|
|
||||||
userId: me.id,
|
|
||||||
});
|
|
||||||
if (currentCount >= (await this.roleService.getUserPolicies(me.id)).noteDraftLimit) {
|
|
||||||
throw new IdentifiableError('9ee33bbe-fde3-4c71-9b51-e50492c6b9c8', 'Too many drafts');
|
|
||||||
}
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
if (data.poll) {
|
|
||||||
if (typeof data.poll.expiresAt === 'number') {
|
|
||||||
if (data.poll.expiresAt < Date.now()) {
|
|
||||||
throw new IdentifiableError('04da457d-b083-4055-9082-955525eda5a5', 'Cannot create expired poll');
|
|
||||||
}
|
|
||||||
} else if (typeof data.poll.expiredAfter === 'number') {
|
|
||||||
data.poll.expiresAt = new Date(Date.now() + data.poll.expiredAfter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const appliedDraft = await this.checkAndSetDraftNoteOptions(me, this.noteDraftsRepository.create(), data);
|
|
||||||
|
|
||||||
appliedDraft.id = this.idService.gen();
|
|
||||||
appliedDraft.userId = me.id;
|
|
||||||
const draft = this.noteDraftsRepository.save(appliedDraft);
|
|
||||||
|
|
||||||
return draft;
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async update(me: MiLocalUser, draftId: MiNoteDraft['id'], data: NoteDraftOptions): Promise<MiNoteDraft> {
|
|
||||||
const draft = await this.noteDraftsRepository.findOneBy({
|
|
||||||
id: draftId,
|
|
||||||
userId: me.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (draft == null) {
|
|
||||||
throw new IdentifiableError('49cd6b9d-848e-41ee-b0b9-adaca711a6b1', 'No such note draft');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.poll) {
|
|
||||||
if (typeof data.poll.expiresAt === 'number') {
|
|
||||||
if (data.poll.expiresAt < Date.now()) {
|
|
||||||
throw new IdentifiableError('04da457d-b083-4055-9082-955525eda5a5', 'Cannot create expired poll');
|
|
||||||
}
|
|
||||||
} else if (typeof data.poll.expiredAfter === 'number') {
|
|
||||||
data.poll.expiresAt = new Date(Date.now() + data.poll.expiredAfter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const appliedDraft = await this.checkAndSetDraftNoteOptions(me, draft, data);
|
|
||||||
|
|
||||||
return await this.noteDraftsRepository.save(appliedDraft);
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async delete(me: MiLocalUser, draftId: MiNoteDraft['id']): Promise<void> {
|
|
||||||
const draft = await this.noteDraftsRepository.findOneBy({
|
|
||||||
id: draftId,
|
|
||||||
userId: me.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (draft == null) {
|
|
||||||
throw new IdentifiableError('49cd6b9d-848e-41ee-b0b9-adaca711a6b1', 'No such note draft');
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.noteDraftsRepository.delete(draft.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async getDraft(me: MiLocalUser, draftId: MiNoteDraft['id']): Promise<MiNoteDraft> {
|
|
||||||
const draft = await this.noteDraftsRepository.findOneBy({
|
|
||||||
id: draftId,
|
|
||||||
userId: me.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (draft == null) {
|
|
||||||
throw new IdentifiableError('49cd6b9d-848e-41ee-b0b9-adaca711a6b1', 'No such note draft');
|
|
||||||
}
|
|
||||||
|
|
||||||
return draft;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 関連エンティティを取得し紐づける部分を共通化する
|
|
||||||
@bindThis
|
|
||||||
public async checkAndSetDraftNoteOptions(
|
|
||||||
me: MiLocalUser,
|
|
||||||
draft: MiNoteDraft,
|
|
||||||
data: NoteDraftOptions,
|
|
||||||
): Promise<MiNoteDraft> {
|
|
||||||
data.visibility ??= 'public';
|
|
||||||
data.localOnly ??= false;
|
|
||||||
if (data.reactionAcceptance === undefined) data.reactionAcceptance = null;
|
|
||||||
if (data.channelId != null) {
|
|
||||||
data.visibility = 'public';
|
|
||||||
data.visibleUserIds = [];
|
|
||||||
data.localOnly = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let appliedDraft = draft;
|
|
||||||
|
|
||||||
//#region visibleUsers
|
|
||||||
let visibleUsers: MiUser[] = [];
|
|
||||||
if (data.visibleUserIds != null) {
|
|
||||||
visibleUsers = await this.usersRepository.findBy({
|
|
||||||
id: In(data.visibleUserIds),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region files
|
|
||||||
let files: MiDriveFile[] = [];
|
|
||||||
const fileIds = data.fileIds ?? null;
|
|
||||||
if (fileIds != null) {
|
|
||||||
files = await this.driveFilesRepository.createQueryBuilder('file')
|
|
||||||
.where('file.userId = :userId AND file.id IN (:...fileIds)', {
|
|
||||||
userId: me.id,
|
|
||||||
fileIds: fileIds,
|
|
||||||
})
|
|
||||||
.orderBy('array_position(ARRAY[:...fileIds], "id"::text)')
|
|
||||||
.setParameters({ fileIds })
|
|
||||||
.getMany();
|
|
||||||
|
|
||||||
if (files.length !== fileIds.length) {
|
|
||||||
throw new IdentifiableError('b6992544-63e7-67f0-fa7f-32444b1b5306', 'No such drive file');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region renote
|
|
||||||
let renote: MiNote | null = null;
|
|
||||||
if (data.renoteId != null) {
|
|
||||||
renote = await this.notesRepository.findOneBy({ id: data.renoteId });
|
|
||||||
|
|
||||||
if (renote == null) {
|
|
||||||
throw new IdentifiableError('64929870-2540-4d11-af41-3b484d78c956', 'No such renote');
|
|
||||||
} else if (isRenote(renote) && !isQuote(renote)) {
|
|
||||||
throw new IdentifiableError('76cc5583-5a14-4ad3-8717-0298507e32db', 'Cannot renote');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check blocking
|
|
||||||
if (renote.userId !== me.id) {
|
|
||||||
const blockExist = await this.blockingsRepository.exists({
|
|
||||||
where: {
|
|
||||||
blockerId: renote.userId,
|
|
||||||
blockeeId: me.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (blockExist) {
|
|
||||||
throw new IdentifiableError('075ca298-e6e7-485a-b570-51a128bb5168', 'You have been blocked by the user');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (renote.visibility === 'followers' && renote.userId !== me.id) {
|
|
||||||
// 他人のfollowers noteはreject
|
|
||||||
throw new IdentifiableError('81eb8188-aea1-4e35-9a8f-3334a3be9855', 'Cannot Renote Due to Visibility');
|
|
||||||
} else if (renote.visibility === 'specified') {
|
|
||||||
// specified / direct noteはreject
|
|
||||||
throw new IdentifiableError('81eb8188-aea1-4e35-9a8f-3334a3be9855', 'Cannot Renote Due to Visibility');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (renote.channelId && renote.channelId !== data.channelId) {
|
|
||||||
// チャンネルのノートに対しリノート要求がきたとき、チャンネル外へのリノート可否をチェック
|
|
||||||
// リノートのユースケースのうち、チャンネル内→チャンネル外は少数だと考えられるため、JOINはせず必要な時に都度取得する
|
|
||||||
const renoteChannel = await this.channelsRepository.findOneBy({ id: renote.channelId });
|
|
||||||
if (renoteChannel == null) {
|
|
||||||
// リノートしたいノートが書き込まれているチャンネルがない
|
|
||||||
throw new IdentifiableError('6815399a-6f13-4069-b60d-ed5156249d12', 'No such channel');
|
|
||||||
} else if (!renoteChannel.allowRenoteToExternal) {
|
|
||||||
// リノート作成のリクエストだが、対象チャンネルがリノート禁止だった場合
|
|
||||||
throw new IdentifiableError('ed1952ac-2d26-4957-8b30-2deda76bedf7', 'Cannot Renote to External');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region reply
|
|
||||||
let reply: MiNote | null = null;
|
|
||||||
if (data.replyId != null) {
|
|
||||||
// Fetch reply
|
|
||||||
reply = await this.notesRepository.findOneBy({ id: data.replyId });
|
|
||||||
|
|
||||||
if (reply == null) {
|
|
||||||
throw new IdentifiableError('c4721841-22fc-4bb7-ad3d-897ef1d375b5', 'No such reply');
|
|
||||||
} else if (isRenote(reply) && !isQuote(reply)) {
|
|
||||||
throw new IdentifiableError('e6c10b57-2c09-4da3-bd4d-eda05d51d140', 'Cannot reply To Pure Renote');
|
|
||||||
} else if (!await this.noteEntityService.isVisibleForMe(reply, me.id)) {
|
|
||||||
throw new IdentifiableError('593c323c-6b6a-4501-a25c-2f36bd2a93d6', 'Cannot reply To Invisible Note');
|
|
||||||
} else if (reply.visibility === 'specified' && data.visibility !== 'specified') {
|
|
||||||
throw new IdentifiableError('215dbc76-336c-4d2a-9605-95766ba7dab0', 'Cannot reply To Specified Note With Extended Visibility');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check blocking
|
|
||||||
if (reply.userId !== me.id) {
|
|
||||||
const blockExist = await this.blockingsRepository.exists({
|
|
||||||
where: {
|
|
||||||
blockerId: reply.userId,
|
|
||||||
blockeeId: me.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (blockExist) {
|
|
||||||
throw new IdentifiableError('075ca298-e6e7-485a-b570-51a128bb5168', 'You have been blocked by the user');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region channel
|
|
||||||
let channel: MiChannel | null = null;
|
|
||||||
if (data.channelId != null) {
|
|
||||||
channel = await this.channelsRepository.findOneBy({ id: data.channelId, isArchived: false });
|
|
||||||
|
|
||||||
if (channel == null) {
|
|
||||||
throw new IdentifiableError('6815399a-6f13-4069-b60d-ed5156249d12', 'No such channel');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
appliedDraft = {
|
|
||||||
...appliedDraft,
|
|
||||||
visibility: data.visibility,
|
|
||||||
cw: data.cw ?? null,
|
|
||||||
fileIds: fileIds ?? [],
|
|
||||||
replyId: data.replyId ?? null,
|
|
||||||
renoteId: data.renoteId ?? null,
|
|
||||||
channelId: data.channelId ?? null,
|
|
||||||
text: data.text ?? null,
|
|
||||||
hashtag: data.hashtag ?? null,
|
|
||||||
hasPoll: data.poll != null,
|
|
||||||
pollChoices: data.poll ? data.poll.choices : [],
|
|
||||||
pollMultiple: data.poll ? data.poll.multiple : false,
|
|
||||||
pollExpiresAt: data.poll ? data.poll.expiresAt : null,
|
|
||||||
pollExpiredAfter: data.poll ? data.poll.expiredAfter ?? null : null,
|
|
||||||
visibleUserIds: data.visibleUserIds ?? [],
|
|
||||||
localOnly: data.localOnly,
|
|
||||||
reactionAcceptance: data.reactionAcceptance,
|
|
||||||
} satisfies MiNoteDraft;
|
|
||||||
|
|
||||||
return appliedDraft;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -66,7 +66,6 @@ export type RolePolicies = {
|
||||||
canImportUserLists: boolean;
|
canImportUserLists: boolean;
|
||||||
chatAvailability: 'available' | 'readonly' | 'unavailable';
|
chatAvailability: 'available' | 'readonly' | 'unavailable';
|
||||||
uploadableFileTypes: string[];
|
uploadableFileTypes: string[];
|
||||||
noteDraftLimit: number;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_POLICIES: RolePolicies = {
|
export const DEFAULT_POLICIES: RolePolicies = {
|
||||||
|
@ -110,7 +109,6 @@ export const DEFAULT_POLICIES: RolePolicies = {
|
||||||
'video/*',
|
'video/*',
|
||||||
'audio/*',
|
'audio/*',
|
||||||
],
|
],
|
||||||
noteDraftLimit: 10,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -432,7 +430,6 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
||||||
}
|
}
|
||||||
return [...set];
|
return [...set];
|
||||||
}),
|
}),
|
||||||
noteDraftLimit: calc('noteDraftLimit', vs => Math.max(...vs)),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,177 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
|
||||||
import { ModuleRef } from '@nestjs/core';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
|
||||||
import type { Packed } from '@/misc/json-schema.js';
|
|
||||||
import { awaitAll } from '@/misc/prelude/await-all.js';
|
|
||||||
import type { MiUser, MiNote, MiNoteDraft } from '@/models/_.js';
|
|
||||||
import type { NoteDraftsRepository, ChannelsRepository } from '@/models/_.js';
|
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
import { DebounceLoader } from '@/misc/loader.js';
|
|
||||||
import { IdService } from '@/core/IdService.js';
|
|
||||||
import type { OnModuleInit } from '@nestjs/common';
|
|
||||||
import type { UserEntityService } from './UserEntityService.js';
|
|
||||||
import type { DriveFileEntityService } from './DriveFileEntityService.js';
|
|
||||||
import type { NoteEntityService } from './NoteEntityService.js';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class NoteDraftEntityService implements OnModuleInit {
|
|
||||||
private userEntityService: UserEntityService;
|
|
||||||
private driveFileEntityService: DriveFileEntityService;
|
|
||||||
private idService: IdService;
|
|
||||||
private noteEntityService: NoteEntityService;
|
|
||||||
private noteDraftLoader = new DebounceLoader(this.findNoteDraftOrFail);
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private moduleRef: ModuleRef,
|
|
||||||
|
|
||||||
@Inject(DI.noteDraftsRepository)
|
|
||||||
private noteDraftsRepository: NoteDraftsRepository,
|
|
||||||
|
|
||||||
@Inject(DI.channelsRepository)
|
|
||||||
private channelsRepository: ChannelsRepository,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
onModuleInit() {
|
|
||||||
this.userEntityService = this.moduleRef.get('UserEntityService');
|
|
||||||
this.driveFileEntityService = this.moduleRef.get('DriveFileEntityService');
|
|
||||||
this.idService = this.moduleRef.get('IdService');
|
|
||||||
this.noteEntityService = this.moduleRef.get('NoteEntityService');
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async packAttachedFiles(fileIds: MiNote['fileIds'], packedFiles: Map<MiNote['fileIds'][number], Packed<'DriveFile'> | null>): Promise<Packed<'DriveFile'>[]> {
|
|
||||||
const missingIds = [];
|
|
||||||
for (const id of fileIds) {
|
|
||||||
if (!packedFiles.has(id)) missingIds.push(id);
|
|
||||||
}
|
|
||||||
if (missingIds.length) {
|
|
||||||
const additionalMap = await this.driveFileEntityService.packManyByIdsMap(missingIds);
|
|
||||||
for (const [k, v] of additionalMap) {
|
|
||||||
packedFiles.set(k, v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fileIds.map(id => packedFiles.get(id)).filter(x => x != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async pack(
|
|
||||||
src: MiNoteDraft['id'] | MiNoteDraft,
|
|
||||||
me?: { id: MiUser['id'] } | null | undefined,
|
|
||||||
options?: {
|
|
||||||
detail?: boolean;
|
|
||||||
skipHide?: boolean;
|
|
||||||
withReactionAndUserPairCache?: boolean;
|
|
||||||
_hint_?: {
|
|
||||||
packedFiles: Map<MiNote['fileIds'][number], Packed<'DriveFile'> | null>;
|
|
||||||
packedUsers: Map<MiUser['id'], Packed<'UserLite'>>
|
|
||||||
};
|
|
||||||
},
|
|
||||||
): Promise<Packed<'NoteDraft'>> {
|
|
||||||
const opts = Object.assign({
|
|
||||||
detail: true,
|
|
||||||
}, options);
|
|
||||||
|
|
||||||
const noteDraft = typeof src === 'object' ? src : await this.noteDraftLoader.load(src);
|
|
||||||
|
|
||||||
const text = noteDraft.text;
|
|
||||||
|
|
||||||
const channel = noteDraft.channelId
|
|
||||||
? noteDraft.channel
|
|
||||||
? noteDraft.channel
|
|
||||||
: await this.channelsRepository.findOneBy({ id: noteDraft.channelId })
|
|
||||||
: null;
|
|
||||||
|
|
||||||
const packedFiles = options?._hint_?.packedFiles;
|
|
||||||
const packedUsers = options?._hint_?.packedUsers;
|
|
||||||
|
|
||||||
const packed: Packed<'NoteDraft'> = await awaitAll({
|
|
||||||
id: noteDraft.id,
|
|
||||||
createdAt: this.idService.parse(noteDraft.id).date.toISOString(),
|
|
||||||
userId: noteDraft.userId,
|
|
||||||
user: packedUsers?.get(noteDraft.userId) ?? this.userEntityService.pack(noteDraft.user ?? noteDraft.userId, me),
|
|
||||||
text: text,
|
|
||||||
cw: noteDraft.cw,
|
|
||||||
visibility: noteDraft.visibility,
|
|
||||||
localOnly: noteDraft.localOnly,
|
|
||||||
reactionAcceptance: noteDraft.reactionAcceptance,
|
|
||||||
visibleUserIds: noteDraft.visibility === 'specified' ? noteDraft.visibleUserIds : undefined,
|
|
||||||
hashtag: noteDraft.hashtag ?? undefined,
|
|
||||||
fileIds: noteDraft.fileIds,
|
|
||||||
files: packedFiles != null ? this.packAttachedFiles(noteDraft.fileIds, packedFiles) : this.driveFileEntityService.packManyByIds(noteDraft.fileIds),
|
|
||||||
replyId: noteDraft.replyId,
|
|
||||||
renoteId: noteDraft.renoteId,
|
|
||||||
channelId: noteDraft.channelId ?? undefined,
|
|
||||||
channel: channel ? {
|
|
||||||
id: channel.id,
|
|
||||||
name: channel.name,
|
|
||||||
color: channel.color,
|
|
||||||
isSensitive: channel.isSensitive,
|
|
||||||
allowRenoteToExternal: channel.allowRenoteToExternal,
|
|
||||||
userId: channel.userId,
|
|
||||||
} : undefined,
|
|
||||||
|
|
||||||
...(opts.detail ? {
|
|
||||||
reply: noteDraft.replyId ? this.noteEntityService.pack(noteDraft.replyId, me, {
|
|
||||||
detail: false,
|
|
||||||
skipHide: opts.skipHide,
|
|
||||||
}) : undefined,
|
|
||||||
|
|
||||||
renote: noteDraft.renoteId ? this.noteEntityService.pack(noteDraft.renoteId, me, {
|
|
||||||
detail: true,
|
|
||||||
skipHide: opts.skipHide,
|
|
||||||
}) : undefined,
|
|
||||||
|
|
||||||
poll: noteDraft.hasPoll ? {
|
|
||||||
choices: noteDraft.pollChoices,
|
|
||||||
multiple: noteDraft.pollMultiple,
|
|
||||||
expiresAt: noteDraft.pollExpiresAt?.toISOString(),
|
|
||||||
expiredAfter: noteDraft.pollExpiredAfter,
|
|
||||||
} : undefined,
|
|
||||||
} : {} ),
|
|
||||||
});
|
|
||||||
|
|
||||||
return packed;
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async packMany(
|
|
||||||
noteDrafts: MiNoteDraft[],
|
|
||||||
me?: { id: MiUser['id'] } | null | undefined,
|
|
||||||
options?: {
|
|
||||||
detail?: boolean;
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
if (noteDrafts.length === 0) return [];
|
|
||||||
|
|
||||||
// TODO: 本当は renote とか reply がないのに renoteId とか replyId があったらここで解決しておく
|
|
||||||
const fileIds = noteDrafts.map(n => [n.fileIds, n.renote?.fileIds, n.reply?.fileIds]).flat(2).filter(x => x != null);
|
|
||||||
const packedFiles = fileIds.length > 0 ? await this.driveFileEntityService.packManyByIdsMap(fileIds) : new Map();
|
|
||||||
const users = [
|
|
||||||
...noteDrafts.map(({ user, userId }) => user ?? userId),
|
|
||||||
];
|
|
||||||
const packedUsers = await this.userEntityService.packMany(users, me)
|
|
||||||
.then(users => new Map(users.map(u => [u.id, u])));
|
|
||||||
|
|
||||||
return await Promise.all(noteDrafts.map(n => this.pack(n, me, {
|
|
||||||
...options,
|
|
||||||
_hint_: {
|
|
||||||
packedFiles,
|
|
||||||
packedUsers,
|
|
||||||
},
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
private findNoteDraftOrFail(id: string): Promise<MiNoteDraft> {
|
|
||||||
return this.noteDraftsRepository.findOneOrFail({
|
|
||||||
where: { id },
|
|
||||||
relations: ['user'],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -89,6 +89,5 @@ export const DI = {
|
||||||
chatRoomInvitationsRepository: Symbol('chatRoomInvitationsRepository'),
|
chatRoomInvitationsRepository: Symbol('chatRoomInvitationsRepository'),
|
||||||
bubbleGameRecordsRepository: Symbol('bubbleGameRecordsRepository'),
|
bubbleGameRecordsRepository: Symbol('bubbleGameRecordsRepository'),
|
||||||
reversiGamesRepository: Symbol('reversiGamesRepository'),
|
reversiGamesRepository: Symbol('reversiGamesRepository'),
|
||||||
noteDraftsRepository: Symbol('noteDraftsRepository'),
|
|
||||||
//#endregion
|
//#endregion
|
||||||
};
|
};
|
||||||
|
|
|
@ -72,7 +72,6 @@ import { packedChatRoomSchema } from '@/models/json-schema/chat-room.js';
|
||||||
import { packedChatRoomInvitationSchema } from '@/models/json-schema/chat-room-invitation.js';
|
import { packedChatRoomInvitationSchema } from '@/models/json-schema/chat-room-invitation.js';
|
||||||
import { packedChatRoomMembershipSchema } from '@/models/json-schema/chat-room-membership.js';
|
import { packedChatRoomMembershipSchema } from '@/models/json-schema/chat-room-membership.js';
|
||||||
import { packedAchievementNameSchema, packedAchievementSchema } from '@/models/json-schema/achievement.js';
|
import { packedAchievementNameSchema, packedAchievementSchema } from '@/models/json-schema/achievement.js';
|
||||||
import { packedNoteDraftSchema } from '@/models/json-schema/note-draft.js';
|
|
||||||
|
|
||||||
export const refs = {
|
export const refs = {
|
||||||
UserLite: packedUserLiteSchema,
|
UserLite: packedUserLiteSchema,
|
||||||
|
@ -90,7 +89,6 @@ export const refs = {
|
||||||
Announcement: packedAnnouncementSchema,
|
Announcement: packedAnnouncementSchema,
|
||||||
App: packedAppSchema,
|
App: packedAppSchema,
|
||||||
Note: packedNoteSchema,
|
Note: packedNoteSchema,
|
||||||
NoteDraft: packedNoteDraftSchema,
|
|
||||||
NoteReaction: packedNoteReactionSchema,
|
NoteReaction: packedNoteReactionSchema,
|
||||||
NoteFavorite: packedNoteFavoriteSchema,
|
NoteFavorite: packedNoteFavoriteSchema,
|
||||||
Notification: packedNotificationSchema,
|
Notification: packedNotificationSchema,
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm';
|
import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm';
|
||||||
import { noteVisibilities, noteReactionAcceptances } from '@/types.js';
|
import { noteVisibilities } from '@/types.js';
|
||||||
import { id } from './util/id.js';
|
import { id } from './util/id.js';
|
||||||
import { MiUser } from './User.js';
|
import { MiUser } from './User.js';
|
||||||
import { MiChannel } from './Channel.js';
|
import { MiChannel } from './Channel.js';
|
||||||
|
@ -96,7 +96,7 @@ export class MiNote {
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 64, nullable: true,
|
length: 64, nullable: true,
|
||||||
})
|
})
|
||||||
public reactionAcceptance: typeof noteReactionAcceptances[number];
|
public reactionAcceptance: 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote' | null;
|
||||||
|
|
||||||
@Column('smallint', {
|
@Column('smallint', {
|
||||||
default: 0,
|
default: 0,
|
||||||
|
|
|
@ -1,157 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Entity, Index, JoinColumn, Column, PrimaryColumn, ManyToOne } from 'typeorm';
|
|
||||||
import { noteVisibilities, noteReactionAcceptances } from '@/types.js';
|
|
||||||
import { id } from './util/id.js';
|
|
||||||
import { MiUser } from './User.js';
|
|
||||||
import { MiChannel } from './Channel.js';
|
|
||||||
import { MiNote } from './Note.js';
|
|
||||||
import type { MiDriveFile } from './DriveFile.js';
|
|
||||||
|
|
||||||
@Entity('note_draft')
|
|
||||||
export class MiNoteDraft {
|
|
||||||
@PrimaryColumn(id())
|
|
||||||
public id: string;
|
|
||||||
|
|
||||||
@Index()
|
|
||||||
@Column({
|
|
||||||
...id(),
|
|
||||||
nullable: true,
|
|
||||||
comment: 'The ID of reply target.',
|
|
||||||
})
|
|
||||||
public replyId: MiNote['id'] | null;
|
|
||||||
|
|
||||||
@ManyToOne(type => MiNote, {
|
|
||||||
onDelete: 'CASCADE',
|
|
||||||
})
|
|
||||||
@JoinColumn()
|
|
||||||
public reply: MiNote | null;
|
|
||||||
|
|
||||||
@Index()
|
|
||||||
@Column({
|
|
||||||
...id(),
|
|
||||||
nullable: true,
|
|
||||||
comment: 'The ID of renote target.',
|
|
||||||
})
|
|
||||||
public renoteId: MiNote['id'] | null;
|
|
||||||
|
|
||||||
@ManyToOne(type => MiNote, {
|
|
||||||
onDelete: 'CASCADE',
|
|
||||||
})
|
|
||||||
@JoinColumn()
|
|
||||||
public renote: MiNote | null;
|
|
||||||
|
|
||||||
// TODO: varcharにしたい(Note.tsと同じ)
|
|
||||||
@Column('text', {
|
|
||||||
nullable: true,
|
|
||||||
})
|
|
||||||
public text: string | null;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 512, nullable: true,
|
|
||||||
})
|
|
||||||
public cw: string | null;
|
|
||||||
|
|
||||||
@Index()
|
|
||||||
@Column({
|
|
||||||
...id(),
|
|
||||||
comment: 'The ID of author.',
|
|
||||||
})
|
|
||||||
public userId: MiUser['id'];
|
|
||||||
|
|
||||||
@ManyToOne(type => MiUser, {
|
|
||||||
onDelete: 'CASCADE',
|
|
||||||
})
|
|
||||||
@JoinColumn()
|
|
||||||
public user: MiUser | null;
|
|
||||||
|
|
||||||
@Column('boolean', {
|
|
||||||
default: false,
|
|
||||||
})
|
|
||||||
public localOnly: boolean;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 64, nullable: true,
|
|
||||||
})
|
|
||||||
public reactionAcceptance: typeof noteReactionAcceptances[number];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* public ... 公開
|
|
||||||
* home ... ホームタイムライン(ユーザーページのタイムライン含む)のみに流す
|
|
||||||
* followers ... フォロワーのみ
|
|
||||||
* specified ... visibleUserIds で指定したユーザーのみ
|
|
||||||
*/
|
|
||||||
@Column('enum', { enum: noteVisibilities })
|
|
||||||
public visibility: typeof noteVisibilities[number];
|
|
||||||
|
|
||||||
@Index('IDX_NOTE_DRAFT_FILE_IDS', { synchronize: false })
|
|
||||||
@Column({
|
|
||||||
...id(),
|
|
||||||
array: true, default: '{}',
|
|
||||||
})
|
|
||||||
public fileIds: MiDriveFile['id'][];
|
|
||||||
|
|
||||||
@Index('IDX_NOTE_DRAFT_VISIBLE_USER_IDS', { synchronize: false })
|
|
||||||
@Column({
|
|
||||||
...id(),
|
|
||||||
array: true, default: '{}',
|
|
||||||
})
|
|
||||||
public visibleUserIds: MiUser['id'][];
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 128, nullable: true,
|
|
||||||
})
|
|
||||||
public hashtag: string | null;
|
|
||||||
|
|
||||||
@Index()
|
|
||||||
@Column({
|
|
||||||
...id(),
|
|
||||||
nullable: true,
|
|
||||||
comment: 'The ID of source channel.',
|
|
||||||
})
|
|
||||||
public channelId: MiChannel['id'] | null;
|
|
||||||
|
|
||||||
@ManyToOne(type => MiChannel, {
|
|
||||||
onDelete: 'CASCADE',
|
|
||||||
})
|
|
||||||
@JoinColumn()
|
|
||||||
public channel: MiChannel | null;
|
|
||||||
|
|
||||||
// 以下、Pollについて追加
|
|
||||||
|
|
||||||
@Column('boolean', {
|
|
||||||
default: false,
|
|
||||||
})
|
|
||||||
public hasPoll: boolean;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
|
||||||
length: 256, array: true, default: '{}',
|
|
||||||
})
|
|
||||||
public pollChoices: string[];
|
|
||||||
|
|
||||||
@Column('boolean')
|
|
||||||
public pollMultiple: boolean;
|
|
||||||
|
|
||||||
@Column('timestamp with time zone', {
|
|
||||||
nullable: true,
|
|
||||||
})
|
|
||||||
public pollExpiresAt: Date | null;
|
|
||||||
|
|
||||||
@Column('bigint', {
|
|
||||||
nullable: true,
|
|
||||||
})
|
|
||||||
public pollExpiredAfter: number | null;
|
|
||||||
|
|
||||||
// ここまで追加
|
|
||||||
|
|
||||||
constructor(data: Partial<MiNoteDraft>) {
|
|
||||||
if (data == null) return;
|
|
||||||
|
|
||||||
for (const [k, v] of Object.entries(data)) {
|
|
||||||
(this as any)[k] = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -42,7 +42,6 @@ import {
|
||||||
MiNoteFavorite,
|
MiNoteFavorite,
|
||||||
MiNoteReaction,
|
MiNoteReaction,
|
||||||
MiNoteThreadMuting,
|
MiNoteThreadMuting,
|
||||||
MiNoteDraft,
|
|
||||||
MiPage,
|
MiPage,
|
||||||
MiPageLike,
|
MiPageLike,
|
||||||
MiPasswordResetRequest,
|
MiPasswordResetRequest,
|
||||||
|
@ -141,12 +140,6 @@ const $noteReactionsRepository: Provider = {
|
||||||
inject: [DI.db],
|
inject: [DI.db],
|
||||||
};
|
};
|
||||||
|
|
||||||
const $noteDraftsRepository: Provider = {
|
|
||||||
provide: DI.noteDraftsRepository,
|
|
||||||
useFactory: (db: DataSource) => db.getRepository(MiNoteDraft).extend(miRepository as MiRepository<MiNoteDraft>),
|
|
||||||
inject: [DI.db],
|
|
||||||
};
|
|
||||||
|
|
||||||
const $pollsRepository: Provider = {
|
const $pollsRepository: Provider = {
|
||||||
provide: DI.pollsRepository,
|
provide: DI.pollsRepository,
|
||||||
useFactory: (db: DataSource) => db.getRepository(MiPoll).extend(miRepository as MiRepository<MiPoll>),
|
useFactory: (db: DataSource) => db.getRepository(MiPoll).extend(miRepository as MiRepository<MiPoll>),
|
||||||
|
@ -549,7 +542,6 @@ const $reversiGamesRepository: Provider = {
|
||||||
$noteFavoritesRepository,
|
$noteFavoritesRepository,
|
||||||
$noteThreadMutingsRepository,
|
$noteThreadMutingsRepository,
|
||||||
$noteReactionsRepository,
|
$noteReactionsRepository,
|
||||||
$noteDraftsRepository,
|
|
||||||
$pollsRepository,
|
$pollsRepository,
|
||||||
$pollVotesRepository,
|
$pollVotesRepository,
|
||||||
$userProfilesRepository,
|
$userProfilesRepository,
|
||||||
|
@ -626,7 +618,6 @@ const $reversiGamesRepository: Provider = {
|
||||||
$noteFavoritesRepository,
|
$noteFavoritesRepository,
|
||||||
$noteThreadMutingsRepository,
|
$noteThreadMutingsRepository,
|
||||||
$noteReactionsRepository,
|
$noteReactionsRepository,
|
||||||
$noteDraftsRepository,
|
|
||||||
$pollsRepository,
|
$pollsRepository,
|
||||||
$pollVotesRepository,
|
$pollVotesRepository,
|
||||||
$userProfilesRepository,
|
$userProfilesRepository,
|
||||||
|
|
|
@ -55,7 +55,6 @@ import { MiMeta } from '@/models/Meta.js';
|
||||||
import { MiModerationLog } from '@/models/ModerationLog.js';
|
import { MiModerationLog } from '@/models/ModerationLog.js';
|
||||||
import { MiMuting } from '@/models/Muting.js';
|
import { MiMuting } from '@/models/Muting.js';
|
||||||
import { MiNote } from '@/models/Note.js';
|
import { MiNote } from '@/models/Note.js';
|
||||||
import { MiNoteDraft } from '@/models/NoteDraft.js';
|
|
||||||
import { MiNoteFavorite } from '@/models/NoteFavorite.js';
|
import { MiNoteFavorite } from '@/models/NoteFavorite.js';
|
||||||
import { MiNoteReaction } from '@/models/NoteReaction.js';
|
import { MiNoteReaction } from '@/models/NoteReaction.js';
|
||||||
import { MiNoteThreadMuting } from '@/models/NoteThreadMuting.js';
|
import { MiNoteThreadMuting } from '@/models/NoteThreadMuting.js';
|
||||||
|
@ -189,7 +188,6 @@ export {
|
||||||
MiMuting,
|
MiMuting,
|
||||||
MiRenoteMuting,
|
MiRenoteMuting,
|
||||||
MiNote,
|
MiNote,
|
||||||
MiNoteDraft,
|
|
||||||
MiNoteFavorite,
|
MiNoteFavorite,
|
||||||
MiNoteReaction,
|
MiNoteReaction,
|
||||||
MiNoteThreadMuting,
|
MiNoteThreadMuting,
|
||||||
|
@ -268,7 +266,6 @@ export type ModerationLogsRepository = Repository<MiModerationLog> & MiRepositor
|
||||||
export type MutingsRepository = Repository<MiMuting> & MiRepository<MiMuting>;
|
export type MutingsRepository = Repository<MiMuting> & MiRepository<MiMuting>;
|
||||||
export type RenoteMutingsRepository = Repository<MiRenoteMuting> & MiRepository<MiRenoteMuting>;
|
export type RenoteMutingsRepository = Repository<MiRenoteMuting> & MiRepository<MiRenoteMuting>;
|
||||||
export type NotesRepository = Repository<MiNote> & MiRepository<MiNote>;
|
export type NotesRepository = Repository<MiNote> & MiRepository<MiNote>;
|
||||||
export type NoteDraftsRepository = Repository<MiNoteDraft> & MiRepository<MiNoteDraft>;
|
|
||||||
export type NoteFavoritesRepository = Repository<MiNoteFavorite> & MiRepository<MiNoteFavorite>;
|
export type NoteFavoritesRepository = Repository<MiNoteFavorite> & MiRepository<MiNoteFavorite>;
|
||||||
export type NoteReactionsRepository = Repository<MiNoteReaction> & MiRepository<MiNoteReaction>;
|
export type NoteReactionsRepository = Repository<MiNoteReaction> & MiRepository<MiNoteReaction>;
|
||||||
export type NoteThreadMutingsRepository = Repository<MiNoteThreadMuting> & MiRepository<MiNoteThreadMuting>;
|
export type NoteThreadMutingsRepository = Repository<MiNoteThreadMuting> & MiRepository<MiNoteThreadMuting>;
|
||||||
|
|
|
@ -1,169 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
export const packedNoteDraftSchema = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
id: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
format: 'id',
|
|
||||||
example: 'xxxxxxxxxx',
|
|
||||||
},
|
|
||||||
createdAt: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
format: 'date-time',
|
|
||||||
},
|
|
||||||
text: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
cw: {
|
|
||||||
type: 'string',
|
|
||||||
optional: true, nullable: true,
|
|
||||||
},
|
|
||||||
userId: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
format: 'id',
|
|
||||||
},
|
|
||||||
user: {
|
|
||||||
type: 'object',
|
|
||||||
ref: 'UserLite',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
replyId: {
|
|
||||||
type: 'string',
|
|
||||||
optional: true, nullable: true,
|
|
||||||
format: 'id',
|
|
||||||
example: 'xxxxxxxxxx',
|
|
||||||
},
|
|
||||||
renoteId: {
|
|
||||||
type: 'string',
|
|
||||||
optional: true, nullable: true,
|
|
||||||
format: 'id',
|
|
||||||
example: 'xxxxxxxxxx',
|
|
||||||
},
|
|
||||||
reply: {
|
|
||||||
type: 'object',
|
|
||||||
optional: true, nullable: true,
|
|
||||||
ref: 'Note',
|
|
||||||
},
|
|
||||||
renote: {
|
|
||||||
type: 'object',
|
|
||||||
optional: true, nullable: true,
|
|
||||||
ref: 'Note',
|
|
||||||
},
|
|
||||||
visibility: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
enum: ['public', 'home', 'followers', 'specified'],
|
|
||||||
},
|
|
||||||
visibleUserIds: {
|
|
||||||
type: 'array',
|
|
||||||
optional: true, nullable: false,
|
|
||||||
items: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
format: 'id',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
fileIds: {
|
|
||||||
type: 'array',
|
|
||||||
optional: true, nullable: false,
|
|
||||||
items: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
format: 'id',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
files: {
|
|
||||||
type: 'array',
|
|
||||||
optional: true, nullable: false,
|
|
||||||
items: {
|
|
||||||
type: 'object',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
ref: 'DriveFile',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
hashtag: {
|
|
||||||
type: 'string',
|
|
||||||
optional: true, nullable: false,
|
|
||||||
},
|
|
||||||
poll: {
|
|
||||||
type: 'object',
|
|
||||||
optional: true, nullable: true,
|
|
||||||
properties: {
|
|
||||||
expiresAt: {
|
|
||||||
type: 'string',
|
|
||||||
optional: true, nullable: true,
|
|
||||||
format: 'date-time',
|
|
||||||
},
|
|
||||||
expiredAfter: {
|
|
||||||
type: 'number',
|
|
||||||
optional: true, nullable: true,
|
|
||||||
},
|
|
||||||
multiple: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
choices: {
|
|
||||||
type: 'array',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
items: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
channelId: {
|
|
||||||
type: 'string',
|
|
||||||
optional: true, nullable: true,
|
|
||||||
format: 'id',
|
|
||||||
example: 'xxxxxxxxxx',
|
|
||||||
},
|
|
||||||
channel: {
|
|
||||||
type: 'object',
|
|
||||||
optional: true, nullable: true,
|
|
||||||
properties: {
|
|
||||||
id: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
isSensitive: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
allowRenoteToExternal: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
userId: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
localOnly: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: true, nullable: false,
|
|
||||||
},
|
|
||||||
reactionAcceptance: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
enum: ['likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote', null],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as const;
|
|
|
@ -309,10 +309,6 @@ export const packedRolePoliciesSchema = {
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
enum: ['available', 'readonly', 'unavailable'],
|
enum: ['available', 'readonly', 'unavailable'],
|
||||||
},
|
},
|
||||||
noteDraftLimit: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,6 @@ import { MiNote } from '@/models/Note.js';
|
||||||
import { MiNoteFavorite } from '@/models/NoteFavorite.js';
|
import { MiNoteFavorite } from '@/models/NoteFavorite.js';
|
||||||
import { MiNoteReaction } from '@/models/NoteReaction.js';
|
import { MiNoteReaction } from '@/models/NoteReaction.js';
|
||||||
import { MiNoteThreadMuting } from '@/models/NoteThreadMuting.js';
|
import { MiNoteThreadMuting } from '@/models/NoteThreadMuting.js';
|
||||||
import { MiNoteDraft } from '@/models/NoteDraft.js';
|
|
||||||
import { MiPage } from '@/models/Page.js';
|
import { MiPage } from '@/models/Page.js';
|
||||||
import { MiPageLike } from '@/models/PageLike.js';
|
import { MiPageLike } from '@/models/PageLike.js';
|
||||||
import { MiPasswordResetRequest } from '@/models/PasswordResetRequest.js';
|
import { MiPasswordResetRequest } from '@/models/PasswordResetRequest.js';
|
||||||
|
@ -211,7 +210,6 @@ export const entities = [
|
||||||
MiNoteFavorite,
|
MiNoteFavorite,
|
||||||
MiNoteReaction,
|
MiNoteReaction,
|
||||||
MiNoteThreadMuting,
|
MiNoteThreadMuting,
|
||||||
MiNoteDraft,
|
|
||||||
MiPage,
|
MiPage,
|
||||||
MiPageLike,
|
MiPageLike,
|
||||||
MiGalleryPost,
|
MiGalleryPost,
|
||||||
|
|
|
@ -34,11 +34,6 @@ export class CleanRemoteFilesProcessorService {
|
||||||
let deletedCount = 0;
|
let deletedCount = 0;
|
||||||
let cursor: MiDriveFile['id'] | null = null;
|
let cursor: MiDriveFile['id'] | null = null;
|
||||||
|
|
||||||
const total = await this.driveFilesRepository.countBy({
|
|
||||||
userHost: Not(IsNull()),
|
|
||||||
isLink: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const files = await this.driveFilesRepository.find({
|
const files = await this.driveFilesRepository.find({
|
||||||
where: {
|
where: {
|
||||||
|
@ -63,7 +58,12 @@ export class CleanRemoteFilesProcessorService {
|
||||||
|
|
||||||
deletedCount += 8;
|
deletedCount += 8;
|
||||||
|
|
||||||
job.updateProgress(deletedCount * total / 100);
|
const total = await this.driveFilesRepository.countBy({
|
||||||
|
userHost: Not(IsNull()),
|
||||||
|
isLink: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
job.updateProgress(100 / total * deletedCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.succ('All cached remote files has been deleted.');
|
this.logger.succ('All cached remote files has been deleted.');
|
||||||
|
|
|
@ -43,10 +43,6 @@ export class DeleteDriveFilesProcessorService {
|
||||||
let deletedCount = 0;
|
let deletedCount = 0;
|
||||||
let cursor: MiDriveFile['id'] | null = null;
|
let cursor: MiDriveFile['id'] | null = null;
|
||||||
|
|
||||||
const total = await this.driveFilesRepository.countBy({
|
|
||||||
userId: user.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const files = await this.driveFilesRepository.find({
|
const files = await this.driveFilesRepository.find({
|
||||||
where: {
|
where: {
|
||||||
|
@ -71,7 +67,11 @@ export class DeleteDriveFilesProcessorService {
|
||||||
deletedCount++;
|
deletedCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
job.updateProgress(deletedCount / total * 100);
|
const total = await this.driveFilesRepository.countBy({
|
||||||
|
userId: user.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
job.updateProgress(deletedCount / total);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.succ(`All drive files (${deletedCount}) of ${user.id} has been deleted.`);
|
this.logger.succ(`All drive files (${deletedCount}) of ${user.id} has been deleted.`);
|
||||||
|
|
|
@ -58,10 +58,6 @@ export class ExportBlockingProcessorService {
|
||||||
let exportedCount = 0;
|
let exportedCount = 0;
|
||||||
let cursor: MiBlocking['id'] | null = null;
|
let cursor: MiBlocking['id'] | null = null;
|
||||||
|
|
||||||
const total = await this.blockingsRepository.countBy({
|
|
||||||
blockerId: user.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const blockings = await this.blockingsRepository.find({
|
const blockings = await this.blockingsRepository.find({
|
||||||
where: {
|
where: {
|
||||||
|
@ -101,7 +97,11 @@ export class ExportBlockingProcessorService {
|
||||||
exportedCount++;
|
exportedCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
job.updateProgress(exportedCount / total * 100);
|
const total = await this.blockingsRepository.countBy({
|
||||||
|
blockerId: user.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
job.updateProgress(exportedCount / total);
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.end();
|
stream.end();
|
||||||
|
|
|
@ -95,10 +95,6 @@ export class ExportClipsProcessorService {
|
||||||
let exportedClipsCount = 0;
|
let exportedClipsCount = 0;
|
||||||
let cursor: MiClip['id'] | null = null;
|
let cursor: MiClip['id'] | null = null;
|
||||||
|
|
||||||
const total = await this.clipsRepository.countBy({
|
|
||||||
userId: user.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const clips = await this.clipsRepository.find({
|
const clips = await this.clipsRepository.find({
|
||||||
where: {
|
where: {
|
||||||
|
@ -130,7 +126,11 @@ export class ExportClipsProcessorService {
|
||||||
exportedClipsCount++;
|
exportedClipsCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
job.updateProgress(exportedClipsCount / total * 100);
|
const total = await this.clipsRepository.countBy({
|
||||||
|
userId: user.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
job.updateProgress(exportedClipsCount / total);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,10 +78,6 @@ export class ExportFavoritesProcessorService {
|
||||||
let exportedFavoritesCount = 0;
|
let exportedFavoritesCount = 0;
|
||||||
let cursor: MiNoteFavorite['id'] | null = null;
|
let cursor: MiNoteFavorite['id'] | null = null;
|
||||||
|
|
||||||
const total = await this.noteFavoritesRepository.countBy({
|
|
||||||
userId: user.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const favorites = await this.noteFavoritesRepository.find({
|
const favorites = await this.noteFavoritesRepository.find({
|
||||||
where: {
|
where: {
|
||||||
|
@ -113,7 +109,11 @@ export class ExportFavoritesProcessorService {
|
||||||
exportedFavoritesCount++;
|
exportedFavoritesCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
job.updateProgress(exportedFavoritesCount / total * 100);
|
const total = await this.noteFavoritesRepository.countBy({
|
||||||
|
userId: user.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
job.updateProgress(exportedFavoritesCount / total);
|
||||||
}
|
}
|
||||||
|
|
||||||
await write(']');
|
await write(']');
|
||||||
|
|
|
@ -58,10 +58,6 @@ export class ExportMutingProcessorService {
|
||||||
let exportedCount = 0;
|
let exportedCount = 0;
|
||||||
let cursor: MiMuting['id'] | null = null;
|
let cursor: MiMuting['id'] | null = null;
|
||||||
|
|
||||||
const total = await this.mutingsRepository.countBy({
|
|
||||||
muterId: user.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const mutes = await this.mutingsRepository.find({
|
const mutes = await this.mutingsRepository.find({
|
||||||
where: {
|
where: {
|
||||||
|
@ -102,7 +98,11 @@ export class ExportMutingProcessorService {
|
||||||
exportedCount++;
|
exportedCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
job.updateProgress(exportedCount / total * 100);
|
const total = await this.mutingsRepository.countBy({
|
||||||
|
muterId: user.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
job.updateProgress(exportedCount / total);
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.end();
|
stream.end();
|
||||||
|
|
|
@ -37,8 +37,6 @@ class NoteStream extends ReadableStream<Record<string, unknown>> {
|
||||||
let exportedNotesCount = 0;
|
let exportedNotesCount = 0;
|
||||||
let cursor: MiNote['id'] | null = null;
|
let cursor: MiNote['id'] | null = null;
|
||||||
|
|
||||||
const totalPromise = notesRepository.countBy({ userId });
|
|
||||||
|
|
||||||
const serialize = (
|
const serialize = (
|
||||||
note: MiNote,
|
note: MiNote,
|
||||||
poll: MiPoll | null,
|
poll: MiPoll | null,
|
||||||
|
@ -90,8 +88,8 @@ class NoteStream extends ReadableStream<Record<string, unknown>> {
|
||||||
exportedNotesCount++;
|
exportedNotesCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
const total = await totalPromise;
|
const total = await notesRepository.countBy({ userId });
|
||||||
job.updateProgress(exportedNotesCount / total * 100);
|
job.updateProgress(exportedNotesCount / total);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -307,11 +307,6 @@ export * as 'notes/clips' from './endpoints/notes/clips.js';
|
||||||
export * as 'notes/conversation' from './endpoints/notes/conversation.js';
|
export * as 'notes/conversation' from './endpoints/notes/conversation.js';
|
||||||
export * as 'notes/create' from './endpoints/notes/create.js';
|
export * as 'notes/create' from './endpoints/notes/create.js';
|
||||||
export * as 'notes/delete' from './endpoints/notes/delete.js';
|
export * as 'notes/delete' from './endpoints/notes/delete.js';
|
||||||
export * as 'notes/drafts/list' from './endpoints/notes/drafts/list.js';
|
|
||||||
export * as 'notes/drafts/create' from './endpoints/notes/drafts/create.js';
|
|
||||||
export * as 'notes/drafts/delete' from './endpoints/notes/drafts/delete.js';
|
|
||||||
export * as 'notes/drafts/update' from './endpoints/notes/drafts/update.js';
|
|
||||||
export * as 'notes/drafts/count' from './endpoints/notes/drafts/count.js';
|
|
||||||
export * as 'notes/favorites/create' from './endpoints/notes/favorites/create.js';
|
export * as 'notes/favorites/create' from './endpoints/notes/favorites/create.js';
|
||||||
export * as 'notes/favorites/delete' from './endpoints/notes/favorites/delete.js';
|
export * as 'notes/favorites/delete' from './endpoints/notes/favorites/delete.js';
|
||||||
export * as 'notes/featured' from './endpoints/notes/featured.js';
|
export * as 'notes/featured' from './endpoints/notes/featured.js';
|
||||||
|
|
|
@ -98,8 +98,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
state: { type: 'string', nullable: true, default: null },
|
state: { type: 'string', nullable: true, default: null },
|
||||||
reporterOrigin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'combined' },
|
reporterOrigin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'combined' },
|
||||||
targetUserOrigin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'combined' },
|
targetUserOrigin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'combined' },
|
||||||
|
@ -117,7 +115,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.abuseUserReportsRepository.createQueryBuilder('report'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate);
|
const query = this.queryService.makePaginationQuery(this.abuseUserReportsRepository.createQueryBuilder('report'), ps.sinceId, ps.untilId);
|
||||||
|
|
||||||
switch (ps.state) {
|
switch (ps.state) {
|
||||||
case 'resolved': query.andWhere('report.resolved = TRUE'); break;
|
case 'resolved': query.andWhere('report.resolved = TRUE'); break;
|
||||||
|
|
|
@ -34,8 +34,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
publishing: { type: 'boolean', default: null, nullable: true },
|
publishing: { type: 'boolean', default: null, nullable: true },
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
|
@ -50,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.adsRepository.createQueryBuilder('ad'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate);
|
const query = this.queryService.makePaginationQuery(this.adsRepository.createQueryBuilder('ad'), ps.sinceId, ps.untilId);
|
||||||
if (ps.publishing === true) {
|
if (ps.publishing === true) {
|
||||||
query.andWhere('ad.expiresAt > :now', { now: new Date() }).andWhere('ad.startsAt <= :now', { now: new Date() });
|
query.andWhere('ad.expiresAt > :now', { now: new Date() }).andWhere('ad.startsAt <= :now', { now: new Date() });
|
||||||
} else if (ps.publishing === false) {
|
} else if (ps.publishing === false) {
|
||||||
|
|
|
@ -68,8 +68,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
userId: { type: 'string', format: 'misskey:id', nullable: true },
|
userId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||||
status: { type: 'string', enum: ['all', 'active', 'archived'], default: 'active' },
|
status: { type: 'string', enum: ['all', 'active', 'archived'], default: 'active' },
|
||||||
},
|
},
|
||||||
|
@ -89,7 +87,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate);
|
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId);
|
||||||
|
|
||||||
if (ps.status === 'archived') {
|
if (ps.status === 'archived') {
|
||||||
query.andWhere('announcement.isActive = false');
|
query.andWhere('announcement.isActive = false');
|
||||||
|
|
|
@ -71,8 +71,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
userId: { type: 'string', format: 'misskey:id', nullable: true },
|
userId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
|
|
|
@ -34,8 +34,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
userId: { type: 'string', format: 'misskey:id', nullable: true },
|
userId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||||
type: { type: 'string', nullable: true, pattern: /^[a-zA-Z0-9\/\-*]+$/.toString().slice(1, -1) },
|
type: { type: 'string', nullable: true, pattern: /^[a-zA-Z0-9\/\-*]+$/.toString().slice(1, -1) },
|
||||||
origin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'local' },
|
origin: { type: 'string', enum: ['combined', 'local', 'remote'], default: 'local' },
|
||||||
|
@ -59,7 +57,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.driveFilesRepository.createQueryBuilder('file'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate);
|
const query = this.queryService.makePaginationQuery(this.driveFilesRepository.createQueryBuilder('file'), ps.sinceId, ps.untilId);
|
||||||
|
|
||||||
if (ps.userId) {
|
if (ps.userId) {
|
||||||
query.andWhere('file.userId = :userId', { userId: ps.userId });
|
query.andWhere('file.userId = :userId', { userId: ps.userId });
|
||||||
|
|
|
@ -74,8 +74,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -91,7 +89,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private emojiEntityService: EmojiEntityService,
|
private emojiEntityService: EmojiEntityService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const q = this.queryService.makePaginationQuery(this.emojisRepository.createQueryBuilder('emoji'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate);
|
const q = this.queryService.makePaginationQuery(this.emojisRepository.createQueryBuilder('emoji'), ps.sinceId, ps.untilId);
|
||||||
|
|
||||||
if (ps.host == null) {
|
if (ps.host == null) {
|
||||||
q.andWhere('emoji.host IS NOT NULL');
|
q.andWhere('emoji.host IS NOT NULL');
|
||||||
|
|
|
@ -68,8 +68,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -84,7 +82,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const q = this.queryService.makePaginationQuery(this.emojisRepository.createQueryBuilder('emoji'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const q = this.queryService.makePaginationQuery(this.emojisRepository.createQueryBuilder('emoji'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('emoji.host IS NULL');
|
.andWhere('emoji.host IS NULL');
|
||||||
|
|
||||||
let emojis: MiEmoji[];
|
let emojis: MiEmoji[];
|
||||||
|
|
|
@ -49,8 +49,6 @@ export const paramDef = {
|
||||||
roleId: { type: 'string', format: 'misskey:id' },
|
roleId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
},
|
},
|
||||||
required: ['roleId'],
|
required: ['roleId'],
|
||||||
|
@ -78,7 +76,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw new ApiError(meta.errors.noSuchRole);
|
throw new ApiError(meta.errors.noSuchRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
const query = this.queryService.makePaginationQuery(this.roleAssignmentsRepository.createQueryBuilder('assign'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.roleAssignmentsRepository.createQueryBuilder('assign'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('assign.roleId = :roleId', { roleId: role.id })
|
.andWhere('assign.roleId = :roleId', { roleId: role.id })
|
||||||
.andWhere(new Brackets(qb => {
|
.andWhere(new Brackets(qb => {
|
||||||
qb
|
qb
|
||||||
|
|
|
@ -9,7 +9,6 @@ import type { ModerationLogsRepository } from '@/models/_.js';
|
||||||
import { QueryService } from '@/core/QueryService.js';
|
import { QueryService } from '@/core/QueryService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { ModerationLogEntityService } from '@/core/entities/ModerationLogEntityService.js';
|
import { ModerationLogEntityService } from '@/core/entities/ModerationLogEntityService.js';
|
||||||
import { sqlLikeEscape } from '@/misc/sql-like-escape.js';
|
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
@ -64,11 +63,8 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
type: { type: 'string', nullable: true },
|
type: { type: 'string', nullable: true },
|
||||||
userId: { type: 'string', format: 'misskey:id', nullable: true },
|
userId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||||
search: { type: 'string', nullable: true },
|
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -83,24 +79,19 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.moderationLogsRepository.createQueryBuilder('log'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate);
|
const query = this.queryService.makePaginationQuery(this.moderationLogsRepository.createQueryBuilder('report'), ps.sinceId, ps.untilId);
|
||||||
|
|
||||||
if (ps.type != null) {
|
if (ps.type != null) {
|
||||||
query.andWhere('log.type = :type', { type: ps.type });
|
query.andWhere('report.type = :type', { type: ps.type });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps.userId != null) {
|
if (ps.userId != null) {
|
||||||
query.andWhere('log.userId = :userId', { userId: ps.userId });
|
query.andWhere('report.userId = :userId', { userId: ps.userId });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps.search != null) {
|
const reports = await query.limit(ps.limit).getMany();
|
||||||
const escapedSearch = sqlLikeEscape(ps.search);
|
|
||||||
query.andWhere('log.info::text ILIKE :search', { search: `%${escapedSearch}%` });
|
|
||||||
}
|
|
||||||
|
|
||||||
const logs = await query.limit(ps.limit).getMany();
|
return await this.moderationLogEntityService.packMany(reports);
|
||||||
|
|
||||||
return await this.moderationLogEntityService.packMany(logs);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,8 +33,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
isActive: { type: 'boolean', default: true },
|
isActive: { type: 'boolean', default: true },
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
|
@ -50,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private announcementEntityService: AnnouncementEntityService,
|
private announcementEntityService: AnnouncementEntityService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('announcement.isActive = :isActive', { isActive: ps.isActive })
|
.andWhere('announcement.isActive = :isActive', { isActive: ps.isActive })
|
||||||
.andWhere(new Brackets(qb => {
|
.andWhere(new Brackets(qb => {
|
||||||
if (me) qb.orWhere('announcement.userId = :meId', { meId: me.id });
|
if (me) qb.orWhere('announcement.userId = :meId', { meId: me.id });
|
||||||
|
|
|
@ -34,8 +34,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -50,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.blockingsRepository.createQueryBuilder('blocking'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.blockingsRepository.createQueryBuilder('blocking'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('blocking.blockerId = :meId', { meId: me.id });
|
.andWhere('blocking.blockerId = :meId', { meId: me.id });
|
||||||
|
|
||||||
const blockings = await query
|
const blockings = await query
|
||||||
|
|
|
@ -33,8 +33,6 @@ export const paramDef = {
|
||||||
properties: {
|
properties: {
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 5 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 5 },
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
|
@ -55,8 +53,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
this.channelFollowingsRepository.createQueryBuilder(),
|
this.channelFollowingsRepository.createQueryBuilder(),
|
||||||
ps.sinceId,
|
ps.sinceId,
|
||||||
ps.untilId,
|
ps.untilId,
|
||||||
ps.sinceDate,
|
null,
|
||||||
ps.untilDate,
|
null,
|
||||||
'followeeId',
|
'followeeId',
|
||||||
)
|
)
|
||||||
.andWhere({ followerId: me.id });
|
.andWhere({ followerId: me.id });
|
||||||
|
|
|
@ -33,8 +33,6 @@ export const paramDef = {
|
||||||
properties: {
|
properties: {
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 5 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 5 },
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
|
@ -50,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.channelsRepository.createQueryBuilder('channel'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.channelsRepository.createQueryBuilder('channel'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('channel.isArchived = FALSE')
|
.andWhere('channel.isArchived = FALSE')
|
||||||
.andWhere({ userId: me.id });
|
.andWhere({ userId: me.id });
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,6 @@ export const paramDef = {
|
||||||
type: { type: 'string', enum: ['nameAndDescription', 'nameOnly'], default: 'nameAndDescription' },
|
type: { type: 'string', enum: ['nameAndDescription', 'nameOnly'], default: 'nameAndDescription' },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 5 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 5 },
|
||||||
},
|
},
|
||||||
required: ['query'],
|
required: ['query'],
|
||||||
|
@ -52,7 +50,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.channelsRepository.createQueryBuilder('channel'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.channelsRepository.createQueryBuilder('channel'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('channel.isArchived = FALSE');
|
.andWhere('channel.isArchived = FALSE');
|
||||||
|
|
||||||
if (ps.query !== '') {
|
if (ps.query !== '') {
|
||||||
|
|
|
@ -9,7 +9,6 @@ import { DI } from '@/di-symbols.js';
|
||||||
import { ChatService } from '@/core/ChatService.js';
|
import { ChatService } from '@/core/ChatService.js';
|
||||||
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
|
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
|
||||||
import { ApiError } from '@/server/api/error.js';
|
import { ApiError } from '@/server/api/error.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['chat'],
|
tags: ['chat'],
|
||||||
|
@ -43,8 +42,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
roomId: { type: 'string', format: 'misskey:id' },
|
roomId: { type: 'string', format: 'misskey:id' },
|
||||||
},
|
},
|
||||||
required: ['roomId'],
|
required: ['roomId'],
|
||||||
|
@ -55,12 +52,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
constructor(
|
constructor(
|
||||||
private chatEntityService: ChatEntityService,
|
private chatEntityService: ChatEntityService,
|
||||||
private chatService: ChatService,
|
private chatService: ChatService,
|
||||||
private idService: IdService,
|
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
|
|
||||||
const sinceId = ps.sinceId ?? (ps.sinceDate ? this.idService.gen(ps.sinceDate!) : null);
|
|
||||||
|
|
||||||
await this.chatService.checkChatAvailability(me.id, 'read');
|
await this.chatService.checkChatAvailability(me.id, 'read');
|
||||||
|
|
||||||
const room = await this.chatService.findRoomById(ps.roomId);
|
const room = await this.chatService.findRoomById(ps.roomId);
|
||||||
|
@ -72,7 +65,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw new ApiError(meta.errors.noSuchRoom);
|
throw new ApiError(meta.errors.noSuchRoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
const messages = await this.chatService.roomTimeline(room.id, ps.limit, sinceId, untilId);
|
const messages = await this.chatService.roomTimeline(room.id, ps.limit, ps.sinceId, ps.untilId);
|
||||||
|
|
||||||
this.chatService.readRoomChatMessage(me.id, room.id);
|
this.chatService.readRoomChatMessage(me.id, room.id);
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ import { GetterService } from '@/server/api/GetterService.js';
|
||||||
import { ChatService } from '@/core/ChatService.js';
|
import { ChatService } from '@/core/ChatService.js';
|
||||||
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
|
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
|
||||||
import { ApiError } from '@/server/api/error.js';
|
import { ApiError } from '@/server/api/error.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['chat'],
|
tags: ['chat'],
|
||||||
|
@ -44,8 +43,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
userId: { type: 'string', format: 'misskey:id' },
|
userId: { type: 'string', format: 'misskey:id' },
|
||||||
},
|
},
|
||||||
required: ['userId'],
|
required: ['userId'],
|
||||||
|
@ -57,12 +54,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private chatEntityService: ChatEntityService,
|
private chatEntityService: ChatEntityService,
|
||||||
private chatService: ChatService,
|
private chatService: ChatService,
|
||||||
private getterService: GetterService,
|
private getterService: GetterService,
|
||||||
private idService: IdService,
|
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
|
|
||||||
const sinceId = ps.sinceId ?? (ps.sinceDate ? this.idService.gen(ps.sinceDate!) : null);
|
|
||||||
|
|
||||||
await this.chatService.checkChatAvailability(me.id, 'read');
|
await this.chatService.checkChatAvailability(me.id, 'read');
|
||||||
|
|
||||||
const other = await this.getterService.getUser(ps.userId).catch(err => {
|
const other = await this.getterService.getUser(ps.userId).catch(err => {
|
||||||
|
@ -70,7 +63,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
|
|
||||||
const messages = await this.chatService.userTimeline(me.id, other.id, ps.limit, sinceId, untilId);
|
const messages = await this.chatService.userTimeline(me.id, other.id, ps.limit, ps.sinceId, ps.untilId);
|
||||||
|
|
||||||
this.chatService.readUserChatMessage(me.id, other.id);
|
this.chatService.readUserChatMessage(me.id, other.id);
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ import { DI } from '@/di-symbols.js';
|
||||||
import { ChatService } from '@/core/ChatService.js';
|
import { ChatService } from '@/core/ChatService.js';
|
||||||
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
|
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
|
||||||
import { ApiError } from '@/server/api/error.js';
|
import { ApiError } from '@/server/api/error.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['chat'],
|
tags: ['chat'],
|
||||||
|
@ -38,8 +37,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@ -48,15 +45,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
constructor(
|
constructor(
|
||||||
private chatEntityService: ChatEntityService,
|
private chatEntityService: ChatEntityService,
|
||||||
private chatService: ChatService,
|
private chatService: ChatService,
|
||||||
private idService: IdService,
|
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
|
|
||||||
const sinceId = ps.sinceId ?? (ps.sinceDate ? this.idService.gen(ps.sinceDate!) : null);
|
|
||||||
|
|
||||||
await this.chatService.checkChatAvailability(me.id, 'read');
|
await this.chatService.checkChatAvailability(me.id, 'read');
|
||||||
|
|
||||||
const invitations = await this.chatService.getReceivedRoomInvitationsWithPagination(me.id, ps.limit, sinceId, untilId);
|
const invitations = await this.chatService.getReceivedRoomInvitationsWithPagination(me.id, ps.limit, ps.sinceId, ps.untilId);
|
||||||
return this.chatEntityService.packRoomInvitations(invitations, me);
|
return this.chatEntityService.packRoomInvitations(invitations, me);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import { DI } from '@/di-symbols.js';
|
||||||
import { ApiError } from '@/server/api/error.js';
|
import { ApiError } from '@/server/api/error.js';
|
||||||
import { ChatService } from '@/core/ChatService.js';
|
import { ChatService } from '@/core/ChatService.js';
|
||||||
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
|
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['chat'],
|
tags: ['chat'],
|
||||||
|
@ -45,8 +44,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: ['roomId'],
|
required: ['roomId'],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -56,12 +53,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
constructor(
|
constructor(
|
||||||
private chatService: ChatService,
|
private chatService: ChatService,
|
||||||
private chatEntityService: ChatEntityService,
|
private chatEntityService: ChatEntityService,
|
||||||
private idService: IdService,
|
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
|
|
||||||
const sinceId = ps.sinceId ?? (ps.sinceDate ? this.idService.gen(ps.sinceDate!) : null);
|
|
||||||
|
|
||||||
await this.chatService.checkChatAvailability(me.id, 'read');
|
await this.chatService.checkChatAvailability(me.id, 'read');
|
||||||
|
|
||||||
const room = await this.chatService.findMyRoomById(me.id, ps.roomId);
|
const room = await this.chatService.findMyRoomById(me.id, ps.roomId);
|
||||||
|
@ -69,7 +62,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw new ApiError(meta.errors.noSuchRoom);
|
throw new ApiError(meta.errors.noSuchRoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
const invitations = await this.chatService.getSentRoomInvitationsWithPagination(ps.roomId, ps.limit, sinceId, untilId);
|
const invitations = await this.chatService.getSentRoomInvitationsWithPagination(ps.roomId, ps.limit, ps.sinceId, ps.untilId);
|
||||||
return this.chatEntityService.packRoomInvitations(invitations, me);
|
return this.chatEntityService.packRoomInvitations(invitations, me);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import { DI } from '@/di-symbols.js';
|
||||||
import { ChatService } from '@/core/ChatService.js';
|
import { ChatService } from '@/core/ChatService.js';
|
||||||
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
|
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
|
||||||
import { ApiError } from '@/server/api/error.js';
|
import { ApiError } from '@/server/api/error.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['chat'],
|
tags: ['chat'],
|
||||||
|
@ -38,8 +37,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@ -48,15 +45,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
constructor(
|
constructor(
|
||||||
private chatService: ChatService,
|
private chatService: ChatService,
|
||||||
private chatEntityService: ChatEntityService,
|
private chatEntityService: ChatEntityService,
|
||||||
private idService: IdService,
|
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
|
|
||||||
const sinceId = ps.sinceId ?? (ps.sinceDate ? this.idService.gen(ps.sinceDate!) : null);
|
|
||||||
|
|
||||||
await this.chatService.checkChatAvailability(me.id, 'read');
|
await this.chatService.checkChatAvailability(me.id, 'read');
|
||||||
|
|
||||||
const memberships = await this.chatService.getMyMemberships(me.id, ps.limit, sinceId, untilId);
|
const memberships = await this.chatService.getMyMemberships(me.id, ps.limit, ps.sinceId, ps.untilId);
|
||||||
|
|
||||||
return this.chatEntityService.packRoomMemberships(memberships, me, {
|
return this.chatEntityService.packRoomMemberships(memberships, me, {
|
||||||
populateUser: false,
|
populateUser: false,
|
||||||
|
|
|
@ -9,7 +9,6 @@ import { DI } from '@/di-symbols.js';
|
||||||
import { ChatService } from '@/core/ChatService.js';
|
import { ChatService } from '@/core/ChatService.js';
|
||||||
import { ApiError } from '@/server/api/error.js';
|
import { ApiError } from '@/server/api/error.js';
|
||||||
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
|
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['chat'],
|
tags: ['chat'],
|
||||||
|
@ -44,8 +43,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: ['roomId'],
|
required: ['roomId'],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -55,12 +52,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
constructor(
|
constructor(
|
||||||
private chatService: ChatService,
|
private chatService: ChatService,
|
||||||
private chatEntityService: ChatEntityService,
|
private chatEntityService: ChatEntityService,
|
||||||
private idService: IdService,
|
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
|
|
||||||
const sinceId = ps.sinceId ?? (ps.sinceDate ? this.idService.gen(ps.sinceDate!) : null);
|
|
||||||
|
|
||||||
await this.chatService.checkChatAvailability(me.id, 'read');
|
await this.chatService.checkChatAvailability(me.id, 'read');
|
||||||
|
|
||||||
const room = await this.chatService.findRoomById(ps.roomId);
|
const room = await this.chatService.findRoomById(ps.roomId);
|
||||||
|
@ -72,7 +65,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw new ApiError(meta.errors.noSuchRoom);
|
throw new ApiError(meta.errors.noSuchRoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
const memberships = await this.chatService.getRoomMembershipsWithPagination(room.id, ps.limit, sinceId, untilId);
|
const memberships = await this.chatService.getRoomMembershipsWithPagination(room.id, ps.limit, ps.sinceId, ps.untilId);
|
||||||
|
|
||||||
return this.chatEntityService.packRoomMemberships(memberships, me, {
|
return this.chatEntityService.packRoomMemberships(memberships, me, {
|
||||||
populateUser: true,
|
populateUser: true,
|
||||||
|
|
|
@ -9,7 +9,6 @@ import { DI } from '@/di-symbols.js';
|
||||||
import { ChatService } from '@/core/ChatService.js';
|
import { ChatService } from '@/core/ChatService.js';
|
||||||
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
|
import { ChatEntityService } from '@/core/entities/ChatEntityService.js';
|
||||||
import { ApiError } from '@/server/api/error.js';
|
import { ApiError } from '@/server/api/error.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['chat'],
|
tags: ['chat'],
|
||||||
|
@ -38,8 +37,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@ -48,15 +45,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
constructor(
|
constructor(
|
||||||
private chatEntityService: ChatEntityService,
|
private chatEntityService: ChatEntityService,
|
||||||
private chatService: ChatService,
|
private chatService: ChatService,
|
||||||
private idService: IdService,
|
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
|
|
||||||
const sinceId = ps.sinceId ?? (ps.sinceDate ? this.idService.gen(ps.sinceDate!) : null);
|
|
||||||
|
|
||||||
await this.chatService.checkChatAvailability(me.id, 'read');
|
await this.chatService.checkChatAvailability(me.id, 'read');
|
||||||
|
|
||||||
const rooms = await this.chatService.getOwnedRoomsWithPagination(me.id, ps.limit, sinceId, untilId);
|
const rooms = await this.chatService.getOwnedRoomsWithPagination(me.id, ps.limit, ps.sinceId, ps.untilId);
|
||||||
return this.chatEntityService.packRooms(rooms, me);
|
return this.chatEntityService.packRooms(rooms, me);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Brackets } from 'typeorm';
|
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import type { NotesRepository, ClipsRepository, ClipNotesRepository } from '@/models/_.js';
|
import type { NotesRepository, ClipsRepository, ClipNotesRepository } from '@/models/_.js';
|
||||||
import { QueryService } from '@/core/QueryService.js';
|
import { QueryService } from '@/core/QueryService.js';
|
||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { sqlLikeEscape } from '@/misc/sql-like-escape.js';
|
|
||||||
import { ApiError } from '../../error.js';
|
import { ApiError } from '../../error.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -46,9 +44,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
search: { type: 'string', minLength: 1, maxLength: 100, nullable: true },
|
|
||||||
},
|
},
|
||||||
required: ['clipId'],
|
required: ['clipId'],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -81,7 +76,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw new ApiError(meta.errors.noSuchClip);
|
throw new ApiError(meta.errors.noSuchClip);
|
||||||
}
|
}
|
||||||
|
|
||||||
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
|
||||||
.innerJoin(this.clipNotesRepository.metadata.targetName, 'clipNote', 'clipNote.noteId = note.id')
|
.innerJoin(this.clipNotesRepository.metadata.targetName, 'clipNote', 'clipNote.noteId = note.id')
|
||||||
.innerJoinAndSelect('note.user', 'user')
|
.innerJoinAndSelect('note.user', 'user')
|
||||||
.leftJoinAndSelect('note.reply', 'reply')
|
.leftJoinAndSelect('note.reply', 'reply')
|
||||||
|
@ -100,15 +95,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
this.queryService.generateBlockedUserQueryForNotes(query, me, { noteColumn: 'renote' });
|
this.queryService.generateBlockedUserQueryForNotes(query, me, { noteColumn: 'renote' });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps.search != null) {
|
|
||||||
for (const word of ps.search!.trim().split(' ')) {
|
|
||||||
query.andWhere(new Brackets(qb => {
|
|
||||||
qb.orWhere('note.text ILIKE :search', { search: `%${sqlLikeEscape(word)}%` });
|
|
||||||
qb.orWhere('note.cw ILIKE :search', { search: `%${sqlLikeEscape(word)}%` });
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const notes = await query
|
const notes = await query
|
||||||
.limit(ps.limit)
|
.limit(ps.limit)
|
||||||
.getMany();
|
.getMany();
|
||||||
|
|
|
@ -34,8 +34,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null },
|
folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null },
|
||||||
type: { type: 'string', nullable: true, pattern: /^[a-zA-Z\/\-*]+$/.toString().slice(1, -1) },
|
type: { type: 'string', nullable: true, pattern: /^[a-zA-Z\/\-*]+$/.toString().slice(1, -1) },
|
||||||
sort: { type: 'string', nullable: true, enum: ['+createdAt', '-createdAt', '+name', '-name', '+size', '-size', null] },
|
sort: { type: 'string', nullable: true, enum: ['+createdAt', '-createdAt', '+name', '-name', '+size', '-size', null] },
|
||||||
|
@ -53,7 +51,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.driveFilesRepository.createQueryBuilder('file'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.driveFilesRepository.createQueryBuilder('file'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('file.userId = :userId', { userId: me.id });
|
.andWhere('file.userId = :userId', { userId: me.id });
|
||||||
|
|
||||||
if (ps.folderId) {
|
if (ps.folderId) {
|
||||||
|
|
|
@ -9,8 +9,8 @@ import type { NotesRepository, DriveFilesRepository } from '@/models/_.js';
|
||||||
import { QueryService } from '@/core/QueryService.js';
|
import { QueryService } from '@/core/QueryService.js';
|
||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { RoleService } from '@/core/RoleService.js';
|
|
||||||
import { ApiError } from '../../../error.js';
|
import { ApiError } from '../../../error.js';
|
||||||
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['drive', 'notes'],
|
tags: ['drive', 'notes'],
|
||||||
|
@ -45,8 +45,6 @@ export const paramDef = {
|
||||||
properties: {
|
properties: {
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
fileId: { type: 'string', format: 'misskey:id' },
|
fileId: { type: 'string', format: 'misskey:id' },
|
||||||
},
|
},
|
||||||
|
@ -77,7 +75,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw new ApiError(meta.errors.noSuchFile);
|
throw new ApiError(meta.errors.noSuchFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate);
|
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId);
|
||||||
query.andWhere(':file <@ note.fileIds', { file: [file.id] });
|
query.andWhere(':file <@ note.fileIds', { file: [file.id] });
|
||||||
|
|
||||||
const notes = await query.limit(ps.limit).getMany();
|
const notes = await query.limit(ps.limit).getMany();
|
||||||
|
|
|
@ -34,8 +34,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null },
|
folderId: { type: 'string', format: 'misskey:id', nullable: true, default: null },
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
|
@ -51,7 +49,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.driveFoldersRepository.createQueryBuilder('folder'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.driveFoldersRepository.createQueryBuilder('folder'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('folder.userId = :userId', { userId: me.id });
|
.andWhere('folder.userId = :userId', { userId: me.id });
|
||||||
|
|
||||||
if (ps.folderId) {
|
if (ps.folderId) {
|
||||||
|
|
|
@ -34,8 +34,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
type: { type: 'string', pattern: /^[a-zA-Z\/\-*]+$/.toString().slice(1, -1) },
|
type: { type: 'string', pattern: /^[a-zA-Z\/\-*]+$/.toString().slice(1, -1) },
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
|
@ -51,7 +49,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.driveFilesRepository.createQueryBuilder('file'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.driveFilesRepository.createQueryBuilder('file'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('file.userId = :userId', { userId: me.id });
|
.andWhere('file.userId = :userId', { userId: me.id });
|
||||||
|
|
||||||
if (ps.type) {
|
if (ps.type) {
|
||||||
|
|
|
@ -32,8 +32,6 @@ export const paramDef = {
|
||||||
host: { type: 'string' },
|
host: { type: 'string' },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
},
|
},
|
||||||
required: ['host'],
|
required: ['host'],
|
||||||
|
@ -49,7 +47,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.followingsRepository.createQueryBuilder('following'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.followingsRepository.createQueryBuilder('following'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('following.followeeHost = :host', { host: ps.host });
|
.andWhere('following.followeeHost = :host', { host: ps.host });
|
||||||
|
|
||||||
const followings = await query
|
const followings = await query
|
||||||
|
|
|
@ -32,8 +32,6 @@ export const paramDef = {
|
||||||
host: { type: 'string' },
|
host: { type: 'string' },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
},
|
},
|
||||||
required: ['host'],
|
required: ['host'],
|
||||||
|
@ -49,7 +47,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.followingsRepository.createQueryBuilder('following'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.followingsRepository.createQueryBuilder('following'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('following.followerHost = :host', { host: ps.host });
|
.andWhere('following.followerHost = :host', { host: ps.host });
|
||||||
|
|
||||||
const followings = await query
|
const followings = await query
|
||||||
|
|
|
@ -32,8 +32,6 @@ export const paramDef = {
|
||||||
host: { type: 'string' },
|
host: { type: 'string' },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
},
|
},
|
||||||
required: ['host'],
|
required: ['host'],
|
||||||
|
@ -49,7 +47,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.usersRepository.createQueryBuilder('user'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.usersRepository.createQueryBuilder('user'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('user.host = :host', { host: ps.host });
|
.andWhere('user.host = :host', { host: ps.host });
|
||||||
|
|
||||||
const users = await query
|
const users = await query
|
||||||
|
|
|
@ -44,8 +44,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -60,7 +58,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.flashLikesRepository.createQueryBuilder('like'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.flashLikesRepository.createQueryBuilder('like'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('like.userId = :meId', { meId: me.id })
|
.andWhere('like.userId = :meId', { meId: me.id })
|
||||||
.leftJoinAndSelect('like.flash', 'flash');
|
.leftJoinAndSelect('like.flash', 'flash');
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -50,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.flashsRepository.createQueryBuilder('flash'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.flashsRepository.createQueryBuilder('flash'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('flash.userId = :meId', { meId: me.id });
|
.andWhere('flash.userId = :meId', { meId: me.id });
|
||||||
|
|
||||||
const flashs = await query
|
const flashs = await query
|
||||||
|
|
|
@ -49,8 +49,6 @@ export const paramDef = {
|
||||||
properties: {
|
properties: {
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
|
@ -66,7 +64,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.followRequestsRepository.createQueryBuilder('request'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.followRequestsRepository.createQueryBuilder('request'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('request.followeeId = :meId', { meId: me.id });
|
.andWhere('request.followeeId = :meId', { meId: me.id });
|
||||||
|
|
||||||
const requests = await query
|
const requests = await query
|
||||||
|
|
|
@ -49,8 +49,6 @@ export const paramDef = {
|
||||||
properties: {
|
properties: {
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
|
@ -66,7 +64,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.followRequestsRepository.createQueryBuilder('request'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.followRequestsRepository.createQueryBuilder('request'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('request.followerId = :meId', { meId: me.id });
|
.andWhere('request.followerId = :meId', { meId: me.id });
|
||||||
|
|
||||||
const requests = await query
|
const requests = await query
|
||||||
|
|
|
@ -30,8 +30,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -46,7 +44,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.galleryPostsRepository.createQueryBuilder('post'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.galleryPostsRepository.createQueryBuilder('post'), ps.sinceId, ps.untilId)
|
||||||
.innerJoinAndSelect('post.user', 'user');
|
.innerJoinAndSelect('post.user', 'user');
|
||||||
|
|
||||||
const posts = await query.limit(ps.limit).getMany();
|
const posts = await query.limit(ps.limit).getMany();
|
||||||
|
|
|
@ -34,8 +34,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -50,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.noteFavoritesRepository.createQueryBuilder('favorite'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.noteFavoritesRepository.createQueryBuilder('favorite'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('favorite.userId = :meId', { meId: me.id })
|
.andWhere('favorite.userId = :meId', { meId: me.id })
|
||||||
.leftJoinAndSelect('favorite.note', 'note');
|
.leftJoinAndSelect('favorite.note', 'note');
|
||||||
|
|
||||||
|
|
|
@ -45,8 +45,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -61,7 +59,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.galleryLikesRepository.createQueryBuilder('like'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.galleryLikesRepository.createQueryBuilder('like'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('like.userId = :meId', { meId: me.id })
|
.andWhere('like.userId = :meId', { meId: me.id })
|
||||||
.leftJoinAndSelect('like.post', 'post');
|
.leftJoinAndSelect('like.post', 'post');
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -50,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.galleryPostsRepository.createQueryBuilder('post'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.galleryPostsRepository.createQueryBuilder('post'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('post.userId = :meId', { meId: me.id });
|
.andWhere('post.userId = :meId', { meId: me.id });
|
||||||
|
|
||||||
const posts = await query
|
const posts = await query
|
||||||
|
|
|
@ -49,8 +49,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
markAsRead: { type: 'boolean', default: true },
|
markAsRead: { type: 'boolean', default: true },
|
||||||
// 後方互換のため、廃止された通知タイプも受け付ける
|
// 後方互換のため、廃止された通知タイプも受け付ける
|
||||||
includeTypes: { type: 'array', items: {
|
includeTypes: { type: 'array', items: {
|
||||||
|
@ -66,14 +64,15 @@ export const paramDef = {
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
constructor(
|
constructor(
|
||||||
|
@Inject(DI.redis)
|
||||||
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
private notificationEntityService: NotificationEntityService,
|
private notificationEntityService: NotificationEntityService,
|
||||||
private notificationService: NotificationService,
|
private notificationService: NotificationService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const EXTRA_LIMIT = 100;
|
const EXTRA_LIMIT = 100;
|
||||||
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : undefined);
|
|
||||||
const sinceId = ps.sinceId ?? (ps.sinceDate ? this.idService.gen(ps.sinceDate!) : undefined);
|
|
||||||
|
|
||||||
// includeTypes が空の場合はクエリしない
|
// includeTypes が空の場合はクエリしない
|
||||||
if (ps.includeTypes && ps.includeTypes.length === 0) {
|
if (ps.includeTypes && ps.includeTypes.length === 0) {
|
||||||
|
@ -88,8 +87,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
const excludeTypes = ps.excludeTypes && ps.excludeTypes.filter(type => !(obsoleteNotificationTypes).includes(type as any)) as typeof groupedNotificationTypes[number][];
|
const excludeTypes = ps.excludeTypes && ps.excludeTypes.filter(type => !(obsoleteNotificationTypes).includes(type as any)) as typeof groupedNotificationTypes[number][];
|
||||||
|
|
||||||
const notifications = await this.notificationService.getNotifications(me.id, {
|
const notifications = await this.notificationService.getNotifications(me.id, {
|
||||||
sinceId: sinceId,
|
sinceId: ps.sinceId,
|
||||||
untilId: untilId,
|
untilId: ps.untilId,
|
||||||
limit: ps.limit,
|
limit: ps.limit,
|
||||||
includeTypes,
|
includeTypes,
|
||||||
excludeTypes,
|
excludeTypes,
|
||||||
|
|
|
@ -44,8 +44,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
markAsRead: { type: 'boolean', default: true },
|
markAsRead: { type: 'boolean', default: true },
|
||||||
// 後方互換のため、廃止された通知タイプも受け付ける
|
// 後方互換のため、廃止された通知タイプも受け付ける
|
||||||
includeTypes: { type: 'array', items: {
|
includeTypes: { type: 'array', items: {
|
||||||
|
@ -61,14 +59,17 @@ export const paramDef = {
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
constructor(
|
constructor(
|
||||||
|
@Inject(DI.redis)
|
||||||
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
|
@Inject(DI.notesRepository)
|
||||||
|
private notesRepository: NotesRepository,
|
||||||
|
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
private notificationEntityService: NotificationEntityService,
|
private notificationEntityService: NotificationEntityService,
|
||||||
private notificationService: NotificationService,
|
private notificationService: NotificationService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : undefined);
|
|
||||||
const sinceId = ps.sinceId ?? (ps.sinceDate ? this.idService.gen(ps.sinceDate!) : undefined);
|
|
||||||
|
|
||||||
// includeTypes が空の場合はクエリしない
|
// includeTypes が空の場合はクエリしない
|
||||||
if (ps.includeTypes && ps.includeTypes.length === 0) {
|
if (ps.includeTypes && ps.includeTypes.length === 0) {
|
||||||
return [];
|
return [];
|
||||||
|
@ -82,8 +83,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
const excludeTypes = ps.excludeTypes && ps.excludeTypes.filter(type => !(obsoleteNotificationTypes).includes(type as any)) as typeof notificationTypes[number][];
|
const excludeTypes = ps.excludeTypes && ps.excludeTypes.filter(type => !(obsoleteNotificationTypes).includes(type as any)) as typeof notificationTypes[number][];
|
||||||
|
|
||||||
const notifications = await this.notificationService.getNotifications(me.id, {
|
const notifications = await this.notificationService.getNotifications(me.id, {
|
||||||
sinceId: sinceId,
|
sinceId: ps.sinceId,
|
||||||
untilId: untilId,
|
untilId: ps.untilId,
|
||||||
limit: ps.limit,
|
limit: ps.limit,
|
||||||
includeTypes,
|
includeTypes,
|
||||||
excludeTypes,
|
excludeTypes,
|
||||||
|
|
|
@ -44,8 +44,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -60,7 +58,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.pageLikesRepository.createQueryBuilder('like'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.pageLikesRepository.createQueryBuilder('like'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('like.userId = :meId', { meId: me.id })
|
.andWhere('like.userId = :meId', { meId: me.id })
|
||||||
.leftJoinAndSelect('like.page', 'page');
|
.leftJoinAndSelect('like.page', 'page');
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -50,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.pagesRepository.createQueryBuilder('page'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.pagesRepository.createQueryBuilder('page'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('page.userId = :meId', { meId: me.id });
|
.andWhere('page.userId = :meId', { meId: me.id });
|
||||||
|
|
||||||
const pages = await query
|
const pages = await query
|
||||||
|
|
|
@ -31,8 +31,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -47,7 +45,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.signinsRepository.createQueryBuilder('signin'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.signinsRepository.createQueryBuilder('signin'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('signin.userId = :meId', { meId: me.id });
|
.andWhere('signin.userId = :meId', { meId: me.id });
|
||||||
|
|
||||||
const history = await query.limit(ps.limit).getMany();
|
const history = await query.limit(ps.limit).getMany();
|
||||||
|
|
|
@ -34,8 +34,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -50,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.registrationTicketsRepository.createQueryBuilder('ticket'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.registrationTicketsRepository.createQueryBuilder('ticket'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('ticket.createdById = :meId', { meId: me.id })
|
.andWhere('ticket.createdById = :meId', { meId: me.id })
|
||||||
.leftJoinAndSelect('ticket.createdBy', 'createdBy')
|
.leftJoinAndSelect('ticket.createdBy', 'createdBy')
|
||||||
.leftJoinAndSelect('ticket.usedBy', 'usedBy');
|
.leftJoinAndSelect('ticket.usedBy', 'usedBy');
|
||||||
|
|
|
@ -34,8 +34,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -50,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.mutingsRepository.createQueryBuilder('muting'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.mutingsRepository.createQueryBuilder('muting'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('muting.muterId = :meId', { meId: me.id });
|
.andWhere('muting.muterId = :meId', { meId: me.id });
|
||||||
|
|
||||||
const mutings = await query
|
const mutings = await query
|
||||||
|
|
|
@ -35,8 +35,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -51,7 +49,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('note.visibility = \'public\'')
|
.andWhere('note.visibility = \'public\'')
|
||||||
.andWhere('note.localOnly = FALSE')
|
.andWhere('note.localOnly = FALSE')
|
||||||
.innerJoinAndSelect('note.user', 'user')
|
.innerJoinAndSelect('note.user', 'user')
|
||||||
|
|
|
@ -34,8 +34,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: ['noteId'],
|
required: ['noteId'],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -50,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
|
||||||
.andWhere(new Brackets(qb => {
|
.andWhere(new Brackets(qb => {
|
||||||
qb
|
qb
|
||||||
.where('note.replyId = :noteId', { noteId: ps.noteId })
|
.where('note.replyId = :noteId', { noteId: ps.noteId })
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
|
||||||
import type { NoteDraftsRepository } from '@/models/_.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
tags: ['notes', 'drafts'],
|
|
||||||
|
|
||||||
requireCredential: true,
|
|
||||||
|
|
||||||
prohibitMoved: true,
|
|
||||||
|
|
||||||
kind: 'read:account',
|
|
||||||
|
|
||||||
res: {
|
|
||||||
type: 'number',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
description: 'The number of drafts',
|
|
||||||
},
|
|
||||||
|
|
||||||
errors: {
|
|
||||||
},
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const paramDef = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
},
|
|
||||||
required: [],
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
|
||||||
constructor(
|
|
||||||
@Inject(DI.noteDraftsRepository)
|
|
||||||
private noteDraftsRepository: NoteDraftsRepository,
|
|
||||||
) {
|
|
||||||
super(meta, paramDef, async (ps, me) => {
|
|
||||||
const count = await this.noteDraftsRepository.createQueryBuilder('drafts')
|
|
||||||
.where('drafts.userId = :meId', { meId: me.id })
|
|
||||||
.getCount();
|
|
||||||
|
|
||||||
return count;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,258 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Injectable } from '@nestjs/common';
|
|
||||||
import ms from 'ms';
|
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
|
||||||
import { NoteDraftService } from '@/core/NoteDraftService.js';
|
|
||||||
import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
|
|
||||||
import { ApiError } from '@/server/api/error.js';
|
|
||||||
import { NoteDraftEntityService } from '@/core/entities/NoteDraftEntityService.js';
|
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
tags: ['notes', 'drafts'],
|
|
||||||
|
|
||||||
requireCredential: true,
|
|
||||||
|
|
||||||
prohibitMoved: true,
|
|
||||||
|
|
||||||
kind: 'write:account',
|
|
||||||
|
|
||||||
res: {
|
|
||||||
type: 'object',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
properties: {
|
|
||||||
createdDraft: {
|
|
||||||
type: 'object',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
ref: 'NoteDraft',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
errors: {
|
|
||||||
noSuchRenoteTarget: {
|
|
||||||
message: 'No such renote target.',
|
|
||||||
code: 'NO_SUCH_RENOTE_TARGET',
|
|
||||||
id: 'b5c90186-4ab0-49c8-9bba-a1f76c282ba4',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotReRenote: {
|
|
||||||
message: 'You can not Renote a pure Renote.',
|
|
||||||
code: 'CANNOT_RENOTE_TO_A_PURE_RENOTE',
|
|
||||||
id: 'fd4cc33e-2a37-48dd-99cc-9b806eb2031a',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotRenoteDueToVisibility: {
|
|
||||||
message: 'You can not Renote due to target visibility.',
|
|
||||||
code: 'CANNOT_RENOTE_DUE_TO_VISIBILITY',
|
|
||||||
id: 'be9529e9-fe72-4de0-ae43-0b363c4938af',
|
|
||||||
},
|
|
||||||
|
|
||||||
noSuchReplyTarget: {
|
|
||||||
message: 'No such reply target.',
|
|
||||||
code: 'NO_SUCH_REPLY_TARGET',
|
|
||||||
id: '749ee0f6-d3da-459a-bf02-282e2da4292c',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotReplyToInvisibleNote: {
|
|
||||||
message: 'You cannot reply to an invisible Note.',
|
|
||||||
code: 'CANNOT_REPLY_TO_AN_INVISIBLE_NOTE',
|
|
||||||
id: 'b98980fa-3780-406c-a935-b6d0eeee10d1',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotReplyToPureRenote: {
|
|
||||||
message: 'You can not reply to a pure Renote.',
|
|
||||||
code: 'CANNOT_REPLY_TO_A_PURE_RENOTE',
|
|
||||||
id: '3ac74a84-8fd5-4bb0-870f-01804f82ce15',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotReplyToSpecifiedVisibilityNoteWithExtendedVisibility: {
|
|
||||||
message: 'You cannot reply to a specified visibility note with extended visibility.',
|
|
||||||
code: 'CANNOT_REPLY_TO_SPECIFIED_VISIBILITY_NOTE_WITH_EXTENDED_VISIBILITY',
|
|
||||||
id: 'ed940410-535c-4d5e-bfa3-af798671e93c',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotCreateAlreadyExpiredPoll: {
|
|
||||||
message: 'Poll is already expired.',
|
|
||||||
code: 'CANNOT_CREATE_ALREADY_EXPIRED_POLL',
|
|
||||||
id: '04da457d-b083-4055-9082-955525eda5a5',
|
|
||||||
},
|
|
||||||
|
|
||||||
noSuchChannel: {
|
|
||||||
message: 'No such channel.',
|
|
||||||
code: 'NO_SUCH_CHANNEL',
|
|
||||||
id: 'b1653923-5453-4edc-b786-7c4f39bb0bbb',
|
|
||||||
},
|
|
||||||
|
|
||||||
youHaveBeenBlocked: {
|
|
||||||
message: 'You have been blocked by this user.',
|
|
||||||
code: 'YOU_HAVE_BEEN_BLOCKED',
|
|
||||||
id: 'b390d7e1-8a5e-46ed-b625-06271cafd3d3',
|
|
||||||
},
|
|
||||||
|
|
||||||
noSuchFile: {
|
|
||||||
message: 'Some files are not found.',
|
|
||||||
code: 'NO_SUCH_FILE',
|
|
||||||
id: 'b6992544-63e7-67f0-fa7f-32444b1b5306',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotRenoteOutsideOfChannel: {
|
|
||||||
message: 'Cannot renote outside of channel.',
|
|
||||||
code: 'CANNOT_RENOTE_OUTSIDE_OF_CHANNEL',
|
|
||||||
id: '33510210-8452-094c-6227-4a6c05d99f00',
|
|
||||||
},
|
|
||||||
|
|
||||||
containsProhibitedWords: {
|
|
||||||
message: 'Cannot post because it contains prohibited words.',
|
|
||||||
code: 'CONTAINS_PROHIBITED_WORDS',
|
|
||||||
id: 'aa6e01d3-a85c-669d-758a-76aab43af334',
|
|
||||||
},
|
|
||||||
|
|
||||||
containsTooManyMentions: {
|
|
||||||
message: 'Cannot post because it exceeds the allowed number of mentions.',
|
|
||||||
code: 'CONTAINS_TOO_MANY_MENTIONS',
|
|
||||||
id: '4de0363a-3046-481b-9b0f-feff3e211025',
|
|
||||||
},
|
|
||||||
|
|
||||||
tooManyDrafts: {
|
|
||||||
message: 'You cannot create drafts any more.',
|
|
||||||
code: 'TOO_MANY_DRAFTS',
|
|
||||||
id: '9ee33bbe-fde3-4c71-9b51-e50492c6b9c8',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotRenoteToExternal: {
|
|
||||||
message: 'Cannot Renote to External.',
|
|
||||||
code: 'CANNOT_RENOTE_TO_EXTERNAL',
|
|
||||||
id: 'ed1952ac-2d26-4957-8b30-2deda76bedf7',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
limit: {
|
|
||||||
duration: ms('1hour'),
|
|
||||||
max: 300,
|
|
||||||
},
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const paramDef = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
visibility: { type: 'string', enum: ['public', 'home', 'followers', 'specified'], default: 'public' },
|
|
||||||
visibleUserIds: { type: 'array', uniqueItems: true, items: {
|
|
||||||
type: 'string', format: 'misskey:id',
|
|
||||||
} },
|
|
||||||
cw: { type: 'string', nullable: true, minLength: 1, maxLength: 100 },
|
|
||||||
hashtag: { type: 'string', nullable: true, maxLength: 200 },
|
|
||||||
localOnly: { type: 'boolean', default: false },
|
|
||||||
reactionAcceptance: { type: 'string', nullable: true, enum: [null, 'likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote'], default: null },
|
|
||||||
replyId: { type: 'string', format: 'misskey:id', nullable: true },
|
|
||||||
renoteId: { type: 'string', format: 'misskey:id', nullable: true },
|
|
||||||
channelId: { type: 'string', format: 'misskey:id', nullable: true },
|
|
||||||
|
|
||||||
// anyOf内にバリデーションを書いても最初の一つしかチェックされない
|
|
||||||
text: {
|
|
||||||
type: 'string',
|
|
||||||
minLength: 0,
|
|
||||||
maxLength: MAX_NOTE_TEXT_LENGTH,
|
|
||||||
nullable: true,
|
|
||||||
},
|
|
||||||
fileIds: {
|
|
||||||
type: 'array',
|
|
||||||
uniqueItems: true,
|
|
||||||
minItems: 1,
|
|
||||||
maxItems: 16,
|
|
||||||
items: { type: 'string', format: 'misskey:id' },
|
|
||||||
},
|
|
||||||
poll: {
|
|
||||||
type: 'object',
|
|
||||||
nullable: true,
|
|
||||||
properties: {
|
|
||||||
choices: {
|
|
||||||
type: 'array',
|
|
||||||
uniqueItems: true,
|
|
||||||
minItems: 0,
|
|
||||||
maxItems: 10,
|
|
||||||
items: { type: 'string', minLength: 1, maxLength: 50 },
|
|
||||||
},
|
|
||||||
multiple: { type: 'boolean' },
|
|
||||||
expiresAt: { type: 'integer', nullable: true },
|
|
||||||
expiredAfter: { type: 'integer', nullable: true, minimum: 1 },
|
|
||||||
},
|
|
||||||
required: ['choices'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
required: [],
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
|
||||||
constructor(
|
|
||||||
private noteDraftService: NoteDraftService,
|
|
||||||
private noteDraftEntityService: NoteDraftEntityService,
|
|
||||||
) {
|
|
||||||
super(meta, paramDef, async (ps, me) => {
|
|
||||||
const draft = await this.noteDraftService.create(me, {
|
|
||||||
fileIds: ps.fileIds,
|
|
||||||
poll: ps.poll ? {
|
|
||||||
choices: ps.poll.choices,
|
|
||||||
multiple: ps.poll.multiple ?? false,
|
|
||||||
expiresAt: ps.poll.expiresAt ? new Date(ps.poll.expiresAt) : null,
|
|
||||||
expiredAfter: ps.poll.expiredAfter ?? null,
|
|
||||||
} : undefined,
|
|
||||||
text: ps.text ?? null,
|
|
||||||
replyId: ps.replyId ?? undefined,
|
|
||||||
renoteId: ps.renoteId ?? undefined,
|
|
||||||
cw: ps.cw ?? null,
|
|
||||||
...(ps.hashtag ? { hashtag: ps.hashtag } : {}),
|
|
||||||
localOnly: ps.localOnly,
|
|
||||||
reactionAcceptance: ps.reactionAcceptance,
|
|
||||||
visibility: ps.visibility,
|
|
||||||
visibleUserIds: ps.visibleUserIds ?? [],
|
|
||||||
channelId: ps.channelId ?? undefined,
|
|
||||||
}).catch((err) => {
|
|
||||||
if (err instanceof IdentifiableError) {
|
|
||||||
switch (err.id) {
|
|
||||||
case '9ee33bbe-fde3-4c71-9b51-e50492c6b9c8':
|
|
||||||
throw new ApiError(meta.errors.tooManyDrafts);
|
|
||||||
case '04da457d-b083-4055-9082-955525eda5a5':
|
|
||||||
throw new ApiError(meta.errors.cannotCreateAlreadyExpiredPoll);
|
|
||||||
case 'b6992544-63e7-67f0-fa7f-32444b1b5306':
|
|
||||||
throw new ApiError(meta.errors.noSuchFile);
|
|
||||||
case '64929870-2540-4d11-af41-3b484d78c956':
|
|
||||||
throw new ApiError(meta.errors.noSuchRenoteTarget);
|
|
||||||
case '76cc5583-5a14-4ad3-8717-0298507e32db':
|
|
||||||
throw new ApiError(meta.errors.cannotReRenote);
|
|
||||||
case '075ca298-e6e7-485a-b570-51a128bb5168':
|
|
||||||
throw new ApiError(meta.errors.youHaveBeenBlocked);
|
|
||||||
case '81eb8188-aea1-4e35-9a8f-3334a3be9855':
|
|
||||||
throw new ApiError(meta.errors.cannotRenoteDueToVisibility);
|
|
||||||
case '6815399a-6f13-4069-b60d-ed5156249d12':
|
|
||||||
throw new ApiError(meta.errors.noSuchChannel);
|
|
||||||
case 'ed1952ac-2d26-4957-8b30-2deda76bedf7':
|
|
||||||
throw new ApiError(meta.errors.cannotRenoteToExternal);
|
|
||||||
case 'c4721841-22fc-4bb7-ad3d-897ef1d375b5':
|
|
||||||
throw new ApiError(meta.errors.noSuchReplyTarget);
|
|
||||||
case 'e6c10b57-2c09-4da3-bd4d-eda05d51d140':
|
|
||||||
throw new ApiError(meta.errors.cannotReplyToPureRenote);
|
|
||||||
case '593c323c-6b6a-4501-a25c-2f36bd2a93d6':
|
|
||||||
throw new ApiError(meta.errors.cannotReplyToInvisibleNote);
|
|
||||||
case '215dbc76-336c-4d2a-9605-95766ba7dab0':
|
|
||||||
throw new ApiError(meta.errors.cannotReplyToSpecifiedVisibilityNoteWithExtendedVisibility);
|
|
||||||
default:
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw err;
|
|
||||||
});
|
|
||||||
|
|
||||||
const createdDraft = await this.noteDraftEntityService.pack(draft, me);
|
|
||||||
|
|
||||||
return {
|
|
||||||
createdDraft,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Injectable } from '@nestjs/common';
|
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
|
||||||
import { NoteDraftService } from '@/core/NoteDraftService.js';
|
|
||||||
import { ApiError } from '../../../error.js';
|
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
tags: ['notes', 'drafts'],
|
|
||||||
|
|
||||||
requireCredential: true,
|
|
||||||
|
|
||||||
prohibitMoved: true,
|
|
||||||
|
|
||||||
kind: 'write:account',
|
|
||||||
|
|
||||||
errors: {
|
|
||||||
noSuchNoteDraft: {
|
|
||||||
message: 'No such note draft.',
|
|
||||||
code: 'NO_SUCH_NOTE_DRAFT',
|
|
||||||
id: '49cd6b9d-848e-41ee-b0b9-adaca711a6b1',
|
|
||||||
},
|
|
||||||
|
|
||||||
accessDenied: {
|
|
||||||
message: 'Access denied.',
|
|
||||||
code: 'ACCESS_DENIED',
|
|
||||||
id: '56f35758-7dd5-468b-8439-5d6fb8ec9b8e',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const paramDef = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
draftId: { type: 'string', nullable: false, format: 'misskey:id' },
|
|
||||||
},
|
|
||||||
required: ['draftId'],
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
|
||||||
constructor(
|
|
||||||
private noteDraftService: NoteDraftService,
|
|
||||||
) {
|
|
||||||
super(meta, paramDef, async (ps, me) => {
|
|
||||||
const draft = await this.noteDraftService.get(me, ps.draftId);
|
|
||||||
if (draft == null) {
|
|
||||||
throw new ApiError(meta.errors.noSuchNoteDraft);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (draft.userId !== me.id) {
|
|
||||||
throw new ApiError(meta.errors.accessDenied);
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.noteDraftService.delete(me, draft.id);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
|
||||||
import type { MiNoteDraft, NoteDraftsRepository } from '@/models/_.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
|
||||||
import { QueryService } from '@/core/QueryService.js';
|
|
||||||
import { NoteDraftEntityService } from '@/core/entities/NoteDraftEntityService.js';
|
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
tags: ['notes', 'drafts'],
|
|
||||||
|
|
||||||
requireCredential: true,
|
|
||||||
|
|
||||||
prohibitMoved: true,
|
|
||||||
|
|
||||||
kind: 'read:account',
|
|
||||||
|
|
||||||
res: {
|
|
||||||
type: 'array',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
items: {
|
|
||||||
type: 'object',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
ref: 'NoteDraft',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
errors: {
|
|
||||||
},
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const paramDef = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
|
||||||
required: [],
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
|
||||||
constructor(
|
|
||||||
@Inject(DI.noteDraftsRepository)
|
|
||||||
private noteDraftsRepository: NoteDraftsRepository,
|
|
||||||
|
|
||||||
private queryService: QueryService,
|
|
||||||
private noteDraftEntityService: NoteDraftEntityService,
|
|
||||||
) {
|
|
||||||
super(meta, paramDef, async (ps, me) => {
|
|
||||||
const query = this.queryService.makePaginationQuery<MiNoteDraft>(this.noteDraftsRepository.createQueryBuilder('drafts'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
|
||||||
.andWhere('drafts.userId = :meId', { meId: me.id });
|
|
||||||
|
|
||||||
const drafts = await query
|
|
||||||
.limit(ps.limit)
|
|
||||||
.getMany();
|
|
||||||
|
|
||||||
return await this.noteDraftEntityService.packMany(drafts, me);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,302 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Injectable } from '@nestjs/common';
|
|
||||||
import ms from 'ms';
|
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
|
||||||
import { NoteDraftService } from '@/core/NoteDraftService.js';
|
|
||||||
import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
|
|
||||||
import { NoteDraftEntityService } from '@/core/entities/NoteDraftEntityService.js';
|
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
|
||||||
import { ApiError } from '../../../error.js';
|
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
tags: ['notes', 'drafts'],
|
|
||||||
|
|
||||||
requireCredential: true,
|
|
||||||
|
|
||||||
prohibitMoved: true,
|
|
||||||
|
|
||||||
kind: 'write:account',
|
|
||||||
|
|
||||||
res: {
|
|
||||||
type: 'object',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
properties: {
|
|
||||||
updatedDraft: {
|
|
||||||
type: 'object',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
ref: 'NoteDraft',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
errors: {
|
|
||||||
noSuchRenoteTarget: {
|
|
||||||
message: 'No such renote target.',
|
|
||||||
code: 'NO_SUCH_RENOTE_TARGET',
|
|
||||||
id: 'b5c90186-4ab0-49c8-9bba-a1f76c282ba4',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotReRenote: {
|
|
||||||
message: 'You can not Renote a pure Renote.',
|
|
||||||
code: 'CANNOT_RENOTE_TO_A_PURE_RENOTE',
|
|
||||||
id: 'fd4cc33e-2a37-48dd-99cc-9b806eb2031a',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotRenoteDueToVisibility: {
|
|
||||||
message: 'You can not Renote due to target visibility.',
|
|
||||||
code: 'CANNOT_RENOTE_DUE_TO_VISIBILITY',
|
|
||||||
id: 'be9529e9-fe72-4de0-ae43-0b363c4938af',
|
|
||||||
},
|
|
||||||
|
|
||||||
noSuchReplyTarget: {
|
|
||||||
message: 'No such reply target.',
|
|
||||||
code: 'NO_SUCH_REPLY_TARGET',
|
|
||||||
id: '749ee0f6-d3da-459a-bf02-282e2da4292c',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotReplyToInvisibleNote: {
|
|
||||||
message: 'You cannot reply to an invisible Note.',
|
|
||||||
code: 'CANNOT_REPLY_TO_AN_INVISIBLE_NOTE',
|
|
||||||
id: 'b98980fa-3780-406c-a935-b6d0eeee10d1',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotReplyToPureRenote: {
|
|
||||||
message: 'You can not reply to a pure Renote.',
|
|
||||||
code: 'CANNOT_REPLY_TO_A_PURE_RENOTE',
|
|
||||||
id: '3ac74a84-8fd5-4bb0-870f-01804f82ce15',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotReplyToSpecifiedNoteWithExtendedVisibility: {
|
|
||||||
message: 'You cannot reply to a specified visibility note with extended visibility.',
|
|
||||||
code: 'CANNOT_REPLY_TO_SPECIFIED_NOTE_WITH_EXTENDED_VISIBILITY',
|
|
||||||
id: 'ed940410-535c-4d5e-bfa3-af798671e93c',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotCreateAlreadyExpiredPoll: {
|
|
||||||
message: 'Poll is already expired.',
|
|
||||||
code: 'CANNOT_CREATE_ALREADY_EXPIRED_POLL',
|
|
||||||
id: '04da457d-b083-4055-9082-955525eda5a5',
|
|
||||||
},
|
|
||||||
|
|
||||||
noSuchChannel: {
|
|
||||||
message: 'No such channel.',
|
|
||||||
code: 'NO_SUCH_CHANNEL',
|
|
||||||
id: 'b1653923-5453-4edc-b786-7c4f39bb0bbb',
|
|
||||||
},
|
|
||||||
|
|
||||||
youHaveBeenBlocked: {
|
|
||||||
message: 'You have been blocked by this user.',
|
|
||||||
code: 'YOU_HAVE_BEEN_BLOCKED',
|
|
||||||
id: 'b390d7e1-8a5e-46ed-b625-06271cafd3d3',
|
|
||||||
},
|
|
||||||
|
|
||||||
noSuchFile: {
|
|
||||||
message: 'Some files are not found.',
|
|
||||||
code: 'NO_SUCH_FILE',
|
|
||||||
id: 'b6992544-63e7-67f0-fa7f-32444b1b5306',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotRenoteOutsideOfChannel: {
|
|
||||||
message: 'Cannot renote outside of channel.',
|
|
||||||
code: 'CANNOT_RENOTE_OUTSIDE_OF_CHANNEL',
|
|
||||||
id: '33510210-8452-094c-6227-4a6c05d99f00',
|
|
||||||
},
|
|
||||||
|
|
||||||
containsProhibitedWords: {
|
|
||||||
message: 'Cannot post because it contains prohibited words.',
|
|
||||||
code: 'CONTAINS_PROHIBITED_WORDS',
|
|
||||||
id: 'aa6e01d3-a85c-669d-758a-76aab43af334',
|
|
||||||
},
|
|
||||||
|
|
||||||
containsTooManyMentions: {
|
|
||||||
message: 'Cannot post because it exceeds the allowed number of mentions.',
|
|
||||||
code: 'CONTAINS_TOO_MANY_MENTIONS',
|
|
||||||
id: '4de0363a-3046-481b-9b0f-feff3e211025',
|
|
||||||
},
|
|
||||||
|
|
||||||
noSuchNoteDraft: {
|
|
||||||
message: 'No such note draft.',
|
|
||||||
code: 'NO_SUCH_NOTE_DRAFT',
|
|
||||||
id: '49cd6b9d-848e-41ee-b0b9-adaca711a6b1',
|
|
||||||
},
|
|
||||||
|
|
||||||
accessDenied: {
|
|
||||||
message: 'Access denied.',
|
|
||||||
code: 'ACCESS_DENIED',
|
|
||||||
id: '56f35758-7dd5-468b-8439-5d6fb8ec9b8e',
|
|
||||||
},
|
|
||||||
|
|
||||||
noSuchRenote: {
|
|
||||||
message: 'No such renote.',
|
|
||||||
code: 'NO_SUCH_RENOTE',
|
|
||||||
id: '64929870-2540-4d11-af41-3b484d78c956',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotRenote: {
|
|
||||||
message: 'Cannot renote.',
|
|
||||||
code: 'CANNOT_RENOTE',
|
|
||||||
id: '76cc5583-5a14-4ad3-8717-0298507e32db',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotRenoteToExternal: {
|
|
||||||
message: 'Cannot Renote to External.',
|
|
||||||
code: 'CANNOT_RENOTE_TO_EXTERNAL',
|
|
||||||
id: 'ed1952ac-2d26-4957-8b30-2deda76bedf7',
|
|
||||||
},
|
|
||||||
|
|
||||||
noSuchReply: {
|
|
||||||
message: 'No such reply.',
|
|
||||||
code: 'NO_SUCH_REPLY',
|
|
||||||
id: 'c4721841-22fc-4bb7-ad3d-897ef1d375b5',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotReplyToSpecifiedVisibilityNoteWithExtendedVisibility: {
|
|
||||||
message: 'You cannot reply to a specified visibility note with extended visibility.',
|
|
||||||
code: 'CANNOT_REPLY_TO_SPECIFIED_VISIBILITY_NOTE_WITH_EXTENDED_VISIBILITY',
|
|
||||||
id: '215dbc76-336c-4d2a-9605-95766ba7dab0',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
limit: {
|
|
||||||
duration: ms('1hour'),
|
|
||||||
max: 300,
|
|
||||||
},
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const paramDef = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
draftId: { type: 'string', nullable: false, format: 'misskey:id' },
|
|
||||||
visibility: { type: 'string', enum: ['public', 'home', 'followers', 'specified'], default: 'public' },
|
|
||||||
visibleUserIds: { type: 'array', uniqueItems: true, items: {
|
|
||||||
type: 'string', format: 'misskey:id',
|
|
||||||
} },
|
|
||||||
cw: { type: 'string', nullable: true, minLength: 1, maxLength: 100 },
|
|
||||||
hashtag: { type: 'string', nullable: true, maxLength: 200 },
|
|
||||||
localOnly: { type: 'boolean', default: false },
|
|
||||||
reactionAcceptance: { type: 'string', nullable: true, enum: [null, 'likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote'], default: null },
|
|
||||||
replyId: { type: 'string', format: 'misskey:id', nullable: true },
|
|
||||||
renoteId: { type: 'string', format: 'misskey:id', nullable: true },
|
|
||||||
channelId: { type: 'string', format: 'misskey:id', nullable: true },
|
|
||||||
|
|
||||||
// anyOf内にバリデーションを書いても最初の一つしかチェックされない
|
|
||||||
// See https://github.com/misskey-dev/misskey/pull/10082
|
|
||||||
text: {
|
|
||||||
type: 'string',
|
|
||||||
minLength: 0,
|
|
||||||
maxLength: MAX_NOTE_TEXT_LENGTH,
|
|
||||||
nullable: true,
|
|
||||||
},
|
|
||||||
fileIds: {
|
|
||||||
type: 'array',
|
|
||||||
uniqueItems: true,
|
|
||||||
minItems: 1,
|
|
||||||
maxItems: 16,
|
|
||||||
items: { type: 'string', format: 'misskey:id' },
|
|
||||||
},
|
|
||||||
poll: {
|
|
||||||
type: 'object',
|
|
||||||
nullable: true,
|
|
||||||
properties: {
|
|
||||||
choices: {
|
|
||||||
type: 'array',
|
|
||||||
uniqueItems: true,
|
|
||||||
minItems: 0,
|
|
||||||
maxItems: 10,
|
|
||||||
items: { type: 'string', minLength: 1, maxLength: 50 },
|
|
||||||
},
|
|
||||||
multiple: { type: 'boolean' },
|
|
||||||
expiresAt: { type: 'integer', nullable: true },
|
|
||||||
expiredAfter: { type: 'integer', nullable: true, minimum: 1 },
|
|
||||||
},
|
|
||||||
required: ['choices'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
required: ['draftId'],
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
|
||||||
constructor(
|
|
||||||
private noteDraftService: NoteDraftService,
|
|
||||||
private noteDraftEntityService: NoteDraftEntityService,
|
|
||||||
) {
|
|
||||||
super(meta, paramDef, async (ps, me) => {
|
|
||||||
const draft = await this.noteDraftService.update(me, ps.draftId, {
|
|
||||||
fileIds: ps.fileIds,
|
|
||||||
poll: ps.poll ? {
|
|
||||||
choices: ps.poll.choices,
|
|
||||||
multiple: ps.poll.multiple ?? false,
|
|
||||||
expiresAt: ps.poll.expiresAt ? new Date(ps.poll.expiresAt) : null,
|
|
||||||
expiredAfter: ps.poll.expiredAfter ?? null,
|
|
||||||
} : undefined,
|
|
||||||
text: ps.text ?? null,
|
|
||||||
replyId: ps.replyId ?? undefined,
|
|
||||||
renoteId: ps.renoteId ?? undefined,
|
|
||||||
cw: ps.cw ?? null,
|
|
||||||
...(ps.hashtag ? { hashtag: ps.hashtag } : {}),
|
|
||||||
localOnly: ps.localOnly,
|
|
||||||
reactionAcceptance: ps.reactionAcceptance,
|
|
||||||
visibility: ps.visibility,
|
|
||||||
visibleUserIds: ps.visibleUserIds ?? [],
|
|
||||||
channelId: ps.channelId ?? undefined,
|
|
||||||
}).catch((err) => {
|
|
||||||
if (err instanceof IdentifiableError) {
|
|
||||||
switch (err.id) {
|
|
||||||
case '49cd6b9d-848e-41ee-b0b9-adaca711a6b1':
|
|
||||||
throw new ApiError(meta.errors.noSuchNoteDraft);
|
|
||||||
case '04da457d-b083-4055-9082-955525eda5a5':
|
|
||||||
throw new ApiError(meta.errors.cannotCreateAlreadyExpiredPoll);
|
|
||||||
case 'b6992544-63e7-67f0-fa7f-32444b1b5306':
|
|
||||||
throw new ApiError(meta.errors.noSuchFile);
|
|
||||||
case '64929870-2540-4d11-af41-3b484d78c956':
|
|
||||||
throw new ApiError(meta.errors.noSuchRenote);
|
|
||||||
case '76cc5583-5a14-4ad3-8717-0298507e32db':
|
|
||||||
throw new ApiError(meta.errors.cannotRenote);
|
|
||||||
case '075ca298-e6e7-485a-b570-51a128bb5168':
|
|
||||||
throw new ApiError(meta.errors.youHaveBeenBlocked);
|
|
||||||
case '81eb8188-aea1-4e35-9a8f-3334a3be9855':
|
|
||||||
throw new ApiError(meta.errors.cannotRenoteDueToVisibility);
|
|
||||||
case '6815399a-6f13-4069-b60d-ed5156249d12':
|
|
||||||
throw new ApiError(meta.errors.noSuchChannel);
|
|
||||||
case 'ed1952ac-2d26-4957-8b30-2deda76bedf7':
|
|
||||||
throw new ApiError(meta.errors.cannotRenoteToExternal);
|
|
||||||
case 'c4721841-22fc-4bb7-ad3d-897ef1d375b5':
|
|
||||||
throw new ApiError(meta.errors.noSuchReply);
|
|
||||||
case 'e6c10b57-2c09-4da3-bd4d-eda05d51d140':
|
|
||||||
throw new ApiError(meta.errors.cannotReplyToPureRenote);
|
|
||||||
case '593c323c-6b6a-4501-a25c-2f36bd2a93d6':
|
|
||||||
throw new ApiError(meta.errors.cannotReplyToInvisibleNote);
|
|
||||||
case '215dbc76-336c-4d2a-9605-95766ba7dab0':
|
|
||||||
throw new ApiError(meta.errors.cannotReplyToSpecifiedNoteWithExtendedVisibility);
|
|
||||||
case 'b5c90186-4ab0-49c8-9bba-a1f76c282ba4':
|
|
||||||
throw new ApiError(meta.errors.noSuchRenoteTarget);
|
|
||||||
case 'fd4cc33e-2a37-48dd-99cc-9b806eb2031a':
|
|
||||||
throw new ApiError(meta.errors.cannotReRenote);
|
|
||||||
case '749ee0f6-d3da-459a-bf02-282e2da4292c':
|
|
||||||
throw new ApiError(meta.errors.noSuchReplyTarget);
|
|
||||||
case '33510210-8452-094c-6227-4a6c05d99f00':
|
|
||||||
throw new ApiError(meta.errors.cannotRenoteOutsideOfChannel);
|
|
||||||
case 'aa6e01d3-a85c-669d-758a-76aab43af334':
|
|
||||||
throw new ApiError(meta.errors.containsProhibitedWords);
|
|
||||||
case '4de0363a-3046-481b-9b0f-feff3e211025':
|
|
||||||
throw new ApiError(meta.errors.containsTooManyMentions);
|
|
||||||
default:
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw err;
|
|
||||||
});
|
|
||||||
|
|
||||||
const updatedDraft = await this.noteDraftEntityService.pack(draft, me);
|
|
||||||
|
|
||||||
return {
|
|
||||||
updatedDraft,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -35,8 +35,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
visibility: { type: 'string' },
|
visibility: { type: 'string' },
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
|
@ -59,7 +57,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
.select('following.followeeId')
|
.select('following.followeeId')
|
||||||
.where('following.followerId = :followerId', { followerId: me.id });
|
.where('following.followerId = :followerId', { followerId: me.id });
|
||||||
|
|
||||||
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
|
||||||
.andWhere(new Brackets(qb => {
|
.andWhere(new Brackets(qb => {
|
||||||
qb // このmeIdAsListパラメータはqueryServiceのgenerateVisibilityQueryでセットされる
|
qb // このmeIdAsListパラメータはqueryServiceのgenerateVisibilityQueryでセットされる
|
||||||
.where(':meIdAsList <@ note.mentions')
|
.where(':meIdAsList <@ note.mentions')
|
||||||
|
|
|
@ -47,8 +47,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: ['noteId'],
|
required: ['noteId'],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -63,7 +61,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.noteReactionsRepository.createQueryBuilder('reaction'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.noteReactionsRepository.createQueryBuilder('reaction'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('reaction.noteId = :noteId', { noteId: ps.noteId })
|
.andWhere('reaction.noteId = :noteId', { noteId: ps.noteId })
|
||||||
.leftJoinAndSelect('reaction.user', 'user')
|
.leftJoinAndSelect('reaction.user', 'user')
|
||||||
.leftJoinAndSelect('reaction.note', 'note');
|
.leftJoinAndSelect('reaction.note', 'note');
|
||||||
|
|
|
@ -43,8 +43,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: ['noteId'],
|
required: ['noteId'],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -65,7 +63,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
|
|
||||||
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('note.renoteId = :renoteId', { renoteId: note.id })
|
.andWhere('note.renoteId = :renoteId', { renoteId: note.id })
|
||||||
.innerJoinAndSelect('note.user', 'user')
|
.innerJoinAndSelect('note.user', 'user')
|
||||||
.leftJoinAndSelect('note.reply', 'reply')
|
.leftJoinAndSelect('note.reply', 'reply')
|
||||||
|
|
|
@ -32,8 +32,6 @@ export const paramDef = {
|
||||||
noteId: { type: 'string', format: 'misskey:id' },
|
noteId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
},
|
},
|
||||||
required: ['noteId'],
|
required: ['noteId'],
|
||||||
|
@ -49,7 +47,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('note.replyId = :replyId', { replyId: ps.noteId })
|
.andWhere('note.replyId = :replyId', { replyId: ps.noteId })
|
||||||
.innerJoinAndSelect('note.user', 'user')
|
.innerJoinAndSelect('note.user', 'user')
|
||||||
.leftJoinAndSelect('note.reply', 'reply')
|
.leftJoinAndSelect('note.reply', 'reply')
|
||||||
|
|
|
@ -72,8 +72,6 @@ export const paramDef = {
|
||||||
poll: { type: 'boolean', nullable: true, default: null },
|
poll: { type: 'boolean', nullable: true, default: null },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -90,7 +88,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
|
||||||
.innerJoinAndSelect('note.user', 'user')
|
.innerJoinAndSelect('note.user', 'user')
|
||||||
.leftJoinAndSelect('note.reply', 'reply')
|
.leftJoinAndSelect('note.reply', 'reply')
|
||||||
.leftJoinAndSelect('note.renote', 'renote')
|
.leftJoinAndSelect('note.renote', 'renote')
|
||||||
|
|
|
@ -8,7 +8,6 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { SearchService } from '@/core/SearchService.js';
|
import { SearchService } from '@/core/SearchService.js';
|
||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
import { RoleService } from '@/core/RoleService.js';
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
|
||||||
import { ApiError } from '../../error.js';
|
import { ApiError } from '../../error.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -41,8 +40,6 @@ export const paramDef = {
|
||||||
query: { type: 'string' },
|
query: { type: 'string' },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
offset: { type: 'integer', default: 0 },
|
offset: { type: 'integer', default: 0 },
|
||||||
host: {
|
host: {
|
||||||
|
@ -63,12 +60,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
private searchService: SearchService,
|
private searchService: SearchService,
|
||||||
private roleService: RoleService,
|
private roleService: RoleService,
|
||||||
private idService: IdService,
|
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : undefined);
|
|
||||||
const sinceId = ps.sinceId ?? (ps.sinceDate ? this.idService.gen(ps.sinceDate!) : undefined);
|
|
||||||
|
|
||||||
const policies = await this.roleService.getUserPolicies(me ? me.id : null);
|
const policies = await this.roleService.getUserPolicies(me ? me.id : null);
|
||||||
if (!policies.canSearchNotes) {
|
if (!policies.canSearchNotes) {
|
||||||
throw new ApiError(meta.errors.unavailable);
|
throw new ApiError(meta.errors.unavailable);
|
||||||
|
@ -79,8 +72,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
channelId: ps.channelId,
|
channelId: ps.channelId,
|
||||||
host: ps.host,
|
host: ps.host,
|
||||||
}, {
|
}, {
|
||||||
untilId: untilId,
|
untilId: ps.untilId,
|
||||||
sinceId: sinceId,
|
sinceId: ps.sinceId,
|
||||||
limit: ps.limit,
|
limit: ps.limit,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -50,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.renoteMutingsRepository.createQueryBuilder('muting'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.renoteMutingsRepository.createQueryBuilder('muting'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('muting.muterId = :meId', { meId: me.id });
|
.andWhere('muting.muterId = :meId', { meId: me.id });
|
||||||
|
|
||||||
const mutings = await query
|
const mutings = await query
|
||||||
|
|
|
@ -27,8 +27,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
my: { type: 'boolean', default: false },
|
my: { type: 'boolean', default: false },
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
|
@ -44,7 +42,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.reversiGamesRepository.createQueryBuilder('game'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.reversiGamesRepository.createQueryBuilder('game'), ps.sinceId, ps.untilId)
|
||||||
.innerJoinAndSelect('game.user1', 'user1')
|
.innerJoinAndSelect('game.user1', 'user1')
|
||||||
.innerJoinAndSelect('game.user2', 'user2');
|
.innerJoinAndSelect('game.user2', 'user2');
|
||||||
|
|
||||||
|
|
|
@ -51,8 +51,6 @@ export const paramDef = {
|
||||||
roleId: { type: 'string', format: 'misskey:id' },
|
roleId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
},
|
},
|
||||||
required: ['roleId'],
|
required: ['roleId'],
|
||||||
|
@ -81,7 +79,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw new ApiError(meta.errors.noSuchRole);
|
throw new ApiError(meta.errors.noSuchRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
const query = this.queryService.makePaginationQuery(this.roleAssignmentsRepository.createQueryBuilder('assign'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.roleAssignmentsRepository.createQueryBuilder('assign'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('assign.roleId = :roleId', { roleId: role.id })
|
.andWhere('assign.roleId = :roleId', { roleId: role.id })
|
||||||
.andWhere(new Brackets(qb => {
|
.andWhere(new Brackets(qb => {
|
||||||
qb
|
qb
|
||||||
|
|
|
@ -33,8 +33,6 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
|
||||||
untilDate: { type: 'integer' },
|
|
||||||
},
|
},
|
||||||
required: ['userId'],
|
required: ['userId'],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -49,7 +47,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.clipsRepository.createQueryBuilder('clip'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery(this.clipsRepository.createQueryBuilder('clip'), ps.sinceId, ps.untilId)
|
||||||
.andWhere('clip.userId = :userId', { userId: ps.userId })
|
.andWhere('clip.userId = :userId', { userId: ps.userId })
|
||||||
.andWhere('clip.isPublic = true');
|
.andWhere('clip.isPublic = true');
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue