Compare commits

..

81 Commits

Author SHA1 Message Date
e967d9ded3 Merge branch 'develop' 2021-08-24 13:20:30 +09:00
c3b55b6849 12.89.1 2021-08-24 13:20:20 +09:00
3e193c9864 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2021-08-24 13:19:28 +09:00
d64e25e449 fix: support DeepL pro account
Fix #7648
2021-08-24 13:19:21 +09:00
c4707c612d New Crowdin updates (#7679)
* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations create-plugin.md (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Esperanto)

* New translations keyboard-shortcut.md (Esperanto)

* New translations timeline.md (Esperanto)

* New translations glossary.md (Esperanto)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Esperanto)

* New translations keyboard-shortcut.md (Esperanto)

* New translations timeline.md (Esperanto)

* New translations glossary.md (Esperanto)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Korean)
2021-08-24 13:08:58 +09:00
9d3448c880 fix(server): use csp to imporve security 2021-08-24 13:08:20 +09:00
dad6a77645 refactoring 2021-08-22 22:22:53 +09:00
f64d3942d7 🎨 2021-08-22 16:18:53 +09:00
45fe754759 🎨 2021-08-22 16:15:40 +09:00
98f1d93628 refactor 2021-08-22 13:16:23 +09:00
8785e1c3a4 enhance(client): ユーザー名についてのヒントを追加 2021-08-22 13:16:15 +09:00
f00ceedae4 Merge branch 'develop' 2021-08-21 17:59:29 +09:00
7387e010c2 12.89.0 2021-08-21 17:59:13 +09:00
a59dfff12f New Crowdin updates (#7646)
* New translations mute-and-block.md (Ukrainian)

* New translations mute-and-block.md (Czech)

* New translations mute-and-block.md (Danish)

* New translations mute-and-block.md (German)

* New translations mute-and-block.md (Italian)

* New translations mute-and-block.md (Korean)

* New translations mute-and-block.md (Dutch)

* New translations mute-and-block.md (Norwegian)

* New translations mute-and-block.md (Polish)

* New translations mute-and-block.md (Portuguese)

* New translations mute-and-block.md (Russian)

* New translations mute-and-block.md (Chinese Simplified)

* New translations mute-and-block.md (Spanish)

* New translations mute-and-block.md (Chinese Traditional)

* New translations mute-and-block.md (English)

* New translations mute-and-block.md (Indonesian)

* New translations mute-and-block.md (Thai)

* New translations mute-and-block.md (Esperanto)

* New translations mute-and-block.md (Uyghur)

* New translations mute-and-block.md (Lojban)

* New translations mute-and-block.md (Kannada)

* New translations mute-and-block.md (Haitian Creole)

* New translations mute-and-block.md (Kabyle)

* New translations mute-and-block.md (Arabic)

* New translations mute-and-block.md (French)

* New translations mute-and-block.md (Japanese, Kansai)

* New translations glossary.md (German)

* New translations links.md (German)

* New translations links.md (English)

* New translations report-issue.md (German)

* New translations changelog.md (German)

* New translations apps.md (German)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations disable-timelines.md (Japanese, Kansai)

* New translations disable-timelines.md (Japanese, Kansai)

* New translations faq.md (Japanese, Kansai)

* New translations aiscript.md (Japanese, Kansai)

* New translations faq.md (Japanese, Kansai)

* New translations misskey.md (Japanese, Kansai)

* New translations aiscript.md (Japanese, Kansai)

* New translations reaction.md (Japanese, Kansai)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations glossary.md (Japanese, Kansai)

* New translations glossary.md (Kabyle)

* New translations glossary.md (Haitian Creole)

* New translations glossary.md (Kannada)

* New translations glossary.md (Lojban)

* New translations glossary.md (Uyghur)

* New translations glossary.md (Esperanto)

* New translations glossary.md (Indonesian)

* New translations misskey.md (English)

* New translations glossary.md (Thai)

* New translations glossary.md (English)

* New translations glossary.md (Chinese Traditional)

* New translations glossary.md (Dutch)

* New translations glossary.md (Chinese Simplified)

* New translations glossary.md (Ukrainian)

* New translations glossary.md (Russian)

* New translations glossary.md (Portuguese)

* New translations glossary.md (Polish)

* New translations glossary.md (Norwegian)

* New translations glossary.md (Korean)

* New translations glossary.md (French)

* New translations glossary.md (Italian)

* New translations glossary.md (German)

* New translations glossary.md (Danish)

* New translations glossary.md (Czech)

* New translations glossary.md (Arabic)

* New translations glossary.md (Spanish)

* New translations note.md (French)

* New translations glossary.md (Chinese Simplified)

* New translations faq.md (French)

* New translations faq.md (Chinese Simplified)

* New translations faq.md (Kabyle)

* New translations faq.md (Haitian Creole)

* New translations faq.md (Kannada)

* New translations faq.md (Lojban)

* New translations faq.md (Uyghur)

* New translations faq.md (Esperanto)

* New translations faq.md (Thai)

* New translations faq.md (Indonesian)

* New translations faq.md (English)

* New translations faq.md (Chinese Traditional)

* New translations faq.md (Ukrainian)

* New translations faq.md (Spanish)

* New translations faq.md (Russian)

* New translations faq.md (Portuguese)

* New translations faq.md (Polish)

* New translations faq.md (Norwegian)

* New translations faq.md (Dutch)

* New translations faq.md (Korean)

* New translations faq.md (Italian)

* New translations faq.md (German)

* New translations faq.md (Danish)

* New translations faq.md (Czech)

* New translations faq.md (Arabic)

* New translations faq.md (Japanese, Kansai)

* New translations faq.md (French)

* New translations misskey.md (French)

* New translations faq.md (French)

* New translations misskey.md (French)

* New translations faq.md (French)

* New translations troubleshooting.md (French)

* New translations troubleshooting.md (French)

* New translations troubleshooting.md (French)

* New translations troubleshooting.md (French)

* New translations troubleshooting.md (French)

* New translations troubleshooting.md (French)

* New translations troubleshooting.md (French)

* New translations word-mute.md (Ukrainian)

* New translations word-mute.md (Czech)

* New translations word-mute.md (Danish)

* New translations word-mute.md (German)

* New translations word-mute.md (Italian)

* New translations word-mute.md (Korean)

* New translations word-mute.md (Dutch)

* New translations word-mute.md (Norwegian)

* New translations word-mute.md (Polish)

* New translations word-mute.md (Portuguese)

* New translations word-mute.md (Russian)

* New translations word-mute.md (Chinese Simplified)

* New translations word-mute.md (Spanish)

* New translations word-mute.md (Chinese Traditional)

* New translations word-mute.md (English)

* New translations word-mute.md (Indonesian)

* New translations word-mute.md (Thai)

* New translations word-mute.md (Esperanto)

* New translations word-mute.md (Uyghur)

* New translations word-mute.md (Lojban)

* New translations word-mute.md (Kannada)

* New translations word-mute.md (Haitian Creole)

* New translations word-mute.md (Kabyle)

* New translations word-mute.md (Arabic)

* New translations word-mute.md (French)

* New translations word-mute.md (Japanese, Kansai)

* New translations glossary.md (English)

* New translations glossary.md (English)

* New translations glossary.md (English)

* New translations glossary.md (English)

* New translations faq.md (English)

* New translations faq.md (English)

* New translations glossary.md (English)

* New translations word-mute.md (English)

* New translations word-mute.md (English)

* New translations word-mute.md (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)
2021-08-21 17:58:32 +09:00
f6128dd3ff 🎨 2021-08-21 17:40:15 +09:00
eeff88ece2 Update CHANGELOG.md 2021-08-21 14:52:41 +09:00
bae1282f74 clean up 2021-08-21 14:47:39 +09:00
d2007add75 feat: Implement api sw/unregister (#7611)
* Implement api sw/unregister

* remove all mode

* add changelog

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
2021-08-21 14:47:18 +09:00
802db92d98 Update setup.en.md (#7675)
Updated PostgreSQL version to 12  

See https://github.com/misskey-dev/misskey/issues/7632#issuecomment-901653826
2021-08-21 14:24:03 +09:00
a53e1e4ec3 enhance: Improve account deletion experience 2021-08-21 12:48:50 +09:00
fd1ef4a62d enhance(server): Use job queue for account delete (#7668)
* enhance(server): Use job queue for account delete

Fix #5336

* ジョブをひとつに

* remove done call

* clean up

* add User.isDeleted

* コミット忘れ

* Update 1629512953000-user-is-deleted.ts

* show dialog

* lint

* Update 1629512953000-user-is-deleted.ts
2021-08-21 12:41:56 +09:00
8ab9068d8e fix bug 2021-08-21 11:51:46 +09:00
47dd30d3b2 fix(client): ノートの「削除して編集」をするとアンケートの選択肢が[object Object]になる問題を修正
Fix #7037
2021-08-21 11:16:56 +09:00
fcdd042b02 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2021-08-21 10:29:30 +09:00
04855f9201 enhance(client): Improve emoji autocomplete behaviour
cherry picked from 4b2c215e25
2021-08-21 10:29:26 +09:00
cf0a5d5735 Bump @redocly/openapi-core from 1.0.0-beta.44 to 1.0.0-beta.54 (#7665)
Bumps [@redocly/openapi-core](https://github.com/Redocly/openapi-cli) from 1.0.0-beta.44 to 1.0.0-beta.54.
- [Release notes](https://github.com/Redocly/openapi-cli/releases)
- [Changelog](https://github.com/Redocly/openapi-cli/blob/master/docs/changelog.md)
- [Commits](https://github.com/Redocly/openapi-cli/compare/v1.0.0-beta.44...v1.0.0-beta.54)

---
updated-dependencies:
- dependency-name: "@redocly/openapi-core"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-20 23:15:17 +09:00
bb2db1cf76 perf: Tune AP job queue timings (#7635)
* perf: Tune AP job queue timings

* CHANGELOG

* chore: add reference

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
2021-08-20 21:59:03 +09:00
0e69091455 doc: add features/word-mute (#7672) 2021-08-20 21:40:45 +09:00
3cb5ed167a fix: meta.jsonをimportしないように
Fix #7671
2021-08-20 21:34:56 +09:00
1ffee15b83 fix: use correct query generate function (#7657)
Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
2021-08-20 20:55:12 +09:00
75b9f31acf fix: import syslog-pro 2021-08-20 20:18:24 +09:00
fc56b12690 refactor: localStorageのaccountsはindexedDBで保持するように (#7609)
* accountsストアはindexedDBで保持するように

* fix lint

* fix indexeddb available detection

* remove debugging code

* fix lint

* resolve ba756204b7 (diff-f565878e8202f0037b830c780b7c0932dc1bb5fd3d05ede14d72d10efbc3740c)
Firefoxでの動作を改善

* fix lint

* fix lint

* add changelog
2021-08-20 19:38:16 +09:00
60e768436e Create dependabot.yml 2021-08-20 00:22:29 +09:00
84f2192cde update deps 2021-08-19 22:40:39 +09:00
97f2675d40 refactor: use path alias to improve readability 2021-08-19 22:04:15 +09:00
6d881d4570 fix import 2021-08-19 21:57:36 +09:00
42cc93dd0f fix: mochaが動かないため拡張子なしに戻した 2021-08-19 21:55:45 +09:00
e9f34a0f09 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2021-08-19 18:33:59 +09:00
b9cb6d1c10 refactor: refactoring imports
将来ESMに移行しやすいように
Related: #7658

なんかmochaが起動しなくなってるけど理由不明
すぐ直したい
2021-08-19 18:33:41 +09:00
7bf517e990 Remove unused packages (#7661)
* Remove unused packages

* Remove unused babel things

* Remove more unused packages
2021-08-19 18:07:32 +09:00
ab54e147f2 Remove is-root dependencies (#7660) 2021-08-19 16:27:12 +09:00
e677540fd6 Update faq.md 2021-08-19 15:42:53 +09:00
31e3aaeda0 Update glossary.md 2021-08-19 11:35:42 +09:00
938fc317c9 Update glossary.md 2021-08-19 11:32:25 +09:00
4c431c5432 refactor 2021-08-19 11:26:26 +09:00
881b914c6a チャンネルを作成しているとアカウントを削除できないのを修正 (#7653)
* チャンネルを作成しているとアカウントを削除できないのを修正

* CHANGELOG

* nullable
2021-08-18 22:04:04 +09:00
df67836c1a Merge branch 'develop' 2021-08-17 22:01:46 +09:00
6a3a8ba4d0 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2021-08-17 22:01:12 +09:00
9e535c341e 12.88.0 2021-08-17 22:00:52 +09:00
17fa4ba804 update vue 2021-08-17 22:00:39 +09:00
dd9a3c91fc New Crowdin updates (#7622)
* New translations create-plugin.md (Chinese Simplified)

* New translations ja-JP.yml (German)

* New translations glossary.md (Esperanto)

* New translations glossary.md (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations glossary.md (Esperanto)

* New translations misskey.md (Esperanto)

* New translations misskey.md (Esperanto)

* New translations misskey.md (Esperanto)

* New translations misskey.md (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations misskey.md (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations glossary.md (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations keyboard-shortcut.md (Esperanto)

* New translations timeline.md (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations keyboard-shortcut.md (Esperanto)

* New translations timeline.md (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations disable-timelines.md (Esperanto)

* New translations glossary.md (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations note.md (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Indonesian)

* New translations troubleshooting.md (Indonesian)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (German)

* New translations faq.md (French)

* New translations faq.md (French)

* New translations misskey.md (French)

* New translations faq.md (French)

* New translations faq.md (French)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations misskey.md (Russian)

* New translations misskey.md (Russian)

* New translations misskey.md (Russian)

* New translations misskey.md (Russian)

* New translations misskey.md (Russian)

* New translations misskey.md (Russian)

* New translations misskey.md (Russian)

* New translations misskey.md (Russian)

* New translations ja-JP.yml (Russian)

* New translations misskey.md (Russian)

* New translations misskey.md (Russian)

* New translations misskey.md (Russian)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations misskey.md (Esperanto)

* New translations misskey.md (Esperanto)

* New translations misskey.md (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Chinese Simplified)

* New translations antenna.md (French)

* New translations antenna.md (French)

* New translations changelog.md (French)

* New translations report-issue.md (French)

* New translations changelog.md (French)

* New translations links.md (French)

* New translations report-issue.md (French)

* New translations links.md (French)

* New translations links.md (French)

* New translations links.md (French)

* New translations misskey.md (Russian)

* New translations misskey.md (Russian)

* New translations links.md (French)

* New translations links.md (French)

* New translations apps.md (French)

* New translations links.md (French)

* New translations troubleshooting.md (French)

* New translations ja-JP.yml (French)

* New translations report-issue.md (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (French)

* New translations glossary.md (French)

* New translations misskey.md (Ukrainian)

* New translations misskey.md (Czech)

* New translations misskey.md (Danish)

* New translations misskey.md (German)

* New translations misskey.md (Italian)

* New translations misskey.md (Korean)

* New translations misskey.md (Dutch)

* New translations misskey.md (Norwegian)

* New translations misskey.md (Polish)

* New translations misskey.md (Portuguese)

* New translations misskey.md (Russian)

* New translations misskey.md (Chinese Simplified)

* New translations misskey.md (Spanish)

* New translations misskey.md (Chinese Traditional)

* New translations misskey.md (Indonesian)

* New translations misskey.md (Thai)

* New translations misskey.md (Esperanto)

* New translations misskey.md (Uyghur)

* New translations misskey.md (Lojban)

* New translations misskey.md (Kannada)

* New translations misskey.md (Haitian Creole)

* New translations misskey.md (Kabyle)

* New translations misskey.md (Arabic)

* New translations misskey.md (French)

* New translations glossary.md (Spanish)

* New translations glossary.md (Russian)

* New translations glossary.md (Arabic)

* New translations glossary.md (Czech)

* New translations glossary.md (Danish)

* New translations glossary.md (German)

* New translations glossary.md (Italian)

* New translations glossary.md (Korean)

* New translations glossary.md (Dutch)

* New translations glossary.md (Norwegian)

* New translations glossary.md (Polish)

* New translations glossary.md (Portuguese)

* New translations glossary.md (Ukrainian)

* New translations glossary.md (Japanese, Kansai)

* New translations glossary.md (Chinese Simplified)

* New translations glossary.md (Chinese Traditional)

* New translations glossary.md (Indonesian)

* New translations glossary.md (Thai)

* New translations glossary.md (Uyghur)

* New translations glossary.md (Lojban)

* New translations glossary.md (Kannada)

* New translations glossary.md (Haitian Creole)

* New translations glossary.md (Kabyle)

* New translations misskey.md (Japanese, Kansai)

* New translations ja-JP.yml (Esperanto)

* New translations note.md (Esperanto)

* New translations note.md (Esperanto)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Esperanto)

* New translations api.md (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations drive.md (Esperanto)

* New translations glossary.md (Esperanto)

* New translations report-issue.md (French)

* New translations troubleshooting.md (French)

* New translations faq.md (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations faq.md (Esperanto)

* New translations troubleshooting.md (French)

* New translations ja-JP.yml (Esperanto)

* New translations misskey.md (Esperanto)

* New translations troubleshooting.md (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations troubleshooting.md (French)

* New translations misskey.md (Russian)

* New translations misskey.md (Russian)

* New translations misskey.md (Russian)

* New translations misskey.md (Russian)

* New translations misskey.md (Russian)

* New translations faq.md (French)

* New translations faq.md (Spanish)

* New translations faq.md (Russian)

* New translations faq.md (Arabic)

* New translations faq.md (Czech)

* New translations faq.md (Danish)

* New translations faq.md (German)

* New translations faq.md (Italian)

* New translations faq.md (Korean)

* New translations faq.md (Dutch)

* New translations faq.md (Norwegian)

* New translations faq.md (Polish)

* New translations faq.md (Portuguese)

* New translations faq.md (Ukrainian)

* New translations faq.md (Japanese, Kansai)

* New translations faq.md (Chinese Simplified)

* New translations faq.md (Chinese Traditional)

* New translations faq.md (English)

* New translations faq.md (Indonesian)

* New translations faq.md (Thai)

* New translations faq.md (Esperanto)

* New translations faq.md (Uyghur)

* New translations faq.md (Lojban)

* New translations faq.md (Kannada)

* New translations faq.md (Haitian Creole)

* New translations faq.md (Kabyle)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations antenna.md (Esperanto)

* New translations glossary.md (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations apps.md (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations deck.md (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations antenna.md (Japanese, Kansai)

* New translations ja-JP.yml (Esperanto)

* New translations antenna.md (Japanese, Kansai)

* New translations ja-JP.yml (Esperanto)

* New translations api.md (Esperanto)

* New translations custom-emoji.md (Japanese, Kansai)

* New translations ja-JP.yml (Esperanto)

* New translations deck.md (Japanese, Kansai)

* New translations deck.md (Japanese, Kansai)

* New translations faq.md (French)

* New translations faq.md (English)

* New translations faq.md (English)

* New translations faq.md (English)

* New translations faq.md (English)

* New translations faq.md (French)

* New translations misskey.md (French)

* New translations faq.md (French)

* New translations faq.md (French)

* New translations faq.md (English)

* New translations faq.md (French)

* New translations faq.md (French)

* New translations faq.md (French)

* New translations faq.md (French)

* New translations faq.md (Chinese Simplified)
2021-08-17 21:51:23 +09:00
7015df37e3 enhance(server): Improve user block (#7640)
* enhance(server): Improve user block

* Update CHANGELOG.md

* ユーザーリスト対応

* 相手から見れなくなるように

* Update 1629004542760-chart-reindex.ts

2365761ba5 (commitcomment-54919821)

* update test

* add test

* add todos

* Update 1629004542760-chart-reindex.ts
2021-08-17 21:48:59 +09:00
7ebdd4739a Fix truncate (#7642) 2021-08-17 17:25:19 +09:00
c4bcb31a00 Update 1629004542760-chart-reindex.ts 2021-08-17 13:40:15 +09:00
0a18ee24ac Update 1629004542760-chart-reindex.ts
2365761ba5 (commitcomment-54919821)
2021-08-17 13:37:16 +09:00
37d10b108e Update faq.md 2021-08-17 11:52:27 +09:00
b5cadeca2e fix(client): コントロールパネルでファイルを削除した際の表示を修正
Fix #7631
2021-08-16 20:07:54 +09:00
c8e93054bc fix(client): タッチ操作でウィンドウを閉じることができない問題を修正 2021-08-16 18:11:15 +09:00
def32107af perf: Improve network request performance (#7636)
* perf: Improve fetch

* CHANGELOG

* lifo
2021-08-16 17:44:43 +09:00
1b84ae9f3f chore: yarn.lockがおかしかったらCIでコケるように (#7634) 2021-08-16 16:33:45 +09:00
73ce1f61a8 Tweak client style 2021-08-16 15:21:58 +09:00
8661cd1ee7 Renoteされた時刻が投稿された時刻のように表示される問題を修正
Fix #7620
2021-08-16 15:20:23 +09:00
53f55defda fix typo 2021-08-16 12:28:12 +09:00
d60dc60bc9 fix(server): use insert instead of save 2021-08-15 22:10:05 +09:00
bf1d7e6252 fix(server): ja-JPのような形式にDeepLが対応してない 2021-08-15 21:52:58 +09:00
c96b2767b9 fix typo 2021-08-15 21:44:00 +09:00
6c1f03eefd enhance(client): Improve stability of version comparison 2021-08-15 20:34:06 +09:00
cced83024b feat: ノートの翻訳機能
Resolve #5213
2021-08-15 20:26:44 +09:00
1cd6ba3c1d chore: Remove vips from Dockerfile (#7633) 2021-08-15 18:12:46 +09:00
2365761ba5 perf(server): Optimize db indexes of chart tables 2021-08-15 17:13:23 +09:00
d3b4b70bfc 🎨 2021-08-14 22:35:15 +09:00
f95d5701a2 feat(client): ジョブキューウィジェットに警報音を鳴らす設定を追加 2021-08-14 18:36:22 +09:00
a8c56afd0f add sound 2021-08-14 18:19:25 +09:00
4de30aa47e Update CHANGELOG.md 2021-08-14 18:13:41 +09:00
f05f7c920e fix: truncate user information if it is too long (#7629)
* truncate user information if it is too long

Some AP software allows for user names or summaries to be very long.
Misskey can not handle this and the profile page can not be opened and
no activities from such users can be seen.

Instead, the user name and summary are cut off after the maximum length
so misskey can still process the activities of the profile.

Co-authored-by: Toast <toast@toast.cafe>

* fix code style

Co-authored-by: Toast <toast@toast.cafe>
Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
2021-08-14 18:11:47 +09:00
5f86509abc Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2021-08-13 17:59:57 +09:00
1561391293 feat(client): Misskey更新時にダイアログを表示するように 2021-08-13 17:59:54 +09:00
60553a8a5e Update PULL_REQUEST_TEMPLATE.md 2021-08-12 23:46:13 +09:00
e656074de4 Update PULL_REQUEST_TEMPLATE.md 2021-08-12 23:45:46 +09:00
b81ff340b1 Introduce e2e test 2021-08-12 19:05:07 +09:00
77456ae0bc Create config.yml 2021-08-12 15:44:16 +09:00
833 changed files with 6994 additions and 3192 deletions

View File

@ -1,13 +0,0 @@
{
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": {
"version": 3,
"proposals": true
}
}
]
]
}

7
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,7 @@
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

View File

@ -1,21 +1,29 @@
<!-- お読みください
PRありがとうございます PRを作成する前に、以下をご確認ください:
可能であればタイトルに、以下で示すようなPRの種類が分かるキーワードをプリフィクスしてください。
fix / refactor / feat / enhance / perf / chore
また、PRの粒度が適切であることを確認してください。ひとつのPRに複数の種類の変更や関心を含めることは避けてください。
このPRによって解決されるIssueがある場合は、そのIssue IDを本文内に記入してください。
CHANGELOG.mdに変更点を追記してください。リファクタリングなど、利用者に影響を与えない変更についてはこの限りではありません。
機能追加やバグ修正をした場合は、可能であればテストケースを追加してください。
- 可能であればタイトルに、以下で示すようなPRの種類が分かるキーワードをプリフィクスしてください。
- fix / refactor / feat / enhance / perf / chore
- また、PRの粒度が適切であることを確認してください。ひとつのPRに複数の種類の変更や関心を含めることは避けてください。
- このPRによって解決されるIssueがある場合は、そのIssueへの参照を本文内に含めてください。
- CHANGELOG.mdに変更点を追記してください。リファクタリングなど、利用者に影響を与えない変更についてはこの限りではありません。
- この変更により新たに作成、もしくは更新すべきドキュメントがないか確認してください。
- 機能追加やバグ修正をした場合は、可能であればテストケースを追加してください。
- テスト、Lintが通っていることを予め確認してください。
- `npm run test``npm run lint`でぞれぞれ実施可能です
- UIに変更がある場合はスクリーンショットを本文内に添付してください。
ご協力ありがとうございます🤗
-->
<!-- README
Thank you for your PR! Before creating a PR, please check the following:
If possible, prefix the title with a keyword that identifies the type of this PR, as shown below.
fix / refactor / feat / enhance / perf / chore
Also, make sure that the granularity of this PR is appropriate. Please do not include more than one type of change or interest in a single PR.
If there is an issue to be resolved by this PR, please include the Issue ID in the text.
Please add the summary of the changes to CHANGELOG.md. However, this is not necessary for changes that do not affect the users, such as refactoring.
If you have added a feature or fixed a bug, please add a test case if possible.
- If possible, prefix the title with a keyword that identifies the type of this PR, as shown below.
- fix / refactor / feat / enhance / perf / chore
- Also, make sure that the granularity of this PR is appropriate. Please do not include more than one type of change or interest in a single PR.
- If there is an Issue which will be resolved by this PR, please include a reference to the Issue in the text.
- Please add the summary of the changes to CHANGELOG.md. However, this is not necessary for changes that do not affect the users, such as refactoring.
- Check if there are any documents that need to be created or updated due to this change.
- If you have added a feature or fixed a bug, please add a test case if possible.
- Please make sure that tests and Lint are passed in advance.
- You can run it with `npm run test` and `npm run lint`.
- If this PR includes UI changes, please attach a screenshot in the text.
Thanks for your cooperation 🤗
-->

11
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "npm" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "daily"

View File

@ -35,6 +35,8 @@ jobs:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: yarn install
- name: Check yarn.lock
run: git diff --exit-code yarn.lock
- name: Copy Configure
run: cp .circleci/misskey/*.yml .config
- name: Build

View File

@ -7,6 +7,55 @@
-->
## 12.89.1 (2021/08/24)
### Improvements
- クライアントのデザインの調整
### Bugfixes
- 翻訳でDeepLのProアカウントに対応していない問題を修正
- インスタンス設定でDeepLのAuth Keyが空で表示される問題を修正
- セキュリティの向上
## 12.89.0 (2021/08/21)
### Improvements
- アカウント削除の安定性を向上
- 絵文字オートコンプリートの挙動を改修
- localStorageのaccountsはindexedDBで保持するように
- ActivityPub: ジョブキューの試行タイミングを調整 (#7635)
- API: sw/unregisterを追加
- ワードミュートのドキュメントを追加
- クライアントのデザインの調整
- 依存関係の更新
### Bugfixes
- チャンネルを作成しているとアカウントを削除できないのを修正
- ノートの「削除して編集」をするとアンケートの選択肢が[object Object]になる問題を修正
## 12.88.0 (2021/08/17)
### Features
- ノートの翻訳機能を追加
- 有効にするには、サーバー管理者がDeepLの無料アカウントを登録し、取得した認証キーを「インスタンス設定 > その他 > DeepL Auth Key」に設定する必要があります。
- Misskey更新時にダイアログを表示するように
- ジョブキューウィジェットに警報音を鳴らす設定を追加
### Improvements
- ブロックの挙動を改修
- ブロックされたユーザーがブロックしたユーザーに対してアクション出来ないようになりました。詳細はドキュメントをご確認ください。
- UIデザインの調整
- データベースのインデックスを最適化
- Proxy使用時にKeep-Aliveをサポート
- DNSキャッシュでネガティブキャッシュをサポート
- 依存関係の更新
### Bugfixes
- タッチ操作でウィンドウを閉じることができない問題を修正
- Renoteされた時刻が投稿された時刻のように表示される問題を修正
- コントロールパネルでファイルを削除した際の表示を修正
- ActivityPub: 長いユーザーの名前や自己紹介の対応
## 12.87.0 (2021/08/12)
### Improvements

View File

@ -35,6 +35,11 @@ If your language is not listed in Crowdin, please open an issue.
## Test
* Test codes are located in [`/test`](/test).
### Run specify test
```
npx cross-env TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT="./test/tsconfig.json" npx mocha test/foo.ts --require ts-node/register
```
## Continuous integration
Misskey uses GitHub Actions for executing automated tests.
Configuration files are located in [`/.github/workflows`](/.github/workflows).
@ -245,6 +250,9 @@ npx ts-node ./node_modules/typeorm/cli.js migration:generate -n 変更の名前
### コネクションには`markRaw`せよ
**Vueのコンポーネントのdataオプションとして**misskey.jsのコネクションを設定するとき、必ず`markRaw`でラップしてください。インスタンスが不必要にリアクティブ化されることで、misskey.js内の処理で不具合が発生するとともに、パフォーマンス上の問題にも繋がる。なお、Composition APIを使う場合はこの限りではない(リアクティブ化はマニュアルなため)。
### JSONのimportに気を付けよう
TypeScriptでjsonをimportすると、tscでコンパイルするときにそのjsonファイルも一緒にdistディレクトリに吐き出されてしまう。この挙動により、意図せずファイルの書き換えが発生することがあるので、jsonをimportするときは書き換えられても良いものかどうか確認すること。書き換えされて欲しくない場合は、importで読み込むのではなく、`fs.readFileSync`などの関数を使って読み込むようにすればよい。
## その他
### HTMLのクラス名で follow という単語は使わない
広告ブロッカーで誤ってブロックされる

View File

@ -18,9 +18,7 @@ RUN apk add --no-cache \
nasm \
pkgconfig \
python3 \
zlib-dev \
vips-dev \
vips
zlib-dev
COPY package.json yarn.lock .yarnrc ./
RUN yarn install
@ -31,8 +29,7 @@ FROM base AS runner
RUN apk add --no-cache \
ffmpeg \
tini \
vips
tini
ENTRYPOINT ["/sbin/tini", "--"]

Binary file not shown.

3
cypress.json Normal file
View File

@ -0,0 +1,3 @@
{
"baseUrl": "http://localhost"
}

View File

@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View File

@ -0,0 +1,69 @@
describe('Basic', () => {
before(() => {
cy.request('POST', '/api/reset-db');
});
beforeEach(() => {
cy.reload(true);
});
it('successfully loads', () => {
cy.visit('/');
});
it('setup instance', () => {
cy.visit('/');
cy.get('[data-cy-admin-username] input').type('admin');
cy.get('[data-cy-admin-password] input').type('admin1234');
cy.get('[data-cy-admin-ok]').click();
});
it('signup', () => {
cy.visit('/');
cy.get('[data-cy-signup]').click();
cy.get('[data-cy-signup-username] input').type('alice');
cy.get('[data-cy-signup-password] input').type('alice1234');
cy.get('[data-cy-signup-password-retype] input').type('alice1234');
cy.get('[data-cy-signup-submit]').click();
});
it('signin', () => {
cy.visit('/');
cy.get('[data-cy-signin]').click();
cy.get('[data-cy-signin-username] input').type('alice');
// Enterキーでサインインできるかの確認も兼ねる
cy.get('[data-cy-signin-password] input').type('alice1234{enter}');
});
it('note', () => {
cy.visit('/');
//#region TODO: この辺はUI操作ではなくAPI操作でログインする
cy.get('[data-cy-signin]').click();
cy.get('[data-cy-signin-username] input').type('alice');
// Enterキーでサインインできるかの確認も兼ねる
cy.get('[data-cy-signin-password] input').type('alice1234{enter}');
//#endregion
cy.get('[data-cy-open-post-form]').click();
cy.get('[data-cy-post-form-text]').type('Hello, Misskey!');
cy.get('[data-cy-open-post-form-submit]').click();
// TODO: 投稿した文字列が画面内にあるか(=タイムラインに流れてきたか)のテスト
});
});

22
cypress/plugins/index.js Normal file
View File

@ -0,0 +1,22 @@
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
/**
* @type {Cypress.PluginConfig}
*/
// eslint-disable-next-line no-unused-vars
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}

View File

@ -0,0 +1,25 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })

20
cypress/support/index.js Normal file
View File

@ -0,0 +1,20 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')

View File

@ -24,7 +24,7 @@ Please install and setup these softwares:
#### Dependencies :package:
* **[Node.js](https://nodejs.org/en/)** (12.x, 14.x)
* **[PostgreSQL](https://www.postgresql.org/)** (>= 10)
* **[PostgreSQL](https://www.postgresql.org/)** (12.x / 13.x is preferred)
* **[Redis](https://redis.io/)**
##### Optional

View File

@ -1,3 +1,13 @@
/*
import * as fs from 'fs';
if (fs.existsSync('./built')) {
import('./built/index.js').then(built => built());
} else {
console.log('Built code is not found. Probably an error occurred during a build or you just forgot to build.');
}
*/
const fs = require('fs');
if (fs.existsSync('./built')) {

View File

@ -1,14 +1,14 @@
---
_lang_: "Deutsch"
headlineMisskey: "Ein durch Notizen verbundenes Netzwerk"
introMisskey: "Willkommen! Misskey ist eine dezentralisierte Open-Source Microblogging-Platform.\nVerfasse \"Notizen\" um mitzuteilen, was gerade passiert oder um Ereignisse mit Anderen zu teilen. 📡\nMit \"Reaktionen\" kannst du außerdem schnell deine Gefühle über Notizen anderer Benutzer zum Ausdruck bringen. 👍\nErforsche eine neue Welt! 🚀"
monthAndDay: "{day}/{month}"
introMisskey: "Willkommen! Misskey ist eine dezentralisierte Open-Source Microblogging-Platform.\nVerfasse Notizen um mitzuteilen, was gerade passiert oder um Ereignisse mit anderen zu teilen. 📡\nMit Reaktionen kannst du außerdem schnell deine Gefühle über Notizen anderer Benutzer zum Ausdruck bringen. 👍\nEine neue Welt wartet auf dich! 🚀"
monthAndDay: "{day}.{month}."
search: "Suchen"
notifications: "Benachrichtigungen"
username: "Benutzername"
password: "Passwort"
forgotPassword: "Passwort vergessen"
fetchingAsApObject: "Wird aus dem Fediverse angefragt..."
fetchingAsApObject: "Wird aus dem Fediverse angefragt"
ok: "OK"
gotIt: "Verstanden!"
cancel: "Abbrechen"
@ -25,10 +25,10 @@ profile: "Profil"
timeline: "Chronik"
noAccountDescription: "Dieser Nutzer hat seine Profilbeschreibung noch nicht ausgefüllt."
login: "Anmelden"
loggingIn: "Du wirst angemeldet..."
loggingIn: "Du wirst angemeldet"
logout: "Abmelden"
signup: "Registrieren"
uploading: "Wird hochgeladen..."
uploading: "Wird hochgeladen"
save: "Speichern"
users: "Benutzer"
addUser: "Benutzer hinzufügen"
@ -63,7 +63,7 @@ import: "Import"
export: "Export"
files: "Dateien"
download: "Herunterladen"
driveFileDeleteConfirm: "Möchtest du die Datei \"{name}\" wirklich löschen? Die zugehörige Notiz wird ebenso verschwinden."
driveFileDeleteConfirm: "Möchtest du die Datei {name} wirklich löschen? Die zugehörige Notiz wird ebenso verschwinden."
unfollowConfirm: "Möchtest du {name} nicht mehr folgen?"
exportRequested: "Du hast einen Export angefragt. Dies kann etwas Zeit in Anspruch nehmen. Sobald der Export abgeschlossen ist, wird er deiner Drive hinzugefügt."
importRequested: "Du hast einen Import angefragt. Dies kann etwas Zeit in Anspruch nehmen."
@ -80,7 +80,7 @@ error: "Fehler"
somethingHappened: "Ein Fehler ist aufgetreten"
retry: "Wiederholen"
pageLoadError: "Laden der Seite fehlgeschlagen."
pageLoadErrorDescription: "Dieser Fehler wird meist durch Netzwerkfehler oder den Browser-Cache verursacht. Versuche bitte den Browser-Cache zu leeren und es nach kurzer Zeit noch einmal zu probieren."
pageLoadErrorDescription: "Dieser Fehler wird meist durch Netzwerkfehler oder den Browser-Cache verursacht. Bitte leere den Cache oder versuche es nach einiger Zeit erneut."
enterListName: "Name der Liste eingeben"
privacy: "Privatsphäre"
makeFollowManuallyApprove: "Follow-Anfragen benötigen Bestätigung"
@ -105,7 +105,7 @@ sensitive: "NSFW"
add: "Hinzufügen"
reaction: "Reaktionen"
reactionSettingDescription: "Wähle die Reaktionen aus, die in der Reaktionsauswahl angezeigt werden sollen."
reactionSettingDescription2: "Ziehe zum Anordnen, Klicke zum Löschen, Drücke \"+\" zum Hinzufügen"
reactionSettingDescription2: "Ziehe zum Anordnen, klicke zum Löschen, drücke + zum Hinzufügen"
rememberNoteVisibility: "Notizsichtbarkeit merken"
attachCancel: "Anhang entfernen"
markAsSensitive: "Als NSFW markieren"
@ -129,14 +129,14 @@ editWidgetsExit: "Fertig"
customEmojis: "Benutzerdefinierte Emojis"
emoji: "Emojis"
emojis: "Emojis"
emojiName: "Emojiname"
emojiName: "Emoji-Name"
emojiUrl: "Emoji-URL"
addEmoji: "Emoji hinzufügen"
settingGuide: "Empfohlene Einstellung"
cacheRemoteFiles: "Dateien von fremden Instanzen im Cache speichern"
cacheRemoteFilesDescription: "Ist diese Einstellung deaktiviert, so werden Dateien fremder Instanzen direkt von dort geladen. Hierdurch wird Speicherplatz auf dem Server gespart, aber durch fehlende Generierung von Vorschaubildern mehr Bandbreite verwendet."
flagAsBot: "Als Bot markieren"
flagAsBotDescription: "Aktiviere diese Option, falls dieses Benutzerkonto durch ein Programm gesteuert wird. Falls aktiviert, agiert es als Flag für andere Entwickler zur Verhinderung von endlosen Kettenreaktionen mit anderen Bots und lässt Misskey's interne Systeme dieses Benutzerkonto als Bot behandeln."
flagAsBotDescription: "Aktiviere diese Option, falls dieses Benutzerkonto durch ein Programm gesteuert wird. Falls aktiviert, agiert es als Flag für andere Entwickler zur Verhinderung von endlosen Kettenreaktionen mit anderen Bots und lässt Misskeys interne Systeme dieses Benutzerkonto als Bot behandeln."
flagAsCat: "Als Katze markieren"
flagAsCatDescription: "Aktiviere diese Option, um dieses Benutzerkonto als Katze zu markieren."
autoAcceptFollowed: "Follow-Anfragen von Benutzern, denen du folgst, automatisch akzeptieren"
@ -196,7 +196,7 @@ noteDeleteConfirm: "Möchtest du diese Notiz wirklich löschen?"
pinLimitExceeded: "Es können nicht noch mehr Notizen angeheftet werden"
intro: "Misskey Installation abgeschlossen! Lass uns nun ein Administratorkonto erstellen."
done: "Fertig"
processing: "In Bearbeitung..."
processing: "In Bearbeitung"
preview: "Vorschau"
default: "Standard"
noCustomEmojis: "Keine benutzerdefinierten Emojis vorhanden"
@ -227,8 +227,8 @@ announcements: "Ankündigungen"
imageUrl: "Bild-URL"
remove: "Löschen"
removed: "Erfolgreich gelöscht"
removeAreYouSure: "Möchtest du \"{x}\" wirklich entfernen?"
deleteAreYouSure: "Möchtest du \"{x}\" wirklich löschen?"
removeAreYouSure: "Möchtest du {x} wirklich entfernen?"
deleteAreYouSure: "Möchtest du {x} wirklich löschen?"
resetAreYouSure: "Wirklich zurücksetzen?"
saved: "Gespeichert"
messaging: "Chat"
@ -240,7 +240,7 @@ uploadFromUrlDescription: "URL der hochzuladenden Datei"
uploadFromUrlRequested: "Upload angefordert"
uploadFromUrlMayTakeTime: "Es kann eine Weile dauern, bis das Hochladen abgeschlossen ist."
explore: "Erkunden"
games: "Misskey Spiele"
games: "Misskey-Spiele"
messageRead: "Gelesen"
noMoreHistory: "Kein weiterer Verlauf vorhanden"
startMessaging: "Neuen Chat erstellen"
@ -256,14 +256,14 @@ birthday: "Geburtstag"
yearsOld: "{age} Jahre alt"
registeredDate: "Registrationsdatum"
location: "Ort"
theme: "Farbthemen"
themeForLightMode: "Farbthema, das im Hellmodus genutzt wird"
themeForDarkMode: "Farbthema, das im Dunkelmodus genutzt wird"
theme: "Farbschema"
themeForLightMode: "Helles Farbschema"
themeForDarkMode: "Dunkles Farbschema"
light: "Hell"
dark: "Dunkel"
lightThemes: "Helle Farbthemen"
darkThemes: "Dunkle Farbthemen"
syncDeviceDarkMode: "Dunkelmodus mit den Einstellungen deines Gerätes synchronisieren"
lightThemes: "Helle Farbschemata"
darkThemes: "Dunkle Farbschemata"
syncDeviceDarkMode: "Einstellung deines Geräts übernehmen"
drive: "Drive"
fileName: "Dateiname"
selectFile: "Datei auswählen"
@ -293,7 +293,7 @@ whenServerDisconnected: "Bei Verbindungsverlust zum Server"
disconnectedFromServer: "Verbindung zum Server wurde getrennt"
reload: "Aktualisieren"
doNothing: "Ignorieren"
reloadConfirm: "Möchtest du die Chronik aktualisieren?"
reloadConfirm: "Seite neu laden?"
watch: "Beobachten"
unwatch: "Nicht mehr beobachten"
accept: "Akzeptieren"
@ -302,10 +302,10 @@ normal: "Normal"
instanceName: "Name der Instanz"
instanceDescription: "Beschreibung der Instanz"
maintainerName: "Betreiber"
maintainerEmail: "Betreiber-Email"
maintainerEmail: "Betreiber-E-Mail"
tosUrl: "URL der Nutzungsbedingungen"
thisYear: "Dieses Jahr"
thisMonth: "Dieser Monat"
thisYear: "Jahr"
thisMonth: "Monat"
today: "Heute"
dayX: "{day}"
monthX: "{month}"
@ -522,7 +522,7 @@ scratchpadDescription: "Die Testumgebung bietet eine Umgebung für AiScript-Expe
output: "Ausgabe"
script: "Skript"
disablePagesScript: "AiScript auf Seiten deaktivieren"
updateRemoteUser: "Informationen über Benutzer fremder Instanzen aktualisieren"
updateRemoteUser: "Benutzerinformationen aktualisieren"
deleteAllFiles: "Alle Dateien löschen"
deleteAllFilesConfirm: "Möchtest du wirklich alle Dateien löschen?"
removeAllFollowing: "Allen gefolgten Benutzern entfolgen"
@ -715,7 +715,7 @@ inChannelSearch: "In Kanal suchen"
useReactionPickerForContextMenu: "Reaktionsauswahl durch Rechtsklick öffnen"
typingUsers: "{users} ist/sind am schreiben..."
jumpToSpecifiedDate: "Zu bestimmtem Datum springen"
showingPastTimeline: "Momentan wird eine alte Chronik angezeigt"
showingPastTimeline: "Es wird eine alte Chronik angezeigt"
clear: "Zurückkehren"
markAllAsRead: "Alle als gelesen markieren"
goBack: "Zurück"
@ -772,6 +772,20 @@ searchResult: "Suchergebnisse"
hashtags: "Hashtags"
troubleshooting: "Problembehandlung"
useBlurEffect: "Weichzeichnungseffekt in der Benutzeroberfläche verwenden"
learnMore: "Mehr erfahren"
misskeyUpdated: "Misskey wurde aktualisiert!"
whatIsNew: "Änderungen anzeigen"
translate: "Übersetzen"
translatedFrom: "Aus {x} übersetzt"
accountDeletionInProgress: "Löschung des Benutzerkontos momentan in Bearbeitung"
usernameInfo: "Ein Name, durch den dein Benutzerkonto auf diesem Server identifiziert werden kann. Du kannst das Alphabet (a~z, A~Z), Ziffern (0~9) oder Unterstriche (_) verwenden. Benutzernamen können später nicht geändert werden."
_accountDelete:
accountDelete: "Benutzerkonto löschen"
mayTakeTime: "Da die Löschung eines Benutzerkontos ein aufwendiger Prozess ist, kann dessen Dauer davon abhängen, wie viel Inhalt in diesem erstellt wurde oder wie viele Dateien hochgeladen wurden."
sendEmail: "Sobald die Löschung abgeschlossen ist, wird an die mit ihm verknüpfte Email-Adresse eine Benachrichtigung versendet."
requestAccountDelete: "Löschung des Benutzerkontos anfordern"
started: "Löschung wurde eingeleitet."
inProgress: "Löschung in Bearbeitung"
_docs:
continueReading: "Mehr lesen"
features: "Funktionen"
@ -793,7 +807,7 @@ _gallery:
unlike: "\"Gefällt mir\" entfernen"
_email:
_follow:
title: "ist dir gefolgt"
title: "Du hast einen neuen Follower"
_receiveFollowRequest:
title: "Du hast eine Follow-Anfrage erhalten"
_plugin:
@ -1047,7 +1061,7 @@ _time:
_tutorial:
title: "Wie du Misskey verwendest"
step1_1: "Willkommen!"
step1_2: "Diese Seite ist die \"Chronik\". Sie zeigt dir deine geschrieben \"Notizen\" sowie die aller Benutzer, denen du \"folgst\", in chronologischer Reihenfolge."
step1_2: "Diese Seite ist die Chronik. Sie zeigt dir deine geschrieben Notizen sowie die aller Benutzer, denen du folgst, in chronologischer Reihenfolge."
step1_3: "Deine Chronik sollte momentan leer sein, da du bis jetzt noch keine Notizen geschrieben hast und auch noch keinen Benutzern folgst."
step2_1: "Lass uns zuerst dein Profil vervollständigen, bevor du Notizen schreibst oder jemandem folgst."
step2_2: "Informationen darüber, was für eine Person du bist, macht es anderen leichter zu wissen, ob sie deine Notizen sehen wollen und ob sie dir folgen möchten."
@ -1056,7 +1070,7 @@ _tutorial:
step3_3: "Fülle das Fenster aus und drücke auf den Knopf oben rechts zum Senden."
step3_4: "Fällt dir nichts ein, das du schreiben möchtest? Versuch's mit \"Hallo Misskey!\""
step4_1: "Fertig mit dem Senden deiner ersten Notiz?"
step4_2: "Falls deine Notiz nun auf deiner Chronik auftaucht, hast du alles richtig gemacht."
step4_2: "Falls deine Notiz nun in deiner Chronik auftaucht, hast du alles richtig gemacht."
step5_1: "Lass uns nun deiner Chronik etwas mehr Leben einhauchen, indem du einigen anderen Benutzern folgst."
step5_2: "{featured} zeigt dir beliebte Notizen dieser Instanz. In {explore} kannst du beliebte Benutzer finden. Schau dort, ob du Benutzer findest, die dich interessieren."
step5_3: "Klicke zum Anzeigen des Profils eines Benutzers auf dessen Profilbild und dann auf den \"Folgen\"-Knopf, um diesem zu folgen."

View File

@ -772,6 +772,20 @@ searchResult: "Search results"
hashtags: "Hashtags"
troubleshooting: "Troubleshooting"
useBlurEffect: "Use blur effects in the UI"
learnMore: "Learn more"
misskeyUpdated: "Misskey has been updated!"
whatIsNew: "Show changes"
translate: "Translate"
translatedFrom: "Translated from {x}"
accountDeletionInProgress: "Account deletion is currently in progress"
usernameInfo: "A name that identifies your account from others on this server. You can use the alphabet (a~z, A~Z), digits (0~9) or underscores (_). Usernames can not be changed later."
_accountDelete:
accountDelete: "Delete Account"
mayTakeTime: "As account deletion is a resource-heavy process, it may take some time to complete depending on how much content you have created and how many files you have uploaded."
sendEmail: "Once account deletion has been completed, an email will be sent to the email address registered to this account."
requestAccountDelete: "Request account deletion"
started: "Deletion has been started."
inProgress: "Deletion is currently in progress"
_docs:
continueReading: "Read more"
features: "Features"

View File

@ -1,7 +1,7 @@
---
_lang_: "Esperanto"
headlineMisskey: "Reto ligiĝanta per notoj"
introMisskey: "Bonvenon! Misskey estas malfermitkoda malcentriza mikrobloga servo.\nKreu \"noto\"n por kunhavu tion ke nun okazas, aŭ por dissendu pri vi📡\nPer la funkcio \"reago\" vi ankaŭ povas rapide esprimi vian senton pri ĉies noto👍\nVolu esplori nova mondo🚀"
headlineMisskey: "Reto ligata per notoj"
introMisskey: "Bonvenon! Misskey estas malfermitkoda malcentraliza mikrobloga servo.\nKreu \"noto\"n por diskonigu tion ke nun okazas, aŭ por dissendu pri vi. 📡\nPer la funkcio \"reago\", vi ankaŭ povas rapide esprimi vian senton pri ĉies noto. 👍\nOni esploru novan mondon. 🚀"
monthAndDay: "{day}-a/{month}"
search: "Serĉi"
notifications: "Sciigoj"
@ -10,10 +10,10 @@ password: "Pasvorto"
forgotPassword: "Ĉu vi forgesis pasvorton?"
fetchingAsApObject: "Informpetado de Fediverso..."
ok: "Akcepteble"
gotIt: "Mi konprenas!"
gotIt: "Mi komprenas"
cancel: "Nuligi"
enterUsername: "Entajpu uzantnomon"
renotedBy: "Renoton faras {user}"
renotedBy: "Renoto farita de {user}"
noNotes: "Neniu noto!"
noNotifications: "Vi ne havas sciigojn."
instance: "Ekzemplo"
@ -44,7 +44,7 @@ copyContent: "Kopii enhavon"
copyLink: "Kopii ligilon"
delete: "Forviŝi"
deleteAndEdit: "Forigi kaj redakti"
deleteAndEditConfirm: "Ĉu vi certas, ke vi volas forigi kaj redakti la noton? Ĉiuj reagoj, renotoj, kaj respondoj ankaŭ foriĝos."
deleteAndEditConfirm: "Ĉu vi certas, ke vi volas forigi kaj redakti la noton? Ankaŭ ĉiuj reagoj, renotoj, kaj respondoj al ĝi foriĝos."
addToList: "Aldoni al la listo"
sendMessage: "Sendi mesaĝon"
copyUsername: "Kopii uzantnomon"
@ -52,12 +52,13 @@ searchUser: "Serĉi uzanton"
reply: "Respondi"
loadMore: "Vidu pli"
showMore: "Vidi pli"
youGotNewFollower: "Vin eksekvis"
receiveFollowRequest: "Eksekvopeton riceviĝis."
followRequestAccepted: "La eksekvopeto akceptiĝis."
youGotNewFollower: "sksekvis vin"
receiveFollowRequest: "Peto de sekvado estas ricevita"
followRequestAccepted: "La peto de sekvado akceptita"
mention: "Mencioj"
mentions: "Al vi"
importAndExport: "Importaĵo / Eksportaĵo"
directNotes: "Rektaj notoj"
importAndExport: "Importi/eksporti"
import: "Importi"
export: "Eksporti"
files: "Dosieroj"
@ -70,17 +71,18 @@ note: "Elsendi noto"
notes: "Notoj"
following: "Sekvatoj"
followers: "Sekvantoj"
followsYou: "Vin sekvas "
followsYou: "Sekvas vin"
createList: "Kreii liston"
manageLists: "Administri liston"
error: "Eraro"
somethingHappened: "Problemo okazis."
retry: "Reprovi"
enterListName: "Entajpu nomon de la listo"
privacy: "Privateco"
follow: "Sekvi"
followRequest: "Peti akcepti de vi eksekvi"
followRequests: "Eksekvopetoj"
unfollow: "Ne plu sekvi"
followRequest: "Peti de sekvado"
followRequests: "Petoj de sekvado"
unfollow: "Malsekvi"
enterEmoji: "Entajpu emoĵion"
renote: "Fari renoton"
unrenote: "Malfari renoton"
@ -95,7 +97,7 @@ clickToShow: "Klaku por malkaŝu"
sensitive: "Enhavo ne estas deca por laborejo (NSFW)"
add: "Aldoni"
reaction: "Reagoj"
enterFileName: "Entajpu dosiernomon"
enterFileName: "Entajpu nomon de dosiero"
mute: "Silentigi"
unmute: "Malsilentigi"
block: "Bloki"
@ -115,25 +117,29 @@ customEmojis: "Personecigitaj emoĵioj"
emoji: "Emoĵio"
emojis: "Emoĵio"
emojiName: "Nomo de emoĵio"
emojiUrl: "URL de la bildo de emoĵio"
emojiUrl: "URL de la emoĵio"
addEmoji: "Aldoni emoĵion"
settingGuide: "Rekomendaj agordoj"
cacheRemoteFiles: "Havi staplon por transaj dosieroj"
cacheRemoteFiles: "Havi staplon de transaj dosieroj"
flagAsBot: "Tiu uzanto estas roboto"
flagAsCat: "Tiu uzanto estas kato"
addAccount: "Aldoni konton"
showOnRemote: "Vidi sur la fora ekzemplo"
general: "Ĝenerala"
wallpaper: "Ekranfonoj"
setWallpaper: "Apliki ekranfonon"
removeWallpaper: "Forviŝi ekranfonon. "
searchWith: "Serĉi: {q}"
youHaveNoLists: "Vi ne havas listojn."
followConfirm: "Ĉu vi certas ke vi volas sekvi {name}'(o)n?"
selectUser: "Elekti uzanton"
annotation: "Komentarioj"
federation: "Konfederacio"
federation: "Kunfederaĵo"
instances: "Ekzemplo"
perHour: "Po horo"
perDay: "Po tago"
blockThisInstance: "Bloki tiu ekzemplo"
version: "Versio"
withNFiles: "{n} dosiero(j)"
disk: "Diskilo"
instanceInfo: "Informo pri la ekzemplo"
@ -146,62 +152,87 @@ blockedUsers: "Blokataj uzantoj"
noUsers: "Sen uzantoj"
editProfile: "Redakti profilon"
noteDeleteConfirm: "Ĉu vi certas ke vi volas forviŝi la noton?"
pinLimitExceeded: "Vi ne plu povas alpingli noton."
pinLimitExceeded: "Vi povas alpingli ne pli noton."
processing: "Traktado..."
noCustomEmojis: "Neniu emoĵio"
federating: "Konfederado"
federating: "Kunfederado"
blocked: "Blokata"
all: "Ĉiuj"
subscribing: "Abonita"
publishing: "Dissendado"
notResponding: "Alvokato ne disponeblas"
instanceFollowing: "Sekvatoj sur la ekzemplo"
instanceFollowing: "Sekvatoj el la ekzemplo"
instanceFollowers: "Sekvantoj el la ekzemplo"
instanceUsers: "Uzantoj de la ekzemplo"
changePassword: "Ŝanĝi pasvorton"
security: "Sekureco"
currentPassword: "Aktuala pasvorto"
newPassword: "Nova pasvorto"
newPasswordRetype: "Reentajpu la novan pasvorton"
attachFile: "Aldoni dosieron"
more: "Plu!"
more: "Plu !"
featured: "Maksimumi"
usernameOrUserId: "Uzantnomo aŭ identigilo de uzanto"
noSuchUser: "Neniuj uzantoj trovitaj."
lookup: "Informpeti"
announcements: "Novaĵoj"
imageUrl: "URL de bildo"
remove: "Forigi"
removed: "Forviŝis"
removeAreYouSure: "Ĉu vi certas ke vi volas forigi \"{x}\"'(o)n?"
deleteAreYouSure: "Ĉu vi certas ke vi volas forviŝi \"{x}\"'(o)n?"
saved: "Konservita"
messaging: "Retbabili"
upload: "Alŝuti"
fromDrive: "De la diskingo"
fromDrive: "De la disko"
fromUrl: "De URL"
uploadFromUrl: "Alŝuti de URL"
uploadFromUrlDescription: "URL de la dosiero kiun vi volu alŝuti"
games: "Ludoj sur Misskey"
uploadFromUrlDescription: "URL de la dosiero kiun vi volas alŝuti"
explore: "Esplori"
games: "Miskiaj Ludoj"
messageRead: "Legita"
startMessaging: "Komenci babiladon"
nUsersRead: "Legita de {n} homoj"
tos: "Kondiĉoj de uzado"
start: "Komenciĝi"
home: "Hejmo"
remoteUserCaution: "Ĉi tiu Infomoj estas ne tute ekzakta pro distanca uzanto."
activity: "Aktiveco"
images: "Bildoj"
birthday: "Naskiĝtago"
birthday: "Naskiĝdato"
registeredDate: "Registriĝdato"
drive: "Diskingo"
location: "Loko"
theme: "Koloraro"
light: "Luma"
dark: "Malluma"
drive: "Disko"
fileName: "Dosiernomo"
selectFile: "Elekti dosieron"
selectFiles: "Elekti dosieron"
selectFolder: "Elekti dosierujon"
selectFolders: "Elekti dosierujon"
renameFile: "Alinomi la dosieron"
folderName: "Nomo de la dosierujo"
createFolder: "Krei dosierujon"
renameFolder: "Alinomi la dosierujon"
deleteFolder: "Forviŝi dosierujon"
addFile: "Aldoni dosieron"
emptyDrive: "La diskingo malplenas."
emptyDrive: "La disko malplenas"
emptyFolder: "La dosierujo malplenas"
unableToDelete: "Ne forigebla"
inputNewFileName: "Entajpu nova dosiernomon"
inputNewFileName: "Entajpu nova nomon de la dosiero"
inputNewFolderName: "Entajpu nova nomon de la dosierujo"
hasChildFilesOrFolders: "La dosierujo ne estas forviŝebla, ĉar ĝi ne malplenas."
copyUrl: "Kopii URL"
rename: "Alinomi"
avatar: "Ikono"
banner: "Standardo"
nsfw: "Enhavo ne estas deca por laborejo (NSFW)"
reload: "Reŝargi"
watch: "Observi"
unwatch: "Malobservi"
accept: "Permesi"
normal: "Normala"
instanceName: "Nomo de la ekzemplo"
maintainerName: "Nomo de la administranto"
maintainerEmail: "Retpoŝto de la administranto"
@ -212,15 +243,26 @@ today: "Hodiaŭ"
dayX: "{day}-a"
monthX: "{month}"
yearX: "La jaro {year}"
pages: "Paĝoj"
connectService: "Konekti"
disconnectService: "Farkonektiĝi"
driveCapacityPerLocalAccount: "Volumo de miskej-diskingo po unu loka uzanto"
driveCapacityPerRemoteAccount: "Volumo de miskej-diskingo po unu transa uzanto"
iconUrl: "URL de la ikono (retpaĝsimbolo, ktp.)"
enableLocalTimeline: "Ebligi lokan templinion"
enableGlobalTimeline: "Ebligi mallokan templinion"
registration: "Registri"
driveCapacityPerLocalAccount: "Volumo de disko po unu loka uzanto"
driveCapacityPerRemoteAccount: "Volumo de disko po unu transa uzanto"
iconUrl: "URL de la ikono (retpaĝsimbolo, ktp)"
bannerUrl: "URL de standardo"
backgroundImageUrl: "URL de fona bildo"
basicInfo: "Baza informo"
pinnedUsers: "Alpinglita uzanto"
pinnedPages: "Alpinglitaj paĝoj"
pinnedNotes: "Pinglita noto"
antennas: "Antenoj"
manageAntennas: "Administri antenojn"
name: "Nomo"
withFileAntenna: "Nur kun aldonaĵo"
withReplies: "Inkluzive respondoj"
notesAndReplies: "Kun respondoj"
withFiles: "Kun aldonaĵo"
silence: "Mutigi"
@ -231,99 +273,195 @@ recentlyUpdatedUsers: "Uzantoj kiu lastatempe faris noton"
recentlyRegisteredUsers: "Nove aniĝintaj uzantoj"
popularTags: "Popularaj kradvortoj"
userList: "Listoj"
about: "Informoj"
aboutMisskey: "Pri Misskey"
administrator: "Administranto"
moderator: "Moderigisto"
securityKey: "Sekureca ŝlosilo"
securityKeyName: "Nomo de la ŝlosilo"
lastUsed: "Plej malnove uzita"
passwordLessLogin: "Ensaluti sen pasvorto"
resetPassword: "Restarigi pasvorton"
newPasswordIs: "La nova pasvorto estas {password}."
share: "Diskonigi"
notFound: "Ne trovita"
cacheClear: "Malplenigi staplon"
help: "Manlibro de uzado"
inputMessageHere: "Entajpu masaĝo tie ĉi"
close: "Fermi"
group: "Grupo"
groups: "Grupoj"
createGroup: "Krei grupon"
groupName: "Grupa nomo"
members: "Membroj"
messagingWithUser: "Mesaĝado kun uzanto"
messagingWithGroup: "Mesaĝi kun grupo"
messagingWithGroup: "Mesaĝado kun grupo"
title: "Titolo"
text: "Teksto"
enable: "Ebligi"
next: "Sekve"
noteOf: "Noto de {user}"
noMessagesYet: "Neniu mesaĝo"
newMessageExists: "Vi ricevis novan mesaĝon."
onlyOneFileCanBeAttached: "Vi povas aldoni nur unu dosieron po unu mesaĝo."
invitationCode: "Kodo de invito"
uiLanguage: "Lingvo de la interfaco"
or: "Aŭ"
language: "Lingvo"
uiLanguage: "Lingvo de la fasado"
aboutX: "Pri {x}"
useOsNativeEmojis: "Oni uzas la emoĵioj de la denaska sistemo"
youHaveNoGroups: "Neniuj grupoj"
category: "Kategorio"
tags: "Etikedoj"
createAccount: "Krei konton"
existingAccount: "Ekzista konto"
noFollowRequests: "Vi ne havas eksekvopetojn."
fontSize: "Tipara grando"
noFollowRequests: "Vi ne havas peto de sekvado"
openImageInNewTab: "Fermi la bildon en nova tablo"
dashboard: "Stirpanelo"
local: "Loka"
remote: "Transa"
total: "Entute"
clientSettings: "Agordoj de kliento"
accountSettings: "Agordoj de Konto"
numberOfDays: "Nombro de tagoj"
hideThisNote: "Kaŝi tiun noton"
objectStorageBaseUrl: "Baza URL"
objectStorageRegion: "Regiono"
objectStorageUseSSL: "Oni uzas SSL"
serverLogs: "Servila protokolo"
deleteAll: "Forviŝi ĉiujn"
sounds: "Sonoj"
listen: "Aŭdi"
none: "Neniu"
showInPage: "Vidi en paĝo"
deleteAllFiles: "Forviŝi ĉiujn dosierojn"
deleteAllFilesConfirm: "Ĉu vi certas, ke vi volas forviŝi ĉiujn viajn dosierojn?"
userSilenced: "Tiu uzanto estas mutigata."
menu: "Menuo"
deletedNote: "Forviŝita noto"
invisibleNote: "Malpublika noto"
poll: "Balotujo"
useCw: "Kaŝi enhavo"
themeEditor: "Redaktilo de koloraroj"
author: "Aŭtoro"
manage: "Administro"
plugins: "Kromaĵoj"
deck: "Kartaro"
medium: "Meza"
small: "Malgranda"
edit: "Redakti"
emailServer: "Retpoŝta servilo"
email: "Retpoŝto"
emailAddress: "Retpoŝta adreso"
smtpConfig: "Agordoj de la servilo SMTP"
smtpPort: "Pordo"
smtpUser: "Uzantnomo"
smtpPass: "Pasvorto"
wordMute: "Silentigo de vortoj"
userSaysSomething: "{name} parolis ion"
display: "Vidi"
copy: "Kopii"
database: "Datumbazo"
channel: "Kanalo"
create: "Krei"
notificationSetting: "Agordoj de sciigoj"
useGlobalSetting: "Oni uzas malloka agordo"
fileIdOrUrl: "Dosiera identigilo aŭ URL"
abuseReports: "Signali"
reportAbuse: "Signali"
reportAbuseOf: "Signali {name}'(o)n"
abuseReports: "Signaloj"
reportAbuse: "Signalo"
reportAbuseOf: "Signali kontraŭ {name}'(o)"
send: "Sendi"
openInNewTab: "Malfermi en nova langeto"
editTheseSettingsMayBreakAccount: "Redakti tiujn agordojn estas eble damaĝi konton."
public: "Publika"
i18nInfo: "Misskey estas tradukata en diversaj lingvoj far volontuloj. Oni povas kontribui por la tradukado ĉe {link}."
accountInfo: "Kontaj Informoj"
notesCount: "Numero de notoj"
repliesCount: "Numero de respondoj senditaj"
renotesCount: "Numero de renotoj kiun vi sendis"
repliedCount: "Numero de respondoj ricevitaj"
renotedCount: "Numero de renotoj kiun vi ricevis"
followingCount: "Numero de sekvatoj"
followersCount: "Numero de sekvantoj"
sentReactionsCount: "Numero de sentitaj reagoj"
receivedReactionsCount: "Numero de ricevitaj reagoj"
yes: "Jes"
no: "Ne"
driveFilesCount: "Numero de dosieroj en la diskingo"
driveFilesCount: "Numero de dosieroj sur la disko"
notSet: "Ne elektita"
noteFavoritesCount: "Numero de la preferataj notoj"
makeExplorable: "Igi videbla konto sur la paĝo \"Esplorado\""
showTitlebar: "Montri titolobredon"
contact: "Kontakto"
makeExplorable: "Videbligi konton sur la paĝo \"Esplori\""
duplicate: "Duobligi"
left: "Maldekstra"
center: "Centra"
showTitlebar: "Montri titola stango"
clearCache: "Malplenigi staplon"
onlineUsersCount: "{n} uzanto(j) estas surlinea"
nUsers: "{n} uzanto(j)"
nNotes: "{n} notoj"
myTheme: "Miaj koloraroj"
backgroundColor: "Fona koloro"
textColor: "Teksto"
saveAs: "Konservi kiel…"
value: "Valoro"
createdAt: "Kreita je"
updatedAt: "Laste ĝisdatigita"
deleteConfirm: "Ĉu certas forviŝi?"
closeAccount: "Forigi konton"
currentVersion: "Nuna versio"
latestVersion: "Plej nova versio"
youAreRunningUpToDateClient: "Vi uzas la plej novan version de via kliento."
newVersionOfClientAvailable: "Nova versio de via kliento estas disponebla."
inUse: "Uzata"
editCode: "Redakti kodon"
emailNotification: "Sciigoj per retpoŝto"
publish: "Publikigi"
inChannelSearch: "Serĉi en kanalo"
useReactionPickerForContextMenu: "Malfermu reago-elektilon per dekstro-kliki"
useReactionPickerForContextMenu: "Oni malfermas reago-elektilon per dekstro-kliki"
typingUsers: "{users} estas entajpanta(j)..."
info: "Informoj"
unknown: "Nekonata"
online: "Surkonektita"
offline: "Forkonektita"
instanceBlocking: "Blokado de ekzemplo"
selectAccount: "Elekti konton"
user: "Uzanto"
administration: "Administro"
accounts: "Kontoj"
global: "Konfederacia"
high: "Alta"
middle: "Meza"
low: "Malalta"
customCss: "Uzantula CSS"
global: "Malloka"
sent: "Sendi"
received: "Ricevita"
searchResult: "Serĉorezultoj"
hashtags: "Kradvorto"
learnMore: "Lernu pli"
translate: "Traduki"
translatedFrom: "Tradukita el {x}"
_docs:
continueReading: "Legi plu"
features: "Funkcioj"
admin: "Administro"
_gallery:
liked: "Ŝatitaj notoj"
like: "Ŝati"
_email:
_follow:
title: "Vin eksekvis"
title: "Vi estas eksekvita"
_receiveFollowRequest:
title: "Vi ricevis eksekvopeton."
title: "Vi ricevis peton de sekvado"
_plugin:
install: "Instali kromaĵon"
manage: "Administri kromaĵojn"
_registry:
key: "Ŝlosilo"
keys: "Ŝlosiloj"
domain: "Nomregno"
createKey: "Krei ŝlosilon"
_aboutMisskey:
about: "Misskey estas malfermitkoda programo evoluigata de syuilo ekde la 2014."
contributors: "Precipaj kontribuantoj"
@ -332,9 +470,14 @@ _aboutMisskey:
translation: "Traduki Misskey'on"
patrons: "Mecenatoj"
_mfm:
dummy: "Misskey vastigas la mondon de Fediverso"
mention: "Mencioj"
hashtag: "Kradvorto"
url: "URL"
link: "Ligilo"
bold: "Grasa"
small: "Malgrande"
center: "Centrigi"
inlineCode: "Kodo (en linio)"
blockCode: "Kodo (bloko)"
inlineMath: "Formulo (en linio)"
@ -342,6 +485,12 @@ _mfm:
quote: "Citi"
emoji: "Personecigitaj emoĵioj"
search: "Serĉi"
flip: "Inversa"
x2: "Granda"
x3: "Grandega"
x4: "Pli grandega"
_reversi:
total: "Entute"
_instanceTicker:
none: "Ne montri"
remote: "Montri al transaj uzantoj"
@ -349,30 +498,41 @@ _instanceTicker:
_channel:
create: "Krei kanalon"
edit: "Redakti kanalon"
following: "Sekvata"
owned: "Posedaĵo"
following: "Sekvante"
usersCount: "{n} partoprenanto(j)"
_menuDisplay:
hide: "Kaŝi"
_wordMute:
muteWords: "Silentigataj vortoj"
muteWords: "Kaŝigitaj vortoj"
mutedNotes: "Silentigataj notoj"
_theme:
manage: "Administri kolorarojn"
code: "Kodo de koloraro"
darken: "Malbrileco"
lighten: "Brileco"
keys:
bg: "Fono"
navBg: "Fono de flanka stango"
hashtag: "Kradvorto"
mention: "Mencioj"
renote: "Fari renoton"
buttonBg: "Fono de butono"
driveFolderBg: "Fono de dosierujo de la disko"
_sfx:
note: "Nova noto"
noteMy: "Mia noto"
notification: "Sciigoj"
chat: "Retbabilejo"
chatBg: "Retbabilejo (BG)"
chat: "Retbabili"
chatBg: "Retbabili (BG)"
antenna: "Ricevo de anteno"
channel: "Sciigoj de kanalo"
_ago:
future: "Futuro"
justNow: "Ĵus"
secondsAgo: "Antaŭ {n} sekundoj"
minutesAgo: "Antaŭ {n} minutoj"
hoursAgo: "Antaŭ {n} horoj"
hoursAgo: "Antaŭ {n} horo(j)"
daysAgo: "Antaŭ {n} tagoj"
weeksAgo: "Antaŭ {n} semajnoj"
monthsAgo: "Antaŭ {n} monatoj"
@ -385,17 +545,17 @@ _time:
_tutorial:
title: "Uzado de Misskey"
step1_1: "Bonvenon."
step7_2: "Se vi volus scii pli pri Miskejon, volu rigardi la fakon {help}."
step7_3: "Do, bonvolu amuziĝi Miskejon🚀"
step7_2: "Se vi volas scii pli pri Misskey, rigardu la fakon {help}."
step7_3: "Do, bonvolu amuziĝi Misskey'on🚀"
_permissions:
"read:blocks": "Vidi la liston de uzantoj kiun vi blokas"
"write:blocks": "Redakti vian liston de blokataj uzantoj"
"read:drive": "Operacio por legi la informon de dosiero en via diskingo de Miskejo"
"write:drive": "Ĉia operacio por skribi, forviŝi, aŭ alimaniere ŝanĝi la informon de dosiero en via diskingo de Miskejo"
"read:drive": "Operacio por legi la informon de dosiero en via disko de Misskey"
"write:drive": "Ĉia operacio por skribi, forviŝi, aŭ alimaniere ŝanĝi la informon de dosiero en via disko de Misskey"
"read:favorites": "Vidi vian liston de preferatoj"
"read:following": "Vidi tion kion vi sekvas"
"write:following": "Sekvi kaj/aŭ malsekvi alian uzanton"
"read:messaging": "Vidi via retbabilado"
"read:following": "Vidi tiun kiun vi sekvas"
"write:following": "Sekvi aŭ malsekvi alian uzanton"
"read:messaging": "Vidi vian retbabiladon"
"read:mutes": "Vidi vian liston de silentigoj"
"write:mutes": "Redakti vian liston de silentigoj"
"write:notes": "Krei / Forviŝi noton"
@ -406,7 +566,8 @@ _permissions:
"read:page-likes": "Vidi ŝatojn de paĝo"
"read:channels": "Vidi kanalojn"
_antennaSources:
homeTimeline: "Notoj far uzantoj sekvataj de vi"
all: "Ĉiuj notoj"
homeTimeline: "Notoj far uzantoj, kiujn vi sekvas"
_weekday:
sunday: "dimanĉo"
monday: "lundo"
@ -419,15 +580,17 @@ _widgets:
notifications: "Sciigoj"
timeline: "Templinio"
clock: "Horloĝo"
federation: "Konfederacio"
activity: "Aktiveco"
federation: "Kunfederaĵo"
slideshow: "Bildoprezento"
button: "Butono"
onlineUsers: "Surkonektita uzanto"
_cw:
show: "Vidu pli"
files: "{count} dosiero(j)"
_poll:
choiceN: "Balotilo {n}"
noMore: "Oni ne plu povas aldoni."
noMore: "Oni ne povas aldoni pli."
infinite: "Neniam"
deadlineTime: "hor"
votesCount: "{n} balotiloj"
@ -438,11 +601,11 @@ _visibility:
home: "Hejmo"
homeDescription: "Elsendi nur sur la hejmtemplinio"
followers: "Sekvantoj"
followersDescription: "Elsendi nur al sekvantoj al mi"
followersDescription: "Nur al sekvantoj al mi"
localOnly: "Nur loka"
localOnlyDescription: "Ne montri al transaj uzantoj"
_postForm:
replyPlaceholder: "Respondado al tiu noto..."
replyPlaceholder: "Respondi al tiu noto..."
quotePlaceholder: "Citado tiun noton..."
channelPlaceholder: "Sendi sur la kanalo"
_profile:
@ -450,16 +613,21 @@ _profile:
username: "Uzantnomo"
metadataEdit: "Redakti kromaj informoj"
changeAvatar: "Ŝanĝi profilbildon"
changeBanner: "Ŝanĝi standardon"
_exportOrImport:
allNotes: "Ĉiuj notoj"
followingList: "Sekvataj"
muteList: "Silentigoj"
blockingList: "Blokado"
userLists: "Listoj"
_charts:
federationInstancesTotal: "Tuta numero de kunfederantaj ekzemploj"
filesTotal: "Tuta numero de dosieroj"
_timelines:
home: "Hejmo"
local: "Loka"
social: "Sociala"
global: "Konfederacia"
home: "HEJMO"
local: "LOKA"
social: "SOCIALA"
global: "MALLOKA"
_rooms:
translate: "Movi"
chooseImage: "Elekti bildon"
@ -472,18 +640,26 @@ _pages:
editThisPage: "Redakti la paĝon"
viewPage: "Vidi via paĝojn"
my: "Miaj paĝoj"
featured: "Ravaĵoj"
content: "Blokado de paĝo"
url: "URL de paĝo"
alignCenter: "Centrigi"
chooseBlock: "Aldoni blokon"
blocks:
image: "Bildoj"
image: "Bildo"
button: "Butono"
_post:
canvasId: "Kanvasa identigilo"
_numberInput:
text: "Titolo"
_canvas:
id: "Kanvasa identigilo"
_note:
id: "Identigilo de noto"
_counter:
text: "Titolo"
_button:
text: "Titolo"
_action:
_pushEvent:
event: "Nomo de la evento"
@ -504,6 +680,8 @@ _pages:
arg1: "Listoj"
_listLen:
arg1: "Listoj"
_splitStrByLine:
arg1: "Teksto"
types:
array: "Listoj"
stringArray: "List de teksto"
@ -511,21 +689,23 @@ _notification:
fileUploaded: "La dosiero sukcese alŝutiĝis."
youGotPoll: "{name} balotis"
youGotMessagingMessageFromUser: "{name} sentis mesaĝon al vi."
youWereFollowed: "Vin eksekvis"
youReceivedFollowRequest: "Vi ricevis eksekvopeton."
yourFollowRequestAccepted: "Via eksekvopeto estas akceptita."
youGotMessagingMessageFromGroup: "Retbabilan mesaĝon oni sendis al la grupo {name}"
youWereFollowed: "sksekvis vin"
youReceivedFollowRequest: "Vi ricevis peton de sekvado"
yourFollowRequestAccepted: "Via peto por sekvado estis akceptita."
_types:
follow: "Sekvatoj"
mention: "Mencioj"
renote: "Fari renoton"
quote: "Citi"
reaction: "Reagoj"
receiveFollowRequest: "Eksekvopeto ricevita"
followRequestAccepted: "Eksekvopeto akceptiĝis."
receiveFollowRequest: "Ricevita peton de sekvado"
followRequestAccepted: "Akceptita peto por sekvado"
_deck:
profile: "Agordaro"
_columns:
notifications: "Sciigoj"
tl: "Templinio"
antenna: "Antenoj"
list: "Listoj"
mentions: "Al vi"

View File

@ -91,11 +91,11 @@ followRequests: "Demandes dabonnement"
unfollow: "Se désabonner"
followRequestPending: "Demande d'abonnement en attente de confirmation"
enterEmoji: "Insérer un émoji"
renote: "Partager"
unrenote: "Annuler le partage"
renoted: "Republié !"
cantRenote: "Ce message ne peut pas être republié."
cantReRenote: "Impossible de repartager un partage."
renote: "Renoter"
unrenote: "Annuler la Renote"
renoted: "Renoté !"
cantRenote: "Ce message ne peut pas être renoté."
cantReRenote: "Impossible de renoter une Renote."
quote: "Citer"
pinnedNote: "Note épinglée"
pinned: "Épingler sur le profil"
@ -638,9 +638,9 @@ manageAccessTokens: "Gérer les jetons d'accès"
accountInfo: " Informations du compte "
notesCount: "Nombre de notes"
repliesCount: "Nombre de réponses envoyées"
renotesCount: "Nombre de notes repartagées"
renotesCount: "Nombre de notes que vous avez renotées"
repliedCount: "Nombre de réponses reçues"
renotedCount: "Nombre de Renotes"
renotedCount: "Nombre de vos notes renotées"
followingCount: "Nombre de comptes suivis"
followersCount: "Nombre d'abonnés"
sentReactionsCount: "Nombre de réactions envoyées"
@ -767,14 +767,22 @@ customCssWarn: "Utilisez cette fonctionnalité uniquement si vous savez exacteme
global: "Global"
squareAvatars: "Avatars carrés"
sent: "Envoyer"
searchResult: "Résultats de la recherche"
hashtags: "Hashtags"
troubleshooting: "Résolution de problèmes"
useBlurEffect: "Utiliser des effets de flou dans l'interface"
learnMore: "Plus d'informations"
misskeyUpdated: "Misskey a été mis à jour !"
whatIsNew: "Voir les derniers changements"
translate: "Traduire"
translatedFrom: "Traduit depuis {x}"
_docs:
continueReading: "Lire plus"
features: "Fonctionnalités"
generalTopics: "Sujets généraux"
advancedTopics: "Sujets avancés"
admin: "Gestion"
translateWarn: "Ceci est une traduction dont le contenu peut différer du texte original."
_ad:
back: "Retour"
reduceFrequencyOfThisAd: "Voir cette publicité moins souvent"
@ -988,7 +996,7 @@ _theme:
hashtag: "Hashtags"
mention: "Mentionner"
mentionMe: "Mentions (Moi)"
renote: "Partager"
renote: "Renoter"
modalBg: "Modal d'arrière-plan"
divider: "Séparateur"
scrollbarHandle: "Poignée de la barre de navigation"

View File

@ -767,9 +767,21 @@ customCssWarn: "Pengaturan ini seharusnya digunakan jika kamu tahu cara kerjanya
global: "Global"
squareAvatars: "Tampilkan avatar sebagai persegi"
sent: "Kirim"
received: "Diterima"
searchResult: "Hasil Penelusuran"
hashtags: "Tagar"
troubleshooting: "Penyelesaian Masalah"
useBlurEffect: "Gunakan efek blur pada antarmuka"
learnMore: "Pelajari lebih lanjut"
misskeyUpdated: "Misskey telah dimutakhirkan!"
whatIsNew: "Lihat perubahan pemutakhiran"
_docs:
continueReading: "Baca lebih lanjut"
features: "Fitur"
generalTopics: "Topik umum"
advancedTopics: "Topik tingkat lanjut"
admin: "Manajemen"
translateWarn: "Ini merupakan dokumen terjemahan. Konten di dalamnya kemungkinan dapat berbeda dari yang aslinya."
_ad:
back: "Kembali"
reduceFrequencyOfThisAd: "Tampilkan iklan ini lebih sedikit"
@ -868,6 +880,8 @@ _mfm:
blurDescription: "Konten dapat diburamkan dengan efek ini. Konten dapat ditampilkan dengan jelas dengan melayangkan kursor tetikus di atasnya."
font: "Font"
fontDescription: "Setel font yang ditampilkan untuk konten."
rainbow: "Pelangi"
rainbowDescription: "Membuat konten muncul dalam warna pelangi."
_reversi:
reversi: "Reversi"
gameSettings: "Pengaturan permainan"

View File

@ -773,6 +773,20 @@ hashtags: "ハッシュタグ"
troubleshooting: "トラブルシューティング"
useBlurEffect: "UIにぼかし効果を使用"
learnMore: "詳しく"
misskeyUpdated: "Misskeyが更新されました"
whatIsNew: "更新情報を見る"
translate: "翻訳"
translatedFrom: "{x}から翻訳"
accountDeletionInProgress: "アカウントの削除が進行中です"
usernameInfo: "サーバー上であなたのアカウントを一意に識別するための名前。アルファベット(a~z, A~Z)、数字(0~9)、およびアンダーバー(_)が使用できます。ユーザー名は後から変更することは出来ません。"
_accountDelete:
accountDelete: "アカウントの削除"
mayTakeTime: "アカウントの削除は負荷のかかる処理であるため、作成したコンテンツの数やアップロードしたファイルの数が多いと完了までに時間がかかることがあります。"
sendEmail: "アカウントの削除が完了する際は、登録してあったメールアドレス宛に通知を送信します。"
requestAccountDelete: "アカウント削除をリクエスト"
started: "削除処理が開始されました。"
inProgress: "削除が進行中"
_docs:
continueReading: "続きを読む"

View File

@ -7,6 +7,7 @@ search: "探す"
notifications: "通知"
username: "ユーザー名"
password: "パスワード"
forgotPassword: "パスワード忘れてん"
fetchingAsApObject: "今ちと連合に照会しとるで"
ok: "OKや"
gotIt: "ほい"
@ -139,6 +140,7 @@ flagAsBotDescription: "もしこのアカウントがプログラムによって
flagAsCat: "Catやで"
flagAsCatDescription: "ワレ、猫ちゃんならこのフラグをつけてみ?"
autoAcceptFollowed: "フォローしとるユーザーからのフォローリクエストを勝手に許可しとく"
addAccount: "アカウントを追加"
loginFailed: "ログインに失敗してしもうた…"
showOnRemote: "リモートで見る"
general: "全般"
@ -278,6 +280,7 @@ emptyDrive: "ドライブにはなんも残っとらん"
emptyFolder: "ふぉろだーにはなんも残っとらん"
unableToDelete: "消そうおもってんけどな、あかんかったわ"
inputNewFileName: "今度のファイル名は何にするん?"
inputNewDescription: "新しいキャプションを入力しましょ"
inputNewFolderName: "今度のフォルダ名は何にするん?"
circularReferenceFolder: "移動先のフォルダーは、移動するフォルダーのサブフォルダーや。"
hasChildFilesOrFolders: "このフォルダ、まだなんか入っとるから消されへん"

View File

@ -770,8 +770,22 @@ sent: "전송"
received: "수신"
searchResult: "검색 결과"
hashtags: "해시태그"
troubleshooting: "트러블 슈팅"
troubleshooting: "문제 해결"
useBlurEffect: "UI에 흐림 효과 사용"
learnMore: "자세히"
misskeyUpdated: "Misskey가 업데이트 되었습니다!"
whatIsNew: "패치 정보 보기"
translate: "번역"
translatedFrom: "{x}에서 번역"
accountDeletionInProgress: "계정 삭제 작업을 진행하고 있습니다"
usernameInfo: "서버상에서 계정을 식별하기 위한 이름. 알파벳(a~z, A~Z), 숫자(0~9) 및 언더바(_)를 사용할 수 있습니다. 사용자명은 나중에 변경할 수 없습니다."
_accountDelete:
accountDelete: "계정 삭제"
mayTakeTime: "계정 삭제는 서버에 부하를 가하기 때문에, 작성한 콘텐츠나 업로드한 파일의 수가 많으면 완료까지 시간이 걸릴 수 있습니다."
sendEmail: "계정 삭제가 완료되면 등록된 이메일 주소로 알림을 보냅니다."
requestAccountDelete: "계정 삭제 요청"
started: "삭제 작업이 시작되었습니다."
inProgress: "삭제 진행 중"
_docs:
continueReading: "계속 읽기"
features: "기능"

View File

@ -772,6 +772,9 @@ searchResult: "Результаты поиска"
hashtags: "Хэштег"
troubleshooting: "Разрешение проблем"
useBlurEffect: "Размытие в интерфейсе"
learnMore: "Подробнее"
misskeyUpdated: "Misskey обновился!"
whatIsNew: "Что новенького?"
_docs:
continueReading: "Читать подробнее"
features: "Возможности"

View File

@ -773,6 +773,15 @@ hashtags: "话题标签"
troubleshooting: "故障排除"
useBlurEffect: "在UI上使用模糊效果"
learnMore: "更多信息"
misskeyUpdated: "Misskey更新完成"
whatIsNew: "显示更新信息"
translate: "翻译"
translatedFrom: "从 {x} 翻译"
accountDeletionInProgress: "正在删除账户"
usernameInfo: "在服务器上唯一标识您的帐户的名称。您可以使用字母 (a ~ z, A ~ Z)、数字 (0 ~ 9) 和下划线 (_)。用户名以后不能更改。"
_accountDelete:
accountDelete: "删除帐户"
inProgress: "正在删除"
_docs:
continueReading: "继续阅读"
features: "特性"

View File

@ -0,0 +1,182 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class chartReindex1629004542760 implements MigrationInterface {
name = 'chartReindex1629004542760'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DELETE FROM "__chart__active_users" a USING "__chart__active_users" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__drive" a USING "__chart__drive" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__federation" a USING "__chart__federation" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__hashtag" a USING "__chart__hashtag" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__instance" a USING "__chart__instance" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__network" a USING "__chart__network" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__notes" a USING "__chart__notes" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__per_user_drive" a USING "__chart__per_user_drive" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__per_user_following" a USING "__chart__per_user_following" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__per_user_notes" a USING "__chart__per_user_notes" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__per_user_reaction" a USING "__chart__per_user_reaction" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__test_grouped" a USING "__chart__test_grouped" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__test_unique" a USING "__chart__test_unique" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DELETE FROM "__chart__users" a USING "__chart__users" b WHERE a.id < b.id AND ((a.group IS NULL AND b.group IS NULL) OR a.group = b.group) AND a.date = b.date;`);
await queryRunner.query(`DROP INDEX "IDX_0ad37b7ef50f4ddc84363d7ccc"`);
await queryRunner.query(`DROP INDEX "IDX_00ed5f86db1f7efafb1978bf21"`);
await queryRunner.query(`DROP INDEX "IDX_9a3ed15a30ab7e3a37702e6e08"`);
await queryRunner.query(`DROP INDEX "IDX_13565815f618a1ff53886c5b28"`);
await queryRunner.query(`DROP INDEX "IDX_7a170f67425e62a8fabb76c872"`);
await queryRunner.query(`DROP INDEX "IDX_3313d7288855ec105b5bbf6c21"`);
await queryRunner.query(`DROP INDEX "IDX_36cb699c49580d4e6c2e6159f9"`);
await queryRunner.query(`DROP INDEX "IDX_76e87c7bfc5d925fcbba405d84"`);
await queryRunner.query(`DROP INDEX "IDX_dd907becf76104e4b656659e6b"`);
await queryRunner.query(`DROP INDEX "IDX_07747a1038c05f532a718fe1de"`);
await queryRunner.query(`DROP INDEX "IDX_99a7d2faaef84a6f728d714ad6"`);
await queryRunner.query(`DROP INDEX "IDX_25a97c02003338124b2b75fdbc"`);
await queryRunner.query(`DROP INDEX "IDX_6b8f34a1a64b06014b6fb66824"`);
await queryRunner.query(`DROP INDEX "IDX_da8a46ba84ca1d8bb5a29bfb63"`);
await queryRunner.query(`DROP INDEX "IDX_39ee857ab2f23493037c6b6631"`);
await queryRunner.query(`DROP INDEX "IDX_a1efd3e0048a5f2793a47360dc"`);
await queryRunner.query(`DROP INDEX "IDX_7b5da130992ec9df96712d4290"`);
await queryRunner.query(`DROP INDEX "IDX_0a905b992fecd2b5c3fb98759e"`);
await queryRunner.query(`DROP INDEX "IDX_42eb716a37d381cdf566192b2b"`);
await queryRunner.query(`DROP INDEX "IDX_7036f2957151588b813185c794"`);
await queryRunner.query(`DROP INDEX "IDX_f09d543e3acb16c5976bdb31fa"`);
await queryRunner.query(`DROP INDEX "IDX_5f86db6492274e07c1a3cdf286"`);
await queryRunner.query(`DROP INDEX "IDX_e496ca8096d28f6b9b509264dc"`);
await queryRunner.query(`DROP INDEX "IDX_30bf67687f483ace115c5ca642"`);
await queryRunner.query(`DROP INDEX "IDX_7af07790712aa3438ff6773f3b"`);
await queryRunner.query(`DROP INDEX "IDX_4b3593098b6edc9c5afe36b18b"`);
await queryRunner.query(`DROP INDEX "IDX_b77d4dd9562c3a899d9a286fcd"`);
await queryRunner.query(`DROP INDEX "IDX_84234bd1abb873f07329681c83"`);
await queryRunner.query(`DROP INDEX "IDX_55bf20f366979f2436de99206b"`);
await queryRunner.query(`DROP INDEX "IDX_5048e9daccbbbc6d567bb142d3"`);
await queryRunner.query(`DROP INDEX "IDX_f7bf4c62059764c2c2bb40fdab"`);
await queryRunner.query(`DROP INDEX "IDX_8cf3156fd7a6b15c43459c6e3b"`);
await queryRunner.query(`DROP INDEX "IDX_229a41ad465f9205f1f5703291"`);
await queryRunner.query(`DROP INDEX "IDX_0c641990ecf47d2545df4edb75"`);
await queryRunner.query(`DROP INDEX "IDX_234dff3c0b56a6150b95431ab9"`);
await queryRunner.query(`DROP INDEX "IDX_b14489029e4b3aaf4bba5fb524"`);
await queryRunner.query(`DROP INDEX "IDX_437bab3c6061d90f6bb65fd2cc"`);
await queryRunner.query(`DROP INDEX "IDX_bbfa573a8181018851ed0b6357"`);
await queryRunner.query(`DROP INDEX "IDX_a0cd75442dd10d0643a17c4a49"`);
await queryRunner.query(`DROP INDEX "IDX_b070a906db04b44c67c6c2144d"`);
await queryRunner.query(`DROP INDEX "IDX_d41cce6aee1a50bfc062038f9b"`);
await queryRunner.query(`DROP INDEX "IDX_a319e5dbf47e8a17497623beae"`);
await queryRunner.query(`DROP INDEX "IDX_845254b3eaf708ae8a6cac3026"`);
await queryRunner.query(`DROP INDEX "IDX_ed9b95919c672a13008e9487ee"`);
await queryRunner.query(`DROP INDEX "IDX_337e9599f278bd7537fe30876f"`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_9a3ed15a30ab7e3a37702e6e08" ON "__chart__active_users" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_60c5c6e7e538c09aa274ecd1cf" ON "__chart__active_users" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_3313d7288855ec105b5bbf6c21" ON "__chart__drive" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ceab80a6729f8e2e6f5b8a1a3d" ON "__chart__drive" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_dd907becf76104e4b656659e6b" ON "__chart__federation" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_eddfed8fb40305a04c6f941050" ON "__chart__federation" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_25a97c02003338124b2b75fdbc" ON "__chart__hashtag" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_53a3604b939e2b479eb2cfaac8" ON "__chart__hashtag" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_39ee857ab2f23493037c6b6631" ON "__chart__instance" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_8111b817b9818c04d7eb8475b1" ON "__chart__instance" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_0a905b992fecd2b5c3fb98759e" ON "__chart__network" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_2082327b2699ce924fa654afc5" ON "__chart__network" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_f09d543e3acb16c5976bdb31fa" ON "__chart__notes" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_e60c358aaced5aab8900a4af31" ON "__chart__notes" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_30bf67687f483ace115c5ca642" ON "__chart__per_user_drive" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a9a806d466b314f253a1a611c4" ON "__chart__per_user_drive" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_b77d4dd9562c3a899d9a286fcd" ON "__chart__per_user_following" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_dabbb38a51ab86ee3cab291326" ON "__chart__per_user_following" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_5048e9daccbbbc6d567bb142d3" ON "__chart__per_user_notes" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_583a157ed0cf0ed1b5ec2a833f" ON "__chart__per_user_notes" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_229a41ad465f9205f1f5703291" ON "__chart__per_user_reaction" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_3b7697a96f522d0478972e6d6f" ON "__chart__per_user_reaction" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_b14489029e4b3aaf4bba5fb524" ON "__chart__test_grouped" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_da522b4008a9f5d7743b87ad55" ON "__chart__test_grouped" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a0cd75442dd10d0643a17c4a49" ON "__chart__test_unique" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_16effb2e888f6763673b579f80" ON "__chart__test_unique" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_a319e5dbf47e8a17497623beae" ON "__chart__test" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_dab383a36f3c9db4a0c9b02cf3" ON "__chart__test" ("date") WHERE "group" IS NULL`);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_337e9599f278bd7537fe30876f" ON "__chart__users" ("date", "group") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_66feba81e1795d176d06c0b1e6" ON "__chart__users" ("date") WHERE "group" IS NULL`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP INDEX "IDX_66feba81e1795d176d06c0b1e6"`);
await queryRunner.query(`DROP INDEX "IDX_337e9599f278bd7537fe30876f"`);
await queryRunner.query(`DROP INDEX "IDX_dab383a36f3c9db4a0c9b02cf3"`);
await queryRunner.query(`DROP INDEX "IDX_a319e5dbf47e8a17497623beae"`);
await queryRunner.query(`DROP INDEX "IDX_16effb2e888f6763673b579f80"`);
await queryRunner.query(`DROP INDEX "IDX_a0cd75442dd10d0643a17c4a49"`);
await queryRunner.query(`DROP INDEX "IDX_da522b4008a9f5d7743b87ad55"`);
await queryRunner.query(`DROP INDEX "IDX_b14489029e4b3aaf4bba5fb524"`);
await queryRunner.query(`DROP INDEX "IDX_3b7697a96f522d0478972e6d6f"`);
await queryRunner.query(`DROP INDEX "IDX_229a41ad465f9205f1f5703291"`);
await queryRunner.query(`DROP INDEX "IDX_583a157ed0cf0ed1b5ec2a833f"`);
await queryRunner.query(`DROP INDEX "IDX_5048e9daccbbbc6d567bb142d3"`);
await queryRunner.query(`DROP INDEX "IDX_dabbb38a51ab86ee3cab291326"`);
await queryRunner.query(`DROP INDEX "IDX_b77d4dd9562c3a899d9a286fcd"`);
await queryRunner.query(`DROP INDEX "IDX_a9a806d466b314f253a1a611c4"`);
await queryRunner.query(`DROP INDEX "IDX_30bf67687f483ace115c5ca642"`);
await queryRunner.query(`DROP INDEX "IDX_e60c358aaced5aab8900a4af31"`);
await queryRunner.query(`DROP INDEX "IDX_f09d543e3acb16c5976bdb31fa"`);
await queryRunner.query(`DROP INDEX "IDX_2082327b2699ce924fa654afc5"`);
await queryRunner.query(`DROP INDEX "IDX_0a905b992fecd2b5c3fb98759e"`);
await queryRunner.query(`DROP INDEX "IDX_8111b817b9818c04d7eb8475b1"`);
await queryRunner.query(`DROP INDEX "IDX_39ee857ab2f23493037c6b6631"`);
await queryRunner.query(`DROP INDEX "IDX_53a3604b939e2b479eb2cfaac8"`);
await queryRunner.query(`DROP INDEX "IDX_25a97c02003338124b2b75fdbc"`);
await queryRunner.query(`DROP INDEX "IDX_eddfed8fb40305a04c6f941050"`);
await queryRunner.query(`DROP INDEX "IDX_dd907becf76104e4b656659e6b"`);
await queryRunner.query(`DROP INDEX "IDX_ceab80a6729f8e2e6f5b8a1a3d"`);
await queryRunner.query(`DROP INDEX "IDX_3313d7288855ec105b5bbf6c21"`);
await queryRunner.query(`DROP INDEX "IDX_60c5c6e7e538c09aa274ecd1cf"`);
await queryRunner.query(`DROP INDEX "IDX_9a3ed15a30ab7e3a37702e6e08"`);
await queryRunner.query(`DROP INDEX "IDX_a9021cc2e1feb5f72d3db6e9f5"`);
await queryRunner.query(`DROP INDEX "IDX_f22169eb10657bded6d875ac8f"`);
await queryRunner.query(`DROP INDEX "IDX_c8cc87bd0f2f4487d17c651fbf"`);
await queryRunner.query(`DROP INDEX "IDX_754499f9b2642336433769518d"`);
await queryRunner.query(`DROP INDEX "IDX_315c779174fe8247ab324f036e"`);
await queryRunner.query(`DROP INDEX "IDX_c5d46cbfda48b1c33ed852e21b"`);
await queryRunner.query(`CREATE INDEX "IDX_337e9599f278bd7537fe30876f" ON "__chart__users" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_ed9b95919c672a13008e9487ee" ON "__chart__users" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_845254b3eaf708ae8a6cac3026" ON "__chart__users" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_a319e5dbf47e8a17497623beae" ON "__chart__test" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_d41cce6aee1a50bfc062038f9b" ON "__chart__test" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_b070a906db04b44c67c6c2144d" ON "__chart__test" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_a0cd75442dd10d0643a17c4a49" ON "__chart__test_unique" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_bbfa573a8181018851ed0b6357" ON "__chart__test_unique" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_437bab3c6061d90f6bb65fd2cc" ON "__chart__test_unique" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_b14489029e4b3aaf4bba5fb524" ON "__chart__test_grouped" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_234dff3c0b56a6150b95431ab9" ON "__chart__test_grouped" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_0c641990ecf47d2545df4edb75" ON "__chart__test_grouped" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_229a41ad465f9205f1f5703291" ON "__chart__per_user_reaction" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_8cf3156fd7a6b15c43459c6e3b" ON "__chart__per_user_reaction" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_f7bf4c62059764c2c2bb40fdab" ON "__chart__per_user_reaction" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_5048e9daccbbbc6d567bb142d3" ON "__chart__per_user_notes" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_55bf20f366979f2436de99206b" ON "__chart__per_user_notes" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_84234bd1abb873f07329681c83" ON "__chart__per_user_notes" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_b77d4dd9562c3a899d9a286fcd" ON "__chart__per_user_following" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_4b3593098b6edc9c5afe36b18b" ON "__chart__per_user_following" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_7af07790712aa3438ff6773f3b" ON "__chart__per_user_following" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_30bf67687f483ace115c5ca642" ON "__chart__per_user_drive" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_e496ca8096d28f6b9b509264dc" ON "__chart__per_user_drive" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_5f86db6492274e07c1a3cdf286" ON "__chart__per_user_drive" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_f09d543e3acb16c5976bdb31fa" ON "__chart__notes" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_7036f2957151588b813185c794" ON "__chart__notes" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_42eb716a37d381cdf566192b2b" ON "__chart__notes" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_0a905b992fecd2b5c3fb98759e" ON "__chart__network" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_7b5da130992ec9df96712d4290" ON "__chart__network" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_a1efd3e0048a5f2793a47360dc" ON "__chart__network" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_39ee857ab2f23493037c6b6631" ON "__chart__instance" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_da8a46ba84ca1d8bb5a29bfb63" ON "__chart__instance" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_6b8f34a1a64b06014b6fb66824" ON "__chart__instance" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_25a97c02003338124b2b75fdbc" ON "__chart__hashtag" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_99a7d2faaef84a6f728d714ad6" ON "__chart__hashtag" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_07747a1038c05f532a718fe1de" ON "__chart__hashtag" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_dd907becf76104e4b656659e6b" ON "__chart__federation" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_76e87c7bfc5d925fcbba405d84" ON "__chart__federation" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_36cb699c49580d4e6c2e6159f9" ON "__chart__federation" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_3313d7288855ec105b5bbf6c21" ON "__chart__drive" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_7a170f67425e62a8fabb76c872" ON "__chart__drive" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_13565815f618a1ff53886c5b28" ON "__chart__drive" ("date") `);
await queryRunner.query(`CREATE INDEX "IDX_9a3ed15a30ab7e3a37702e6e08" ON "__chart__active_users" ("date", "group") `);
await queryRunner.query(`CREATE INDEX "IDX_00ed5f86db1f7efafb1978bf21" ON "__chart__active_users" ("group") `);
await queryRunner.query(`CREATE INDEX "IDX_0ad37b7ef50f4ddc84363d7ccc" ON "__chart__active_users" ("date") `);
}
}

View File

@ -0,0 +1,14 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class deeplIntegration1629024377804 implements MigrationInterface {
name = 'deeplIntegration1629024377804'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "meta" ADD "deeplAuthKey" character varying(128)`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "deeplAuthKey"`);
}
}

View File

@ -0,0 +1,14 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class fixChannelUserId1629288472000 implements MigrationInterface {
name = 'fixChannelUserId1629288472000'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "channel" ALTER COLUMN "userId" DROP NOT NULL;`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "channel" ALTER COLUMN "userId" SET NOT NULL;`);
}
}

View File

@ -0,0 +1,15 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class isUserDeleted1629512953000 implements MigrationInterface {
name = 'isUserDeleted1629512953000'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "user" ADD "isDeleted" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`COMMENT ON COLUMN "user"."isDeleted" IS 'Whether the User is deleted.'`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "isDeleted"`);
}
}

View File

@ -0,0 +1,14 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class deeplIntegration21629778475000 implements MigrationInterface {
name = 'deeplIntegration21629778475000'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "meta" ADD "deeplIsPro" boolean NOT NULL DEFAULT false`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "deeplIsPro"`);
}
}

View File

@ -1,7 +1,7 @@
{
"name": "misskey",
"author": "syuilo <syuilotan@yahoo.co.jp>",
"version": "12.87.0",
"version": "12.89.1",
"codename": "indigo",
"repository": {
"type": "git",
@ -10,7 +10,8 @@
"main": "./index.js",
"private": true,
"scripts": {
"start": "node ./index.js",
"start": "node --experimental-json-modules ./index.js",
"start:test": "cross-env NODE_ENV=test node --experimental-json-modules ./index.js",
"init": "npm run migrate",
"ormconfig": "node ./built/ormconfig.js",
"migrate": "ts-node ./node_modules/typeorm/cli.js migration:run",
@ -26,6 +27,9 @@
"clean": "gulp clean",
"cleanall": "gulp cleanall",
"lint": "tslint 'src/**/*.ts'",
"cy:open": "cypress open",
"cy:run": "cypress run",
"e2e": "start-server-and-test start:test http://localhost cy:run",
"test": "cross-env TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT=\"./test/tsconfig.json\" mocha",
"format": "gulp format"
},
@ -34,7 +38,6 @@
"lodash": "^4.17.21"
},
"dependencies": {
"@babel/plugin-transform-runtime": "7.14.5",
"@elastic/elasticsearch": "7.11.0",
"@koa/cors": "3.1.0",
"@koa/multer": "3.0.0",
@ -70,7 +73,7 @@
"@types/markdown-it": "12.0.3",
"@types/matter-js": "0.17.5",
"@types/mocha": "8.2.3",
"@types/node": "16.6.0",
"@types/node": "16.6.2",
"@types/node-fetch": "2.5.12",
"@types/nodemailer": "6.4.4",
"@types/nprogress": "0.2.0",
@ -86,7 +89,7 @@
"@types/redis": "2.8.31",
"@types/rename": "1.0.4",
"@types/request-stats": "3.0.0",
"@types/rimraf": "3.0.1",
"@types/rimraf": "3.0.2",
"@types/seedrandom": "2.4.28",
"@types/sharp": "0.28.5",
"@types/sinonjs__fake-timers": "6.0.3",
@ -100,8 +103,8 @@
"@types/webpack-stream": "3.2.12",
"@types/websocket": "1.0.4",
"@types/ws": "7.4.7",
"@typescript-eslint/parser": "4.29.1",
"@vue/compiler-sfc": "3.2.2",
"@typescript-eslint/parser": "4.29.2",
"@vue/compiler-sfc": "3.2.4",
"abort-controller": "3.0.0",
"apexcharts": "3.27.3",
"autobind-decorator": "2.4.0",
@ -109,23 +112,23 @@
"autwh": "0.1.0",
"aws-sdk": "2.966.0",
"bcryptjs": "2.4.3",
"blurhash": "1.1.3",
"broadcast-channel": "3.7.0",
"bull": "3.26.0",
"blurhash": "1.1.4",
"broadcast-channel": "4.2.0",
"bull": "3.28.1",
"cacheable-lookup": "6.0.0",
"cafy": "15.2.1",
"cbor": "8.0.0",
"chalk": "4.1.2",
"chart.js": "2.9.4",
"cli-highlight": "2.1.11",
"commander": "7.2.0",
"concurrently": "6.2.0",
"commander": "8.1.0",
"compare-versions": "3.6.0",
"concurrently": "6.2.1",
"content-disposition": "0.5.3",
"core-js": "3.16.1",
"crc-32": "1.2.0",
"css-loader": "6.2.0",
"cssnano": "5.0.7",
"cssnano": "5.0.8",
"dateformat": "4.5.1",
"diskusage": "1.1.3",
"escape-regexp": "0.0.1",
"eslint": "7.32.0",
"eslint-plugin-vue": "7.16.0",
@ -141,14 +144,10 @@
"gulp-replace": "1.1.3",
"gulp-terser": "2.0.1",
"gulp-tslint": "8.1.4",
"hard-source-webpack-plugin": "0.13.1",
"html-minifier": "4.0.0",
"http-proxy-agent": "4.0.1",
"hpagent": "0.1.2",
"http-signature": "1.3.5",
"https-proxy-agent": "5.0.0",
"idb-keyval": "5.1.3",
"insert-text-at-cursor": "0.3.0",
"is-root": "2.1.0",
"is-svg": "4.3.1",
"js-yaml": "4.1.0",
"jsdom": "16.7.0",
@ -167,30 +166,26 @@
"koa-slow": "2.1.0",
"koa-views": "7.0.1",
"langmap": "0.0.16",
"lookup-dns-cache": "2.1.0",
"markdown-it": "12.2.0",
"markdown-it-anchor": "7.1.0",
"matter-js": "0.17.1",
"mfm-js": "0.19.0",
"misskey-js": "0.0.6",
"mocha": "8.4.0",
"moji": "0.5.1",
"ms": "2.1.3",
"multer": "1.4.3",
"nested-property": "4.0.0",
"node-fetch": "2.6.1",
"nodemailer": "6.6.3",
"object-assign-deep": "0.4.0",
"os-utils": "0.0.14",
"parse5": "6.0.1",
"pg": "8.6.0",
"pg": "8.7.1",
"portscanner": "2.2.0",
"postcss": "8.3.6",
"postcss-loader": "6.1.1",
"prismjs": "1.24.1",
"probe-image-size": "7.2.1",
"promise-limit": "2.7.0",
"promise-sequential": "1.1.1",
"pug": "3.0.2",
"punycode": "2.1.1",
"pureimage": "0.3.2",
@ -198,21 +193,19 @@
"random-seed": "0.3.0",
"ratelimiter": "3.4.1",
"re2": "1.16.0",
"reconnecting-websocket": "4.4.0",
"redis": "3.1.2",
"redis-lock": "0.1.4",
"reflect-metadata": "0.1.13",
"regenerator-runtime": "0.13.9",
"rename": "1.0.4",
"request-stats": "3.0.0",
"require-all": "3.0.0",
"rimraf": "3.0.2",
"rndstr": "1.0.0",
"s-age": "1.1.2",
"sass": "1.37.5",
"sass": "1.38.0",
"sass-loader": "12.1.0",
"seedrandom": "3.0.5",
"sharp": "0.28.3",
"sharp": "0.29.0",
"speakeasy": "2.0.0",
"stringz": "2.1.0",
"style-loader": "3.2.1",
@ -226,21 +219,18 @@
"tinycolor2": "1.4.2",
"tmp": "0.2.1",
"ts-loader": "9.2.5",
"ts-node": "10.2.0",
"tsc-alias": "1.3.8",
"ts-node": "10.2.1",
"tsc-alias": "1.3.9",
"tsconfig-paths": "3.10.1",
"tslint": "6.1.3",
"tslint-sonarts": "1.9.0",
"twemoji-parser": "13.1.0",
"typeorm": "0.2.32",
"typeorm": "0.2.37",
"typescript": "4.3.5",
"ulid": "2.3.0",
"uuid": "8.3.2",
"v-debounce": "0.1.2",
"vanilla-tilt": "1.7.1",
"vue": "3.2.2",
"vue-color": "2.8.1",
"vue-json-pretty": "1.8.1",
"vue": "3.2.4",
"vue-loader": "16.5.0",
"vue-prism-editor": "2.0.0-alpha.2",
"vue-router": "4.0.5",
@ -248,17 +238,17 @@
"vue-svg-loader": "0.17.0-beta.2",
"vuedraggable": "4.0.1",
"web-push": "3.4.5",
"webpack": "5.50.0",
"webpack-cli": "4.7.2",
"webpack": "5.51.0",
"webpack-cli": "4.8.0",
"websocket": "1.0.34",
"ws": "8.1.0",
"ws": "8.2.0",
"xev": "2.0.1"
},
"devDependencies": {
"@redocly/openapi-core": "1.0.0-beta.44",
"@types/chai": "4.2.16",
"@redocly/openapi-core": "1.0.0-beta.54",
"@types/fluent-ffmpeg": "2.1.17",
"chai": "4.3.4",
"cross-env": "7.0.3"
"cross-env": "7.0.3",
"cypress": "8.3.0",
"start-server-and-test": "1.13.1"
}
}

View File

@ -1,7 +0,0 @@
declare module 'is-root' {
function isRoot(): boolean;
namespace isRoot {} // Hack
export = isRoot;
}

View File

@ -1,9 +0,0 @@
declare module 'lookup-dns-cache' {
import { LookupOneOptions, LookupAllOptions, LookupOptions, LookupAddress } from 'dns';
function lookup(hostname: string, family: number, callback: (err: NodeJS.ErrnoException | null, address: string, family: number) => void): void;
function lookup(hostname: string, options: LookupOneOptions, callback: (err: NodeJS.ErrnoException | null, address: string, family: number) => void): void;
function lookup(hostname: string, options: LookupAllOptions, callback: (err: NodeJS.ErrnoException | null, addresses: LookupAddress[]) => void): void;
function lookup(hostname: string, options: LookupOptions, callback: (err: NodeJS.ErrnoException | null, address: string | LookupAddress[], family: number) => void): void;
function lookup(hostname: string, callback: (err: NodeJS.ErrnoException | null, address: string, family: number) => void): void;
}

View File

@ -1,24 +1,23 @@
import { Command } from 'commander';
import config from '@/config';
import config from '@/config/index';
const program = new Command();
program
.version(config.version)
.option('--no-daemons', 'Disable daemon processes (for debbuging)')
.option('--disable-clustering', 'Disable clustering')
.option('--only-server', 'Run server only (without job queue processing)')
.option('--only-queue', 'Pocessing job queue only (without server)')
.option('--quiet', 'Suppress all logs')
.option('--verbose', 'Enable all logs')
.option('--with-log-time', 'Include timestamp for each logs')
.option('--slow', 'Delay all requests (for debbuging)')
.option('--color', 'This option is a dummy for some external program\'s (e.g. forever) issue.')
.parse(process.argv);
program.version(config.version);
program.option('--no-daemons', 'Disable daemon processes (for debbuging)');
program.option('--disable-clustering', 'Disable clustering');
program.option('--only-server', 'Run server only (without job queue processing)');
program.option('--only-queue', 'Pocessing job queue only (without server)');
program.option('--quiet', 'Suppress all logs');
program.option('--verbose', 'Enable all logs');
program.option('--with-log-time', 'Include timestamp for each logs');
program.option('--slow', 'Delay all requests (for debbuging)');
program.option('--color', 'This option is a dummy for some external program\'s (e.g. forever) issue.');
program.parse(process.argv);
if (process.env.MK_ONLY_QUEUE) program.onlyQueue = true;
if (process.env.NODE_ENV === 'test') program.disableClustering = true;
if (process.env.NODE_ENV === 'test') program.quiet = true;
//if (process.env.NODE_ENV === 'test') program.quiet = true;
if (process.env.NODE_ENV === 'test') program.noDaemons = true;
export { program };

View File

@ -2,7 +2,7 @@ import * as cluster from 'cluster';
import * as chalk from 'chalk';
import Xev from 'xev';
import Logger from '../services/logger';
import Logger from '@/services/logger';
import { program } from '../argv';
// for typeorm

View File

@ -1,18 +1,25 @@
import * as fs from 'fs';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import * as os from 'os';
import * as cluster from 'cluster';
import * as chalk from 'chalk';
import * as portscanner from 'portscanner';
import * as isRoot from 'is-root';
import { getConnection } from 'typeorm';
import Logger from '../services/logger';
import Logger from '@/services/logger';
import loadConfig from '@/config/load';
import { Config } from '@/config/types';
import { lessThan } from '../prelude/array';
import { lessThan } from '@/prelude/array';
import { program } from '../argv';
import { showMachineInfo } from '@/misc/show-machine-info';
import { initDb } from '../db/postgre';
const meta = require('../meta.json');
//const _filename = fileURLToPath(import.meta.url);
const _filename = __filename;
const _dirname = dirname(_filename);
const meta = JSON.parse(fs.readFileSync(`${_dirname}/../meta.json`, 'utf-8'));
const logger = new Logger('core', 'cyan');
const bootLogger = logger.createSubLogger('boot', 'magenta', false);
@ -39,6 +46,11 @@ function greet() {
bootLogger.info(`Misskey v${meta.version}`, null, true);
}
function isRoot() {
// maybe process.getuid will be undefined under not POSIX environment (e.g. Windows)
return process.getuid != null && process.getuid() === 0;
}
/**
* Init master process
*/

View File

@ -1,7 +1,8 @@
import { get, set } from '@client/scripts/idb-proxy';
import { reactive } from 'vue';
import { apiUrl } from '@client/config';
import { waiting } from '@client/os';
import { unisonReload } from '@client/scripts/unison-reload';
import { unisonReload, reloadChannel } from '@client/scripts/unison-reload';
// TODO: 他のタブと永続化されたstateを同期
@ -10,6 +11,7 @@ type Account = {
token: string;
isModerator: boolean;
isAdmin: boolean;
isDeleted: boolean;
};
const data = localStorage.getItem('account');
@ -17,22 +19,45 @@ const data = localStorage.getItem('account');
// TODO: 外部からはreadonlyに
export const $i = data ? reactive(JSON.parse(data) as Account) : null;
export function signout() {
export async function signout() {
waiting();
localStorage.removeItem('account');
//#region Remove account
const accounts = await getAccounts();
accounts.splice(accounts.findIndex(x => x.id === $i.id), 1);
set('accounts', accounts);
//#endregion
//#region Remove push notification registration
try {
const registration = await navigator.serviceWorker.ready;
const push = await registration.pushManager.getSubscription();
if (!push) return;
await fetch(`${apiUrl}/sw/unregister`, {
method: 'POST',
body: JSON.stringify({
i: $i.token,
endpoint: push.endpoint,
}),
});
} catch (e) {}
//#endregion
document.cookie = `igi=; path=/`;
location.href = '/';
if (accounts.length > 0) login(accounts[0].token);
else unisonReload();
}
export function getAccounts() {
const accountsData = localStorage.getItem('accounts');
const accounts: { id: Account['id'], token: Account['token'] }[] = accountsData ? JSON.parse(accountsData) : [];
return accounts;
export async function getAccounts(): Promise<{ id: Account['id'], token: Account['token'] }[]> {
return (await get('accounts')) || [];
}
export function addAccount(id: Account['id'], token: Account['token']) {
const accounts = getAccounts();
export async function addAccount(id: Account['id'], token: Account['token']) {
const accounts = await getAccounts();
if (!accounts.some(x => x.id === id)) {
localStorage.setItem('accounts', JSON.stringify(accounts.concat([{ id, token }])));
await set('accounts', accounts.concat([{ id, token }]));
}
}
@ -47,7 +72,7 @@ function fetchAccount(token): Promise<Account> {
})
.then(res => {
// When failed to authenticate user
if (res.status >= 400 && res.status < 500) {
if (res.status !== 200 && res.status < 500) {
return signout();
}
@ -69,15 +94,22 @@ export function updateAccount(data) {
}
export function refreshAccount() {
fetchAccount($i.token).then(updateAccount);
return fetchAccount($i.token).then(updateAccount);
}
export async function login(token: Account['token']) {
export async function login(token: Account['token'], redirect?: string) {
waiting();
if (_DEV_) console.log('logging as token ', token);
const me = await fetchAccount(token);
localStorage.setItem('account', JSON.stringify(me));
addAccount(me.id, token);
await addAccount(me.id, token);
if (redirect) {
reloadChannel.postMessage('reload');
location.href = redirect;
return;
}
unisonReload();
}

View File

@ -93,13 +93,13 @@ export default defineComponent({
});
return h(this.$store.state.animation ? TransitionGroup : 'div', this.$store.state.animation ? {
class: 'sqadhkmv' + (this.noGap ? ' noGap _block' : ''),
class: 'sqadhkmv' + (this.noGap ? ' noGap' : ''),
name: 'list',
tag: 'div',
'data-direction': this.direction,
'data-reversed': this.reversed ? 'true' : 'false',
} : {
class: 'sqadhkmv' + (this.noGap ? ' noGap _block' : ''),
class: 'sqadhkmv' + (this.noGap ? ' noGap' : ''),
}, {
default: renderChildren
});

View File

@ -1,5 +1,5 @@
<template>
<div class="yxspomdl" :class="{ inline, colored }">
<div class="yxspomdl" :class="{ inline, colored, mini }">
<div class="ring"></div>
</div>
</template>
@ -18,7 +18,12 @@ export default defineComponent({
type: Boolean,
required: false,
default: true
}
},
mini: {
type: Boolean,
required: false,
default: false
},
}
});
</script>
@ -38,6 +43,8 @@ export default defineComponent({
text-align: center;
cursor: wait;
--size: 48px;
&.colored {
color: var(--accent);
}
@ -45,19 +52,12 @@ export default defineComponent({
&.inline {
display: inline;
padding: 0;
--size: 32px;
}
> .ring:after {
width: 32px;
height: 32px;
}
> .ring {
&:before,
&:after {
width: 32px;
height: 32px;
}
}
&.mini {
padding: 16px;
--size: 32px;
}
> .ring {
@ -70,8 +70,8 @@ export default defineComponent({
content: " ";
display: block;
box-sizing: border-box;
width: 48px;
height: 48px;
width: var(--size);
height: var(--size);
border-radius: 50%;
border: solid 4px;
}

View File

@ -1,6 +1,6 @@
<template>
<div
class="note _block"
class="lxwezrsl _block"
v-if="!muted"
v-show="!isDeleted"
:tabindex="!isDeleted ? '-1' : null"
@ -67,6 +67,13 @@
<MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><i class="fas fa-reply"></i></MkA>
<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/>
<a class="rp" v-if="appearNote.renote != null">RN:</a>
<div class="translation" v-if="translating || translation">
<MkLoading v-if="translating" mini/>
<div class="translated" v-else>
<b>{{ $t('translatedFrom', { x: translation.sourceLang }) }}:</b>
{{ translation.text }}
</div>
</div>
</div>
<div class="files" v-if="appearNote.files.length > 0">
<XMediaList :media-list="appearNote.files"/>
@ -79,8 +86,8 @@
</div>
<footer class="footer">
<div class="info">
<span class="mobile" v-if="note.viaMobile"><i class="fas fa-mobile-alt"></i></span>
<MkTime class="created-at" :time="note.createdAt" mode="detail"/>
<span class="mobile" v-if="appearNote.viaMobile"><i class="fas fa-mobile-alt"></i></span>
<MkTime class="created-at" :time="appearNote.createdAt" mode="detail"/>
</div>
<XReactionsViewer :note="appearNote" ref="reactionsViewer"/>
<button @click="reply()" class="button _button">
@ -178,6 +185,8 @@ export default defineComponent({
showContent: false,
isDeleted: false,
muted: false,
translation: null,
translating: false,
};
},
@ -619,6 +628,11 @@ export default defineComponent({
text: this.$ts.share,
action: this.share
},
this.$instance.translatorAvailable ? {
icon: 'fas fa-language',
text: this.$ts.translate,
action: this.translate
} : undefined,
null,
statePromise.then(state => state.isFavorited ? {
icon: 'fas fa-star',
@ -852,6 +866,17 @@ export default defineComponent({
});
},
async translate() {
if (this.translation != null) return;
this.translating = true;
const res = await os.api('notes/translate', {
noteId: this.appearNote.id,
targetLang: localStorage.getItem('lang') || navigator.language,
});
this.translating = false;
this.translation = res;
},
focus() {
this.$el.focus();
},
@ -874,7 +899,7 @@ export default defineComponent({
</script>
<style lang="scss" scoped>
.note {
.lxwezrsl {
position: relative;
transition: box-shadow 0.1s ease;
overflow: hidden;
@ -1050,6 +1075,13 @@ export default defineComponent({
font-style: oblique;
color: var(--renote);
}
> .translation {
border: solid 0.5px var(--divider);
border-radius: var(--radius);
padding: 12px;
margin-top: 8px;
}
}
> .url-preview {

View File

@ -51,6 +51,13 @@
<MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><i class="fas fa-reply"></i></MkA>
<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/>
<a class="rp" v-if="appearNote.renote != null">RN:</a>
<div class="translation" v-if="translating || translation">
<MkLoading v-if="translating" mini/>
<div class="translated" v-else>
<b>{{ $t('translatedFrom', { x: translation.sourceLang }) }}:</b>
{{ translation.text }}
</div>
</div>
</div>
<div class="files" v-if="appearNote.files.length > 0">
<XMediaList :media-list="appearNote.files"/>
@ -164,6 +171,8 @@ export default defineComponent({
collapsed: false,
isDeleted: false,
muted: false,
translation: null,
translating: false,
};
},
@ -594,6 +603,11 @@ export default defineComponent({
text: this.$ts.share,
action: this.share
},
this.$instance.translatorAvailable ? {
icon: 'fas fa-language',
text: this.$ts.translate,
action: this.translate
} : undefined,
null,
statePromise.then(state => state.isFavorited ? {
icon: 'fas fa-star',
@ -827,6 +841,17 @@ export default defineComponent({
});
},
async translate() {
if (this.translation != null) return;
this.translating = true;
const res = await os.api('notes/translate', {
noteId: this.appearNote.id,
targetLang: localStorage.getItem('lang') || navigator.language,
});
this.translating = false;
this.translation = res;
},
focus() {
this.$el.focus();
},
@ -1053,6 +1078,13 @@ export default defineComponent({
font-style: oblique;
color: var(--renote);
}
> .translation {
border: solid 0.5px var(--divider);
border-radius: var(--radius);
padding: 12px;
margin-top: 8px;
}
}
> .url-preview {

View File

@ -9,7 +9,7 @@
<div>{{ $ts.noNotes }}</div>
</div>
<div v-else>
<div v-else class="giivymft" :class="{ noGap }">
<div v-show="more && reversed" style="margin-bottom: var(--margin);">
<MkButton style="margin: 0 auto;" @click="fetchMoreFeature" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
<template v-if="!moreFetching">{{ $ts.loadMore }}</template>
@ -17,8 +17,8 @@
</MkButton>
</div>
<XList ref="notes" :items="notes" v-slot="{ item: note }" :direction="reversed ? 'up' : 'down'" :reversed="reversed" :no-gap="noGap" :ad="true">
<XNote :note="note" class="_block" @update:note="updated(note, $event)" :key="note._featuredId_ || note._prId_ || note.id"/>
<XList ref="notes" :items="notes" v-slot="{ item: note }" :direction="reversed ? 'up' : 'down'" :reversed="reversed" :no-gap="noGap" :ad="true" class="notes">
<XNote class="qtqtichx" :note="note" @update:note="updated(note, $event)" :key="note._featuredId_ || note._prId_ || note.id"/>
</XList>
<div v-show="more && !reversed" style="margin-top: var(--margin);">
@ -108,4 +108,23 @@ export default defineComponent({
.fade-leave-to {
opacity: 0;
}
.giivymft {
&.noGap {
> .notes {
background: var(--panel);
}
}
&:not(.noGap) {
> .notes {
background: var(--bg);
.qtqtichx {
background: var(--panel);
border-radius: var(--radius);
}
}
}
}
</style>

View File

@ -7,7 +7,7 @@
<p class="mfcuwfyp" v-else-if="empty">{{ $ts.noNotifications }}</p>
<div v-else>
<XList class="notifications" :items="items" v-slot="{ item: notification }" :no-gap="true">
<XList class="elsfgstc" :items="items" v-slot="{ item: notification }" :no-gap="true">
<XNote v-if="['reply', 'quote', 'mention'].includes(notification.type)" :note="notification.note" @update:note="noteUpdated(notification.note, $event)" :key="notification.id"/>
<XNotification v-else :notification="notification" :with-time="true" :full="true" class="_panel notification" :key="notification.id"/>
</XList>
@ -141,4 +141,8 @@ export default defineComponent({
text-align: center;
color: var(--fg);
}
.elsfgstc {
background: var(--panel);
}
</style>

View File

@ -17,7 +17,7 @@
<span v-if="visibility === 'followers'"><i class="fas fa-unlock"></i></span>
<span v-if="visibility === 'specified'"><i class="fas fa-envelope"></i></span>
</button>
<button class="submit _buttonPrimary" :disabled="!canPost" @click="post">{{ submitText }}<i :class="reply ? 'fas fa-reply' : renote ? 'fas fa-quote-right' : 'fas fa-paper-plane'"></i></button>
<button class="submit _buttonPrimary" :disabled="!canPost" @click="post" data-cy-open-post-form-submit>{{ submitText }}<i :class="reply ? 'fas fa-reply' : renote ? 'fas fa-quote-right' : 'fas fa-paper-plane'"></i></button>
</div>
</header>
<div class="form" :class="{ fixed }">
@ -36,7 +36,7 @@
</div>
<MkInfo warn v-if="hasNotSpecifiedMentions" class="hasNotSpecifiedMentions">{{ $ts.notSpecifiedMentionWarning }} - <button class="_textButton" @click="addMissingMention()">{{ $ts.add }}</button></MkInfo>
<input v-show="useCw" ref="cw" class="cw" v-model="cw" :placeholder="$ts.annotation" @keydown="onKeydown">
<textarea v-model="text" class="text" :class="{ withCw: useCw }" ref="text" :disabled="posting" :placeholder="placeholder" @keydown="onKeydown" @paste="onPaste" @compositionupdate="onCompositionUpdate" @compositionend="onCompositionEnd" />
<textarea v-model="text" class="text" :class="{ withCw: useCw }" ref="text" :disabled="posting" :placeholder="placeholder" @keydown="onKeydown" @paste="onPaste" @compositionupdate="onCompositionUpdate" @compositionend="onCompositionEnd" data-cy-post-form-text/>
<input v-show="withHashtags" ref="hashtags" class="hashtags" v-model="hashtags" :placeholder="$ts.hashtags" list="hashtags">
<XPostFormAttaches class="attaches" :files="files" @updated="updateFiles" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName"/>
<XPollEditor v-if="poll" :poll="poll" @destroyed="poll = null" @updated="onPollUpdate"/>
@ -339,7 +339,12 @@ export default defineComponent({
this.cw = init.cw;
this.useCw = init.cw != null;
if (init.poll) {
this.poll = init.poll;
this.poll = {
choices: init.poll.choices.map(x => x.text),
multiple: init.poll.multiple,
expiresAt: init.poll.expiresAt,
expiredAfter: init.poll.expiredAfter,
};
}
this.visibility = init.visibility;
this.localOnly = init.localOnly;

View File

@ -3,11 +3,11 @@
<div class="auth _section">
<div class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null }" v-show="withAvatar"></div>
<div class="normal-signin" v-if="!totpLogin">
<MkInput v-model="username" :placeholder="$ts.username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @update:modelValue="onUsernameChange">
<MkInput v-model="username" :placeholder="$ts.username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @update:modelValue="onUsernameChange" data-cy-signin-username>
<template #prefix>@</template>
<template #suffix>@{{ host }}</template>
</MkInput>
<MkInput v-model="password" :placeholder="$ts.password" type="password" :with-password-toggle="true" v-if="!user || user && !user.usePasswordLessLogin" required>
<MkInput v-model="password" :placeholder="$ts.password" type="password" :with-password-toggle="true" v-if="!user || user && !user.usePasswordLessLogin" required data-cy-signin-password>
<template #prefix><i class="fas fa-lock"></i></template>
<template #caption><button class="_textButton" @click="resetPassword" type="button">{{ $ts.forgotPassword }}</button></template>
</MkInput>

View File

@ -1,12 +1,12 @@
<template>
<form class="mk-signup" @submit.prevent="onSubmit" :autocomplete="Math.random()">
<form class="qlvuhzng" @submit.prevent="onSubmit" :autocomplete="Math.random()">
<template v-if="meta">
<MkInput v-if="meta.disableRegistration" v-model="invitationCode" type="text" :autocomplete="Math.random()" spellcheck="false" required>
<MkInput class="_inputNoTopMargin" v-if="meta.disableRegistration" v-model="invitationCode" type="text" :autocomplete="Math.random()" spellcheck="false" required>
<template #label>{{ $ts.invitationCode }}</template>
<template #prefix><i class="fas fa-key"></i></template>
</MkInput>
<MkInput v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @update:modelValue="onChangeUsername">
<template #label>{{ $ts.username }}</template>
<MkInput class="_inputNoTopMargin" v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @update:modelValue="onChangeUsername" data-cy-signup-username>
<template #label>{{ $ts.username }} <div class="_button _help" v-tooltip:dialog="$ts.usernameInfo"><i class="far fa-question-circle"></i></div></template>
<template #prefix>@</template>
<template #suffix>@{{ host }}</template>
<template #caption>
@ -19,7 +19,7 @@
<span v-if="usernameState == 'max-range'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.tooLong }}</span>
</template>
</MkInput>
<MkInput v-model="password" type="password" :autocomplete="Math.random()" required @update:modelValue="onChangePassword">
<MkInput v-model="password" type="password" :autocomplete="Math.random()" required @update:modelValue="onChangePassword" data-cy-signup-password>
<template #label>{{ $ts.password }}</template>
<template #prefix><i class="fas fa-lock"></i></template>
<template #caption>
@ -28,7 +28,7 @@
<span v-if="passwordStrength == 'high'" style="color: var(--success)"><i class="fas fa-check fa-fw"></i> {{ $ts.strongPassword }}</span>
</template>
</MkInput>
<MkInput v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @update:modelValue="onChangePasswordRetype">
<MkInput v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @update:modelValue="onChangePasswordRetype" data-cy-signup-password-retype>
<template #label>{{ $ts.password }} ({{ $ts.retype }})</template>
<template #prefix><i class="fas fa-lock"></i></template>
<template #caption>
@ -46,7 +46,7 @@
</label>
<captcha v-if="meta.enableHcaptcha" class="captcha" provider="hcaptcha" ref="hcaptcha" v-model:value="hCaptchaResponse" :sitekey="meta.hcaptchaSiteKey"/>
<captcha v-if="meta.enableRecaptcha" class="captcha" provider="recaptcha" ref="recaptcha" v-model:value="reCaptchaResponse" :sitekey="meta.recaptchaSiteKey"/>
<MkButton type="submit" :disabled="shouldDisableSubmitting" primary>{{ $ts.start }}</MkButton>
<MkButton type="submit" :disabled="shouldDisableSubmitting" primary data-cy-signup-submit>{{ $ts.start }}</MkButton>
</template>
</form>
</template>
@ -204,7 +204,7 @@ export default defineComponent({
</script>
<style lang="scss" scoped>
.mk-signup {
.qlvuhzng {
.captcha {
margin: 16px 0;
}

View File

@ -1,5 +1,5 @@
<template>
<transition :name="$store.state.animation ? 'popup-menu' : ''" :duration="$store.state.animation ? 300 : 0" appear @after-leave="onClosed" @enter="$emit('opening')" @after-enter="childRendered">
<transition :name="$store.state.animation ? 'popup-menu' : ''" appear @after-leave="onClosed" @enter="$emit('opening')" @after-enter="childRendered">
<div v-show="manualShowing != null ? manualShowing : showing" class="ccczpooj" :class="{ front, fixed, top: position === 'top' }" ref="content" :style="{ pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
<slot :point="point"></slot>
</div>

View File

@ -0,0 +1,58 @@
<template>
<MkModal ref="modal" @click="$refs.modal.close()" @closed="$emit('closed')">
<div class="ewlycnyt">
<div class="title">{{ $ts.misskeyUpdated }}</div>
<div class="version">{{ version }}🚀</div>
<MkButton full @click="whatIsNew">{{ $ts.whatIsNew }}</MkButton>
<MkButton primary full @click="$refs.modal.close()">{{ $ts.gotIt }}</MkButton>
</div>
</MkModal>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import MkModal from '@client/components/ui/modal.vue';
import MkButton from '@client/components/ui/button.vue';
import { version } from '@client/config';
export default defineComponent({
components: {
MkModal,
MkButton,
},
data() {
return {
version: version,
};
},
methods: {
whatIsNew() {
this.$refs.modal.close();
this.$router.push('/docs/general/changelog');
}
}
});
</script>
<style lang="scss" scoped>
.ewlycnyt {
position: relative;
padding: 32px;
min-width: 320px;
max-width: 480px;
box-sizing: border-box;
text-align: center;
background: var(--panel);
border-radius: var(--radius);
> .title {
font-weight: bold;
}
> .version {
margin: 1em 0;
}
}
</style>

View File

@ -1,6 +1,6 @@
import { Directive, ref } from 'vue';
import { isDeviceTouch } from '@client/scripts/is-device-touch';
import { popup } from '@client/os';
import { popup, dialog } from '@client/os';
const start = isDeviceTouch ? 'touchstart' : 'mouseover';
const end = isDeviceTouch ? 'touchend' : 'mouseleave';
@ -24,6 +24,18 @@ export default {
}
};
if (binding.arg === 'dialog') {
el.addEventListener('click', (ev) => {
ev.preventDefault();
ev.stopPropagation();
dialog({
type: 'info',
text: binding.value,
});
return false;
});
}
const show = e => {
if (!document.body.contains(el)) return;
if (self._close) return;

View File

@ -4,9 +4,19 @@
import '@client/style.scss';
//#region account indexedDB migration
import { set } from '@client/scripts/idb-proxy';
if (localStorage.getItem('accounts') != null) {
set('accounts', JSON.parse(localStorage.getItem('accounts')));
localStorage.removeItem('accounts');
}
//#endregion
import * as Sentry from '@sentry/browser';
import { Integrations } from '@sentry/tracing';
import { computed, createApp, watch, markRaw } from 'vue';
import compareVersions from 'compare-versions';
import widgets from '@client/widgets';
import directives from '@client/directives';
@ -91,15 +101,12 @@ window.addEventListener('resize', () => {
});
//#endregion
// Get the <head> element
const head = document.getElementsByTagName('head')[0];
// If mobile, insert the viewport meta tag
if (isMobile || window.innerWidth <= 1024) {
const viewport = document.getElementsByName('viewport').item(0);
viewport.setAttribute('content',
`${viewport.getAttribute('content')},minimum-scale=1,maximum-scale=1,user-scalable=no`);
head.appendChild(viewport);
document.head.appendChild(viewport);
}
//#region Set lang attr
@ -206,8 +213,12 @@ if (lastVersion !== version) {
// テーマリビルドするため
localStorage.removeItem('theme');
// TODO: バージョンが新しくなった時だけダイアログ出す
//popup();
try { // 変なバージョン文字列来るとcompareVersionsでエラーになるため
if (lastVersion != null && compareVersions(version, lastVersion) === 1) {
popup(import('@client/components/updated.vue'), {}, {}, 'closed');
}
} catch (e) {
}
}
// NOTE: この処理は必ず↑のクライアント更新時処理より後に来ること(テーマ再構築のため)
@ -296,6 +307,13 @@ for (const plugin of ColdDeviceStorage.get('plugins').filter(p => p.active)) {
}
if ($i) {
if ($i.isDeleted) {
dialog({
type: 'warning',
text: i18n.locale.accountDeletionInProgress,
});
}
if ('Notification' in window) {
// 許可を得ていなかったらリクエスト
if (Notification.permission === 'default') {

View File

@ -25,6 +25,7 @@ export async function fetchInstance() {
}
export const emojiCategories = computed(() => {
if (instance.emojis == null) return [];
const categories = new Set();
for (const emoji of instance.emojis) {
categories.add(emoji.category);
@ -33,6 +34,7 @@ export const emojiCategories = computed(() => {
});
export const emojiTags = computed(() => {
if (instance.emojis == null) return [];
const tags = new Set();
for (const emoji of instance.emojis) {
for (const tag of emoji.aliases) {

View File

@ -214,7 +214,11 @@ export function modalPageWindow(path: string) {
}, {}, 'closed');
}
export function dialog(props: Record<string, any>) {
export function dialog(props: {
type: 'error' | 'info' | 'success' | 'warning' | 'waiting';
title?: string | null;
text?: string | null;
}) {
return new Promise((resolve, reject) => {
popup(import('@client/components/dialog.vue'), props, {
done: result => {

View File

@ -60,7 +60,7 @@ import FormBase from '@client/components/form/base.vue';
import FormGroup from '@client/components/form/group.vue';
import FormKeyValueView from '@client/components/form/key-value-view.vue';
import MkLink from '@client/components/link.vue';
import { physics } from '@client/scripts/physics.ts';
import { physics } from '@client/scripts/physics';
import * as symbols from '@client/symbols';
const patrons = [

View File

@ -1,7 +1,7 @@
<template>
<div class="_root">
<div class="_block" style="padding: 24px;">
<MkInput v-model="endpoint" :datalist="endpoints" @update:modelValue="onEndpointChange()">
<MkInput v-model="endpoint" :datalist="endpoints" @update:modelValue="onEndpointChange()" class="_inputNoTopMargin">
<template #label>Endpoint</template>
</MkInput>
<MkTextarea v-model="body" code>

View File

@ -1,50 +1,54 @@
<template>
<div class="vtaihdtm">
<div class="search">
<MkInput v-model="query" :debounce="true" type="search" class="_inputNoTopMargin _inputNoBottomMargin" :placeholder="$ts.search">
<template #prefix><i class="fas fa-search"></i></template>
</MkInput>
<div class="body">
<div class="search">
<MkInput v-model="query" :debounce="true" type="search" class="_inputNoTopMargin _inputNoBottomMargin" :placeholder="$ts.search">
<template #prefix><i class="fas fa-search"></i></template>
</MkInput>
</div>
<div class="list">
<MkFolder>
<template #header>{{ $ts._docs.generalTopics }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('general/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
<MkFolder>
<template #header>{{ $ts._docs.features }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('features/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
<MkFolder>
<template #header>{{ $ts._docs.advancedTopics }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('advanced/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
<MkFolder>
<template #header>{{ $ts._docs.admin }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('admin/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
</div>
</div>
<MkFolder>
<template #header>{{ $ts._docs.generalTopics }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('general/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
<MkFolder>
<template #header>{{ $ts._docs.features }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('features/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
<MkFolder>
<template #header>{{ $ts._docs.advancedTopics }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('advanced/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
<MkFolder>
<template #header>{{ $ts._docs.admin }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('admin/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
</div>
</template>
@ -97,41 +101,50 @@ export default defineComponent({
.vtaihdtm {
background: var(--panel);
> .search {
padding: 16px;
}
> .body {
max-width: 900px;
margin: 0 auto;
.docs {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
grid-gap: 12px;
margin: 0 16px 16px 16px;
> .doc {
display: inline-block;
> .search {
padding: 16px;
border: solid 1px var(--divider);
border-radius: 6px;
}
&:hover {
border: solid 1px var(--accent);
text-decoration: none;
}
> .list {
padding: 0 16px;
> .title {
font-weight: bold;
}
.docs {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
grid-gap: 12px;
margin: 0 0 16px 0;
> .summary {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 0.9em;
}
> .doc {
display: inline-block;
padding: 16px;
border: solid 1px var(--divider);
border-radius: 6px;
> .read {
color: var(--link);
font-size: 0.9em;
&:hover {
border: solid 1px var(--accent);
text-decoration: none;
}
> .title {
font-weight: bold;
}
> .summary {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 0.9em;
}
> .read {
color: var(--link);
font-size: 0.9em;
}
}
}
}
}

View File

@ -1,6 +1,8 @@
<template>
<div class="_section">
<XNotes class="_content" :pagination="pagination" :detail="true" :prop="'note'" @before="before()" @after="after()"/>
<div class="jmelgwjh">
<div class="body">
<XNotes class="notes" :pagination="pagination" :detail="true" :prop="'note'" @before="before()" @after="after()"/>
</div>
</div>
</template>
@ -42,3 +44,16 @@ export default defineComponent({
}
});
</script>
<style lang="scss" scoped>
.jmelgwjh {
background: var(--bg);
> .body {
box-sizing: border-box;
max-width: 800px;
margin: 0 auto;
padding: 16px;
}
}
</style>

View File

@ -93,10 +93,8 @@ export default defineComponent({
});
if (canceled) return;
os.api('drive/files/delete', {
os.apiWithDialog('drive/files/delete', {
fileId: this.file.id
}).then(() => {
this.$refs.files.removeItem(x => x.id === this.file.id);
});
},

View File

@ -7,7 +7,15 @@
Summaly Proxy URL
</FormInput>
</FormGroup>
<FormGroup>
<FormInput v-model:value="deeplAuthKey">
<template #prefix><i class="fas fa-key"></i></template>
DeepL Auth Key
</FormInput>
<FormSwitch v-model:value="deeplIsPro">
Pro account
</FormSwitch>
</FormGroup>
<FormButton @click="save" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
</FormSuspense>
</FormBase>
@ -44,6 +52,8 @@ export default defineComponent({
icon: 'fas fa-cogs'
},
summalyProxy: '',
deeplAuthKey: '',
deeplIsPro: false,
}
},
@ -55,10 +65,14 @@ export default defineComponent({
async init() {
const meta = await os.api('meta', { detail: true });
this.summalyProxy = meta.summalyProxy;
this.deeplAuthKey = meta.deeplAuthKey;
this.deeplIsPro = meta.deeplIsPro;
},
save() {
os.apiWithDialog('admin/update-meta', {
summalyProxy: this.summalyProxy,
deeplAuthKey: this.deeplAuthKey,
deeplIsPro: this.deeplIsPro,
}).then(() => {
fetchInstance();
});

View File

@ -8,9 +8,9 @@
<div class="main _gap">
<MkButton v-if="!showNext && hasNext" class="load next" @click="showNext = true"><i class="fas fa-chevron-up"></i></MkButton>
<div class="_content _gap">
<MkRemoteCaution v-if="note.user.host != null" :href="note.url || note.uri" class="_gap"/>
<XNoteDetailed v-model:note="note" :key="note.id" class="_gap"/>
<div class="note _gap">
<MkRemoteCaution v-if="note.user.host != null" :href="note.url || note.uri" class="_isolated"/>
<XNoteDetailed v-model:note="note" :key="note.id" class="_isolated note"/>
</div>
<div class="_content clips _gap" v-if="clips && clips.length > 0">
<div class="title">{{ $ts.clip }}</div>
@ -108,6 +108,7 @@ export default defineComponent({
os.api('notes/show', {
noteId: this.noteId
}).then(note => {
this.note = note;
Promise.all([
os.api('notes/clips', {
noteId: note.id,
@ -126,7 +127,6 @@ export default defineComponent({
this.clips = clips;
this.hasPrev = prev.length !== 0;
this.hasNext = next.length !== 0;
this.note = note;
});
}).catch(e => {
this.error = e;
@ -147,6 +147,8 @@ export default defineComponent({
}
.fcuexfpr {
background: var(--bg);
> .note {
> .main {
> .load {
@ -163,6 +165,13 @@ export default defineComponent({
}
}
> .note {
> .note {
border-radius: var(--radius);
background: var(--panel);
}
}
> .clips {
> .title {
font-weight: bold;

View File

@ -1,6 +1,6 @@
<template>
<div class="_root">
<XNotifications class="_content" @before="before" @after="after" page/>
<div class="clupoqwt" v-size="{ min: [800] }">
<XNotifications class="notifications" @before="before" @after="after" page/>
</div>
</template>
@ -43,3 +43,17 @@ export default defineComponent({
}
});
</script>
<style lang="scss" scoped>
.clupoqwt {
&.min-width_800px {
background: var(--bg);
padding: 32px 0;
> .notifications {
max-width: 800px;
margin: 0 auto;
}
}
}
</style>

View File

@ -48,10 +48,10 @@ export default defineComponent({
title: this.$ts.accounts,
icon: 'fas fa-users',
},
storedAccounts: getAccounts().filter(x => x.id !== this.$i.id),
storedAccounts: getAccounts().then(accounts => accounts.filter(x => x.id !== this.$i.id)),
accounts: null,
init: () => os.api('users/show', {
userIds: this.storedAccounts.map(x => x.id)
init: async () => os.api('users/show', {
userIds: (await this.storedAccounts).map(x => x.id)
}).then(accounts => {
this.accounts = accounts;
}),
@ -104,8 +104,8 @@ export default defineComponent({
}, 'closed');
},
switchAccount(account: any) {
const storedAccounts = getAccounts();
async switchAccount(account: any) {
const storedAccounts = await getAccounts();
const token = storedAccounts.find(x => x.id === account.id).token;
this.switchAccountWithToken(token);
},

View File

@ -0,0 +1,67 @@
<template>
<FormBase>
<FormInfo warn>{{ $ts._accountDelete.mayTakeTime }}</FormInfo>
<FormInfo>{{ $ts._accountDelete.sendEmail }}</FormInfo>
<FormButton @click="deleteAccount" danger v-if="!$i.isDeleted">{{ $ts._accountDelete.requestAccountDelete }}</FormButton>
<FormButton disabled v-else>{{ $ts._accountDelete.inProgress }}</FormButton>
</FormBase>
</template>
<script lang="ts">
import { defineAsyncComponent, defineComponent } from 'vue';
import FormInfo from '@client/components/form/info.vue';
import FormBase from '@client/components/form/base.vue';
import FormGroup from '@client/components/form/group.vue';
import FormButton from '@client/components/form/button.vue';
import * as os from '@client/os';
import { debug } from '@client/config';
import { signout } from '@client/account';
import * as symbols from '@client/symbols';
export default defineComponent({
components: {
FormBase,
FormButton,
FormGroup,
FormInfo,
},
emits: ['info'],
data() {
return {
[symbols.PAGE_INFO]: {
title: this.$ts._accountDelete.accountDelete,
icon: 'fas fa-exclamation-triangle'
},
debug,
}
},
mounted() {
this.$emit('info', this[symbols.PAGE_INFO]);
},
methods: {
async deleteAccount() {
const { canceled, result: password } = await os.dialog({
title: this.$ts.password,
input: {
type: 'password'
}
});
if (canceled) return;
await os.apiWithDialog('i/delete-account', {
password: password
});
await os.dialog({
title: this.$ts._accountDelete.started,
});
signout();
}
}
});
</script>

View File

@ -132,6 +132,7 @@ export default defineComponent({
case 'account-info': return defineAsyncComponent(() => import('./account-info.vue'));
case 'update': return defineAsyncComponent(() => import('./update.vue'));
case 'registry': return defineAsyncComponent(() => import('./registry.vue'));
case 'delete-account': return defineAsyncComponent(() => import('./delete-account.vue'));
case 'experimental-features': return defineAsyncComponent(() => import('./experimental-features.vue'));
}
if (page.value.startsWith('registry/keys/system/')) {

View File

@ -26,7 +26,7 @@
<FormLink to="/bios" behavior="browser"><template #icon><i class="fas fa-door-open"></i></template>BIOS</FormLink>
<FormLink to="/cli" behavior="browser"><template #icon><i class="fas fa-door-open"></i></template>CLI</FormLink>
<FormButton @click="closeAccount" danger>{{ $ts.closeAccount }}</FormButton>
<FormLink to="./delete-account"><template #icon><i class="fas fa-exclamation-triangle"></i></template>{{ $ts.closeAccount }}</FormLink>
</FormBase>
</template>
@ -41,7 +41,6 @@ import FormButton from '@client/components/form/button.vue';
import * as os from '@client/os';
import { debug } from '@client/config';
import { defaultStore } from '@client/store';
import { signout } from '@client/account';
import { unisonReload } from '@client/scripts/unison-reload';
import * as symbols from '@client/symbols';
@ -92,22 +91,6 @@ export default defineComponent({
os.popup(import('@client/components/taskmanager.vue'), {
}, {}, 'closed');
},
closeAccount() {
os.dialog({
title: this.$ts.password,
input: {
type: 'password'
}
}).then(({ canceled, result: password }) => {
if (canceled) return;
os.api('i/delete-account', {
password: password
}).then(() => {
signout();
});
});
}
}
});
</script>

View File

@ -48,6 +48,7 @@ const soundsTypes = [
'syuilo/ryukyu',
'syuilo/kick',
'syuilo/snare',
'syuilo/queue-jammed',
'aisha/1',
'aisha/2',
'aisha/3',

View File

@ -1,5 +1,5 @@
<template>
<div class="cmuxhskf _root" v-hotkey.global="keymap">
<div class="cmuxhskf" v-hotkey.global="keymap" v-size="{ min: [800] }">
<XTutorial v-if="$store.reactiveState.tutorial.value != -1" class="tutorial _block _isolated"/>
<XPostForm v-if="$store.reactiveState.showFixedPostForm.value" class="post-form _block _isolated" fixed/>
<div class="tabs">
@ -19,17 +19,19 @@
</div>
</div>
<div class="new" v-if="queue > 0"><button class="_buttonPrimary" @click="top()">{{ $ts.newNoteRecived }}</button></div>
<XTimeline ref="tl"
:key="src === 'list' ? `list:${list.id}` : src === 'antenna' ? `antenna:${antenna.id}` : src === 'channel' ? `channel:${channel.id}` : src"
:src="src"
:list="list ? list.id : null"
:antenna="antenna ? antenna.id : null"
:channel="channel ? channel.id : null"
:sound="true"
@before="before()"
@after="after()"
@queue="queueUpdated"
/>
<div class="tl">
<XTimeline ref="tl" class="tl"
:key="src === 'list' ? `list:${list.id}` : src === 'antenna' ? `antenna:${antenna.id}` : src === 'channel' ? `channel:${channel.id}` : src"
:src="src"
:list="list ? list.id : null"
:antenna="antenna ? antenna.id : null"
:channel="channel ? channel.id : null"
:sound="true"
@before="before()"
@after="after()"
@queue="queueUpdated"
/>
</div>
</div>
</template>
@ -211,8 +213,6 @@ export default defineComponent({
<style lang="scss" scoped>
.cmuxhskf {
background: var(--bg);
> .new {
position: sticky;
top: calc(var(--stickyTop, 0px) + 16px);
@ -233,6 +233,7 @@ export default defineComponent({
padding: 0 8px;
white-space: nowrap;
overflow: auto;
border-bottom: solid 0.5px var(--divider);
// 影の都合上
position: relative;
@ -262,10 +263,9 @@ export default defineComponent({
left: 0;
right: 0;
margin: 0 auto;
width: calc(100% - 16px);
height: 4px;
width: 100%;
height: 2px;
background: var(--accent);
border-radius: 8px 8px 0 0;
}
}
@ -289,5 +289,17 @@ export default defineComponent({
}
}
}
&.min-width_800px {
> .tl {
background: var(--bg);
padding: 32px 0;
> .tl {
max-width: 800px;
margin: 0 auto;
}
}
}
}
</style>

View File

@ -27,8 +27,8 @@
<div class="desc" v-html="meta.description || $ts.headlineMisskey"></div>
</div>
<div class="action">
<MkButton @click="signup()" inline primary>{{ $ts.signup }}</MkButton>
<MkButton @click="signin()" inline>{{ $ts.login }}</MkButton>
<MkButton @click="signup()" inline primary data-cy-signup>{{ $ts.signup }}</MkButton>
<MkButton @click="signin()" inline data-cy-signin>{{ $ts.login }}</MkButton>
</div>
<div class="status" v-if="onlineUsersCount && stats">
<div>

View File

@ -3,17 +3,19 @@
<h1>Welcome to Misskey!</h1>
<div>
<p>{{ $ts.intro }}</p>
<MkInput v-model="username" pattern="^[a-zA-Z0-9_]{1,20}$" spellcheck="false" required>
<MkInput v-model="username" pattern="^[a-zA-Z0-9_]{1,20}$" spellcheck="false" required data-cy-admin-username>
<template #label>{{ $ts.username }}</template>
<template #prefix>@</template>
<template #suffix>@{{ host }}</template>
</MkInput>
<MkInput v-model="password" type="password">
<MkInput v-model="password" type="password" data-cy-admin-password>
<template #label>{{ $ts.password }}</template>
<template #prefix><i class="fas fa-lock"></i></template>
</MkInput>
<footer>
<MkButton primary type="submit" :disabled="submitting">{{ submitting ? $ts.processing : $ts.done }}<MkEllipsis v-if="submitting"/></MkButton>
<MkButton primary type="submit" :disabled="submitting" data-cy-admin-ok>
{{ submitting ? $ts.processing : $ts.done }}<MkEllipsis v-if="submitting"/>
</MkButton>
</footer>
</div>
</form>

View File

@ -65,7 +65,7 @@ export class Autocomplete {
*/
private onInput() {
const caretPos = this.textarea.selectionStart;
const text = this.text.substr(0, caretPos).split('\n').pop();
const text = this.text.substr(0, caretPos).split('\n').pop()!;
const mentionIndex = text.lastIndexOf('@');
const hashtagIndex = text.lastIndexOf('#');
@ -83,7 +83,7 @@ export class Autocomplete {
const isMention = mentionIndex != -1;
const isHashtag = hashtagIndex != -1;
const isEmoji = emojiIndex != -1;
const isEmoji = emojiIndex != -1 && text.split(/:[a-z0-9_+\-]+:/).pop()!.includes(':');
let opened = false;

View File

@ -0,0 +1,7 @@
import { get } from '@client/scripts/idb-proxy';
export async function getAccountFromId(id: string) {
const accounts = await get('accounts') as { token: string; id: string; }[];
if (!accounts) console.log('Accounts are not recorded');
return accounts.find(e => e.id === id);
}

View File

@ -0,0 +1,38 @@
// FirefoxのプライベートモードなどではindexedDBが使用不可能なので、
// indexedDBが使えない環境ではlocalStorageを使う
import {
get as iget,
set as iset,
del as idel,
createStore,
} from 'idb-keyval';
const fallbackName = (key: string) => `idbfallback::${key}`;
let idbAvailable = typeof window !== 'undefined' ? !!window.indexedDB : true;
if (idbAvailable) {
try {
await createStore('keyval-store', 'keyval');
} catch (e) {
console.error('idb open error', e);
idbAvailable = false;
}
}
if (!idbAvailable) console.error('indexedDB is unavailable. It will use localStorage.');
export async function get(key: string) {
if (idbAvailable) return iget(key);
return JSON.parse(localStorage.getItem(fallbackName(key)));
}
export async function set(key: string, val: any) {
if (idbAvailable) return iset(key, val);
return localStorage.setItem(fallbackName(key), JSON.stringify(val));
}
export async function del(key: string) {
if (idbAvailable) return idel(key);
return localStorage.removeItem(fallbackName(key));
}

View File

@ -2,6 +2,23 @@ import { ColdDeviceStorage } from '@client/store';
const cache = new Map<string, HTMLAudioElement>();
export function getAudio(file: string, useCache = true): HTMLAudioElement {
let audio: HTMLAudioElement;
if (useCache && cache.has(file)) {
audio = cache.get(file);
} else {
audio = new Audio(`/static-assets/client/sounds/${file}.mp3`);
if (useCache) cache.set(file, audio);
}
return audio;
}
export function setVolume(audio: HTMLAudioElement, volume: number): HTMLAudioElement {
const masterVolume = ColdDeviceStorage.get('sound_masterVolume');
audio.volume = masterVolume - ((1 - volume) * masterVolume);
return audio;
}
export function play(type: string) {
const sound = ColdDeviceStorage.get('sound_' + type as any);
if (sound.type == null) return;
@ -12,13 +29,6 @@ export function playFile(file: string, volume: number) {
const masterVolume = ColdDeviceStorage.get('sound_masterVolume');
if (masterVolume === 0) return;
let audio: HTMLAudioElement;
if (cache.has(file)) {
audio = cache.get(file);
} else {
audio = new Audio(`/static-assets/client/sounds/${file}.mp3`);
cache.set(file, audio);
}
audio.volume = masterVolume - ((1 - volume) * masterVolume);
const audio = setVolume(getAudio(file), volume);
audio.play();
}

View File

@ -156,8 +156,10 @@ hr {
._button {
appearance: none;
display: inline-block;
padding: 0;
margin: 0; // for Safari
width: max-content;
background: none;
border: none;
cursor: pointer;
@ -201,6 +203,11 @@ hr {
}
}
._help {
color: var(--accent);
cursor: help
}
._textButton {
@extend ._button;
color: var(--accent);
@ -330,6 +337,7 @@ hr {
contain: layout; // ふき出しがボックスから飛び出て表示されるようなデザインをする場合もあるので paint は contain することができない
}
// TODO: 廃止
._root {
box-sizing: border-box;
margin: var(--root-margin, 32px) auto;

View File

@ -2,7 +2,7 @@
<div class="fdidabkb" :class="{ center }" :style="`--height:${height};`" :key="key">
<transition :name="$store.state.animation ? 'header' : ''" mode="out-in" appear>
<div class="buttons left" v-if="backButton">
<button class="_button button back" @click.stop="$emit('back')" v-tooltip="$ts.goBack"><i class="fas fa-chevron-left"></i></button>
<button class="_button button back" @click.stop="$emit('back')" @touchstart="preventDrag" v-tooltip="$ts.goBack"><i class="fas fa-chevron-left"></i></button>
</div>
</transition>
<template v-if="info">
@ -20,10 +20,10 @@
</div>
<div class="buttons right">
<template v-if="info.actions && showActions">
<button v-for="action in info.actions" class="_button button" :class="{ highlighted: action.highlighted }" @click.stop="action.handler" v-tooltip="action.text"><i :class="action.icon"></i></button>
<button v-for="action in info.actions" class="_button button" :class="{ highlighted: action.highlighted }" @click.stop="action.handler" @touchstart="preventDrag" v-tooltip="action.text"><i :class="action.icon"></i></button>
</template>
<button v-if="shouldShowMenu" class="_button button" @click.stop="showMenu" v-tooltip="$ts.menu"><i class="fas fa-ellipsis-h"></i></button>
<button v-if="closeButton" class="_button button" @click.stop="$emit('close')" v-tooltip="$ts.close"><i class="fas fa-times"></i></button>
<button v-if="shouldShowMenu" class="_button button" @click.stop="showMenu" @touchstart="preventDrag" v-tooltip="$ts.menu"><i class="fas fa-ellipsis-h"></i></button>
<button v-if="closeButton" class="_button button" @click.stop="$emit('close')" @touchstart="preventDrag" v-tooltip="$ts.close"><i class="fas fa-times"></i></button>
</div>
</template>
</div>
@ -122,6 +122,10 @@ export default defineComponent({
menu = menu.concat(this.menu);
}
popupMenu(menu, ev.currentTarget || ev.target);
},
preventDrag(ev) {
ev.stopPropagation();
}
}
});

View File

@ -135,7 +135,7 @@ export default defineComponent({
},
async openAccountMenu(ev) {
const storedAccounts = getAccounts().filter(x => x.id !== this.$i.id);
const storedAccounts = await getAccounts().then(accounts => accounts.filter(x => x.id !== this.$i.id));
const accountsPromise = os.api('users/show', { userIds: storedAccounts.map(x => x.id) });
const accountItemPromises = storedAccounts.map(a => new Promise(res => {
@ -195,8 +195,8 @@ export default defineComponent({
}, 'closed');
},
switchAccount(account: any) {
const storedAccounts = getAccounts();
async switchAccount(account: any) {
const storedAccounts = await getAccounts();
const token = storedAccounts.find(x => x.id === account.id).token;
this.switchAccountWithToken(token);
},

View File

@ -101,7 +101,7 @@ export default defineComponent({
},
async openAccountMenu(ev) {
const storedAccounts = getAccounts().filter(x => x.id !== this.$i.id);
const storedAccounts = await getAccounts().then(accounts => accounts.filter(x => x.id !== this.$i.id));
const accountsPromise = os.api('users/show', { userIds: storedAccounts.map(x => x.id) });
const accountItemPromises = storedAccounts.map(a => new Promise(res => {
@ -161,8 +161,8 @@ export default defineComponent({
}, 'closed');
},
switchAccount(account: any) {
const storedAccounts = getAccounts();
async switchAccount(account: any) {
const storedAccounts = await getAccounts();
const token = storedAccounts.find(x => x.id === account.id).token;
this.switchAccountWithToken(token);
},

View File

@ -3,7 +3,7 @@
<button class="item _button account" @click="openAccountMenu" v-click-anime>
<MkAvatar :user="$i" class="avatar"/><MkAcct class="text" :user="$i"/>
</button>
<div class="post" @click="post">
<div class="post" @click="post" data-cy-open-post-form>
<MkButton class="button" primary full>
<i class="fas fa-pencil-alt fa-fw"></i><span class="text" v-if="!iconOnly">{{ $ts.note }}</span>
</MkButton>
@ -121,7 +121,7 @@ export default defineComponent({
},
async openAccountMenu(ev) {
const storedAccounts = getAccounts().filter(x => x.id !== this.$i.id);
const storedAccounts = await getAccounts().then(accounts => accounts.filter(x => x.id !== this.$i.id));
const accountsPromise = os.api('users/show', { userIds: storedAccounts.map(x => x.id) });
const accountItemPromises = storedAccounts.map(a => new Promise(res => {
@ -181,8 +181,8 @@ export default defineComponent({
}, 'closed');
},
switchAccount(account: any) {
const storedAccounts = getAccounts();
async switchAccount(account: any) {
const storedAccounts = await getAccounts();
const token = storedAccounts.find(x => x.id === account.id).token;
this.switchAccountWithToken(token);
},

View File

@ -4,7 +4,7 @@
<div class="contents" ref="contents" @contextmenu.stop="onContextmenu">
<header class="header" ref="header" @click="onHeaderClick">
<XHeader :info="pageInfo"/>
<XHeader :info="pageInfo" :back-button="true" @back="back()"/>
</header>
<main ref="main">
<div class="content">
@ -175,6 +175,10 @@ export default defineComponent({
window.scroll({ top: 0, behavior: 'smooth' });
},
back() {
history.back();
},
onTransition() {
if (window._scroll) window._scroll();
},
@ -253,11 +257,16 @@ export default defineComponent({
//backdrop-filter: var(--blur, blur(4px));
}
> .sidebar {
border-right: solid 0.5px var(--divider);
}
> .contents {
width: 100%;
min-width: 0;
--stickyTop: #{$header-height};
padding-top: $header-height;
background: var(--panel);
> .header {
position: fixed;
@ -272,7 +281,7 @@ export default defineComponent({
-webkit-backdrop-filter: var(--blur, blur(32px));
backdrop-filter: var(--blur, blur(32px));
background-color: var(--header);
//border-bottom: solid 0.5px var(--divider);
border-bottom: solid 0.5px var(--divider);
user-select: none;
}

View File

@ -50,6 +50,7 @@ import { defineComponent, markRaw } from 'vue';
import define from './define';
import * as os from '@client/os';
import number from '@client/filters/number';
import * as sound from '@client/scripts/sound';
const widget = define({
name: 'jobQueue',
@ -58,6 +59,10 @@ const widget = define({
type: 'boolean',
default: false,
},
sound: {
type: 'boolean',
default: false,
},
})
});
@ -79,6 +84,7 @@ export default defineComponent({
delayed: 0,
},
prev: {},
sound: sound.setVolume(sound.getAudio('syuilo/queue-jammed'), 1)
};
},
created() {
@ -107,6 +113,10 @@ export default defineComponent({
this[domain].active = stats[domain].active;
this[domain].waiting = stats[domain].waiting;
this[domain].delayed = stats[domain].delayed;
if (this[domain].waiting > 0 && this.props.sound && this.sound.paused) {
this.sound.play();
}
}
},

View File

@ -3,14 +3,19 @@
*/
import * as fs from 'fs';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import * as yaml from 'js-yaml';
import { Source, Mixin } from './types';
const meta = require('../meta.json');
//const _filename = fileURLToPath(import.meta.url);
const _filename = __filename;
const _dirname = dirname(_filename);
/**
* Path of configuration directory
*/
const dir = `${__dirname}/../../.config`;
const dir = `${_dirname}/../../.config`;
/**
* Path of configuration file
@ -20,6 +25,7 @@ const path = process.env.NODE_ENV === 'test'
: `${dir}/default.yml`;
export default function load() {
const meta = JSON.parse(fs.readFileSync(`${_dirname}/../meta.json`, 'utf-8'));
const config = yaml.load(fs.readFileSync(path, 'utf-8')) as Source;
const mixin = {} as Mixin;

View File

@ -1,7 +1,7 @@
// TODO: 消したい
const interval = 30 * 60 * 1000;
import { AttestationChallenges } from '../models';
import { AttestationChallenges } from '@/models/index';
import { LessThan } from 'typeorm';
/**

View File

@ -1,5 +1,5 @@
import * as elasticsearch from '@elastic/elasticsearch';
import config from '@/config';
import config from '@/config/index';
const index = {
settings: {

View File

@ -1,3 +1,3 @@
import Logger from '../services/logger';
import Logger from '@/services/logger';
export const dbLogger = new Logger('db');

View File

@ -3,74 +3,74 @@ const types = require('pg').types;
types.setTypeParser(20, Number);
import { createConnection, Logger, getConnection } from 'typeorm';
import config from '@/config';
import { entities as charts } from '../services/chart/entities';
import config from '@/config/index';
import { entities as charts } from '@/services/chart/entities';
import { dbLogger } from './logger';
import * as highlight from 'cli-highlight';
import { Log } from '../models/entities/log';
import { User } from '../models/entities/user';
import { DriveFile } from '../models/entities/drive-file';
import { DriveFolder } from '../models/entities/drive-folder';
import { AccessToken } from '../models/entities/access-token';
import { App } from '../models/entities/app';
import { PollVote } from '../models/entities/poll-vote';
import { Note } from '../models/entities/note';
import { NoteReaction } from '../models/entities/note-reaction';
import { NoteWatching } from '../models/entities/note-watching';
import { NoteUnread } from '../models/entities/note-unread';
import { Notification } from '../models/entities/notification';
import { Meta } from '../models/entities/meta';
import { Following } from '../models/entities/following';
import { Instance } from '../models/entities/instance';
import { Muting } from '../models/entities/muting';
import { SwSubscription } from '../models/entities/sw-subscription';
import { Blocking } from '../models/entities/blocking';
import { UserList } from '../models/entities/user-list';
import { UserListJoining } from '../models/entities/user-list-joining';
import { UserGroup } from '../models/entities/user-group';
import { UserGroupJoining } from '../models/entities/user-group-joining';
import { UserGroupInvitation } from '../models/entities/user-group-invitation';
import { Hashtag } from '../models/entities/hashtag';
import { NoteFavorite } from '../models/entities/note-favorite';
import { AbuseUserReport } from '../models/entities/abuse-user-report';
import { RegistrationTicket } from '../models/entities/registration-tickets';
import { MessagingMessage } from '../models/entities/messaging-message';
import { Signin } from '../models/entities/signin';
import { AuthSession } from '../models/entities/auth-session';
import { FollowRequest } from '../models/entities/follow-request';
import { Emoji } from '../models/entities/emoji';
import { ReversiGame } from '../models/entities/games/reversi/game';
import { ReversiMatching } from '../models/entities/games/reversi/matching';
import { UserNotePining } from '../models/entities/user-note-pining';
import { Poll } from '../models/entities/poll';
import { UserKeypair } from '../models/entities/user-keypair';
import { UserPublickey } from '../models/entities/user-publickey';
import { UserProfile } from '../models/entities/user-profile';
import { UserSecurityKey } from '../models/entities/user-security-key';
import { AttestationChallenge } from '../models/entities/attestation-challenge';
import { Page } from '../models/entities/page';
import { PageLike } from '../models/entities/page-like';
import { GalleryPost } from '../models/entities/gallery-post';
import { GalleryLike } from '../models/entities/gallery-like';
import { ModerationLog } from '../models/entities/moderation-log';
import { UsedUsername } from '../models/entities/used-username';
import { Announcement } from '../models/entities/announcement';
import { AnnouncementRead } from '../models/entities/announcement-read';
import { Clip } from '../models/entities/clip';
import { ClipNote } from '../models/entities/clip-note';
import { Antenna } from '../models/entities/antenna';
import { AntennaNote } from '../models/entities/antenna-note';
import { PromoNote } from '../models/entities/promo-note';
import { PromoRead } from '../models/entities/promo-read';
import { Log } from '@/models/entities/log';
import { User } from '@/models/entities/user';
import { DriveFile } from '@/models/entities/drive-file';
import { DriveFolder } from '@/models/entities/drive-folder';
import { AccessToken } from '@/models/entities/access-token';
import { App } from '@/models/entities/app';
import { PollVote } from '@/models/entities/poll-vote';
import { Note } from '@/models/entities/note';
import { NoteReaction } from '@/models/entities/note-reaction';
import { NoteWatching } from '@/models/entities/note-watching';
import { NoteUnread } from '@/models/entities/note-unread';
import { Notification } from '@/models/entities/notification';
import { Meta } from '@/models/entities/meta';
import { Following } from '@/models/entities/following';
import { Instance } from '@/models/entities/instance';
import { Muting } from '@/models/entities/muting';
import { SwSubscription } from '@/models/entities/sw-subscription';
import { Blocking } from '@/models/entities/blocking';
import { UserList } from '@/models/entities/user-list';
import { UserListJoining } from '@/models/entities/user-list-joining';
import { UserGroup } from '@/models/entities/user-group';
import { UserGroupJoining } from '@/models/entities/user-group-joining';
import { UserGroupInvitation } from '@/models/entities/user-group-invitation';
import { Hashtag } from '@/models/entities/hashtag';
import { NoteFavorite } from '@/models/entities/note-favorite';
import { AbuseUserReport } from '@/models/entities/abuse-user-report';
import { RegistrationTicket } from '@/models/entities/registration-tickets';
import { MessagingMessage } from '@/models/entities/messaging-message';
import { Signin } from '@/models/entities/signin';
import { AuthSession } from '@/models/entities/auth-session';
import { FollowRequest } from '@/models/entities/follow-request';
import { Emoji } from '@/models/entities/emoji';
import { ReversiGame } from '@/models/entities/games/reversi/game';
import { ReversiMatching } from '@/models/entities/games/reversi/matching';
import { UserNotePining } from '@/models/entities/user-note-pining';
import { Poll } from '@/models/entities/poll';
import { UserKeypair } from '@/models/entities/user-keypair';
import { UserPublickey } from '@/models/entities/user-publickey';
import { UserProfile } from '@/models/entities/user-profile';
import { UserSecurityKey } from '@/models/entities/user-security-key';
import { AttestationChallenge } from '@/models/entities/attestation-challenge';
import { Page } from '@/models/entities/page';
import { PageLike } from '@/models/entities/page-like';
import { GalleryPost } from '@/models/entities/gallery-post';
import { GalleryLike } from '@/models/entities/gallery-like';
import { ModerationLog } from '@/models/entities/moderation-log';
import { UsedUsername } from '@/models/entities/used-username';
import { Announcement } from '@/models/entities/announcement';
import { AnnouncementRead } from '@/models/entities/announcement-read';
import { Clip } from '@/models/entities/clip';
import { ClipNote } from '@/models/entities/clip-note';
import { Antenna } from '@/models/entities/antenna';
import { AntennaNote } from '@/models/entities/antenna-note';
import { PromoNote } from '@/models/entities/promo-note';
import { PromoRead } from '@/models/entities/promo-read';
import { program } from '../argv';
import { Relay } from '../models/entities/relay';
import { MutedNote } from '../models/entities/muted-note';
import { Channel } from '../models/entities/channel';
import { ChannelFollowing } from '../models/entities/channel-following';
import { ChannelNotePining } from '../models/entities/channel-note-pining';
import { RegistryItem } from '../models/entities/registry-item';
import { Ad } from '../models/entities/ad';
import { Relay } from '@/models/entities/relay';
import { MutedNote } from '@/models/entities/muted-note';
import { Channel } from '@/models/entities/channel';
import { ChannelFollowing } from '@/models/entities/channel-following';
import { ChannelNotePining } from '@/models/entities/channel-note-pining';
import { RegistryItem } from '@/models/entities/registry-item';
import { Ad } from '@/models/entities/ad';
import { PasswordResetRequest } from '@/models/entities/password-reset-request';
const sqlLogger = dbLogger.createSubLogger('sql', 'white', false);
@ -211,3 +211,13 @@ export function initDb(justBorrow = false, sync = false, forceRecreate = false)
entities: entities
});
}
export async function resetDb() {
const conn = await getConnection();
const tables = await conn.query(`SELECT relname AS "table"
FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE nspname NOT IN ('pg_catalog', 'information_schema')
AND C.relkind = 'r'
AND nspname !~ '^pg_toast';`);
await Promise.all(tables.map(t => t.table).map(x => conn.query(`DELETE FROM "${x}" CASCADE`)));
}

View File

@ -1,5 +1,5 @@
import * as redis from 'redis';
import config from '@/config';
import config from '@/config/index';
export function createConnection() {
return redis.createClient(

View File

@ -0,0 +1,41 @@
# تم كتمها / تم حجبها
好みではないユーザーがいる場合は、ミュートを行うことでそのユーザーが自分から見えないようにすることができます。 また、より強力な措置として、ブロックを行うことでそのユーザーから自分のコンテンツが見えないようになるほか、自分に対して関わることができないようにすることができます。 ミュートされていることは相手は分かりませんが、ブロックされていることは相手に分かります。どちらを選ぶかはご自身の判断で行ってください。
<div class="info"> ミュートとブロックは併用できます。</div>
<div class="warn">⚠️ 利用規約に違反するような、迷惑なユーザーがいる場合は運営者に報告することも検討してください。</div>
設定>ミュートとブロック から、自分がミュートまたはブロックしているユーザー一覧を確認することができます。
## اكتم
ユーザーをミュートすると、そのユーザーに関する次のコンテンツがMisskeyに表示されなくなります:
- タイムラインや投稿の検索結果内の、そのユーザーの投稿(およびそれらの投稿に対する返信やRenote)
- そのユーザーからの通知
- メッセージ履歴一覧内の、そのユーザーとのメッセージ履歴
- など
ユーザーをミュートするには、対象のユーザーのユーザーページのメニューを開き、「ミュート」ボタンを押します。
<div class="info"> ミュートを行ったことは相手に通知されず、ミュートされていることを知ることもできません。</div>
## احجب
ユーザーをブロックすると、そのユーザーからあなたのコンテンツが見えないようになり、またあなたに対して以下のようなアクションをすることができなくなります。
- フォローする
- ユーザーリストに追加する
- 返信する、Renoteする
- リアクションする、アンケートに投票する
- メッセージを送信する
- など
また、
- ブロックする際に既にそのユーザーからフォローされていた場合はフォローが解除されます。
- ブロックする際に既にそのユーザーがあなたをユーザーリストに入れていた場合はそのリストからあなたが削除されます。
ユーザーをブロックするには、対象のユーザーのユーザーページのメニューを開き、「ブロック」ボタンを押します。
<div class="warn">⚠️ ブロックを行ったこと自体は相手に通知されませんが、フォローを行ったりなどの上記のアクションが行えなくなるので間接的にブロックされていることは分かります。</div>
<div class="warn">⚠️ 相手から自分のコンテンツが見えなくなりますが、相手がアカウントを切り替えたりログアウト状態になれば見ることができます。あくまで簡易的、補助的なものとしてお考えください。</div>

View File

@ -0,0 +1,20 @@
# ワードミュート
ワードミュートの設定をすると、条件に合致したノートが表示されなくなります。
ワードミュートには、ソフトワードミュートとハードワードミュートの2種類があります。それぞれについて設定の方法と挙動を説明します。
## ソフトワードミュート
ソフトワードミュートは、クライアント(アプリ)側でミュートを判断するワードミュートです。
ノートが設定した条件に合致すると、「(ユーザー名)が何かを言いました」という表示で隠れます。
クリックすると元の通りに表示されます。
## ハードワードミュート
ハードワードミュートは、アンテナのようにサーバーが新しいノートの本文に対して条件に合致するかどうか判断し、タイムラインから対象となったノートを除外します。
つまり、ハードワードミュートには、以下のような特徴があります。
* 条件設定後、新しい投稿のみがミュートの対象になります。
* 条件を変更しても、過去にハードミュートされたノートはミュートされたままになります。
* 「○○が何かを言いました」でタイムラインが埋まることがありません。
* ソフトミュートに非対応のアプリでも、ハードミュートは適用されます。

View File

@ -1,11 +1,14 @@
# よくある質問
ここでは利用上のよくある質問について掲載しています。 Misskeyのプロジェクト自体についてのよくある質問は[こちら](./misskey)に掲載されています。
### iOS/Androidのアプリはありますか
## iOS/Androidのアプリはありますか
公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。
ただ、サードパーティ製アプリはどうしても機能への対応が遅れてしまうため、とくに拘りがなければ公式のWebクライアントの利用をおすすめします。 なお、MisskeyのWebクライアントはPWAに対応しているので、ネイティブアプリのように動作させることも可能です。 詳しくは[こちら](todo)をご覧ください。
## Mastodonクライアントでログインできないのですが
MisskeyはMastodonのAPIと互換性がないため、一部を除きMastodonクライアントでMisskeyを利用することはできません。
## 他のサーバーのユーザーをフォローするときは?
メニューから検索を選び、ユーザー名をホスト込みで入力します。例: `@syuilo@misskey.io`
@ -20,3 +23,6 @@ MFMには、そのURLのプレビューを無効にする構文があります
## Botを開発したい
Misskey APIを利用してBotの開発が可能です。[こちら](../advanced/develop-bot)をご確認ください。
## ノートの翻訳機能はどのサービスを使用していますか?
[DeepL](https://www.deepl.com/)を使用しています。

View File

@ -1,7 +1,7 @@
# 用語集
Misskeyに関する用語集です。
## AcitivityPub
## ActivityPub
(読み: あくてぃびてぃぱぶ) 分散型を実現するために用いられるプロトコル(仕様)。このプロトコルに則ってサーバー同士通信を行うことで、連合が行われ、Fediverseを形成しています。
## AiScript
@ -49,6 +49,9 @@ Misskeyに関する用語集です。
## مثيل الخادم
todo
## إيموجي مخصص
サーバーで用意された絵文字。カスタム絵文字ではない通常の絵文字は「Unicode絵文字」と区別して呼ばれる。
## コントロールパネル
インスタンスの設定画面のこと。
@ -58,6 +61,9 @@ todo
## اكتم
ノートをパブリックな公開範囲で投稿できなくされている状態。モデレーターの判断でユーザーごとに設定されます。詳細は[こちら。](../features/silence)
## قائمة الانتظار
アクティビティ配送などを順番に行うためのシステム。
## علِق
アカウントが使用不可に設定されている状態。

View File

@ -3,7 +3,7 @@
Misskeyはオープンソースの分散型マイクロブログプラットフォームプロジェクトです。 開発は日本でsyuiloによって2014年から開始されました。 ドライブ、リアクションなどの豊富な機能や、高いカスタマイズ性を備えたUIを持つことが特徴です。
## 歴史
開発当初は掲示板がメインのサービスでしたが、ユーザーが短文を投稿し、それを時系列で流れるタイムライン機能を追加したところ人気が高まり、徐々にそれがメインとして開発が進むようになりました。 当初は分散型ではありませんでしたが、2018年にAcitivityPubを実装し分散型になったことで、より多くの方に認知され利用されるサービスになり、現在に至ります。
開発当初は掲示板がメインのサービスでしたが、ユーザーが短文を投稿し、それを時系列で流れるタイムライン機能を追加したところ人気が高まり、徐々にそれがメインとして開発が進むようになりました。 当初は分散型ではありませんでしたが、2018年にActivityPubを実装し分散型になったことで、より多くの方に認知され利用されるサービスになり、現在に至ります。
<div class="info"> Misskeyという名前は、syuiloが当時聴いていたMay'nというアーティストの楽曲、Brain Diverの歌詞に由来します。</div>
誰でも開発に参加することができ、現在でも活発に開発が続いています。
@ -72,7 +72,7 @@ Misskeyは開発が進むにつれ使用する技術も大きく変わってき
また、MFMやAiScriptなどの、Misskeyから派生して独自の技術も開発しています。
### Mastodonのフォークですか
いいえ。MisskeyはMastodonやその他のプロジェクトとは全く別のプロジェクトです。 開発に関しても、Misskeyの方が昔から開発されています。ただし、分散型になったのはMastodonの登場より後です。 同じAcitivityPubという分散のためのプロトコルを実装しているという点以外、両者に特に関りがあるわけでもありません。
いいえ。MisskeyはMastodonやその他のプロジェクトとは全く別のプロジェクトです。 開発に関しても、Misskeyの方が昔から開発されています。ただし、分散型になったのはMastodonの登場より後です。 同じActivityPubという分散のためのプロトコルを実装しているという点以外、両者に特に関りがあるわけでもありません。
### iOS/Androidのアプリはありますか
公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。

View File

@ -0,0 +1,41 @@
# ミュートとブロック
好みではないユーザーがいる場合は、ミュートを行うことでそのユーザーが自分から見えないようにすることができます。 また、より強力な措置として、ブロックを行うことでそのユーザーから自分のコンテンツが見えないようになるほか、自分に対して関わることができないようにすることができます。 ミュートされていることは相手は分かりませんが、ブロックされていることは相手に分かります。どちらを選ぶかはご自身の判断で行ってください。
<div class="info"> ミュートとブロックは併用できます。</div>
<div class="warn">⚠️ 利用規約に違反するような、迷惑なユーザーがいる場合は運営者に報告することも検討してください。</div>
設定>ミュートとブロック から、自分がミュートまたはブロックしているユーザー一覧を確認することができます。
## Ztlumit
ユーザーをミュートすると、そのユーザーに関する次のコンテンツがMisskeyに表示されなくなります:
- タイムラインや投稿の検索結果内の、そのユーザーの投稿(およびそれらの投稿に対する返信やRenote)
- そのユーザーからの通知
- メッセージ履歴一覧内の、そのユーザーとのメッセージ履歴
- など
ユーザーをミュートするには、対象のユーザーのユーザーページのメニューを開き、「ミュート」ボタンを押します。
<div class="info"> ミュートを行ったことは相手に通知されず、ミュートされていることを知ることもできません。</div>
## Zablokovat
ユーザーをブロックすると、そのユーザーからあなたのコンテンツが見えないようになり、またあなたに対して以下のようなアクションをすることができなくなります。
- フォローする
- ユーザーリストに追加する
- 返信する、Renoteする
- リアクションする、アンケートに投票する
- メッセージを送信する
- など
また、
- ブロックする際に既にそのユーザーからフォローされていた場合はフォローが解除されます。
- ブロックする際に既にそのユーザーがあなたをユーザーリストに入れていた場合はそのリストからあなたが削除されます。
ユーザーをブロックするには、対象のユーザーのユーザーページのメニューを開き、「ブロック」ボタンを押します。
<div class="warn">⚠️ ブロックを行ったこと自体は相手に通知されませんが、フォローを行ったりなどの上記のアクションが行えなくなるので間接的にブロックされていることは分かります。</div>
<div class="warn">⚠️ 相手から自分のコンテンツが見えなくなりますが、相手がアカウントを切り替えたりログアウト状態になれば見ることができます。あくまで簡易的、補助的なものとしてお考えください。</div>

View File

@ -0,0 +1,20 @@
# ワードミュート
ワードミュートの設定をすると、条件に合致したノートが表示されなくなります。
ワードミュートには、ソフトワードミュートとハードワードミュートの2種類があります。それぞれについて設定の方法と挙動を説明します。
## ソフトワードミュート
ソフトワードミュートは、クライアント(アプリ)側でミュートを判断するワードミュートです。
ノートが設定した条件に合致すると、「(ユーザー名)が何かを言いました」という表示で隠れます。
クリックすると元の通りに表示されます。
## ハードワードミュート
ハードワードミュートは、アンテナのようにサーバーが新しいノートの本文に対して条件に合致するかどうか判断し、タイムラインから対象となったノートを除外します。
つまり、ハードワードミュートには、以下のような特徴があります。
* 条件設定後、新しい投稿のみがミュートの対象になります。
* 条件を変更しても、過去にハードミュートされたノートはミュートされたままになります。
* 「○○が何かを言いました」でタイムラインが埋まることがありません。
* ソフトミュートに非対応のアプリでも、ハードミュートは適用されます。

View File

@ -1,11 +1,14 @@
# よくある質問
ここでは利用上のよくある質問について掲載しています。 Misskeyのプロジェクト自体についてのよくある質問は[こちら](./misskey)に掲載されています。
### iOS/Androidのアプリはありますか
## iOS/Androidのアプリはありますか
公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。
ただ、サードパーティ製アプリはどうしても機能への対応が遅れてしまうため、とくに拘りがなければ公式のWebクライアントの利用をおすすめします。 なお、MisskeyのWebクライアントはPWAに対応しているので、ネイティブアプリのように動作させることも可能です。 詳しくは[こちら](todo)をご覧ください。
## Mastodonクライアントでログインできないのですが
MisskeyはMastodonのAPIと互換性がないため、一部を除きMastodonクライアントでMisskeyを利用することはできません。
## 他のサーバーのユーザーをフォローするときは?
メニューから検索を選び、ユーザー名をホスト込みで入力します。例: `@syuilo@misskey.io`
@ -20,3 +23,6 @@ MFMには、そのURLのプレビューを無効にする構文があります
## Botを開発したい
Misskey APIを利用してBotの開発が可能です。[こちら](../advanced/develop-bot)をご確認ください。
## ノートの翻訳機能はどのサービスを使用していますか?
[DeepL](https://www.deepl.com/)を使用しています。

View File

@ -1,7 +1,7 @@
# 用語集
Misskeyに関する用語集です。
## AcitivityPub
## ActivityPub
(読み: あくてぃびてぃぱぶ) 分散型を実現するために用いられるプロトコル(仕様)。このプロトコルに則ってサーバー同士通信を行うことで、連合が行われ、Fediverseを形成しています。
## AiScript
@ -49,6 +49,9 @@ Misskeyに関する用語集です。
## Instance
todo
## Vlastní emoji
サーバーで用意された絵文字。カスタム絵文字ではない通常の絵文字は「Unicode絵文字」と区別して呼ばれる。
## コントロールパネル
インスタンスの設定画面のこと。
@ -58,6 +61,9 @@ todo
## サイレンス
ノートをパブリックな公開範囲で投稿できなくされている状態。モデレーターの判断でユーザーごとに設定されます。詳細は[こちら。](../features/silence)
## Fronta úloh
アクティビティ配送などを順番に行うためのシステム。
## Zmrazit
アカウントが使用不可に設定されている状態。

View File

@ -3,7 +3,7 @@
Misskeyはオープンソースの分散型マイクロブログプラットフォームプロジェクトです。 開発は日本でsyuiloによって2014年から開始されました。 ドライブ、リアクションなどの豊富な機能や、高いカスタマイズ性を備えたUIを持つことが特徴です。
## 歴史
開発当初は掲示板がメインのサービスでしたが、ユーザーが短文を投稿し、それを時系列で流れるタイムライン機能を追加したところ人気が高まり、徐々にそれがメインとして開発が進むようになりました。 当初は分散型ではありませんでしたが、2018年にAcitivityPubを実装し分散型になったことで、より多くの方に認知され利用されるサービスになり、現在に至ります。
開発当初は掲示板がメインのサービスでしたが、ユーザーが短文を投稿し、それを時系列で流れるタイムライン機能を追加したところ人気が高まり、徐々にそれがメインとして開発が進むようになりました。 当初は分散型ではありませんでしたが、2018年にActivityPubを実装し分散型になったことで、より多くの方に認知され利用されるサービスになり、現在に至ります。
<div class="info"> Misskeyという名前は、syuiloが当時聴いていたMay'nというアーティストの楽曲、Brain Diverの歌詞に由来します。</div>
誰でも開発に参加することができ、現在でも活発に開発が続いています。
@ -72,7 +72,7 @@ Misskeyは開発が進むにつれ使用する技術も大きく変わってき
また、MFMやAiScriptなどの、Misskeyから派生して独自の技術も開発しています。
### Mastodonのフォークですか
いいえ。MisskeyはMastodonやその他のプロジェクトとは全く別のプロジェクトです。 開発に関しても、Misskeyの方が昔から開発されています。ただし、分散型になったのはMastodonの登場より後です。 同じAcitivityPubという分散のためのプロトコルを実装しているという点以外、両者に特に関りがあるわけでもありません。
いいえ。MisskeyはMastodonやその他のプロジェクトとは全く別のプロジェクトです。 開発に関しても、Misskeyの方が昔から開発されています。ただし、分散型になったのはMastodonの登場より後です。 同じActivityPubという分散のためのプロトコルを実装しているという点以外、両者に特に関りがあるわけでもありません。
### iOS/Androidのアプリはありますか
公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。

View File

@ -0,0 +1,41 @@
# ミュートとブロック
好みではないユーザーがいる場合は、ミュートを行うことでそのユーザーが自分から見えないようにすることができます。 また、より強力な措置として、ブロックを行うことでそのユーザーから自分のコンテンツが見えないようになるほか、自分に対して関わることができないようにすることができます。 ミュートされていることは相手は分かりませんが、ブロックされていることは相手に分かります。どちらを選ぶかはご自身の判断で行ってください。
<div class="info"> ミュートとブロックは併用できます。</div>
<div class="warn">⚠️ 利用規約に違反するような、迷惑なユーザーがいる場合は運営者に報告することも検討してください。</div>
設定>ミュートとブロック から、自分がミュートまたはブロックしているユーザー一覧を確認することができます。
## ミュート
ユーザーをミュートすると、そのユーザーに関する次のコンテンツがMisskeyに表示されなくなります:
- タイムラインや投稿の検索結果内の、そのユーザーの投稿(およびそれらの投稿に対する返信やRenote)
- そのユーザーからの通知
- メッセージ履歴一覧内の、そのユーザーとのメッセージ履歴
- など
ユーザーをミュートするには、対象のユーザーのユーザーページのメニューを開き、「ミュート」ボタンを押します。
<div class="info"> ミュートを行ったことは相手に通知されず、ミュートされていることを知ることもできません。</div>
## ブロック
ユーザーをブロックすると、そのユーザーからあなたのコンテンツが見えないようになり、またあなたに対して以下のようなアクションをすることができなくなります。
- フォローする
- ユーザーリストに追加する
- 返信する、Renoteする
- リアクションする、アンケートに投票する
- メッセージを送信する
- など
また、
- ブロックする際に既にそのユーザーからフォローされていた場合はフォローが解除されます。
- ブロックする際に既にそのユーザーがあなたをユーザーリストに入れていた場合はそのリストからあなたが削除されます。
ユーザーをブロックするには、対象のユーザーのユーザーページのメニューを開き、「ブロック」ボタンを押します。
<div class="warn">⚠️ ブロックを行ったこと自体は相手に通知されませんが、フォローを行ったりなどの上記のアクションが行えなくなるので間接的にブロックされていることは分かります。</div>
<div class="warn">⚠️ 相手から自分のコンテンツが見えなくなりますが、相手がアカウントを切り替えたりログアウト状態になれば見ることができます。あくまで簡易的、補助的なものとしてお考えください。</div>

View File

@ -0,0 +1,20 @@
# ワードミュート
ワードミュートの設定をすると、条件に合致したノートが表示されなくなります。
ワードミュートには、ソフトワードミュートとハードワードミュートの2種類があります。それぞれについて設定の方法と挙動を説明します。
## ソフトワードミュート
ソフトワードミュートは、クライアント(アプリ)側でミュートを判断するワードミュートです。
ノートが設定した条件に合致すると、「(ユーザー名)が何かを言いました」という表示で隠れます。
クリックすると元の通りに表示されます。
## ハードワードミュート
ハードワードミュートは、アンテナのようにサーバーが新しいノートの本文に対して条件に合致するかどうか判断し、タイムラインから対象となったノートを除外します。
つまり、ハードワードミュートには、以下のような特徴があります。
* 条件設定後、新しい投稿のみがミュートの対象になります。
* 条件を変更しても、過去にハードミュートされたノートはミュートされたままになります。
* 「○○が何かを言いました」でタイムラインが埋まることがありません。
* ソフトミュートに非対応のアプリでも、ハードミュートは適用されます。

View File

@ -1,11 +1,14 @@
# よくある質問
ここでは利用上のよくある質問について掲載しています。 Misskeyのプロジェクト自体についてのよくある質問は[こちら](./misskey)に掲載されています。
### iOS/Androidのアプリはありますか
## iOS/Androidのアプリはありますか
公式にはそういったOSのネイティブアプリを開発していませんが、サードパーティ製のアプリがいくつかあります。 詳しくは[こちら](./apps)をご覧ください。
ただ、サードパーティ製アプリはどうしても機能への対応が遅れてしまうため、とくに拘りがなければ公式のWebクライアントの利用をおすすめします。 なお、MisskeyのWebクライアントはPWAに対応しているので、ネイティブアプリのように動作させることも可能です。 詳しくは[こちら](todo)をご覧ください。
## Mastodonクライアントでログインできないのですが
MisskeyはMastodonのAPIと互換性がないため、一部を除きMastodonクライアントでMisskeyを利用することはできません。
## 他のサーバーのユーザーをフォローするときは?
メニューから検索を選び、ユーザー名をホスト込みで入力します。例: `@syuilo@misskey.io`
@ -20,3 +23,6 @@ MFMには、そのURLのプレビューを無効にする構文があります
## Botを開発したい
Misskey APIを利用してBotの開発が可能です。[こちら](../advanced/develop-bot)をご確認ください。
## ノートの翻訳機能はどのサービスを使用していますか?
[DeepL](https://www.deepl.com/)を使用しています。

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