Merge branch 'main' into fix-chat-continuation
This commit is contained in:
commit
7d4cbd6ecf
275 changed files with 3571 additions and 5420 deletions
|
@ -72,24 +72,6 @@ redis:
|
|||
# user:
|
||||
# pass:
|
||||
|
||||
# ┌───────────────┐
|
||||
#───┘ ID generation └───────────────────────────────────────────
|
||||
|
||||
# You can select the ID generation method.
|
||||
# You don't usually need to change this setting, but you can
|
||||
# change it according to your preferences.
|
||||
|
||||
# Available methods:
|
||||
# aid ... Short, Millisecond accuracy
|
||||
# meid ... Similar to ObjectID, Millisecond accuracy
|
||||
# ulid ... Millisecond accuracy
|
||||
# objectid ... This is left for backward compatibility
|
||||
|
||||
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
|
||||
# ID SETTINGS AFTER THAT!
|
||||
|
||||
id: 'aid'
|
||||
|
||||
# ┌─────────────────────┐
|
||||
#───┘ Other configuration └─────────────────────────────────────
|
||||
|
||||
|
|
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
|
@ -1,3 +0,0 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
patreon: syuilo
|
42
.github/ISSUE_TEMPLATE/01_bug-report.md
vendored
42
.github/ISSUE_TEMPLATE/01_bug-report.md
vendored
|
@ -1,42 +0,0 @@
|
|||
---
|
||||
name: 🐛 Bug Report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ⚠️bug?
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Thanks for reporting!
|
||||
First, in order to avoid duplicate Issues, please search to see if the problem you found has already been reported.
|
||||
-->
|
||||
|
||||
## 💡 Summary
|
||||
|
||||
<!-- Tell us what the bug is -->
|
||||
|
||||
## 🥰 Expected Behavior
|
||||
|
||||
<!--- Tell us what should happen -->
|
||||
|
||||
## 🤬 Actual Behavior
|
||||
|
||||
<!--
|
||||
Tell us what happens instead of the expected behavior.
|
||||
Please include errors from the developer console and/or server log files if you have access to them.
|
||||
-->
|
||||
|
||||
## 📝 Steps to Reproduce
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
## 📌 Environment
|
||||
|
||||
<!-- Tell us where on the platform it happens -->
|
||||
|
||||
Misskey version:
|
||||
Your OS:
|
||||
Your browser:
|
12
.github/ISSUE_TEMPLATE/02_feature-request.md
vendored
12
.github/ISSUE_TEMPLATE/02_feature-request.md
vendored
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
name: ✨ Feature Request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ✨Feature
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
<!-- Tell us what the suggestion is -->
|
7
.github/ISSUE_TEMPLATE/config.yml
vendored
7
.github/ISSUE_TEMPLATE/config.yml
vendored
|
@ -1,7 +0,0 @@
|
|||
contact_links:
|
||||
- name: 👪 Misskey Forum
|
||||
url: https://forum.misskey.io/
|
||||
about: Ask questions and share knowledge
|
||||
- name: 💬 Misskey official Discord
|
||||
url: https://discord.gg/Wp8gVStHW3
|
||||
about: Chat freely about Misskey
|
17
.github/PULL_REQUEST_TEMPLATE.md
vendored
17
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -1,17 +0,0 @@
|
|||
<!-- ℹ お読みください / README
|
||||
PRありがとうございます! PRを作成する前に、コントリビューションガイドをご確認ください:
|
||||
Thank you for your PR! Before creating a PR, please check the contribution guide:
|
||||
https://github.com/misskey-dev/misskey/blob/develop/CONTRIBUTING.md
|
||||
-->
|
||||
|
||||
# What
|
||||
<!-- このPRで何をしたのか? どう変わるのか? -->
|
||||
<!-- What did you do with this PR? How will it change things? -->
|
||||
|
||||
# Why
|
||||
<!-- なぜそうするのか? どういう意図なのか? 何が困っているのか? -->
|
||||
<!-- Why do you do it? What are your intentions? What is the problem? -->
|
||||
|
||||
# Additional info (optional)
|
||||
<!-- テスト観点など -->
|
||||
<!-- Test perspective, etc -->
|
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -11,15 +11,25 @@ You should also include the user name that made the change.
|
|||
|
||||
## 12.x.x (unreleased)
|
||||
|
||||
### Changes
|
||||
- ハイライトがみつけるに統合されました
|
||||
- カスタム絵文字ページはインスタンス情報ページに統合されました
|
||||
- 連合ページはインスタンス情報ページに統合されました
|
||||
|
||||
### Improvements
|
||||
- Client: Fix URL-encoded routing
|
||||
- Server: Allow GET method for some endpoints @syuilo
|
||||
- Server: Add rate limit to i/notifications @tamaina
|
||||
- Client: Improve control panel @syuilo
|
||||
- Client: Show warning in control panel when there is an unresolved abuse report @syuilo
|
||||
- Client: For notes with specified visibility, show recipients when hovering over visibility symbol. @Johann150
|
||||
- Client: Add rss-ticker widget @syuilo
|
||||
- Client: Removing entries from a clip @futchitwo
|
||||
- Client: Poll highlights in explore page @syuilo
|
||||
- Make possible to delete an account by admin @syuilo
|
||||
- Improve player detection in URL preview @mei23
|
||||
- Add Badge Image to Push Notification #8012 @tamaina
|
||||
- Client: Removing entries from a clip @futchitwo
|
||||
- Server: Improve performance
|
||||
- Server: Supports IPv6 on Redis transport. @mei23
|
||||
IPv4/IPv6 is used by default. You can tune this behavior via `redis.family`.
|
||||
|
||||
|
|
|
@ -734,7 +734,6 @@ gallery: "المعرض"
|
|||
recentPosts: "المشاركات الحديثة"
|
||||
popularPosts: "المشاركات المتداولة"
|
||||
shareWithNote: "شاركه في ملاحظة"
|
||||
ads: "الإعلانات"
|
||||
expiration: "ينتهي استطلاع الرأي في"
|
||||
memo: "تذكير"
|
||||
priority: "الأولوية"
|
||||
|
@ -786,7 +785,6 @@ voteConfirm: "متيقِّن من تصويتك لـ {choice}؟"
|
|||
hide: "إخفاء"
|
||||
leaveGroup: "مغادرة الفريق"
|
||||
leaveGroupConfirm: "متيقن من مغادرة \"{name}\"؟"
|
||||
welcomeBackWithName: "مرحبًا بك مجددًا {name}"
|
||||
clickToFinishEmailVerification: "انقر [{ok}] لاستيثاق بريدك الإلكتروني."
|
||||
overridedDeviceKind: "نوع الجهاز"
|
||||
smartphone: "هاتف ذكي"
|
||||
|
|
|
@ -765,7 +765,6 @@ gallery: "গ্যালারী"
|
|||
recentPosts: "নতুন পোস্ট"
|
||||
popularPosts: "জনপ্রিয় পোস্ট"
|
||||
shareWithNote: "নোটের মাধ্যমে শেয়ার করুন"
|
||||
ads: "বিজ্ঞাপন"
|
||||
expiration: "নির্দিষ্ট সময়সীমা"
|
||||
memo: "মেমো"
|
||||
priority: "অগ্রাধিকার"
|
||||
|
@ -821,7 +820,6 @@ hide: "লুকান"
|
|||
leaveGroup: "গ্রুপ ছেড়ে চলে যান"
|
||||
leaveGroupConfirm: "\"{name}\" গ্রুপ ছেড়ে চলে যেতে চান?"
|
||||
useDrawerReactionPickerForMobile: "মোবাইলে রিঅ্যাকশন পিকারকে ড্রয়ারে প্রদর্শন করুন"
|
||||
welcomeBackWithName: "আবার স্বাগতম, {name}"
|
||||
clickToFinishEmailVerification: " [{ok}] ক্লিক করার মাধ্যমে আপনার ইমেল ঠিকানা নিশ্চিত করুন।"
|
||||
overridedDeviceKind: "ডিভাইসের ধরন"
|
||||
smartphone: "স্মার্টফোন"
|
||||
|
|
|
@ -766,7 +766,6 @@ gallery: "Galerie"
|
|||
recentPosts: "Neue Beiträge"
|
||||
popularPosts: "Beliebte Beiträge"
|
||||
shareWithNote: "Mit Notiz teilen"
|
||||
ads: "Werbung"
|
||||
expiration: "Frist"
|
||||
memo: "Merkzettel"
|
||||
priority: "Priorität"
|
||||
|
@ -822,7 +821,6 @@ hide: "Inhalt verbergen"
|
|||
leaveGroup: "Gruppe verlassen"
|
||||
leaveGroupConfirm: "Möchtest du „{name}“ wirklich verlassen?"
|
||||
useDrawerReactionPickerForMobile: "Auf mobilen Geräten ausfahrbare Reaktionsauswahl anzeigen"
|
||||
welcomeBackWithName: "Willkommen zurück, {name}"
|
||||
clickToFinishEmailVerification: "Drücke bitte auf [{ok}], um die Email-Bestätigung abzuschließen."
|
||||
overridedDeviceKind: "Gerätetyp"
|
||||
smartphone: "Smartphone"
|
||||
|
@ -1659,3 +1657,17 @@ _deck:
|
|||
list: "Listen"
|
||||
mentions: "Erwähnungen"
|
||||
direct: "Direktnachrichten"
|
||||
recentNHours: "Letzten {n} Stunden"
|
||||
recentNDays: "Letzten {n} Tage"
|
||||
isSystemAccount: "Ein Benutzerkonto, dass durch das System erstellt und automatisch kontrolliert wird."
|
||||
typeToConfirm: "Bitte gib zur Bestätigung {x} ein"
|
||||
deleteAccount: "Benutzerkonto löschen"
|
||||
numberOfPageCache: "Seitencachegröße"
|
||||
numberOfPageCacheDescription: "Das Erhöhen dieses Caches führt zu einer angenehmerern Benutzererfahrung, erhöht aber Serverlast und Arbeitsspeicherauslastung."
|
||||
file: "Datei"
|
||||
unclip: "Aus Clip entfernen"
|
||||
confirmToUnclipAlreadyClippedNote: "Diese Notiz ist bereits im \"{name}\" Clip enthalten. Möchtest du sie aus diesem Clip entfernen?"
|
||||
noEmailServerWarning: "Es ist kein Email-Server konfiguriert."
|
||||
thereIsUnresolvedAbuseReportWarning: "Es liegen ungelöste Meldungen vor."
|
||||
recommended: "Empfehlung"
|
||||
check: "Check"
|
||||
|
|
|
@ -766,7 +766,6 @@ gallery: "Gallery"
|
|||
recentPosts: "Recent posts"
|
||||
popularPosts: "Popular posts"
|
||||
shareWithNote: "Share with note"
|
||||
ads: "Advertisements"
|
||||
expiration: "Deadline"
|
||||
memo: "Memo"
|
||||
priority: "Priority"
|
||||
|
@ -822,7 +821,6 @@ hide: "Hide"
|
|||
leaveGroup: "Leave group"
|
||||
leaveGroupConfirm: "Are you sure you want to leave \"{name}\"?"
|
||||
useDrawerReactionPickerForMobile: "Display reaction picker as drawer on mobile"
|
||||
welcomeBackWithName: "Welcome back, {name}"
|
||||
clickToFinishEmailVerification: "Please click [{ok}] to complete email verification."
|
||||
overridedDeviceKind: "Device type"
|
||||
smartphone: "Smartphone"
|
||||
|
@ -852,6 +850,13 @@ typeToConfirm: "Please enter {x} to confirm"
|
|||
deleteAccount: "Delete account"
|
||||
numberOfPageCache: "Number of cached pages"
|
||||
numberOfPageCacheDescription: "Increasing this number will improve convenience for users but cause more server load as well as more memory to be used."
|
||||
file: "File"
|
||||
unclip: "Unclip"
|
||||
confirmToUnclipAlreadyClippedNote: "This note is already part of the \"{name}\" clip. Do you want to remove it from this clip instead?"
|
||||
noEmailServerWarning: "Email server not configured."
|
||||
thereIsUnresolvedAbuseReportWarning: "There are unsolved reports."
|
||||
recommended: "Recommended"
|
||||
check: "Check"
|
||||
_emailUnavailable:
|
||||
used: "This email address is already being used"
|
||||
format: "The format of this email address is invalid"
|
||||
|
@ -1206,6 +1211,7 @@ _widgets:
|
|||
trends: "Trending"
|
||||
clock: "Clock"
|
||||
rss: "RSS reader"
|
||||
rssMarquee: "RSS ticker"
|
||||
activity: "Activity"
|
||||
photos: "Photos"
|
||||
digitalClock: "Digital clock"
|
||||
|
|
|
@ -761,7 +761,6 @@ gallery: "Galería"
|
|||
recentPosts: "Posts recientes"
|
||||
popularPosts: "Más vistos"
|
||||
shareWithNote: "Compartir con una nota"
|
||||
ads: "Anuncios"
|
||||
expiration: "Termina el"
|
||||
memo: "Notas"
|
||||
priority: "Prioridad"
|
||||
|
|
|
@ -760,7 +760,6 @@ gallery: "Galerie"
|
|||
recentPosts: "Les plus récentes"
|
||||
popularPosts: "Les plus consultées"
|
||||
shareWithNote: "Partager dans une note"
|
||||
ads: "Publicité"
|
||||
expiration: "Échéance"
|
||||
memo: "Pense-bête"
|
||||
priority: "Priorité"
|
||||
|
@ -815,7 +814,6 @@ voteConfirm: "Confirmez-vous votre vote pour « {choice} » ?"
|
|||
hide: "Masquer"
|
||||
leaveGroup: "Quitter le groupe"
|
||||
leaveGroupConfirm: "Êtes vous sûr de vouloir quitter \"{name}\" ?"
|
||||
welcomeBackWithName: "Heureux de vous revoir, {name}"
|
||||
clickToFinishEmailVerification: "Veuillez cliquer sur [{ok}] afin de compléter la vérification par courriel."
|
||||
overridedDeviceKind: "Type d’appareil"
|
||||
smartphone: "Smartphone"
|
||||
|
|
|
@ -765,7 +765,6 @@ gallery: "Galeri"
|
|||
recentPosts: "Postingan terbaru"
|
||||
popularPosts: "Postingan populer"
|
||||
shareWithNote: "Bagikan dengan catatan"
|
||||
ads: "Iklan"
|
||||
expiration: "Batas akhir"
|
||||
memo: "Memo"
|
||||
priority: "Prioritas"
|
||||
|
@ -821,7 +820,6 @@ hide: "Sembunyikan"
|
|||
leaveGroup: "Keluar grup"
|
||||
leaveGroupConfirm: "Apakah kamu yakin untuk keluar dari \"{name}\"?"
|
||||
useDrawerReactionPickerForMobile: "Tampilkan bilah reaksi sebagai laci di ponsel"
|
||||
welcomeBackWithName: "Selamat datang kembali, {name}."
|
||||
clickToFinishEmailVerification: "Mohon klik [{ok}] untuk menyelesaikan verifikasi email."
|
||||
overridedDeviceKind: "Tipe perangkat"
|
||||
smartphone: "Ponsel"
|
||||
|
|
|
@ -753,7 +753,6 @@ gallery: "Galleria"
|
|||
recentPosts: "Le più recenti"
|
||||
popularPosts: "Le più visualizzate"
|
||||
shareWithNote: "Condividere in nota"
|
||||
ads: "Pubblicità"
|
||||
expiration: "Scadenza"
|
||||
memo: "Promemoria"
|
||||
priority: "Priorità"
|
||||
|
@ -801,7 +800,6 @@ hide: "Nascondere"
|
|||
leaveGroup: "Esci dal gruppo"
|
||||
leaveGroupConfirm: "Uscire da「{name}」?"
|
||||
useDrawerReactionPickerForMobile: "Mostra sul drawer da dispositivo mobile"
|
||||
welcomeBackWithName: "Bentornato/a, {name}"
|
||||
clickToFinishEmailVerification: "Fai click su [{ok}] per completare la verifica dell'indirizzo email."
|
||||
indefinitely: "Non scade"
|
||||
tenMinutes: "10 minuti"
|
||||
|
|
|
@ -768,7 +768,6 @@ gallery: "ギャラリー"
|
|||
recentPosts: "最近の投稿"
|
||||
popularPosts: "人気の投稿"
|
||||
shareWithNote: "ノートで共有"
|
||||
ads: "広告"
|
||||
expiration: "期限"
|
||||
memo: "メモ"
|
||||
priority: "優先度"
|
||||
|
@ -824,7 +823,6 @@ hide: "隠す"
|
|||
leaveGroup: "グループから抜ける"
|
||||
leaveGroupConfirm: "「{name}」から抜けますか?"
|
||||
useDrawerReactionPickerForMobile: "モバイルデバイスのときドロワーで表示"
|
||||
welcomeBackWithName: "おかえりなさい、{name}さん"
|
||||
clickToFinishEmailVerification: "[{ok}]を押して、メールアドレスの確認を完了してください。"
|
||||
overridedDeviceKind: "デバイスタイプ"
|
||||
smartphone: "スマートフォン"
|
||||
|
@ -1244,6 +1242,7 @@ _widgets:
|
|||
trends: "トレンド"
|
||||
clock: "時計"
|
||||
rss: "RSSリーダー"
|
||||
rssTicker: "RSSティッカー"
|
||||
activity: "アクティビティ"
|
||||
photos: "フォト"
|
||||
digitalClock: "デジタル時計"
|
||||
|
|
|
@ -645,7 +645,6 @@ goBack: "戻る"
|
|||
info: "情報"
|
||||
user: "ユーザー"
|
||||
administration: "管理"
|
||||
ads: "広告"
|
||||
expiration: "期限"
|
||||
memo: "メモ"
|
||||
high: "高い"
|
||||
|
|
|
@ -765,7 +765,6 @@ gallery: "갤러리"
|
|||
recentPosts: "최근 포스트"
|
||||
popularPosts: "인기 포스트"
|
||||
shareWithNote: "노트로 공유"
|
||||
ads: "광고"
|
||||
expiration: "기한"
|
||||
memo: "메모"
|
||||
priority: "우선순위"
|
||||
|
@ -821,7 +820,6 @@ hide: "숨기기"
|
|||
leaveGroup: "그룹 나가기"
|
||||
leaveGroupConfirm: "\"{name}\"에서 나갈까요?"
|
||||
useDrawerReactionPickerForMobile: "모바일에서 드로어 메뉴로 표시"
|
||||
welcomeBackWithName: "환영합니다, {name}님"
|
||||
clickToFinishEmailVerification: "[{ok}]를 눌러 이메일 인증을 완료하세요."
|
||||
overridedDeviceKind: "장치 유형"
|
||||
smartphone: "스마트폰"
|
||||
|
|
|
@ -739,7 +739,6 @@ gallery: "Galeria"
|
|||
recentPosts: "Ostatnie wpisy"
|
||||
popularPosts: "Popularne wpisy"
|
||||
shareWithNote: "Udostępnij z wpisem"
|
||||
ads: "Reklamy"
|
||||
expiration: "Ankieta kończy się"
|
||||
memo: "Notatki"
|
||||
priority: "Priorytet"
|
||||
|
|
|
@ -763,7 +763,6 @@ gallery: "Галерея"
|
|||
recentPosts: "Недавние публикации"
|
||||
popularPosts: "Популярные публикации"
|
||||
shareWithNote: "Поделиться заметкой"
|
||||
ads: "Реклама"
|
||||
expiration: "Опрос длится"
|
||||
memo: "Памятка"
|
||||
priority: "Приоритет"
|
||||
|
@ -819,7 +818,6 @@ hide: "Спрятать"
|
|||
leaveGroup: "Покинуть группу"
|
||||
leaveGroupConfirm: "Покинуть группу «{name}»?"
|
||||
useDrawerReactionPickerForMobile: "Выдвижная палитра на мобильном устройстве"
|
||||
welcomeBackWithName: "С возвращением, {name}!"
|
||||
clickToFinishEmailVerification: "Пожалуйста, нажмите [{ok}], чтобы завершить подтверждение адреса электронной почты."
|
||||
overridedDeviceKind: "Тип устройства"
|
||||
smartphone: "Смартфон"
|
||||
|
|
|
@ -764,7 +764,6 @@ gallery: "Galéria"
|
|||
recentPosts: "Najnovšie príspevky"
|
||||
popularPosts: "Populárne príspevky"
|
||||
shareWithNote: "Zdieľať s poznámkou"
|
||||
ads: "Reklamy"
|
||||
expiration: "Ukončiť hlasovanie"
|
||||
memo: "Memo"
|
||||
priority: "Priorita"
|
||||
|
@ -820,7 +819,6 @@ hide: "Skryť"
|
|||
leaveGroup: "Opustiť skupiny"
|
||||
leaveGroupConfirm: "Naozaj chcete opustiť \"{name}\"?"
|
||||
useDrawerReactionPickerForMobile: "Zobraziť výber reakcií ako šuflík na mobile"
|
||||
welcomeBackWithName: "Vitajte späť, {name}"
|
||||
clickToFinishEmailVerification: "Kliknutím na [{ok}] dokončíte overeniu emailu."
|
||||
overridedDeviceKind: "Typ zariadenia"
|
||||
smartphone: "Smartfón"
|
||||
|
|
|
@ -765,7 +765,6 @@ gallery: "Thư viện ảnh"
|
|||
recentPosts: "Tút gần đây"
|
||||
popularPosts: "Tút được xem nhiều nhất"
|
||||
shareWithNote: "Chia sẻ kèm với tút"
|
||||
ads: "Quảng cáo"
|
||||
expiration: "Thời hạn"
|
||||
memo: "Lưu ý"
|
||||
priority: "Ưu tiên"
|
||||
|
@ -821,7 +820,6 @@ hide: "Ẩn"
|
|||
leaveGroup: "Rời khỏi nhóm"
|
||||
leaveGroupConfirm: "Bạn có chắc muốn rời khỏi nhóm \"{name}\"?"
|
||||
useDrawerReactionPickerForMobile: "Hiện bộ chọn biểu cảm dạng xổ ra trên điện thoại"
|
||||
welcomeBackWithName: "Chào mừng trở lại, {name}"
|
||||
clickToFinishEmailVerification: "Vui lòng nhấn [{ok}] để hoàn tất việc đăng ký."
|
||||
overridedDeviceKind: "Loại thiết bị"
|
||||
smartphone: "Điện thoại"
|
||||
|
|
|
@ -765,7 +765,6 @@ gallery: "图库"
|
|||
recentPosts: "最新发布"
|
||||
popularPosts: "热门投稿"
|
||||
shareWithNote: "在帖子中分享"
|
||||
ads: "广告"
|
||||
expiration: "截止时间"
|
||||
memo: "便笺"
|
||||
priority: "优先级"
|
||||
|
@ -821,7 +820,6 @@ hide: "隐藏"
|
|||
leaveGroup: "离开群组"
|
||||
leaveGroupConfirm: "确定离开「{name}」?"
|
||||
useDrawerReactionPickerForMobile: "在移动设备上使用抽屉显示"
|
||||
welcomeBackWithName: "欢迎回来,{name}"
|
||||
clickToFinishEmailVerification: "点击 [{ok}] 完成电子邮件地址认证。"
|
||||
overridedDeviceKind: "设备类型"
|
||||
smartphone: "智能手机"
|
||||
|
|
|
@ -765,7 +765,6 @@ gallery: "相簿"
|
|||
recentPosts: "最新貼文"
|
||||
popularPosts: "熱門的貼文"
|
||||
shareWithNote: "在貼文中分享"
|
||||
ads: "廣告"
|
||||
expiration: "期限"
|
||||
memo: "備忘錄"
|
||||
priority: "優先級"
|
||||
|
@ -821,7 +820,6 @@ hide: "隱藏"
|
|||
leaveGroup: "離開群組"
|
||||
leaveGroupConfirm: "確定離開「{name}」?"
|
||||
useDrawerReactionPickerForMobile: "在移動設備上使用抽屜顯示"
|
||||
welcomeBackWithName: "歡迎回來,{name}"
|
||||
clickToFinishEmailVerification: "點擊 [{ok}] 完成電子郵件地址認證。"
|
||||
overridedDeviceKind: "裝置類型"
|
||||
smartphone: "智慧型手機"
|
||||
|
|
11
package.json
11
package.json
|
@ -1,10 +1,9 @@
|
|||
{
|
||||
"name": "misskey",
|
||||
"name": "foundkey",
|
||||
"version": "12.111.1-test.1",
|
||||
"codename": "indigo",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/misskey-dev/misskey.git"
|
||||
"url": "https://akkoma.dev/FoundKeyGang/FoundKey.git"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
@ -41,10 +40,10 @@
|
|||
"devDependencies": {
|
||||
"@types/gulp": "4.0.9",
|
||||
"@types/gulp-rename": "2.0.1",
|
||||
"@typescript-eslint/parser": "5.27.1",
|
||||
"@typescript-eslint/parser": "5.30.0",
|
||||
"cross-env": "7.0.3",
|
||||
"cypress": "10.0.3",
|
||||
"cypress": "10.3.0",
|
||||
"start-server-and-test": "1.14.0",
|
||||
"typescript": "4.7.3"
|
||||
"typescript": "4.7.4"
|
||||
}
|
||||
}
|
||||
|
|
12
packages/backend/migration/1657570176749-remove-ads.ts
Normal file
12
packages/backend/migration/1657570176749-remove-ads.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
export class removeAds1657570176749 {
|
||||
name = 'removeAds1657570176749'
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`DROP TABLE "ad"`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`CREATE TABLE public.ad ("id" character varying(32) NOT NULL, "createdAt" timestamp with time zone NOT NULL, "expiresAt" timestamp with time zone NOT NULL, "place" character varying(32) NOT NULL, "priority" character varying(32) NOT NULL, "url" character varying(1024) NOT NULL, "imageUrl" character varying(1024) NOT NULL, "memo" character varying(8192) NOT NULL, "ratio" integer DEFAULT 1 NOT NULL)`);
|
||||
}
|
||||
|
||||
}
|
13
packages/backend/migration/1658146000392-remove-repo-url.js
Normal file
13
packages/backend/migration/1658146000392-remove-repo-url.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
export class removeRepoUrl1658146000392 {
|
||||
name = 'removeRepoUrl1658146000392';
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "repositoryUrl"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "feedbackUrl"`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "repositoryUrl" character varying(512) not null default 'https://github.com/misskey-dev/misskey'`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "feedbackUrl" character varying(512) default 'https://github.com/misskey-dev/misskey/issues/new'`);
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json || echo done. && tsc-alias -p tsconfig.json",
|
||||
"watch": "node watch.mjs",
|
||||
"lint": "eslint --quiet \"src/**/*.ts\"",
|
||||
"lint": "eslint --quiet src --ext .ts",
|
||||
"mocha": "cross-env NODE_ENV=test TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT=\"./test/tsconfig.json\" mocha",
|
||||
"test": "npm run mocha"
|
||||
},
|
||||
|
@ -14,7 +14,7 @@
|
|||
"lodash": "^4.17.21"
|
||||
},
|
||||
"dependencies": {
|
||||
"@bull-board/koa": "3.11.1",
|
||||
"@bull-board/koa": "4.0.0",
|
||||
"@discordapp/twemoji": "14.0.2",
|
||||
"@elastic/elasticsearch": "7.11.0",
|
||||
"@koa/cors": "3.1.0",
|
||||
|
@ -28,10 +28,10 @@
|
|||
"archiver": "5.3.1",
|
||||
"autobind-decorator": "2.4.0",
|
||||
"autwh": "0.1.0",
|
||||
"aws-sdk": "2.1152.0",
|
||||
"aws-sdk": "2.1165.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"blurhash": "1.1.5",
|
||||
"bull": "4.8.3",
|
||||
"bull": "4.8.4",
|
||||
"cacheable-lookup": "6.0.4",
|
||||
"cbor": "8.1.0",
|
||||
"chalk": "5.0.1",
|
||||
|
@ -51,7 +51,7 @@
|
|||
"ip-cidr": "3.0.10",
|
||||
"is-svg": "4.3.2",
|
||||
"js-yaml": "4.1.0",
|
||||
"jsdom": "19.0.0",
|
||||
"jsdom": "20.0.0",
|
||||
"json5": "2.2.1",
|
||||
"json5-loader": "4.0.1",
|
||||
"jsonld": "6.0.0",
|
||||
|
@ -69,29 +69,29 @@
|
|||
"mime-types": "2.1.35",
|
||||
"misskey-js": "0.0.14",
|
||||
"mocha": "10.0.0",
|
||||
"ms": "3.0.0-canary.1",
|
||||
"multer": "1.4.4",
|
||||
"nested-property": "4.0.0",
|
||||
"node-fetch": "3.2.6",
|
||||
"nodemailer": "6.7.5",
|
||||
"nodemailer": "6.7.6",
|
||||
"os-utils": "0.0.14",
|
||||
"parse5": "6.0.1",
|
||||
"parse5": "7.0.0",
|
||||
"pg": "8.7.3",
|
||||
"private-ip": "2.3.3",
|
||||
"probe-image-size": "7.2.3",
|
||||
"promise-limit": "2.7.0",
|
||||
"pug": "3.0.2",
|
||||
"punycode": "2.1.1",
|
||||
"pureimage": "0.3.8",
|
||||
"pureimage": "0.3.14",
|
||||
"qrcode": "1.5.0",
|
||||
"random-seed": "0.3.0",
|
||||
"ratelimiter": "3.4.1",
|
||||
"re2": "1.17.4",
|
||||
"re2": "1.17.7",
|
||||
"redis-lock": "0.1.4",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rename": "1.0.4",
|
||||
"require-all": "3.0.0",
|
||||
"rndstr": "1.0.0",
|
||||
"rss-parser": "3.12.0",
|
||||
"s-age": "1.1.2",
|
||||
"sanitize-html": "2.7.0",
|
||||
"semver": "7.3.7",
|
||||
|
@ -102,16 +102,15 @@
|
|||
"style-loader": "3.3.1",
|
||||
"summaly": "2.6.0",
|
||||
"syslog-pro": "1.0.0",
|
||||
"systeminformation": "5.11.16",
|
||||
"systeminformation": "5.11.22",
|
||||
"tinycolor2": "1.4.2",
|
||||
"tmp": "0.2.1",
|
||||
"ts-loader": "9.3.0",
|
||||
"ts-loader": "9.3.1",
|
||||
"ts-node": "10.8.1",
|
||||
"tsc-alias": "1.6.9",
|
||||
"tsc-alias": "1.6.11",
|
||||
"tsconfig-paths": "4.0.0",
|
||||
"twemoji-parser": "14.0.0",
|
||||
"typeorm": "0.3.6",
|
||||
"ulid": "2.3.0",
|
||||
"typeorm": "0.3.7",
|
||||
"unzipper": "0.10.11",
|
||||
"uuid": "8.3.2",
|
||||
"web-push": "3.5.0",
|
||||
|
@ -121,7 +120,6 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@redocly/openapi-core": "1.0.0-beta.97",
|
||||
"@types/semver": "7.3.9",
|
||||
"@types/bcryptjs": "2.4.2",
|
||||
"@types/bull": "3.15.8",
|
||||
"@types/cbor": "6.0.0",
|
||||
|
@ -144,11 +142,10 @@
|
|||
"@types/koa__multer": "2.0.4",
|
||||
"@types/koa__router": "8.0.11",
|
||||
"@types/mocha": "9.1.1",
|
||||
"@types/node": "17.0.41",
|
||||
"@types/node": "18.0.0",
|
||||
"@types/node-fetch": "3.0.3",
|
||||
"@types/nodemailer": "6.4.4",
|
||||
"@types/oauth": "0.9.1",
|
||||
"@types/parse5": "6.0.3",
|
||||
"@types/pug": "2.0.6",
|
||||
"@types/punycode": "2.1.0",
|
||||
"@types/qrcode": "1.4.2",
|
||||
|
@ -157,7 +154,8 @@
|
|||
"@types/redis": "4.0.11",
|
||||
"@types/rename": "1.0.4",
|
||||
"@types/sanitize-html": "2.6.2",
|
||||
"@types/sharp": "0.30.2",
|
||||
"@types/semver": "7.3.10",
|
||||
"@types/sharp": "0.30.4",
|
||||
"@types/sinonjs__fake-timers": "8.1.2",
|
||||
"@types/speakeasy": "2.0.7",
|
||||
"@types/tinycolor2": "1.4.3",
|
||||
|
@ -166,12 +164,12 @@
|
|||
"@types/web-push": "3.3.2",
|
||||
"@types/websocket": "1.0.5",
|
||||
"@types/ws": "8.5.3",
|
||||
"@typescript-eslint/eslint-plugin": "5.27.1",
|
||||
"@typescript-eslint/parser": "5.27.1",
|
||||
"typescript": "4.7.3",
|
||||
"eslint": "8.17.0",
|
||||
"eslint-plugin-import": "2.26.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.30.0",
|
||||
"@typescript-eslint/parser": "^5.30.0",
|
||||
"cross-env": "7.0.3",
|
||||
"execa": "6.1.0"
|
||||
"eslint": "^8.20.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"execa": "6.1.0",
|
||||
"typescript": "^4.7.4"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ export default function load() {
|
|||
const clientManifest = JSON.parse(fs.readFileSync(`${_dirname}/../../../../built/_client_dist_/manifest.json`, 'utf-8'));
|
||||
const config = yaml.load(fs.readFileSync(path, 'utf-8')) as Source;
|
||||
|
||||
if (config.id && config.id !== 'aid') throw new Error('Unsupported ID algorithm. Only "aid" is supported.');
|
||||
|
||||
const mixin = {} as Mixin;
|
||||
|
||||
const url = tryCreateUrl(config.url);
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
export const MAX_NOTE_TEXT_LENGTH = 3000;
|
||||
|
||||
export const SECOND = 1000;
|
||||
export const MINUTE = 60 * SECOND;
|
||||
export const HOUR = 60 * MINUTE;
|
||||
export const DAY = 24 * HOUR;
|
||||
|
||||
export const USER_ONLINE_THRESHOLD = 1000 * 60 * 10; // 10min
|
||||
export const USER_ACTIVE_THRESHOLD = 1000 * 60 * 60 * 24 * 3; // 3days
|
||||
|
||||
|
|
|
@ -65,7 +65,6 @@ import { Channel } from '@/models/entities/channel.js';
|
|||
import { ChannelFollowing } from '@/models/entities/channel-following.js';
|
||||
import { ChannelNotePining } from '@/models/entities/channel-note-pining.js';
|
||||
import { RegistryItem } from '@/models/entities/registry-item.js';
|
||||
import { Ad } from '@/models/entities/ad.js';
|
||||
import { PasswordResetRequest } from '@/models/entities/password-reset-request.js';
|
||||
import { UserPending } from '@/models/entities/user-pending.js';
|
||||
|
||||
|
@ -168,7 +167,6 @@ export const entities = [
|
|||
ChannelFollowing,
|
||||
ChannelNotePining,
|
||||
RegistryItem,
|
||||
Ad,
|
||||
PasswordResetRequest,
|
||||
UserPending,
|
||||
Webhook,
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import * as parse5 from 'parse5';
|
||||
import treeAdapter from 'parse5/lib/tree-adapters/default.js';
|
||||
import { URL } from 'node:url';
|
||||
import * as parse5 from 'parse5';
|
||||
import * as TreeAdapter from '../../node_modules/parse5/dist/tree-adapters/default.js';
|
||||
|
||||
const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/;
|
||||
const treeAdapter = TreeAdapter.defaultTreeAdapter;
|
||||
|
||||
const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/;
|
||||
const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/;
|
||||
|
||||
export function fromHtml(html: string, hashtagNames?: string[]): string {
|
||||
|
@ -19,7 +21,7 @@ export function fromHtml(html: string, hashtagNames?: string[]): string {
|
|||
|
||||
return text.trim();
|
||||
|
||||
function getText(node: parse5.Node): string {
|
||||
function getText(node: TreeAdapter.Node): string {
|
||||
if (treeAdapter.isTextNode(node)) return node.value;
|
||||
if (!treeAdapter.isElementNode(node)) return '';
|
||||
if (node.nodeName === 'br') return '\n';
|
||||
|
@ -31,7 +33,7 @@ export function fromHtml(html: string, hashtagNames?: string[]): string {
|
|||
return '';
|
||||
}
|
||||
|
||||
function appendChildren(childNodes: parse5.ChildNode[]): void {
|
||||
function appendChildren(childNodes: TreeAdapter.ChildNode[]): void {
|
||||
if (childNodes) {
|
||||
for (const n of childNodes) {
|
||||
analyze(n);
|
||||
|
@ -39,7 +41,7 @@ export function fromHtml(html: string, hashtagNames?: string[]): string {
|
|||
}
|
||||
}
|
||||
|
||||
function analyze(node: parse5.Node) {
|
||||
function analyze(node: TreeAdapter.Node) {
|
||||
if (treeAdapter.isTextNode(node)) {
|
||||
text += node.value;
|
||||
return;
|
||||
|
@ -170,7 +172,7 @@ export function fromHtml(html: string, hashtagNames?: string[]): string {
|
|||
const t = getText(node);
|
||||
if (t) {
|
||||
text += '\n> ';
|
||||
text += t.split('\n').join(`\n> `);
|
||||
text += t.split('\n').join('\n> ');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
import { ulid } from 'ulid';
|
||||
import { genAid } from './id/aid.js';
|
||||
import { genMeid } from './id/meid.js';
|
||||
import { genMeidg } from './id/meidg.js';
|
||||
import { genObjectId } from './id/object-id.js';
|
||||
import config from '@/config/index.js';
|
||||
import * as crypto from 'node:crypto';
|
||||
|
||||
const metohd = config.id.toLowerCase();
|
||||
// AID generation
|
||||
// 8 chars: milliseconds elapsed since 2000-01-01 00:00:00.000Z encoded as base36
|
||||
// + 2 random chars
|
||||
|
||||
const TIME2000 = 946684800000;
|
||||
let counter = crypto.randomBytes(2).readUInt16LE(0);
|
||||
|
||||
export function genId(date?: Date): string {
|
||||
if (!date || (date > new Date())) date = new Date();
|
||||
|
||||
switch (metohd) {
|
||||
case 'aid': return genAid(date);
|
||||
case 'meid': return genMeid(date);
|
||||
case 'meidg': return genMeidg(date);
|
||||
case 'ulid': return ulid(date.getTime());
|
||||
case 'objectid': return genObjectId(date);
|
||||
default: throw new Error('unrecognized id generation method');
|
||||
}
|
||||
let t = date.getTime();
|
||||
t -= TIME2000;
|
||||
if (t < 0) t = 0;
|
||||
if (isNaN(t)) throw 'Failed to create AID: Invalid Date';
|
||||
const time = t.toString(36).padStart(8, '0');
|
||||
|
||||
counter++;
|
||||
const noise = counter.toString(36).padStart(2, '0').slice(-2);
|
||||
|
||||
return time + noise;
|
||||
}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
// AID
|
||||
// 長さ8の[2000年1月1日からの経過ミリ秒をbase36でエンコードしたもの] + 長さ2の[ノイズ文字列]
|
||||
|
||||
import * as crypto from 'node:crypto';
|
||||
|
||||
const TIME2000 = 946684800000;
|
||||
let counter = crypto.randomBytes(2).readUInt16LE(0);
|
||||
|
||||
function getTime(time: number) {
|
||||
time = time - TIME2000;
|
||||
if (time < 0) time = 0;
|
||||
|
||||
return time.toString(36).padStart(8, '0');
|
||||
}
|
||||
|
||||
function getNoise() {
|
||||
return counter.toString(36).padStart(2, '0').slice(-2);
|
||||
}
|
||||
|
||||
export function genAid(date: Date): string {
|
||||
const t = date.getTime();
|
||||
if (isNaN(t)) throw 'Failed to create AID: Invalid Date';
|
||||
counter++;
|
||||
return getTime(t) + getNoise();
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
const CHARS = '0123456789abcdef';
|
||||
|
||||
function getTime(time: number) {
|
||||
if (time < 0) time = 0;
|
||||
if (time === 0) {
|
||||
return CHARS[0];
|
||||
}
|
||||
|
||||
time += 0x800000000000;
|
||||
|
||||
return time.toString(16).padStart(12, CHARS[0]);
|
||||
}
|
||||
|
||||
function getRandom() {
|
||||
let str = '';
|
||||
|
||||
for (let i = 0; i < 12; i++) {
|
||||
str += CHARS[Math.floor(Math.random() * CHARS.length)];
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
export function genMeid(date: Date): string {
|
||||
return getTime(date.getTime()) + getRandom();
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
const CHARS = '0123456789abcdef';
|
||||
|
||||
// 4bit Fixed hex value 'g'
|
||||
// 44bit UNIX Time ms in Hex
|
||||
// 48bit Random value in Hex
|
||||
|
||||
function getTime(time: number) {
|
||||
if (time < 0) time = 0;
|
||||
if (time === 0) {
|
||||
return CHARS[0];
|
||||
}
|
||||
|
||||
return time.toString(16).padStart(11, CHARS[0]);
|
||||
}
|
||||
|
||||
function getRandom() {
|
||||
let str = '';
|
||||
|
||||
for (let i = 0; i < 12; i++) {
|
||||
str += CHARS[Math.floor(Math.random() * CHARS.length)];
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
export function genMeidg(date: Date): string {
|
||||
return 'g' + getTime(date.getTime()) + getRandom();
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
const CHARS = '0123456789abcdef';
|
||||
|
||||
function getTime(time: number) {
|
||||
if (time < 0) time = 0;
|
||||
if (time === 0) {
|
||||
return CHARS[0];
|
||||
}
|
||||
|
||||
time = Math.floor(time / 1000);
|
||||
|
||||
return time.toString(16).padStart(8, CHARS[0]);
|
||||
}
|
||||
|
||||
function getRandom() {
|
||||
let str = '';
|
||||
|
||||
for (let i = 0; i < 16; i++) {
|
||||
str += CHARS[Math.floor(Math.random() * CHARS.length)];
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
export function genObjectId(date: Date): string {
|
||||
return getTime(date.getTime()) + getRandom();
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
import { Entity, Index, Column, PrimaryColumn } from 'typeorm';
|
||||
import { id } from '../id.js';
|
||||
|
||||
@Entity()
|
||||
export class Ad {
|
||||
@PrimaryColumn(id())
|
||||
public id: string;
|
||||
|
||||
@Index()
|
||||
@Column('timestamp with time zone', {
|
||||
comment: 'The created date of the Ad.',
|
||||
})
|
||||
public createdAt: Date;
|
||||
|
||||
@Index()
|
||||
@Column('timestamp with time zone', {
|
||||
comment: 'The expired date of the Ad.',
|
||||
})
|
||||
public expiresAt: Date;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 32, nullable: false,
|
||||
})
|
||||
public place: string;
|
||||
|
||||
// 今は使われていないが将来的に活用される可能性はある
|
||||
@Column('varchar', {
|
||||
length: 32, nullable: false,
|
||||
})
|
||||
public priority: string;
|
||||
|
||||
@Column('integer', {
|
||||
default: 1, nullable: false,
|
||||
})
|
||||
public ratio: number;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024, nullable: false,
|
||||
})
|
||||
public url: string;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024, nullable: false,
|
||||
})
|
||||
public imageUrl: string;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 8192, nullable: false,
|
||||
})
|
||||
public memo: string;
|
||||
|
||||
constructor(data: Partial<Ad>) {
|
||||
if (data == null) return;
|
||||
|
||||
for (const [k, v] of Object.entries(data)) {
|
||||
(this as any)[k] = v;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -316,20 +316,6 @@ export class Meta {
|
|||
})
|
||||
public ToSUrl: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 512,
|
||||
default: 'https://github.com/misskey-dev/misskey',
|
||||
nullable: false,
|
||||
})
|
||||
public repositoryUrl: string;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 512,
|
||||
default: 'https://github.com/misskey-dev/misskey/issues/new',
|
||||
nullable: true,
|
||||
})
|
||||
public feedbackUrl: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 8192,
|
||||
nullable: true,
|
||||
|
|
|
@ -59,7 +59,6 @@ import { MutedNote } from './entities/muted-note.js';
|
|||
import { ChannelFollowing } from './entities/channel-following.js';
|
||||
import { ChannelNotePining } from './entities/channel-note-pining.js';
|
||||
import { RegistryItem } from './entities/registry-item.js';
|
||||
import { Ad } from './entities/ad.js';
|
||||
import { PasswordResetRequest } from './entities/password-reset-request.js';
|
||||
import { UserPending } from './entities/user-pending.js';
|
||||
import { InstanceRepository } from './repositories/instance.js';
|
||||
|
@ -126,5 +125,4 @@ export const ChannelFollowings = db.getRepository(ChannelFollowing);
|
|||
export const ChannelNotePinings = db.getRepository(ChannelNotePining);
|
||||
export const RegistryItems = db.getRepository(RegistryItem);
|
||||
export const Webhooks = db.getRepository(Webhook);
|
||||
export const Ads = db.getRepository(Ad);
|
||||
export const PasswordResetRequests = db.getRepository(PasswordResetRequest);
|
||||
|
|
|
@ -12,13 +12,15 @@ export async function readNotification(
|
|||
if (notificationIds.length === 0) return;
|
||||
|
||||
// Update documents
|
||||
await Notifications.update({
|
||||
const result = await Notifications.update({
|
||||
id: In(notificationIds),
|
||||
isRead: false,
|
||||
}, {
|
||||
isRead: true,
|
||||
});
|
||||
|
||||
if (result.affected === 0) return;
|
||||
|
||||
if (!await Users.getHasUnreadNotification(userId)) return postReadAllNotifications(userId);
|
||||
else return postReadNotifications(userId, notificationIds);
|
||||
}
|
||||
|
@ -27,7 +29,7 @@ export async function readNotificationByQuery(
|
|||
userId: User['id'],
|
||||
query: Record<string, any>
|
||||
) {
|
||||
const notificationIds = await Notifications.find({
|
||||
const notificationIds = await Notifications.findBy({
|
||||
...query,
|
||||
notifieeId: userId,
|
||||
isRead: false,
|
||||
|
|
|
@ -4,10 +4,6 @@ import * as ep___admin_meta from './endpoints/admin/meta.js';
|
|||
import * as ep___admin_abuseUserReports from './endpoints/admin/abuse-user-reports.js';
|
||||
import * as ep___admin_accounts_create from './endpoints/admin/accounts/create.js';
|
||||
import * as ep___admin_accounts_delete from './endpoints/admin/accounts/delete.js';
|
||||
import * as ep___admin_ad_create from './endpoints/admin/ad/create.js';
|
||||
import * as ep___admin_ad_delete from './endpoints/admin/ad/delete.js';
|
||||
import * as ep___admin_ad_list from './endpoints/admin/ad/list.js';
|
||||
import * as ep___admin_ad_update from './endpoints/admin/ad/update.js';
|
||||
import * as ep___admin_announcements_create from './endpoints/admin/announcements/create.js';
|
||||
import * as ep___admin_announcements_delete from './endpoints/admin/announcements/delete.js';
|
||||
import * as ep___admin_announcements_list from './endpoints/admin/announcements/list.js';
|
||||
|
@ -311,16 +307,13 @@ import * as ep___users_searchByUsernameAndHost from './endpoints/users/search-by
|
|||
import * as ep___users_search from './endpoints/users/search.js';
|
||||
import * as ep___users_show from './endpoints/users/show.js';
|
||||
import * as ep___users_stats from './endpoints/users/stats.js';
|
||||
import * as ep___fetchRss from './endpoints/fetch-rss.js';
|
||||
|
||||
const eps = [
|
||||
['admin/meta', ep___admin_meta],
|
||||
['admin/abuse-user-reports', ep___admin_abuseUserReports],
|
||||
['admin/accounts/create', ep___admin_accounts_create],
|
||||
['admin/accounts/delete', ep___admin_accounts_delete],
|
||||
['admin/ad/create', ep___admin_ad_create],
|
||||
['admin/ad/delete', ep___admin_ad_delete],
|
||||
['admin/ad/list', ep___admin_ad_list],
|
||||
['admin/ad/update', ep___admin_ad_update],
|
||||
['admin/announcements/create', ep___admin_announcements_create],
|
||||
['admin/announcements/delete', ep___admin_announcements_delete],
|
||||
['admin/announcements/list', ep___admin_announcements_list],
|
||||
|
@ -624,6 +617,7 @@ const eps = [
|
|||
['users/search', ep___users_search],
|
||||
['users/show', ep___users_show],
|
||||
['users/stats', ep___users_stats],
|
||||
['fetch-rss', ep___fetchRss],
|
||||
];
|
||||
|
||||
export interface IEndpointMeta {
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
import define from '../../../define.js';
|
||||
import { Ads } from '@/models/index.js';
|
||||
import { genId } from '@/misc/gen-id.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
url: { type: 'string', minLength: 1 },
|
||||
memo: { type: 'string' },
|
||||
place: { type: 'string' },
|
||||
priority: { type: 'string' },
|
||||
ratio: { type: 'integer' },
|
||||
expiresAt: { type: 'integer' },
|
||||
imageUrl: { type: 'string', minLength: 1 },
|
||||
},
|
||||
required: ['url', 'memo', 'place', 'priority', 'ratio', 'expiresAt', 'imageUrl'],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default define(meta, paramDef, async (ps) => {
|
||||
await Ads.insert({
|
||||
id: genId(),
|
||||
createdAt: new Date(),
|
||||
expiresAt: new Date(ps.expiresAt),
|
||||
url: ps.url,
|
||||
imageUrl: ps.imageUrl,
|
||||
priority: ps.priority,
|
||||
ratio: ps.ratio,
|
||||
place: ps.place,
|
||||
memo: ps.memo,
|
||||
});
|
||||
});
|
|
@ -1,35 +0,0 @@
|
|||
import define from '../../../define.js';
|
||||
import { Ads } from '@/models/index.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
|
||||
errors: {
|
||||
noSuchAd: {
|
||||
message: 'No such ad.',
|
||||
code: 'NO_SUCH_AD',
|
||||
id: 'ccac9863-3a03-416e-b899-8a64041118b1',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', format: 'misskey:id' },
|
||||
},
|
||||
required: ['id'],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default define(meta, paramDef, async (ps, me) => {
|
||||
const ad = await Ads.findOneBy({ id: ps.id });
|
||||
|
||||
if (ad == null) throw new ApiError(meta.errors.noSuchAd);
|
||||
|
||||
await Ads.delete(ad.id);
|
||||
});
|
|
@ -1,30 +0,0 @@
|
|||
import define from '../../../define.js';
|
||||
import { Ads } from '@/models/index.js';
|
||||
import { makePaginationQuery } from '../../../common/make-pagination-query.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||
sinceId: { type: 'string', format: 'misskey:id' },
|
||||
untilId: { type: 'string', format: 'misskey:id' },
|
||||
},
|
||||
required: [],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default define(meta, paramDef, async (ps) => {
|
||||
const query = makePaginationQuery(Ads.createQueryBuilder('ad'), ps.sinceId, ps.untilId)
|
||||
.andWhere('ad.expiresAt > :now', { now: new Date() });
|
||||
|
||||
const ads = await query.take(ps.limit).getMany();
|
||||
|
||||
return ads;
|
||||
});
|
|
@ -1,50 +0,0 @@
|
|||
import define from '../../../define.js';
|
||||
import { Ads } from '@/models/index.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
|
||||
errors: {
|
||||
noSuchAd: {
|
||||
message: 'No such ad.',
|
||||
code: 'NO_SUCH_AD',
|
||||
id: 'b7aa1727-1354-47bc-a182-3a9c3973d300',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', format: 'misskey:id' },
|
||||
memo: { type: 'string' },
|
||||
url: { type: 'string', minLength: 1 },
|
||||
imageUrl: { type: 'string', minLength: 1 },
|
||||
place: { type: 'string' },
|
||||
priority: { type: 'string' },
|
||||
ratio: { type: 'integer' },
|
||||
expiresAt: { type: 'integer' },
|
||||
},
|
||||
required: ['id', 'memo', 'url', 'imageUrl', 'place', 'priority', 'ratio', 'expiresAt'],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default define(meta, paramDef, async (ps, me) => {
|
||||
const ad = await Ads.findOneBy({ id: ps.id });
|
||||
|
||||
if (ad == null) throw new ApiError(meta.errors.noSuchAd);
|
||||
|
||||
await Ads.update(ad.id, {
|
||||
url: ps.url,
|
||||
place: ps.place,
|
||||
priority: ps.priority,
|
||||
ratio: ps.ratio,
|
||||
memo: ps.memo,
|
||||
imageUrl: ps.imageUrl,
|
||||
expiresAt: new Date(ps.expiresAt),
|
||||
});
|
||||
});
|
|
@ -97,30 +97,6 @@ export const meta = {
|
|||
},
|
||||
},
|
||||
},
|
||||
ads: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
properties: {
|
||||
place: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
url: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'url',
|
||||
},
|
||||
imageUrl: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'url',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
enableEmail: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
|
@ -318,8 +294,6 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
description: instance.description,
|
||||
langs: instance.langs,
|
||||
tosUrl: instance.ToSUrl,
|
||||
repositoryUrl: instance.repositoryUrl,
|
||||
feedbackUrl: instance.feedbackUrl,
|
||||
disableRegistration: instance.disableRegistration,
|
||||
disableLocalTimeline: instance.disableLocalTimeline,
|
||||
disableGlobalTimeline: instance.disableGlobalTimeline,
|
||||
|
|
|
@ -78,8 +78,6 @@ export const paramDef = {
|
|||
swPublicKey: { type: 'string', nullable: true },
|
||||
swPrivateKey: { type: 'string', nullable: true },
|
||||
tosUrl: { type: 'string', nullable: true },
|
||||
repositoryUrl: { type: 'string' },
|
||||
feedbackUrl: { type: 'string' },
|
||||
useObjectStorage: { type: 'boolean' },
|
||||
objectStorageBaseUrl: { type: 'string', nullable: true },
|
||||
objectStorageBucket: { type: 'string', nullable: true },
|
||||
|
@ -313,14 +311,6 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
set.ToSUrl = ps.tosUrl;
|
||||
}
|
||||
|
||||
if (ps.repositoryUrl !== undefined) {
|
||||
set.repositoryUrl = ps.repositoryUrl;
|
||||
}
|
||||
|
||||
if (ps.feedbackUrl !== undefined) {
|
||||
set.feedbackUrl = ps.feedbackUrl;
|
||||
}
|
||||
|
||||
if (ps.useObjectStorage !== undefined) {
|
||||
set.useObjectStorage = ps.useObjectStorage;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import define from '../../define.js';
|
||||
import Resolver from '@/remote/activitypub/resolver.js';
|
||||
import ms from 'ms';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['federation'],
|
||||
|
@ -8,7 +8,7 @@ export const meta = {
|
|||
requireCredential: true,
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 30,
|
||||
},
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@ import { Note } from '@/models/entities/note.js';
|
|||
import { CacheableLocalUser, User } from '@/models/entities/user.js';
|
||||
import { fetchMeta } from '@/misc/fetch-meta.js';
|
||||
import { isActor, isPost, getApId } from '@/remote/activitypub/type.js';
|
||||
import ms from 'ms';
|
||||
import { SchemaType } from '@/misc/schema.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['federation'],
|
||||
|
@ -20,7 +20,7 @@ export const meta = {
|
|||
requireCredential: true,
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 30,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import ms from 'ms';
|
||||
import create from '@/services/blocking/create.js';
|
||||
import define from '../../define.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
import { getUser } from '../../common/getters.js';
|
||||
import { Blockings, NoteWatchings, Users } from '@/models/index.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['account'],
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 100,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import ms from 'ms';
|
||||
import deleteBlocking from '@/services/blocking/delete.js';
|
||||
import define from '../../define.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
import { getUser } from '../../common/getters.js';
|
||||
import { Blockings, Users } from '@/models/index.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['account'],
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 100,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import ms from 'ms';
|
||||
import { addFile } from '@/services/drive/add-file.js';
|
||||
import define from '../../../define.js';
|
||||
import { apiLogger } from '../../../logger.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
import { DriveFiles } from '@/models/index.js';
|
||||
import { DB_MAX_IMAGE_COMMENT_LENGTH } from '@/misc/hard-limits.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['drive'],
|
||||
|
@ -12,7 +12,7 @@ export const meta = {
|
|||
requireCredential: true,
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 120,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import ms from 'ms';
|
||||
import { uploadFromUrl } from '@/services/drive/upload-from-url.js';
|
||||
import define from '../../../define.js';
|
||||
import { DriveFiles } from '@/models/index.js';
|
||||
import { publishMainStream } from '@/services/stream.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['drive'],
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 60,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import ms from 'ms';
|
||||
import { createExportCustomEmojisJob } from '@/queue/index.js';
|
||||
import define from '../define.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
secure: true,
|
||||
requireCredential: true,
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 1,
|
||||
},
|
||||
} as const;
|
||||
|
|
39
packages/backend/src/server/api/endpoints/fetch-rss.ts
Normal file
39
packages/backend/src/server/api/endpoints/fetch-rss.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
import Parser from 'rss-parser';
|
||||
import { getResponse } from '@/misc/fetch.js';
|
||||
import config from '@/config/index.js';
|
||||
import define from '../define.js';
|
||||
|
||||
const rssParser = new Parser();
|
||||
|
||||
export const meta = {
|
||||
tags: ['meta'],
|
||||
|
||||
requireCredential: false,
|
||||
allowGet: true,
|
||||
cacheSec: 60 * 3,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
url: { type: 'string' },
|
||||
},
|
||||
required: ['url'],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default define(meta, paramDef, async (ps) => {
|
||||
const res = await getResponse({
|
||||
url: ps.url,
|
||||
method: 'GET',
|
||||
headers: Object.assign({
|
||||
'User-Agent': config.userAgent,
|
||||
Accept: 'application/rss+xml, */*',
|
||||
}),
|
||||
timeout: 5000,
|
||||
});
|
||||
|
||||
const text = await res.text();
|
||||
|
||||
return rssParser.parseString(text);
|
||||
});
|
|
@ -1,16 +1,16 @@
|
|||
import ms from 'ms';
|
||||
import create from '@/services/following/create.js';
|
||||
import define from '../../define.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
import { getUser } from '../../common/getters.js';
|
||||
import { Followings, Users } from '@/models/index.js';
|
||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['following', 'users'],
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 100,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import ms from 'ms';
|
||||
import deleteFollowing from '@/services/following/delete.js';
|
||||
import define from '../../define.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
import { getUser } from '../../common/getters.js';
|
||||
import { Followings, Users } from '@/models/index.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['following', 'users'],
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 100,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import ms from 'ms';
|
||||
import deleteFollowing from '@/services/following/delete.js';
|
||||
import define from '../../define.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
import { getUser } from '../../common/getters.js';
|
||||
import { Followings, Users } from '@/models/index.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['following', 'users'],
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 100,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import ms from 'ms';
|
||||
import define from '../../../define.js';
|
||||
import { DriveFiles, GalleryPosts } from '@/models/index.js';
|
||||
import { genId } from '../../../../../misc/gen-id.js';
|
||||
import { GalleryPost } from '@/models/entities/gallery-post.js';
|
||||
import { DriveFile } from '@/models/entities/drive-file.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['gallery'],
|
||||
|
@ -13,7 +13,7 @@ export const meta = {
|
|||
kind: 'write:gallery',
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 300,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import ms from 'ms';
|
||||
import define from '../../../define.js';
|
||||
import { DriveFiles, GalleryPosts } from '@/models/index.js';
|
||||
import { DriveFile } from '@/models/entities/drive-file.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['gallery'],
|
||||
|
@ -11,7 +11,7 @@ export const meta = {
|
|||
kind: 'write:gallery',
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 300,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import define from '../../define.js';
|
||||
import { createExportBlockingJob } from '@/queue/index.js';
|
||||
import ms from 'ms';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
secure: true,
|
||||
requireCredential: true,
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 1,
|
||||
},
|
||||
} as const;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import define from '../../define.js';
|
||||
import { createExportFollowingJob } from '@/queue/index.js';
|
||||
import ms from 'ms';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
secure: true,
|
||||
requireCredential: true,
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 1,
|
||||
},
|
||||
} as const;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import define from '../../define.js';
|
||||
import { createExportMuteJob } from '@/queue/index.js';
|
||||
import ms from 'ms';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
secure: true,
|
||||
requireCredential: true,
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 1,
|
||||
},
|
||||
} as const;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import define from '../../define.js';
|
||||
import { createExportNotesJob } from '@/queue/index.js';
|
||||
import ms from 'ms';
|
||||
import { DAY } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
secure: true,
|
||||
requireCredential: true,
|
||||
limit: {
|
||||
duration: ms('1day'),
|
||||
duration: DAY,
|
||||
max: 1,
|
||||
},
|
||||
} as const;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import define from '../../define.js';
|
||||
import { createExportUserListsJob } from '@/queue/index.js';
|
||||
import ms from 'ms';
|
||||
import { MINUTE } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
secure: true,
|
||||
requireCredential: true,
|
||||
limit: {
|
||||
duration: ms('1min'),
|
||||
duration: MINUTE,
|
||||
max: 1,
|
||||
},
|
||||
} as const;
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import define from '../../define.js';
|
||||
import { createImportBlockingJob } from '@/queue/index.js';
|
||||
import ms from 'ms';
|
||||
import { ApiError } from '../../error.js';
|
||||
import { DriveFiles } from '@/models/index.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
secure: true,
|
||||
requireCredential: true,
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 1,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import define from '../../define.js';
|
||||
import { createImportFollowingJob } from '@/queue/index.js';
|
||||
import ms from 'ms';
|
||||
import { ApiError } from '../../error.js';
|
||||
import { DriveFiles } from '@/models/index.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
secure: true,
|
||||
requireCredential: true,
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duratition: HOUR,
|
||||
max: 1,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import define from '../../define.js';
|
||||
import { createImportMutingJob } from '@/queue/index.js';
|
||||
import ms from 'ms';
|
||||
import { ApiError } from '../../error.js';
|
||||
import { DriveFiles } from '@/models/index.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
secure: true,
|
||||
requireCredential: true,
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 1,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import define from '../../define.js';
|
||||
import { createImportUserListsJob } from '@/queue/index.js';
|
||||
import ms from 'ms';
|
||||
import { ApiError } from '../../error.js';
|
||||
import { DriveFiles } from '@/models/index.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
secure: true,
|
||||
requireCredential: true,
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 1,
|
||||
},
|
||||
|
||||
|
|
|
@ -2,12 +2,12 @@ import { publishMainStream } from '@/services/stream.js';
|
|||
import define from '../../define.js';
|
||||
import rndstr from 'rndstr';
|
||||
import config from '@/config/index.js';
|
||||
import ms from 'ms';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import { Users, UserProfiles } from '@/models/index.js';
|
||||
import { sendEmail } from '@/services/send-email.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
import { validateEmailForAccount } from '@/services/validate-email-for-account.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
|
@ -15,7 +15,7 @@ export const meta = {
|
|||
secure: true,
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 3,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import define from '../../../define.js';
|
||||
import ms from 'ms';
|
||||
import { ApiError } from '../../../error.js';
|
||||
import { MessagingMessages } from '@/models/index.js';
|
||||
import { deleteMessage } from '@/services/messages/delete.js';
|
||||
import { SECOND, HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['messaging'],
|
||||
|
@ -12,9 +12,9 @@ export const meta = {
|
|||
kind: 'write:messaging',
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 300,
|
||||
minInterval: ms('1sec'),
|
||||
minInterval: SECOND,
|
||||
},
|
||||
|
||||
errors: {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { IsNull, MoreThan } from 'typeorm';
|
||||
import config from '@/config/index.js';
|
||||
import { fetchMeta } from '@/misc/fetch-meta.js';
|
||||
import { Ads, Emojis, Users } from '@/models/index.js';
|
||||
import { Emojis, Users } from '@/models/index.js';
|
||||
import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
|
||||
import define from '../define.js';
|
||||
|
||||
|
@ -53,16 +53,6 @@ export const meta = {
|
|||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
repositoryUrl: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
default: 'https://github.com/misskey-dev/misskey',
|
||||
},
|
||||
feedbackUrl: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
default: 'https://github.com/misskey-dev/misskey/issues/new',
|
||||
},
|
||||
defaultDarkTheme: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
|
@ -168,30 +158,6 @@ export const meta = {
|
|||
},
|
||||
},
|
||||
},
|
||||
ads: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
properties: {
|
||||
place: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
url: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'url',
|
||||
},
|
||||
imageUrl: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
format: 'url',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
requireSetup: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
|
@ -310,12 +276,6 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
},
|
||||
});
|
||||
|
||||
const ads = await Ads.find({
|
||||
where: {
|
||||
expiresAt: MoreThan(new Date()),
|
||||
},
|
||||
});
|
||||
|
||||
const response: any = {
|
||||
maintainerName: instance.maintainerName,
|
||||
maintainerEmail: instance.maintainerEmail,
|
||||
|
@ -327,8 +287,6 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
description: instance.description,
|
||||
langs: instance.langs,
|
||||
tosUrl: instance.ToSUrl,
|
||||
repositoryUrl: instance.repositoryUrl,
|
||||
feedbackUrl: instance.feedbackUrl,
|
||||
disableRegistration: instance.disableRegistration,
|
||||
disableLocalTimeline: instance.disableLocalTimeline,
|
||||
disableGlobalTimeline: instance.disableGlobalTimeline,
|
||||
|
@ -349,13 +307,6 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
emojis: await Emojis.packMany(emojis),
|
||||
defaultLightTheme: instance.defaultLightTheme,
|
||||
defaultDarkTheme: instance.defaultDarkTheme,
|
||||
ads: ads.map(ad => ({
|
||||
id: ad.id,
|
||||
url: ad.url,
|
||||
place: ad.place,
|
||||
ratio: ad.ratio,
|
||||
imageUrl: ad.imageUrl,
|
||||
})),
|
||||
enableEmail: instance.enableEmail,
|
||||
|
||||
enableTwitterIntegration: instance.enableTwitterIntegration,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import ms from 'ms';
|
||||
import { In } from 'typeorm';
|
||||
import create from '@/services/note/create.js';
|
||||
import { User } from '@/models/entities/user.js';
|
||||
|
@ -10,6 +9,7 @@ import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
|
|||
import { noteVisibilities } from '../../../../types.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
import define from '../../define.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['notes'],
|
||||
|
@ -17,7 +17,7 @@ export const meta = {
|
|||
requireCredential: true,
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 300,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import ms from 'ms';
|
||||
import deleteNote from '@/services/note/delete.js';
|
||||
import { Users } from '@/models/index.js';
|
||||
import define from '../../define.js';
|
||||
import { getNote } from '../../common/getters.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
import { SECOND, HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['notes'],
|
||||
|
@ -13,9 +13,9 @@ export const meta = {
|
|||
kind: 'write:notes',
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 300,
|
||||
minInterval: ms('1sec'),
|
||||
minInterval: SECOND,
|
||||
},
|
||||
|
||||
errors: {
|
||||
|
|
|
@ -60,12 +60,21 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
query.setParameters(mutingQuery.getParameters());
|
||||
//#endregion
|
||||
|
||||
const polls = await query.take(ps.limit).skip(ps.offset).getMany();
|
||||
const polls = await query
|
||||
.orderBy('poll.noteId', 'DESC')
|
||||
.take(ps.limit)
|
||||
.skip(ps.offset)
|
||||
.getMany();
|
||||
|
||||
if (polls.length === 0) return [];
|
||||
|
||||
const notes = await Notes.findBy({
|
||||
id: In(polls.map(poll => poll.noteId)),
|
||||
const notes = await Notes.find({
|
||||
where: {
|
||||
id: In(polls.map(poll => poll.noteId)),
|
||||
},
|
||||
order: {
|
||||
createdAt: 'DESC',
|
||||
},
|
||||
});
|
||||
|
||||
return await Notes.packMany(notes, user, {
|
||||
|
|
|
@ -8,6 +8,9 @@ export const meta = {
|
|||
|
||||
requireCredential: false,
|
||||
|
||||
allowGet: true,
|
||||
cacheSec: 60,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import ms from 'ms';
|
||||
import deleteReaction from '@/services/note/reaction/delete.js';
|
||||
import define from '../../../define.js';
|
||||
import { getNote } from '../../../common/getters.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
import { SECOND, HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['reactions', 'notes'],
|
||||
|
@ -12,9 +12,9 @@ export const meta = {
|
|||
kind: 'write:reactions',
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 60,
|
||||
minInterval: ms('3sec'),
|
||||
minInterval: 3 * SECOND,
|
||||
},
|
||||
|
||||
errors: {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import ms from 'ms';
|
||||
import deleteNote from '@/services/note/delete.js';
|
||||
import { Notes, Users } from '@/models/index.js';
|
||||
import define from '../../define.js';
|
||||
import { getNote } from '../../common/getters.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
import { SECOND, HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['notes'],
|
||||
|
@ -13,9 +13,9 @@ export const meta = {
|
|||
kind: 'write:notes',
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 300,
|
||||
minInterval: ms('1sec'),
|
||||
minInterval: SECOND,
|
||||
},
|
||||
|
||||
errors: {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import ms from 'ms';
|
||||
import { Pages, DriveFiles } from '@/models/index.js';
|
||||
import { genId } from '@/misc/gen-id.js';
|
||||
import { Page } from '@/models/entities/page.js';
|
||||
import define from '../../define.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['pages'],
|
||||
|
@ -13,7 +13,7 @@ export const meta = {
|
|||
kind: 'write:pages',
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 300,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import ms from 'ms';
|
||||
import { Not } from 'typeorm';
|
||||
import { Pages, DriveFiles } from '@/models/index.js';
|
||||
import define from '../../define.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['pages'],
|
||||
|
@ -12,7 +12,7 @@ export const meta = {
|
|||
kind: 'write:pages',
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 300,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import rndstr from 'rndstr';
|
||||
import ms from 'ms';
|
||||
import { IsNull } from 'typeorm';
|
||||
import config from '@/config/index.js';
|
||||
import { Users, UserProfiles, PasswordResetRequests } from '@/models/index.js';
|
||||
import { sendEmail } from '@/services/send-email.js';
|
||||
import { genId } from '@/misc/gen-id.js';
|
||||
import define from '../define.js';
|
||||
import { HOUR } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['reset password'],
|
||||
|
@ -15,7 +15,7 @@ export const meta = {
|
|||
description: 'Request a users password to be reset.',
|
||||
|
||||
limit: {
|
||||
duration: ms('1hour'),
|
||||
duration: HOUR,
|
||||
max: 3,
|
||||
},
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import ms from 'ms';
|
||||
import { Users, Followings } from '@/models/index.js';
|
||||
import define from '../../define.js';
|
||||
import { generateMutedUserQueryForUsers } from '../../common/generate-muted-user-query.js';
|
||||
import { generateBlockedUserQuery, generateBlockQueryForUsers } from '../../common/generate-block-query.js';
|
||||
import { DAY } from '@/const.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['users'],
|
||||
|
@ -39,7 +39,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
.where('user.isLocked = FALSE')
|
||||
.andWhere('user.isExplorable = TRUE')
|
||||
.andWhere('user.host IS NULL')
|
||||
.andWhere('user.updatedAt >= :date', { date: new Date(Date.now() - ms('7days')) })
|
||||
.andWhere('user.updatedAt >= :date', { date: new Date(Date.now() - (7 * DAY)) })
|
||||
.andWhere('user.id != :meId', { meId: me.id })
|
||||
.orderBy('user.followersCount', 'DESC');
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ export default class extends Channel {
|
|||
}
|
||||
|
||||
// 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
|
||||
if (iUserRelated(note, this.muting)) return;
|
||||
if (isUserRelated(note, this.muting)) return;
|
||||
// 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する
|
||||
if (isUserRelated(note, this.blocking)) return;
|
||||
|
||||
|
|
|
@ -11,10 +11,10 @@ const router = new Router();
|
|||
const nodeinfo2_1path = '/nodeinfo/2.1';
|
||||
const nodeinfo2_0path = '/nodeinfo/2.0';
|
||||
|
||||
export const links = [/* (awaiting release) {
|
||||
export const links = [{
|
||||
rel: 'http://nodeinfo.diaspora.software/ns/schema/2.1',
|
||||
href: config.url + nodeinfo2_1path
|
||||
}, */{
|
||||
}, {
|
||||
rel: 'http://nodeinfo.diaspora.software/ns/schema/2.0',
|
||||
href: config.url + nodeinfo2_0path,
|
||||
}];
|
||||
|
@ -39,9 +39,9 @@ const nodeinfo2 = async () => {
|
|||
|
||||
return {
|
||||
software: {
|
||||
name: 'misskey',
|
||||
name: 'foundkey',
|
||||
version: config.version,
|
||||
repository: meta.repositoryUrl,
|
||||
repository: 'https://akkoma.dev/FoundKeyGang/FoundKey',
|
||||
},
|
||||
protocols: ['activitypub'],
|
||||
services: {
|
||||
|
@ -64,7 +64,7 @@ const nodeinfo2 = async () => {
|
|||
langs: meta.langs,
|
||||
tosUrl: meta.ToSUrl,
|
||||
repositoryUrl: meta.repositoryUrl,
|
||||
feedbackUrl: meta.feedbackUrl,
|
||||
feedbackUrl: 'ircs://irc.akkoma.dev/foundkey',
|
||||
disableRegistration: meta.disableRegistration,
|
||||
disableLocalTimeline: meta.disableLocalTimeline,
|
||||
disableGlobalTimeline: meta.disableGlobalTimeline,
|
||||
|
|
|
@ -106,15 +106,39 @@
|
|||
function renderError(code, details) {
|
||||
let errorsElement = document.getElementById('errors');
|
||||
if (!errorsElement) {
|
||||
document.getElementsByTagName("head")[0].insertAdjacentHTML(
|
||||
"beforeend",
|
||||
`<link rel="stylesheet" href="../error.css" />`);
|
||||
document.documentElement.innerHTML = `
|
||||
<h1>⚠ An error has occurred. ⚠</h1>
|
||||
<p>If the problem persists, please contact the administrator. You may also try the following options:</p>
|
||||
<ul>
|
||||
<li>Start <a href="/cli">the simple client</a></li>
|
||||
<li>Attempt to repair in <a href="/bios">BIOS</a></li>
|
||||
<li><a href="/flush">Flush preferences and cache</a></li>
|
||||
</ul>
|
||||
<hr>
|
||||
<svg class="icon-warning" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-alert-triangle" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
<path d="M12 9v2m0 4v.01"></path>
|
||||
<path d="M5 19h14a2 2 0 0 0 1.84 -2.75l-7.1 -12.25a2 2 0 0 0 -3.5 0l-7.1 12.25a2 2 0 0 0 1.75 2.75"></path>
|
||||
</svg>
|
||||
<h1>An error has occurred!</h1>
|
||||
<button class="button-big" onclick="location.reload(true);">
|
||||
<span class="button-label-big">Refresh</span>
|
||||
</button>
|
||||
<p class="dont-worry">Don't worry, it's (probably) not your fault.</p>
|
||||
<p>If the problem persists after refreshing, please contact your instance's administrator.<br>You may also try the following options:</p>
|
||||
<a href="/flush">
|
||||
<button class="button-small">
|
||||
<span class="button-label-small">Flush preferences and cache</span>
|
||||
</button>
|
||||
</a>
|
||||
<br>
|
||||
<a href="/cli">
|
||||
<button class="button-small">
|
||||
<span class="button-label-small">Start the simple client</span>
|
||||
</button>
|
||||
</a>
|
||||
<br>
|
||||
<a href="/bios">
|
||||
<button class="button-small">
|
||||
<span class="button-label-small">Attempt to repair in Repair Tool</span>
|
||||
</button>
|
||||
</a>
|
||||
<br>
|
||||
<div id="errors"></div>
|
||||
`;
|
||||
|
||||
|
@ -122,8 +146,7 @@
|
|||
}
|
||||
|
||||
const detailsElement = document.createElement('details');
|
||||
detailsElement.innerHTML = `<summary><code>ERROR CODE: ${code}</code></summary>${JSON.stringify(details)}`;
|
||||
|
||||
detailsElement.innerHTML = `<br><summary><code>ERROR CODE: ${code}</code></summary>${JSON.stringify(details)}`;
|
||||
errorsElement.appendChild(detailsElement);
|
||||
}
|
||||
|
||||
|
|
98
packages/backend/src/server/web/error.css
Normal file
98
packages/backend/src/server/web/error.css
Normal file
|
@ -0,0 +1,98 @@
|
|||
* {
|
||||
font-family: BIZ UDGothic, Roboto, HelveticaNeue, Arial, sans-serif;
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
background-color: #222;
|
||||
color: #dfddcc;
|
||||
justify-content: center;
|
||||
margin: auto;
|
||||
width: 80%;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 999px;
|
||||
padding: 0px 12px 0px 12px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.button-big {
|
||||
background: linear-gradient(90deg, rgb(134, 179, 0), rgb(74, 179, 0));
|
||||
line-height: 50px;
|
||||
}
|
||||
|
||||
.button-big:hover {
|
||||
background: rgb(153, 204, 0);
|
||||
}
|
||||
|
||||
.button-small {
|
||||
background: #444;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
.button-small:hover {
|
||||
background: #555;
|
||||
}
|
||||
|
||||
.button-label-big {
|
||||
color: #222;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.button-label-small {
|
||||
color: rgb(153, 204, 0);
|
||||
font-size: 16px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: rgb(134, 179, 0);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
p,
|
||||
li {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.dont-worry,
|
||||
#msg {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.icon-warning {
|
||||
color: #dec340;
|
||||
height: 4rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: Fira, FiraCode, monospace;
|
||||
}
|
||||
|
||||
details {
|
||||
background: #333;
|
||||
margin-bottom: 2rem;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 5px;
|
||||
justify-content: center;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
summary {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
summary > * {
|
||||
display: inline;
|
||||
}
|
|
@ -5,7 +5,6 @@
|
|||
import { dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import ms from 'ms';
|
||||
import Koa from 'koa';
|
||||
import Router from '@koa/router';
|
||||
import send from 'koa-send';
|
||||
|
@ -27,6 +26,7 @@ import { genOpenapiSpec } from '../api/openapi/gen-spec.js';
|
|||
import { urlPreviewHandler } from './url-preview.js';
|
||||
import { manifestHandler } from './manifest.js';
|
||||
import packFeed from './feed.js';
|
||||
import { MINUTE, DAY } from '@/const.js';
|
||||
|
||||
const _filename = fileURLToPath(import.meta.url);
|
||||
const _dirname = dirname(_filename);
|
||||
|
@ -100,21 +100,21 @@ const router = new Router();
|
|||
router.get('/static-assets/(.*)', async ctx => {
|
||||
await send(ctx as any, ctx.path.replace('/static-assets/', ''), {
|
||||
root: staticAssets,
|
||||
maxage: ms('7 days'),
|
||||
maxage: 7 * DAY,
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/client-assets/(.*)', async ctx => {
|
||||
await send(ctx as any, ctx.path.replace('/client-assets/', ''), {
|
||||
root: clientAssets,
|
||||
maxage: ms('7 days'),
|
||||
maxage: 7 * DAY,
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/assets/(.*)', async ctx => {
|
||||
await send(ctx as any, ctx.path.replace('/assets/', ''), {
|
||||
root: assets,
|
||||
maxage: ms('7 days'),
|
||||
maxage: 7 * DAY,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -137,7 +137,7 @@ router.get('/twemoji/(.*)', async ctx => {
|
|||
|
||||
await send(ctx as any, path, {
|
||||
root: `${_dirname}/../../../node_modules/@discordapp/twemoji/dist/svg/`,
|
||||
maxage: ms('30 days'),
|
||||
maxage: 30 * DAY,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -188,7 +188,7 @@ router.get('/twemoji-badge/(.*)', async ctx => {
|
|||
router.get(`/sw.js`, async ctx => {
|
||||
await send(ctx as any, `/sw.js`, {
|
||||
root: swAssets,
|
||||
maxage: ms('10 minutes'),
|
||||
maxage: 10 * MINUTE,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ html
|
|||
block meta
|
||||
|
||||
block og
|
||||
meta(property='og:title' content= title || 'Misskey')
|
||||
meta(property='og:title' content= title || 'Misskey')
|
||||
meta(property='og:description' content= desc || '✨🌎✨ A interplanetary communication platform ✨🚀✨')
|
||||
meta(property='og:image' content= img)
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ html
|
|||
head
|
||||
meta(charset='utf-8')
|
||||
meta(name='application-name' content='Misskey')
|
||||
title Misskey BIOS
|
||||
title Misskey Repair Tool
|
||||
style
|
||||
include ../bios.css
|
||||
script
|
||||
|
@ -13,7 +13,7 @@ html
|
|||
|
||||
body
|
||||
header
|
||||
h1 Misskey BIOS #{version}
|
||||
h1 Misskey Repair Tool #{version}
|
||||
main
|
||||
div.tabs
|
||||
button#ls edit local storage
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
doctype html
|
||||
|
||||
html
|
||||
head
|
||||
meta(charset='utf-8')
|
||||
meta(name='application-name' content='Misskey')
|
||||
title Flushing Misskey
|
||||
style
|
||||
include ../error.css
|
||||
#msg
|
||||
script.
|
||||
const msg = document.getElementById('msg');
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -186,7 +186,7 @@ export function connectStream(user: any, channel: string, listener: (message: Re
|
|||
});
|
||||
}
|
||||
|
||||
export const waitFire = async (user: any, channel: string, trgr: () => any, cond: (msg: Record<string, any>) => boolean) => {
|
||||
export const waitFire = async (user: any, channel: string, trgr: () => any, cond: (msg: Record<string, any>) => boolean, params?: any) => {
|
||||
return new Promise<boolean>(async (res, rej) => {
|
||||
let timer: NodeJS.Timeout;
|
||||
|
||||
|
@ -198,7 +198,7 @@ export const waitFire = async (user: any, channel: string, trgr: () => any, cond
|
|||
if (timer) clearTimeout(timer);
|
||||
res(true);
|
||||
}
|
||||
});
|
||||
}, params);
|
||||
} catch (e) {
|
||||
rej(e);
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ export const waitFire = async (user: any, channel: string, trgr: () => any, cond
|
|||
timer = setTimeout(() => {
|
||||
ws.close();
|
||||
res(false);
|
||||
}, 5000);
|
||||
}, 3000);
|
||||
|
||||
try {
|
||||
await trgr();
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3,7 +3,7 @@
|
|||
"scripts": {
|
||||
"watch": "vite build --watch --mode development",
|
||||
"build": "vite build",
|
||||
"lint": "eslint --quiet \"src/**/*.{ts,vue}\""
|
||||
"lint": "eslint --quiet src --ext .ts,.vue"
|
||||
},
|
||||
"resolutions": {
|
||||
"chokidar": "^3.3.1",
|
||||
|
@ -15,7 +15,7 @@
|
|||
"@rollup/plugin-alias": "3.1.9",
|
||||
"@rollup/plugin-json": "4.1.0",
|
||||
"@syuilo/aiscript": "0.11.1",
|
||||
"@vitejs/plugin-vue": "2.3.3",
|
||||
"@vitejs/plugin-vue": "^3.0.0",
|
||||
"@vue/compiler-sfc": "3.2.37",
|
||||
"abort-controller": "3.0.0",
|
||||
"autobind-decorator": "2.4.0",
|
||||
|
@ -35,7 +35,7 @@
|
|||
"escape-regexp": "0.0.1",
|
||||
"eventemitter3": "4.0.7",
|
||||
"feed": "4.2.2",
|
||||
"idb-keyval": "6.1.0",
|
||||
"idb-keyval": "6.2.0",
|
||||
"insert-text-at-cursor": "0.3.0",
|
||||
"json5": "2.2.1",
|
||||
"katex": "0.15.6",
|
||||
|
@ -45,36 +45,34 @@
|
|||
"mocha": "10.0.0",
|
||||
"ms": "2.1.3",
|
||||
"nested-property": "4.0.0",
|
||||
"photoswipe": "5.2.7",
|
||||
"photoswipe": "5.2.8",
|
||||
"prismjs": "1.28.0",
|
||||
"private-ip": "2.3.3",
|
||||
"promise-limit": "2.7.0",
|
||||
"pug": "3.0.2",
|
||||
"punycode": "2.1.1",
|
||||
"qrcode": "1.5.0",
|
||||
"querystring": "0.2.1",
|
||||
"random-seed": "0.3.0",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"rndstr": "1.0.0",
|
||||
"rollup": "2.75.6",
|
||||
"rollup": "2.75.7",
|
||||
"s-age": "1.1.2",
|
||||
"sass": "1.52.3",
|
||||
"sass": "1.53.0",
|
||||
"seedrandom": "3.0.5",
|
||||
"strict-event-emitter-types": "2.0.0",
|
||||
"stringz": "2.1.0",
|
||||
"syuilo-password-strength": "0.0.1",
|
||||
"textarea-caret": "3.1.0",
|
||||
"three": "0.141.0",
|
||||
"three": "0.142.0",
|
||||
"throttle-debounce": "5.0.0",
|
||||
"tinycolor2": "1.4.2",
|
||||
"tsc-alias": "1.6.9",
|
||||
"tsc-alias": "1.6.11",
|
||||
"tsconfig-paths": "4.0.0",
|
||||
"twemoji-parser": "14.0.0",
|
||||
"typescript": "4.7.3",
|
||||
"typescript": "4.7.4",
|
||||
"uuid": "8.3.2",
|
||||
"v-debounce": "0.1.2",
|
||||
"vanilla-tilt": "1.7.2",
|
||||
"vite": "2.9.10",
|
||||
"vite": "3.0.0",
|
||||
"vue": "3.2.37",
|
||||
"vue-prism-editor": "2.0.0-alpha.2",
|
||||
"vuedraggable": "4.0.1",
|
||||
|
@ -93,20 +91,19 @@
|
|||
"@types/oauth": "0.9.1",
|
||||
"@types/punycode": "2.1.0",
|
||||
"@types/qrcode": "1.4.2",
|
||||
"@types/random-seed": "0.3.3",
|
||||
"@types/seedrandom": "3.0.2",
|
||||
"@types/throttle-debounce": "5.0.0",
|
||||
"@types/tinycolor2": "1.4.3",
|
||||
"@types/uuid": "8.3.4",
|
||||
"@types/websocket": "1.0.5",
|
||||
"@types/ws": "8.5.3",
|
||||
"@typescript-eslint/eslint-plugin": "5.27.1",
|
||||
"@typescript-eslint/parser": "5.27.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.30.0",
|
||||
"@typescript-eslint/parser": "^5.30.0",
|
||||
"cross-env": "7.0.3",
|
||||
"cypress": "10.0.3",
|
||||
"eslint": "8.17.0",
|
||||
"eslint-plugin-import": "2.26.0",
|
||||
"eslint-plugin-vue": "9.1.0",
|
||||
"cypress": "10.3.0",
|
||||
"eslint": "^8.20.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-vue": "^9.1.1",
|
||||
"start-server-and-test": "1.14.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<XWindow ref="window" :initial-width="400" :initial-height="500" :can-resize="true" @closed="emit('closed')">
|
||||
<XWindow ref="uiWindow" :initial-width="400" :initial-height="500" :can-resize="true" @closed="emit('closed')">
|
||||
<template #header>
|
||||
<i class="fas fa-exclamation-circle" style="margin-right: 0.5em;"></i>
|
||||
<I18n :src="i18n.ts.reportAbuseOf" tag="span">
|
||||
|
@ -40,19 +40,19 @@ const emit = defineEmits<{
|
|||
(ev: 'closed'): void;
|
||||
}>();
|
||||
|
||||
const window = ref<InstanceType<typeof XWindow>>();
|
||||
const uiWindow = ref<InstanceType<typeof XWindow>>();
|
||||
const comment = ref(props.initialComment || '');
|
||||
|
||||
function send() {
|
||||
os.apiWithDialog('users/report-abuse', {
|
||||
userId: props.user.id,
|
||||
comment: comment.value,
|
||||
}, undefined).then(res => {
|
||||
}).then(res => {
|
||||
os.alert({
|
||||
type: 'success',
|
||||
text: i18n.ts.abuseReported
|
||||
});
|
||||
window.value?.close();
|
||||
uiWindow.value?.close();
|
||||
emit('closed');
|
||||
});
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
<span v-if="emoji.isCustomEmoji" class="emoji"><img :src="defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url" :alt="emoji.emoji"/></span>
|
||||
<span v-else-if="!defaultStore.state.useOsNativeEmojis" class="emoji"><img :src="emoji.url" :alt="emoji.emoji"/></span>
|
||||
<span v-else class="emoji">{{ emoji.emoji }}</span>
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<span class="name" v-html="emoji.name.replace(q, `<b>${q}</b>`)"></span>
|
||||
<span v-if="emoji.aliasOf" class="alias">({{ emoji.aliasOf }})</span>
|
||||
</li>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<!-- eslint-disable vue/no-v-html -->
|
||||
<template>
|
||||
<code v-if="inline" :class="`language-${prismLang}`" v-html="html"></code>
|
||||
<pre v-else :class="`language-${prismLang}`"><code :class="`language-${prismLang}`" v-html="html"></code></pre>
|
||||
|
@ -5,7 +6,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import 'prismjs';
|
||||
import Prism from 'prismjs';
|
||||
import 'prismjs/themes/prism-okaidia.css';
|
||||
|
||||
const props = defineProps<{
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent, h, PropType, TransitionGroup } from 'vue';
|
||||
import MkAd from '@/components/global/ad.vue';
|
||||
import { i18n } from '@/i18n';
|
||||
import { defaultStore } from '@/store';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
items: {
|
||||
type: Array as PropType<{ id: string; createdAt: string; _shouldInsertAd_: boolean; }[]>,
|
||||
type: Array as PropType<{ id: string; createdAt: string; }[]>,
|
||||
required: true,
|
||||
},
|
||||
direction: {
|
||||
|
@ -25,11 +24,6 @@ export default defineComponent({
|
|||
required: false,
|
||||
default: false
|
||||
},
|
||||
ad: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
|
||||
setup(props, { slots, expose }) {
|
||||
|
@ -78,15 +72,7 @@ export default defineComponent({
|
|||
|
||||
return [el, separator];
|
||||
} else {
|
||||
if (props.ad && item._shouldInsertAd_) {
|
||||
return [h(MkAd, {
|
||||
class: 'a', // advertiseの意(ブロッカー対策)
|
||||
key: item.id + ':ad',
|
||||
prefer: ['horizontal', 'horizontal-big'],
|
||||
}), el];
|
||||
} else {
|
||||
return el;
|
||||
}
|
||||
return el;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -9,12 +9,12 @@
|
|||
|
||||
<form v-if="instance.enableEmail" class="bafeceda" @submit.prevent="onSubmit">
|
||||
<div class="main _formRoot">
|
||||
<MkInput v-model="username" class="_formBlock" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required>
|
||||
<MkInput v-model="username" class="_formBlock" type="text" pattern="^[a-zA-Z0-9_]+$" :spellcheck="false" autofocus required>
|
||||
<template #label>{{ i18n.ts.username }}</template>
|
||||
<template #prefix>@</template>
|
||||
</MkInput>
|
||||
|
||||
<MkInput v-model="email" class="_formBlock" type="email" spellcheck="false" required>
|
||||
<MkInput v-model="email" class="_formBlock" type="email" :spellcheck="false" required>
|
||||
<template #label>{{ i18n.ts.emailAddress }}</template>
|
||||
<template #caption>{{ i18n.ts._forgotPassword.enterEmail }}</template>
|
||||
</MkInput>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue