Merge remote-tracking branch 'misskey-original/develop' into develop
# Conflicts: # package.json # packages/frontend/src/components/MkPostForm.vue
This commit is contained in:
		
						commit
						8cb7ba0c16
					
				
							
								
								
									
										13
									
								
								CHANGELOG.md
								
								
								
								
							
							
						
						
									
										13
									
								
								CHANGELOG.md
								
								
								
								
							|  | @ -12,6 +12,19 @@ | |||
| 
 | ||||
| --> | ||||
| 
 | ||||
| ## 202x.x.x (Unreleased) | ||||
| 
 | ||||
| ### Client | ||||
| - Enhance: ハッシュタグ入力時に、本文の末尾の行に何も書かれていない場合は新たにスペースを追加しないように | ||||
| 
 | ||||
| ## 2023.12.2 | ||||
| 
 | ||||
| ### General | ||||
| - v2023.12.1でDockerを利用してサーバーを起動できない問題を修正 | ||||
| 
 | ||||
| ### Client | ||||
| - Enhance: 検索画面においてEnterキー押下で検索できるように | ||||
| 
 | ||||
| ## 2023.12.1 | ||||
| 
 | ||||
| ### Note | ||||
|  |  | |||
							
								
								
									
										2
									
								
								COPYING
								
								
								
								
							
							
						
						
									
										2
									
								
								COPYING
								
								
								
								
							|  | @ -1,5 +1,5 @@ | |||
| Unless otherwise stated this repository is | ||||
| Copyright © 2014-2023 syuilo and contributers | ||||
| Copyright © 2014-2023 syuilo and contributors | ||||
| 
 | ||||
| And is distributed under The GNU Affero General Public License Version 3, you should have received a copy of the license file as LICENSE. | ||||
| 
 | ||||
|  |  | |||
|  | @ -51,6 +51,7 @@ WORKDIR /misskey | |||
| COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"] | ||||
| COPY --link ["scripts", "./scripts"] | ||||
| COPY --link ["packages/backend/package.json", "./packages/backend/"] | ||||
| COPY --link ["packages/misskey-js/package.json", "./packages/misskey-js/"] | ||||
| 
 | ||||
| RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \ | ||||
| 	pnpm i --frozen-lockfile --aggregate-output | ||||
|  | @ -77,7 +78,9 @@ WORKDIR /misskey | |||
| 
 | ||||
| COPY --chown=misskey:misskey --from=target-builder /misskey/node_modules ./node_modules | ||||
| COPY --chown=misskey:misskey --from=target-builder /misskey/packages/backend/node_modules ./packages/backend/node_modules | ||||
| COPY --chown=misskey:misskey --from=target-builder /misskey/packages/misskey-js/node_modules ./packages/misskey-js/node_modules | ||||
| COPY --chown=misskey:misskey --from=native-builder /misskey/built ./built | ||||
| COPY --chown=misskey:misskey --from=native-builder /misskey/packages/misskey-js/built ./packages/misskey-js/built | ||||
| COPY --chown=misskey:misskey --from=native-builder /misskey/packages/backend/built ./packages/backend/built | ||||
| COPY --chown=misskey:misskey --from=native-builder /misskey/fluent-emojis /misskey/fluent-emojis | ||||
| COPY --chown=misskey:misskey . ./ | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| _lang_: "বাংলা" | ||||
| headlineMisskey: "নোট ব্যাবহার করে সংযুক্ত নেটওয়ার্ক" | ||||
| introMisskey: "স্বাগতম! মিসকি একটি ওপেন সোর্স, ডিসেন্ট্রালাইজড মাইক্রোব্লগিং পরিষেবা। \n\"নোট\" তৈরির মাধ্যমে যা ঘটছে তা সবার সাথে শেয়ার করুন 📡\n\"রিঅ্যাকশন\" গুলির মাধ্যমে যেকোনো নোট সম্পর্কে আপনার অনুভূতি ব্যাক্ত করতে পারেন 👍\nএকটি নতুন দুনিয়া ঘুরে দেখুন 🚀\n" | ||||
| poweredByMisskeyDescription: "{name} হল ওপেন সোর্স প্ল্যাটফর্ম <b>Misskey</b>-এর সার্ভারগুলির একটি৷" | ||||
| monthAndDay: "{day}/{month}" | ||||
| search: "খুঁজুন" | ||||
| notifications: "বিজ্ঞপ্তি" | ||||
|  | @ -12,12 +13,14 @@ fetchingAsApObject: "ফেডিভার্স থেকে খবর আন | |||
| ok: "ঠিক" | ||||
| gotIt: "বুঝেছি" | ||||
| cancel: "বাতিল" | ||||
| noThankYou: "না, ধন্যবাদ" | ||||
| enterUsername: "ইউজারনেম লিখুন" | ||||
| renotedBy: "{user} রিনোট করেছেন" | ||||
| noNotes: "কোন নোট নেই" | ||||
| noNotifications: "কোনো বিজ্ঞপ্তি নেই" | ||||
| instance: "ইন্সট্যান্স" | ||||
| settings: "সেটিংস" | ||||
| notificationSettings: "বিজ্ঞপ্তির সেটিংস" | ||||
| basicSettings: "সাধারণ সেটিংস" | ||||
| otherSettings: "অন্যান্য সেটিংস" | ||||
| openInWindow: "নতুন উইন্ডোতে খুলা" | ||||
|  | @ -42,12 +45,20 @@ pin: "পিন করা" | |||
| unpin: "পিন সরান" | ||||
| copyContent: "বিষয়বস্তু কপি করুন" | ||||
| copyLink: "লিঙ্ক কপি করুন" | ||||
| copyLinkRenote: "রিনোট লিঙ্ক কপি করুন" | ||||
| delete: "মুছুন" | ||||
| deleteAndEdit: "মুছুন এবং সম্পাদনা করুন" | ||||
| deleteAndEditConfirm: "আপনি কি এই নোটটি মুছে এটি সম্পাদনা করার বিষয়ে নিশ্চিত? আপনি এটির সমস্ত রিঅ্যাকশন, রিনোট এবং জবাব হারাবেন।" | ||||
| addToList: "লিস্ট এ যোগ করুন" | ||||
| addToAntenna: "অ্যান্টেনা এ যোগ করুন" | ||||
| sendMessage: "একটি বার্তা পাঠান" | ||||
| copyRSS: "RSS কপি করুন" | ||||
| copyUsername: "ব্যবহারকারীর নাম কপি করুন" | ||||
| copyUserId: "ব্যবহারকারীর ID কপি করুন" | ||||
| copyNoteId: "নোটের ID কপি করুন" | ||||
| copyFileId: "ফাইল ID কপি করুন" | ||||
| copyFolderId: "ফোল্ডার ID কপি করুন" | ||||
| copyProfileUrl: "প্রোফাইল URL কপি করুন" | ||||
| searchUser: "ব্যবহারকারী খুঁজুন..." | ||||
| reply: "জবাব" | ||||
| loadMore: "আরও দেখুন" | ||||
|  | @ -100,6 +111,8 @@ renoted: "রিনোট করা হয়েছে" | |||
| cantRenote: "এই নোটটি রিনোট করা যাবে না।" | ||||
| cantReRenote: "রিনোটকে রিনোট করা যাবে না।" | ||||
| quote: "উদ্ধৃতি" | ||||
| inChannelRenote: "চ্যানেলে রিনোট" | ||||
| inChannelQuote: "চ্যানেলে উদ্ধৃতি" | ||||
| pinnedNote: "পিন করা নোট" | ||||
| pinned: "পিন করা" | ||||
| you: "আপনি" | ||||
|  | @ -108,6 +121,10 @@ sensitive: "সংবেদনশীল বিষয়বস্তু" | |||
| add: "যুক্ত করুন" | ||||
| reaction: "প্রতিক্রিয়া" | ||||
| reactions: "প্রতিক্রিয়া" | ||||
| emojiPicker: "ইমোজি পিকার" | ||||
| pinnedEmojisForReactionSettingDescription: "রিঅ্যাকশন দেয়ার সময় আপনি ইমোজিটিকে পিন করা এবং প্রদর্শিত হওয়ার জন্য সেট করতে পারেন।" | ||||
| pinnedEmojisSettingDescription: "ইমোজি ইনপুট দেয়ার সময় আপনি ইমোজিটিকে পিন করা এবং প্রদর্শিত হওয়ার জন্য সেট করতে পারেন।" | ||||
| emojiPickerDisplay: "পিকার ডিসপ্লে" | ||||
| reactionSettingDescription2: "পুনরায় সাজাতে টেনে আনুন, মুছতে ক্লিক করুন, যোগ করতে + টিপুন।" | ||||
| rememberNoteVisibility: "নোটের দৃশ্যমান্যতার সেটিংস মনে রাখুন" | ||||
| attachCancel: "অ্যাটাচমেন্ট সরান " | ||||
|  | @ -1034,6 +1051,7 @@ _2fa: | |||
|   step3: "অ্যাপে প্রদর্শিত টোকেনটি লিখুন এবং আপনার কাজ শেষ।" | ||||
|   step4: "আপনাকে এখন থেকে লগ ইন করার সময়, এইভাবে টোকেন লিখতে হবে।" | ||||
|   securityKeyInfo: "আপনি একটি হার্ডওয়্যার সিকিউরিটি কী ব্যবহার করে লগ ইন করতে পারেন যা FIDO2 বা ডিভাইসের ফিঙ্গারপ্রিন্ট সেন্সর বা পিন সমর্থন করে৷" | ||||
|   renewTOTPCancel: "না, ধন্যবাদ" | ||||
| _permissions: | ||||
|   "read:account": "অ্যাকাউন্টের তথ্য দেখুন" | ||||
|   "write:account": "অ্যাকাউন্টের তথ্য সম্পাদন করুন" | ||||
|  |  | |||
|  | @ -121,6 +121,10 @@ sensitive: "Konten sensitif" | |||
| add: "Tambahkan" | ||||
| reaction: "Reaksi" | ||||
| reactions: "Reaksi" | ||||
| emojiPicker: "Emoji Picker" | ||||
| pinnedEmojisForReactionSettingDescription: "Atur sematan emoji pada reaksi" | ||||
| pinnedEmojisSettingDescription: "Atur sematan emoji pada masukan emoji" | ||||
| emojiPickerDisplay: "Tampilan Emoji Picker" | ||||
| reactionSettingDescription2: "Geser untuk memindah urutan emoji, klik untuk menghapus, tekan \"+\" untuk menambahkan" | ||||
| rememberNoteVisibility: "Ingat pengaturan visibilitas catatan" | ||||
| attachCancel: "Hapus lampiran" | ||||
|  | @ -641,6 +645,7 @@ smtpSecure: "Gunakan SSL/TLS implisit untuk koneksi SMTP" | |||
| smtpSecureInfo: "Matikan ini ketika menggunakan STARTTLS" | ||||
| testEmail: "Tes pengiriman surel" | ||||
| wordMute: "Bisukan kata" | ||||
| hardWordMute: "Pembisuan kata keras" | ||||
| regexpError: "Kesalahan ekspresi reguler" | ||||
| regexpErrorDescription: "Galat terjadi pada baris {line} ekspresi reguler dari {tab} kata yang dibisukan:" | ||||
| instanceMute: "Bisukan instansi" | ||||
|  | @ -1154,6 +1159,7 @@ tosAndPrivacyPolicy: "Syarat dan Ketentuan serta Kebijakan Privasi" | |||
| avatarDecorations: "Dekorasi avatar" | ||||
| attach: "Lampirkan" | ||||
| detach: "Hapus" | ||||
| detachAll: "Lepas Semua" | ||||
| angle: "Sudut" | ||||
| flip: "Balik" | ||||
| showAvatarDecorations: "Tampilkan dekorasi avatar" | ||||
|  | @ -1168,6 +1174,7 @@ doReaction: "Tambahkan reaksi" | |||
| code: "Kode" | ||||
| reloadRequiredToApplySettings: "Muat ulang diperlukan untuk menerapkan pengaturan." | ||||
| remainingN: "Sisa : {n}" | ||||
| decorate: "Dekor" | ||||
| _announcement: | ||||
|   forExistingUsers: "Hanya pengguna yang telah ada" | ||||
|   forExistingUsersDescription: "Pengumuman ini akan dimunculkan ke pengguna yang sudah ada dari titik waktu publikasi jika dinyalakan. Apabila dimatikan, mereka yang baru mendaftar setelah publikasi ini akan juga melihatnya." | ||||
|  | @ -1215,6 +1222,7 @@ _initialTutorial: | |||
|       followers: "Perlihatkan ke pengikut saja. Hanya pengikut yang dapat melihat postinganmu dan tidak dapat direnote oleh siapapun." | ||||
|       direct: "Hanya perlihatkan ke pengguna spesifik dan penerima akan diberi tahu. Dapat juga digunakan sebagai alternatif dari pesan langsung." | ||||
|     _cw: | ||||
|       title: "Peringatan Konten (CW)" | ||||
|       _exampleNote: | ||||
|         cw: "Peringatan: Bikin Lapar!" | ||||
|         note: "Baru aja makan donat berlapis coklat 🍩😋" | ||||
|  |  | |||
|  | @ -260,6 +260,7 @@ removed: "뭉캣십니다" | |||
| removeAreYouSure: "‘{x}’(얼)럴 뭉캡니꺼?" | ||||
| deleteAreYouSure: "‘{x}’(얼)럴 뭉캡니꺼?" | ||||
| resetAreYouSure: "아시로 데돌립니꺼?" | ||||
| areYouSure: "갠찮십니꺼?" | ||||
| saved: "저장햇십니다" | ||||
| messaging: "대화" | ||||
| upload: "올리기" | ||||
|  | @ -458,6 +459,7 @@ noMessagesYet: "아직 대화가 없십니다" | |||
| newMessageExists: "새 메시지가 있십니다" | ||||
| onlyOneFileCanBeAttached: "메시지엔 파일 하나까제밖에 몬 넣십니다" | ||||
| invitations: "초대하기" | ||||
| invitationCode: "초대장" | ||||
| checking: "학인하고 잇십니다" | ||||
| passwordMatched: "맞십니다" | ||||
| passwordNotMatched: "안 맞십니다" | ||||
|  | @ -564,6 +566,11 @@ removeAllFollowing: "팔로잉 말캉 무루기" | |||
| removeAllFollowingDescription: "{host} 서버랑 걸어놓은 모든 팔로잉을 무룹니다. 고 서버가 아예 없어지삐맀든가, 그런 경우에 하이소." | ||||
| userSuspended: "요 게정은... 얼어 있십니다." | ||||
| userSilenced: "요 게정은... 수ᇚ혀 있십니다." | ||||
| relays: "릴레이" | ||||
| addRelay: "릴레이 옇기" | ||||
| addedRelays: "옇은 릴레이" | ||||
| enableInfiniteScroll: "알아서 더 보기" | ||||
| author: "맨던 사람" | ||||
| manage: "간리" | ||||
| emailServer: "전자우펜 서버" | ||||
| email: "전자우펜" | ||||
|  | @ -572,6 +579,8 @@ smtpHost: "호스트 이럼" | |||
| smtpPort: "포트" | ||||
| smtpUser: "사용자 이럼" | ||||
| smtpPass: "비밀번호" | ||||
| display: "보기" | ||||
| create: "맨걸기" | ||||
| abuseReports: "신고하기" | ||||
| reportAbuse: "신고하기" | ||||
| reportAbuseRenote: "리노트 신고하기" | ||||
|  | @ -583,6 +592,7 @@ forwardReport: "웬겍 서버에 신고 보내기" | |||
| random: "무작이" | ||||
| system: "시스템" | ||||
| clip: "클립 맨걸기" | ||||
| createNew: "새로 맨걸기" | ||||
| notesCount: "노트 수" | ||||
| renotesCount: "리노트한 수" | ||||
| renotedCount: "리노트덴 수" | ||||
|  | @ -608,6 +618,7 @@ tools: "도구" | |||
| like: "좋네예!" | ||||
| unlike: "좋네예 무루기" | ||||
| numberOfLikes: "좋네예 수" | ||||
| show: "보기" | ||||
| roles: "옉할" | ||||
| role: "옉할" | ||||
| noRole: "옉할이 없십니다" | ||||
|  | @ -637,6 +648,8 @@ _gallery: | |||
| _email: | ||||
|   _follow: | ||||
|     title: "새 팔로워가 잇십니다" | ||||
| _serverDisconnectedBehavior: | ||||
|   reload: "알아서 새로곤침" | ||||
| _channel: | ||||
|   removeBanner: "배너 뭉캐기" | ||||
| _theme: | ||||
|  |  | |||
|  | @ -425,9 +425,9 @@ setupOf2fa: "2단계 인증 설정" | |||
| totp: "인증 앱" | ||||
| totpDescription: "인증 앱을 사용하여 일회성 비밀번호 입력" | ||||
| moderator: "모더레이터" | ||||
| moderation: "모더레이션" | ||||
| moderationNote: "모더레이션 노트" | ||||
| addModerationNote: "모더레이션 노트 추가하기" | ||||
| moderation: "조정" | ||||
| moderationNote: "조정 기록" | ||||
| addModerationNote: "조정 기록 추가하기" | ||||
| moderationLogs: "모더레이션 로그" | ||||
| nUsersMentioned: "{n}명이 언급함" | ||||
| securityKeyAndPasskey: "보안 키 또는 패스 키" | ||||
|  | @ -513,7 +513,7 @@ dayOverDayChanges: "어제보다" | |||
| appearance: "모양" | ||||
| clientSettings: "클라이언트 설정" | ||||
| accountSettings: "계정 설정" | ||||
| promotion: "프로모션" | ||||
| promotion: "홍보" | ||||
| promote: "프로모션하기" | ||||
| numberOfDays: "며칠동안" | ||||
| hideThisNote: "이 노트를 숨기기" | ||||
|  | @ -863,8 +863,8 @@ devMode: "개발자 모드" | |||
| keepCw: "CW 유지하기" | ||||
| pubSub: "Pub/Sub 계정" | ||||
| lastCommunication: "마지막 통신" | ||||
| resolved: "해결됨" | ||||
| unresolved: "해결되지 않음" | ||||
| resolved: "처리함" | ||||
| unresolved: "처리되지 않음" | ||||
| breakFollow: "팔로워 해제" | ||||
| breakFollowConfirm: "팔로우를 해제하시겠습니까?" | ||||
| itsOn: "켜져 있습니다" | ||||
|  | @ -1181,6 +1181,8 @@ remainingN: "나머지: {n}" | |||
| overwriteContentConfirm: "현재 내용을 덮어쓰기 합니다. 계속 진행하시겠습니까?" | ||||
| seasonalScreenEffect: "계절에 따른 효과 보이기" | ||||
| decorate: "장식하기" | ||||
| addMfmFunction: "장식 추가하기" | ||||
| enableQuickAddMfmFunction: "상급자용 MFM 선택기 표시하기" | ||||
| _announcement: | ||||
|   forExistingUsers: "기존 유저에게만 알림" | ||||
|   forExistingUsersDescription: "활성화하면 이 공지사항을 게시한 시점에서 이미 가입한 유저에게만 표시합니다. 비활성화하면 게시 후에 가입한 유저에게도 표시합니다." | ||||
|  | @ -1557,7 +1559,7 @@ _role: | |||
|   name: "역할 이름" | ||||
|   description: "역할 설명" | ||||
|   permission: "역할 권한" | ||||
|   descriptionOfPermission: "<b>모더레이터</b>는 기본적인 중재와 관련된 작업을 수행할 수 있습니다.\n<b>관리자</b>는 서버의 모든 설정을 변경할 수 있습니다." | ||||
|   descriptionOfPermission: "<b>조정자</b>는 기본적인 조정 작업을 진행할 수 있습니다.\n<b>관리자</b>는 서버의 모든 설정을 변경할 수 있습니다." | ||||
|   assignTarget: "할당 대상" | ||||
|   descriptionOfAssignTarget: "<b>수동</b>을 선택하면 누가 이 역할에 포함되는지를 수동으로 관리할 수 있습니다.\n<b>조건부</b>를 선택하면 조건을 설정해 일치하는 사용자를 자동으로 포함되게 할 수 있습니다." | ||||
|   manual: "수동" | ||||
|  | @ -1628,7 +1630,7 @@ _role: | |||
|     or: "다음을 하나라도 만족" | ||||
|     not: "다음을 만족하지 않음" | ||||
| _sensitiveMediaDetection: | ||||
|   description: "기계학습을 통해 자동으로 민감한 미디어를 탐지하여, 모더레이션에 참고할 수 있도록 합니다. 서버의 부하를 약간 증가시킵니다." | ||||
|   description: "기계 학습으로 민감한 미디어를 알아서 찾아내어 조정에 참고하도록 합니다. 서버가 부하를 다소 받습니다." | ||||
|   sensitivity: "탐지 민감도" | ||||
|   sensitivityDescription: "민감도가 낮을수록 안전한 미디어가 잘못 탐지될 확률이 줄어들며, 높을수록 민감한 미디어가 탐지되지 않을 확률이 줄어듭니다." | ||||
|   setSensitiveFlagAutomatically: "자동으로 NSFW로 설정하기" | ||||
|  | @ -1933,6 +1935,55 @@ _permissions: | |||
|   "write:flash": "Play를 조작합니다" | ||||
|   "read:flash-likes": "Play의 좋아요를 봅니다" | ||||
|   "write:flash-likes": "Play의 좋아요를 조작합니다" | ||||
|   "read:admin:abuse-user-reports": "사용자 신고 보기" | ||||
|   "write:admin:delete-account": "사용자 계정 삭제하기" | ||||
|   "write:admin:delete-all-files-of-a-user": "모든 사용자 파일 삭제하기" | ||||
|   "read:admin:index-stats": "데이터베이스 색인 정보 보기" | ||||
|   "read:admin:table-stats": "데이터베이스 테이블 정보 보기" | ||||
|   "read:admin:user-ips": "사용자 IP 주소 보기" | ||||
|   "read:admin:meta": "인스턴스 메타데이터 보기" | ||||
|   "write:admin:reset-password": "사용자 비밀번호 재설정하기" | ||||
|   "write:admin:resolve-abuse-user-report": "사용자 신고 처리하기" | ||||
|   "write:admin:send-email": "이메일 보내기" | ||||
|   "read:admin:server-info": "서버 정보 보기" | ||||
|   "read:admin:show-moderation-log": "조정 기록 보기" | ||||
|   "read:admin:show-user": "사용자 개인정보 보기" | ||||
|   "read:admin:show-users": "사용자 개인정보 보기" | ||||
|   "write:admin:suspend-user": "사용자 정지하기" | ||||
|   "write:admin:unset-user-avatar": "사용자 아바타 삭제하기" | ||||
|   "write:admin:unset-user-banner": "사용자 배너 삭제하기" | ||||
|   "write:admin:unsuspend-user": "사용자 정지 해제하기" | ||||
|   "write:admin:meta": "인스턴스 메타데이터 수정하기" | ||||
|   "write:admin:user-note": "조정 기록 수정하기" | ||||
|   "write:admin:roles": "역할 수정하기" | ||||
|   "read:admin:roles": "역할 보기" | ||||
|   "write:admin:relays": "릴레이 수정하기" | ||||
|   "read:admin:relays": "릴레이 보기" | ||||
|   "write:admin:invite-codes": "초대 코드 수정하기" | ||||
|   "read:admin:invite-codes": "초대 코드 보기" | ||||
|   "write:admin:announcements": "공지사항 수정하기" | ||||
|   "read:admin:announcements": "공지사항 보기" | ||||
|   "write:admin:avatar-decorations": "아바타 꾸미기 수정하기" | ||||
|   "read:admin:avatar-decorations": "아바타 꾸미기 보기" | ||||
|   "write:admin:federation": "연합 정보 수정하기" | ||||
|   "write:admin:account": "사용자 계정 수정하기" | ||||
|   "read:admin:account": "사용자 정보 보기" | ||||
|   "write:admin:emoji": "이모지 수정하기" | ||||
|   "read:admin:emoji": "이모지 보기" | ||||
|   "write:admin:queue": "작업 대기열 수정하기" | ||||
|   "read:admin:queue": "작업 대기열 정보 보기" | ||||
|   "write:admin:promo": "홍보 기록 수정하기" | ||||
|   "write:admin:drive": "사용자 드라이브 수정하기" | ||||
|   "read:admin:drive": "사용자 드라이브 정보 보기" | ||||
|   "read:admin:stream": "관리자용 Websocket API 사용하기" | ||||
|   "write:admin:ad": "광고 수정하기" | ||||
|   "read:admin:ad": "광고 보기" | ||||
|   "write:invite-codes": "초대 코드 만들기" | ||||
|   "read:invite-codes": "초대 코드 불러오기" | ||||
|   "write:clip-favorite": "클립의 좋아요 수정하기" | ||||
|   "read:clip-favorite": "클립의 좋아요 보기" | ||||
|   "read:federation": "연합 정보 불러오기" | ||||
|   "write:report-abuse": "위반 내용 신고하기" | ||||
| _auth: | ||||
|   shareAccessTitle: "어플리케이션의 접근 허가" | ||||
|   shareAccess: "\"{name}\" 이 계정에 접근하는 것을 허용하시겠습니까?" | ||||
|  | @ -2267,21 +2318,21 @@ _moderationLogTypes: | |||
|   updateCustomEmoji: "커스텀 이모지 수정" | ||||
|   deleteCustomEmoji: "커스텀 이모지 삭제" | ||||
|   updateServerSettings: "서버 설정 갱신" | ||||
|   updateUserNote: "모더레이션 노트 갱신" | ||||
|   updateUserNote: "조정 기록 갱신" | ||||
|   deleteDriveFile: "파일 삭제" | ||||
|   deleteNote: "노트 삭제" | ||||
|   createGlobalAnnouncement: "전역 공지사항 생성" | ||||
|   createUserAnnouncement: "유저 공지사항 생성" | ||||
|   updateGlobalAnnouncement: "전역 공지사항 수정" | ||||
|   updateUserAnnouncement: "유저 공지사항 수정" | ||||
|   deleteGlobalAnnouncement: "전역 공지사항 삭제" | ||||
|   deleteUserAnnouncement: "유저 공지사항 삭제" | ||||
|   createGlobalAnnouncement: "모든 공지사항 만들기" | ||||
|   createUserAnnouncement: "사용자 공지사항 만들기" | ||||
|   updateGlobalAnnouncement: "모든 공지사항 수정" | ||||
|   updateUserAnnouncement: "사용자 공지사항 수정" | ||||
|   deleteGlobalAnnouncement: "모든 공지사항 삭제" | ||||
|   deleteUserAnnouncement: "사용자 공지사항 삭제" | ||||
|   resetPassword: "비밀번호 재설정" | ||||
|   suspendRemoteInstance: "리모트 서버를 정지" | ||||
|   unsuspendRemoteInstance: "리모트 서버의 정지를 해제" | ||||
|   markSensitiveDriveFile: "파일에 열람주의를 설정" | ||||
|   unmarkSensitiveDriveFile: "파일에 열람주의를 해제" | ||||
|   resolveAbuseReport: "신고 해결" | ||||
|   resolveAbuseReport: "신고 처리" | ||||
|   createInvitation: "초대 코드 생성" | ||||
|   createAd: "광고 생성" | ||||
|   deleteAd: "광고 삭제" | ||||
|  |  | |||
|  | @ -1181,6 +1181,8 @@ remainingN: "剩餘:{n}" | |||
| overwriteContentConfirm: "確定要覆蓋目前的內容嗎?" | ||||
| seasonalScreenEffect: "隨季節變換畫面的呈現" | ||||
| decorate: "設置頭像裝飾" | ||||
| addMfmFunction: "插入MFM功能語法" | ||||
| enableQuickAddMfmFunction: "顯示高級MFM選擇器" | ||||
| _announcement: | ||||
|   forExistingUsers: "僅限既有的使用者" | ||||
|   forExistingUsersDescription: "啟用代表僅向現存使用者顯示;停用代表張貼後註冊的新使用者也會看到。" | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| { | ||||
| 	"name": "misskey", | ||||
| 	"version": "2023.12.1-PrisMisskey.1", | ||||
| 	"version": "2023.12.2-PrisMisskey.1", | ||||
| 	"codename": "nasubi", | ||||
| 	"repository": { | ||||
| 		"type": "git", | ||||
|  | @ -18,7 +18,7 @@ | |||
| 		"build-assets": "node ./scripts/build-assets.mjs", | ||||
| 		"build": "pnpm build-pre && pnpm -r build && pnpm build-assets", | ||||
| 		"build-storybook": "pnpm --filter frontend build-storybook", | ||||
| 		"build-misskey-js-with-types": "pnpm --filter backend build && pnpm --filter backend generate-api-json && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build", | ||||
| 		"build-misskey-js-with-types": "pnpm --filter backend build && pnpm --filter backend generate-api-json && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api", | ||||
| 		"start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js", | ||||
| 		"start:test": "cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js", | ||||
| 		"init": "pnpm migrate", | ||||
|  |  | |||
|  | @ -0,0 +1,20 @@ | |||
| /* | ||||
|  * SPDX-FileCopyrightText: syuilo and other misskey contributors | ||||
|  * SPDX-License-Identifier: AGPL-3.0-only | ||||
|  */ | ||||
| 
 | ||||
| export class SupportTrueMailApi1703658526000 { | ||||
|     name = 'SupportTrueMailApi1703658526000' | ||||
| 
 | ||||
|     async up(queryRunner) { | ||||
|     	  await queryRunner.query(`ALTER TABLE "meta" ADD "truemailInstance" character varying(1024)`); | ||||
|         await queryRunner.query(`ALTER TABLE "meta" ADD "truemailAuthKey" character varying(1024)`); | ||||
|         await queryRunner.query(`ALTER TABLE "meta" ADD "enableTruemailApi" boolean NOT NULL DEFAULT false`); | ||||
|     } | ||||
| 
 | ||||
|     async down(queryRunner) { | ||||
|         await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableTruemailApi"`); | ||||
|         await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "truemailInstance"`); | ||||
|         await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "truemailAuthKey"`); | ||||
|     } | ||||
| } | ||||
|  | @ -156,7 +156,7 @@ export class EmailService { | |||
| 	@bindThis | ||||
| 	public async validateEmailForAccount(emailAddress: string): Promise<{ | ||||
| 		available: boolean; | ||||
| 		reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp' | 'banned'; | ||||
| 		reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp' | 'banned' | 'network' | 'blacklist'; | ||||
| 	}> { | ||||
| 		const meta = await this.metaService.fetch(); | ||||
| 
 | ||||
|  | @ -173,6 +173,8 @@ export class EmailService { | |||
| 		if (meta.enableActiveEmailValidation) { | ||||
| 			if (meta.enableVerifymailApi && meta.verifymailAuthKey != null) { | ||||
| 				validated = await this.verifyMail(emailAddress, meta.verifymailAuthKey); | ||||
| 			} else if (meta.enableTruemailApi && meta.truemailInstance && meta.truemailAuthKey != null) { | ||||
| 				validated = await this.trueMail(meta.truemailInstance, emailAddress, meta.truemailAuthKey); | ||||
| 			} else { | ||||
| 				validated = await validateEmail({ | ||||
| 					email: emailAddress, | ||||
|  | @ -212,6 +214,8 @@ export class EmailService { | |||
| 			validated.reason === 'disposable' ? 'disposable' : | ||||
| 			validated.reason === 'mx' ? 'mx' : | ||||
| 			validated.reason === 'smtp' ? 'smtp' : | ||||
| 			validated.reason === 'network' ? 'network' : | ||||
| 			validated.reason === 'blacklist' ? 'blacklist' : | ||||
| 			null, | ||||
| 		}; | ||||
| 	} | ||||
|  | @ -276,4 +280,67 @@ export class EmailService { | |||
| 			reason: null, | ||||
| 		}; | ||||
| 	} | ||||
| 
 | ||||
| 	private async trueMail<T>(truemailInstance: string, emailAddress: string, truemailAuthKey: string): Promise<{ | ||||
| 		valid: boolean; | ||||
| 		reason: 'used' | 'format' | 'blacklist' | 'mx' | 'smtp' | 'network' | T | null; | ||||
| 	}> { | ||||
| 		const endpoint = truemailInstance + '?email=' + emailAddress; | ||||
| 		try { | ||||
| 			const res = await this.httpRequestService.send(endpoint, { | ||||
| 				method: 'POST', | ||||
| 				headers: { | ||||
| 					'Content-Type': 'application/json', | ||||
| 					Accept: 'application/json', | ||||
| 					Authorization: truemailAuthKey | ||||
| 				}, | ||||
| 			}); | ||||
| 			 | ||||
| 			const json = (await res.json()) as { | ||||
| 				email: string; | ||||
| 				success: boolean; | ||||
| 				errors?: {  | ||||
| 					list_match?: string; | ||||
| 					regex?: string; | ||||
| 					mx?: string; | ||||
| 					smtp?: string; | ||||
| 				} | null; | ||||
| 			}; | ||||
| 			 | ||||
| 			if (json.email === undefined || (json.email !== undefined && json.errors?.regex)) { | ||||
| 				return { | ||||
| 						valid: false, | ||||
| 						reason: 'format', | ||||
| 				}; | ||||
| 			} | ||||
| 			if (json.errors?.smtp) { | ||||
| 				return { | ||||
| 					valid: false, | ||||
| 					reason: 'smtp', | ||||
| 				}; | ||||
| 			} | ||||
| 			if (json.errors?.mx) { | ||||
| 				return { | ||||
| 					valid: false, | ||||
| 					reason: 'mx', | ||||
| 				}; | ||||
| 			} | ||||
| 			if (!json.success) { | ||||
| 				return { | ||||
| 					valid: false, | ||||
| 					reason: json.errors?.list_match as T || 'blacklist', | ||||
| 				}; | ||||
| 			} | ||||
| 			 | ||||
| 			return { | ||||
| 				valid: true, | ||||
| 				reason: null, | ||||
| 			}; | ||||
| 		} catch (error) { | ||||
| 			return { | ||||
| 				valid: false, | ||||
| 				reason: 'network', | ||||
| 			}; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -472,6 +472,23 @@ export class MiMeta { | |||
| 	}) | ||||
| 	public verifymailAuthKey: string | null; | ||||
| 
 | ||||
| 	@Column('boolean', { | ||||
| 		default: false, | ||||
| 	}) | ||||
| 	public enableTruemailApi: boolean; | ||||
| 
 | ||||
| 	@Column('varchar', { | ||||
| 		length: 1024, | ||||
| 		nullable: true, | ||||
| 	}) | ||||
| 	public truemailInstance: string | null; | ||||
| 	 | ||||
| 	@Column('varchar', { | ||||
| 		length: 1024, | ||||
| 		nullable: true, | ||||
| 	}) | ||||
| 	public truemailAuthKey: string | null; | ||||
| 
 | ||||
| 	@Column('boolean', { | ||||
| 		default: true, | ||||
| 	}) | ||||
|  |  | |||
|  | @ -284,6 +284,18 @@ export const meta = { | |||
| 				type: 'string', | ||||
| 				optional: false, nullable: true, | ||||
| 			}, | ||||
| 			enableTruemailApi: { | ||||
| 				type: 'boolean', | ||||
| 				optional: false, nullable: false, | ||||
| 			}, | ||||
| 			truemailInstance: { | ||||
| 				type: 'string', | ||||
| 				optional: false, nullable: true, | ||||
| 			}, | ||||
| 			truemailAuthKey: { | ||||
| 				type: 'string', | ||||
| 				optional: false, nullable: true, | ||||
| 			}, | ||||
| 			enableChartsForRemoteUser: { | ||||
| 				type: 'boolean', | ||||
| 				optional: false, nullable: false, | ||||
|  | @ -525,6 +537,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 				enableActiveEmailValidation: instance.enableActiveEmailValidation, | ||||
| 				enableVerifymailApi: instance.enableVerifymailApi, | ||||
| 				verifymailAuthKey: instance.verifymailAuthKey, | ||||
| 				enableTruemailApi: instance.enableTruemailApi, | ||||
| 				truemailInstance: instance.truemailInstance, | ||||
| 				truemailAuthKey: instance.truemailAuthKey, | ||||
| 				enableChartsForRemoteUser: instance.enableChartsForRemoteUser, | ||||
| 				enableChartsForFederatedInstances: instance.enableChartsForFederatedInstances, | ||||
| 				enableServerMachineStats: instance.enableServerMachineStats, | ||||
|  |  | |||
|  | @ -118,6 +118,9 @@ export const paramDef = { | |||
| 		enableActiveEmailValidation: { type: 'boolean' }, | ||||
| 		enableVerifymailApi: { type: 'boolean' }, | ||||
| 		verifymailAuthKey: { type: 'string', nullable: true }, | ||||
| 		enableTruemailApi: { type: 'boolean' }, | ||||
| 		truemailInstance: { type: 'string', nullable: true }, | ||||
| 		truemailAuthKey: { type: 'string', nullable: true }, | ||||
| 		enableChartsForRemoteUser: { type: 'boolean' }, | ||||
| 		enableChartsForFederatedInstances: { type: 'boolean' }, | ||||
| 		enableServerMachineStats: { type: 'boolean' }, | ||||
|  | @ -484,6 +487,26 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | |||
| 					set.verifymailAuthKey = ps.verifymailAuthKey; | ||||
| 				} | ||||
| 			} | ||||
| 			 | ||||
| 			if (ps.enableTruemailApi !== undefined) { | ||||
| 				set.enableTruemailApi = ps.enableTruemailApi; | ||||
| 			} | ||||
| 
 | ||||
| 			if (ps.truemailInstance !== undefined) { | ||||
| 				if (ps.truemailInstance === '') { | ||||
| 					set.truemailInstance = null; | ||||
| 				} else { | ||||
| 					set.truemailInstance = ps.truemailInstance; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if (ps.truemailAuthKey !== undefined) { | ||||
| 				if (ps.truemailAuthKey === '') { | ||||
| 					set.truemailAuthKey = null; | ||||
| 				} else { | ||||
| 					set.truemailAuthKey = ps.truemailAuthKey; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if (ps.enableChartsForRemoteUser !== undefined) { | ||||
| 				set.enableChartsForRemoteUser = ps.enableChartsForRemoteUser; | ||||
|  |  | |||
|  | @ -773,10 +773,20 @@ async function post(ev?: MouseEvent) { | |||
|   noteId: props.updateMode ? props.initialNote?.id : undefined, | ||||
| 	}; | ||||
| 
 | ||||
|   if (withHashtags.value && hashtags.value && hashtags.value.trim() !== '') { | ||||
|     const hashtags_ = hashtags.value.trim().split(' ').map(x => x.startsWith('#') ? x : '#' + x).join(' '); | ||||
|     postData.text = postData.text ? `${postData.text} ${hashtags_}` : hashtags_; | ||||
|   } | ||||
| 	if (withHashtags.value && hashtags.value && hashtags.value.trim() !== '') { | ||||
| 		const hashtags_ = hashtags.value.trim().split(' ').map(x => x.startsWith('#') ? x : '#' + x).join(' '); | ||||
| 		if (!postData.text) { | ||||
| 			postData.text = hashtags_; | ||||
| 		} else { | ||||
| 			const postTextLines = postData.text.split('\n'); | ||||
| 			if (postTextLines[postTextLines.length - 1].trim() === '') { | ||||
| 				postTextLines[postTextLines.length - 1] += hashtags_; | ||||
| 			} else { | ||||
| 				postTextLines[postTextLines.length - 1] += ' ' + hashtags_; | ||||
| 			} | ||||
| 			postData.text = postTextLines.join('\n'); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|   // plugin | ||||
|   if (notePostInterruptors.length > 0) { | ||||
|  |  | |||
|  | @ -80,6 +80,17 @@ SPDX-License-Identifier: AGPL-3.0-only | |||
| 							<template #prefix><i class="ti ti-key"></i></template> | ||||
| 							<template #label>Verifymail.io API Auth Key</template> | ||||
| 						</MkInput> | ||||
| 						<MkSwitch v-model="enableTruemailApi" @update:modelValue="save"> | ||||
| 							<template #label>Use TrueMail API</template> | ||||
| 						</MkSwitch> | ||||
| 						<MkInput v-model="truemailInstance" @update:modelValue="save"> | ||||
| 							<template #prefix><i class="ti ti-key"></i></template> | ||||
| 							<template #label>TrueMail API Instance</template> | ||||
| 						</MkInput> | ||||
| 						<MkInput v-model="truemailAuthKey" @update:modelValue="save"> | ||||
| 							<template #prefix><i class="ti ti-key"></i></template> | ||||
| 							<template #label>TrueMail API Auth Key</template> | ||||
| 						</MkInput> | ||||
| 					</div> | ||||
| 				</MkFolder> | ||||
| 
 | ||||
|  | @ -153,6 +164,9 @@ const enableIpLogging = ref<boolean>(false); | |||
| const enableActiveEmailValidation = ref<boolean>(false); | ||||
| const enableVerifymailApi = ref<boolean>(false); | ||||
| const verifymailAuthKey = ref<string | null>(null); | ||||
| const enableTruemailApi = ref<boolean>(false); | ||||
| const truemailInstance = ref<string | null>(null); | ||||
| const truemailAuthKey = ref<string | null>(null); | ||||
| const bannedEmailDomains = ref<string>(''); | ||||
| 
 | ||||
| async function init() { | ||||
|  | @ -194,6 +208,9 @@ function save() { | |||
| 		enableActiveEmailValidation: enableActiveEmailValidation.value, | ||||
| 		enableVerifymailApi: enableVerifymailApi.value, | ||||
| 		verifymailAuthKey: verifymailAuthKey.value, | ||||
| 		enableTruemailApi: enableTruemailApi.value, | ||||
| 		truemailInstance: truemailInstance.value, | ||||
| 		truemailAuthKey: truemailAuthKey.value, | ||||
| 		bannedEmailDomains: bannedEmailDomains.value.split('\n'), | ||||
| 	}).then(() => { | ||||
| 		fetchInstance(); | ||||
|  |  | |||
|  | @ -46,7 +46,7 @@ SPDX-License-Identifier: AGPL-3.0-only | |||
| 		<div v-else-if="tab === 'search'"> | ||||
| 			<div class="_gaps"> | ||||
| 				<div> | ||||
| 					<MkInput v-model="searchQuery"> | ||||
| 					<MkInput v-model="searchQuery" @enter="search()"> | ||||
| 						<template #prefix><i class="ti ti-search"></i></template> | ||||
| 					</MkInput> | ||||
| 					<MkButton primary rounded style="margin-top: 8px;" @click="search()">{{ i18n.ts.search }}</MkButton> | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only | |||
| 	<MkSpacer :contentMax="700"> | ||||
| 		<div v-if="tab === 'search'"> | ||||
| 			<div class="_gaps"> | ||||
| 				<MkInput v-model="searchQuery" :large="true" :autofocus="true" type="search"> | ||||
| 				<MkInput v-model="searchQuery" :large="true" :autofocus="true" type="search" @enter="search"> | ||||
| 					<template #prefix><i class="ti ti-search"></i></template> | ||||
| 				</MkInput> | ||||
| 				<MkRadios v-model="searchType" @update:modelValue="search()"> | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only | |||
| <template> | ||||
| <div class="_gaps"> | ||||
| 	<div class="_gaps"> | ||||
| 		<MkInput v-model="searchQuery" :large="true" :autofocus="true" type="search"> | ||||
| 		<MkInput v-model="searchQuery" :large="true" :autofocus="true" type="search" @enter="search"> | ||||
| 			<template #prefix><i class="ti ti-search"></i></template> | ||||
| 		</MkInput> | ||||
| 		<MkFolder> | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only | |||
| <template> | ||||
| <div class="_gaps"> | ||||
| 	<div class="_gaps"> | ||||
| 		<MkInput v-model="searchQuery" :large="true" :autofocus="true" type="search"> | ||||
| 		<MkInput v-model="searchQuery" :large="true" :autofocus="true" type="search" @enter="search"> | ||||
| 			<template #prefix><i class="ti ti-search"></i></template> | ||||
| 		</MkInput> | ||||
| 		<MkRadios v-model="searchOrigin" @update:modelValue="search()"> | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue