Compare commits
51 Commits
Author | SHA1 | Date | |
---|---|---|---|
15cac10d7b | |||
49958ca03f | |||
280dbe9853 | |||
bf964ee969 | |||
61dcd51888 | |||
5448c22031 | |||
27768081e2 | |||
c3140f57b9 | |||
7275bc6d3b | |||
485f2f460e | |||
336912e442 | |||
dd9c94e47e | |||
055863144d | |||
0bf602bae6 | |||
6fc28d1df7 | |||
2ef795aba8 | |||
1d2c50fc26 | |||
cef8aa5e7a | |||
edf3e75344 | |||
62835c6011 | |||
60fb22cb3c | |||
20dea3a793 | |||
aba37ae701 | |||
2c6e6275aa | |||
20ef362854 | |||
4692aa8d9b | |||
f7b6dc08f7 | |||
7dfe7005e0 | |||
b91de4ac12 | |||
d5205d7328 | |||
f44ce535fa | |||
7177fd27c8 | |||
cf304f88d4 | |||
dff1d84031 | |||
96bc17aa10 | |||
41ba06a5e6 | |||
d7ac0418d7 | |||
f4319a9c01 | |||
f4c4d53bbb | |||
0ed43e1bdf | |||
d25bd876cb | |||
b9782397c2 | |||
ea0abc9f71 | |||
27d16c6a12 | |||
ede70d354e | |||
66fa583f6e | |||
77bcb58f12 | |||
61036e3a70 | |||
bcd886c4f5 | |||
4d868aaf1f | |||
80ea747db6 |
@ -6,6 +6,8 @@ mongodb:
|
|||||||
db: misskey
|
db: misskey
|
||||||
user: syuilo
|
user: syuilo
|
||||||
pass: ''
|
pass: ''
|
||||||
|
drive:
|
||||||
|
storage: 'db'
|
||||||
redis:
|
redis:
|
||||||
host: localhost
|
host: localhost
|
||||||
port: 6379
|
port: 6379
|
||||||
|
@ -6,6 +6,8 @@ mongodb:
|
|||||||
db: test-misskey
|
db: test-misskey
|
||||||
user: admin
|
user: admin
|
||||||
pass: ''
|
pass: ''
|
||||||
|
drive:
|
||||||
|
storage: 'db'
|
||||||
# __REDIS__
|
# __REDIS__
|
||||||
redis:
|
redis:
|
||||||
host: localhost
|
host: localhost
|
||||||
|
@ -108,5 +108,8 @@ autoAdmin: true
|
|||||||
# port: 9200
|
# port: 9200
|
||||||
# pass: null
|
# pass: null
|
||||||
|
|
||||||
|
# Whether disable HSTS
|
||||||
|
#disableHsts: true
|
||||||
|
|
||||||
# Clustering
|
# Clustering
|
||||||
#clusterLimit: 1
|
#clusterLimit: 1
|
||||||
|
10
.github/ISSUE_TEMPLATE/bug_report.md
vendored
10
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,22 +1,30 @@
|
|||||||
---
|
---
|
||||||
name: Bug Report
|
name: Bug Report
|
||||||
about: Create a report to help us improve
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: bug
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
|
|
||||||
<!-- Tell us what the bug is -->
|
<!-- Tell us what the bug is -->
|
||||||
|
|
||||||
# Expected Behavior
|
# Expected Behavior
|
||||||
|
|
||||||
<!--- Tell us what should happen -->
|
<!--- Tell us what should happen -->
|
||||||
|
|
||||||
# Actual Behavior
|
# Actual Behavior
|
||||||
|
|
||||||
<!--- Tell us what happens instead of the expected behavior -->
|
<!--- Tell us what happens instead of the expected behavior -->
|
||||||
|
|
||||||
# Steps to Reproduce
|
# Steps to Reproduce
|
||||||
|
|
||||||
1.
|
1.
|
||||||
2.
|
2.
|
||||||
3.
|
3.
|
||||||
|
|
||||||
# Environment
|
# Environment
|
||||||
|
|
||||||
<!-- Tell us where on the platform it happens -->
|
<!-- Tell us where on the platform it happens -->
|
||||||
<!-- e.g. desktop or mobile version, your browser, your OS -->
|
|
||||||
|
31
.github/ISSUE_TEMPLATE/client-side-bug-report.md
vendored
Normal file
31
.github/ISSUE_TEMPLATE/client-side-bug-report.md
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
name: Client-side Bug Report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: bug, client-side
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
|
||||||
|
<!-- Tell us what the bug is -->
|
||||||
|
|
||||||
|
# Expected Behavior
|
||||||
|
|
||||||
|
<!--- Tell us what should happen -->
|
||||||
|
|
||||||
|
# Actual Behavior
|
||||||
|
|
||||||
|
<!--- Tell us what happens instead of the expected behavior -->
|
||||||
|
|
||||||
|
# Steps to Reproduce
|
||||||
|
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
|
||||||
|
# Environment
|
||||||
|
|
||||||
|
<!-- Tell us where on the platform it happens -->
|
||||||
|
<!-- e.g. desktop or mobile version, your browser, your OS -->
|
12
.github/ISSUE_TEMPLATE/client-side-feature-request.md
vendored
Normal file
12
.github/ISSUE_TEMPLATE/client-side-feature-request.md
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
name: Client-side Feature Request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
labels: client-side, feature
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
|
||||||
|
<!-- Tell us what the suggestion is -->
|
9
.github/ISSUE_TEMPLATE/feature_request.md
vendored
9
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,11 +1,12 @@
|
|||||||
---
|
---
|
||||||
name: Feature Request
|
name: Feature Request
|
||||||
about: Suggest an idea for this project
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
labels: feature
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
<!-- Tell us what the suggestion is -->
|
|
||||||
|
|
||||||
# Environment
|
<!-- Tell us what the suggestion is -->
|
||||||
<!-- Tell us where on the platform it related -->
|
|
||||||
<!-- e.g. desktop or mobile version, your browser, your OS -->
|
|
||||||
|
31
.github/ISSUE_TEMPLATE/server-side-bug-report.md
vendored
Normal file
31
.github/ISSUE_TEMPLATE/server-side-bug-report.md
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
name: Server-side Bug Report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: bug, server-side
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
|
||||||
|
<!-- Tell us what the bug is -->
|
||||||
|
|
||||||
|
# Expected Behavior
|
||||||
|
|
||||||
|
<!--- Tell us what should happen -->
|
||||||
|
|
||||||
|
# Actual Behavior
|
||||||
|
|
||||||
|
<!--- Tell us what happens instead of the expected behavior -->
|
||||||
|
|
||||||
|
# Steps to Reproduce
|
||||||
|
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
|
||||||
|
# Environment
|
||||||
|
|
||||||
|
<!-- Tell us where on the platform it happens -->
|
||||||
|
<!-- e.g. your Node.js version, your OS -->
|
12
.github/ISSUE_TEMPLATE/server-side-feature-request.md
vendored
Normal file
12
.github/ISSUE_TEMPLATE/server-side-feature-request.md
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
name: Server-side Feature Request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
labels: feature, server-side
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
|
||||||
|
<!-- Tell us what the suggestion is -->
|
11
CHANGELOG.md
11
CHANGELOG.md
@ -1,6 +1,17 @@
|
|||||||
ChangeLog
|
ChangeLog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
10.82.4
|
||||||
|
----------
|
||||||
|
* 起動できなくなることがある問題を修正
|
||||||
|
|
||||||
|
10.82.3
|
||||||
|
----------
|
||||||
|
* フォロー/ミュート/ブロックデータをエクスポート可能に
|
||||||
|
* バグ修正
|
||||||
|
* デザインの調整
|
||||||
|
* ジョブキューの動作を修正
|
||||||
|
|
||||||
10.82.2
|
10.82.2
|
||||||
----------
|
----------
|
||||||
* ジョブキューの動作を修正
|
* ジョブキューの動作を修正
|
||||||
|
@ -44,3 +44,15 @@ Stands for _**S**ervice**W**orker_.
|
|||||||
|
|
||||||
#### Denyaize
|
#### Denyaize
|
||||||
Nyaizeを解除すること
|
Nyaizeを解除すること
|
||||||
|
|
||||||
|
## Code style
|
||||||
|
### Don't use `export default`
|
||||||
|
Bad:
|
||||||
|
``` ts
|
||||||
|
export default function(foo: string): string {
|
||||||
|
```
|
||||||
|
|
||||||
|
Good:
|
||||||
|
``` ts
|
||||||
|
export function something(foo: string): string {
|
||||||
|
```
|
||||||
|
@ -115,6 +115,7 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
|||||||
<td><img src="https://c8.patreon.com/2/200/16542964" alt="Takumi Sugita" width="100"></td>
|
<td><img src="https://c8.patreon.com/2/200/16542964" alt="Takumi Sugita" width="100"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13039004/509d0c412eb14ae08d6a812a3054f7d6/1?token-time=2145916800&token-hash=2PsbFNw0tnubZzgSXD01R6hIgncfiElG7H7HX2Y3dyo%3D" alt="nemu" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13039004/509d0c412eb14ae08d6a812a3054f7d6/1?token-time=2145916800&token-hash=2PsbFNw0tnubZzgSXD01R6hIgncfiElG7H7HX2Y3dyo%3D" alt="nemu" width="100"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/3?token-time=2145916800&token-hash=9JtETp0X8gI280Ne1E8bxn6j4Lw5o2k4mJkICx97V_k%3D" alt="YUKIMOCHI" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/3?token-time=2145916800&token-hash=9JtETp0X8gI280Ne1E8bxn6j4Lw5o2k4mJkICx97V_k%3D" alt="YUKIMOCHI" width="100"></td>
|
||||||
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/17195955/be45e5e14c3e48b2bee0456c84e19df4/4?token-time=2145916800&token-hash=SbdZeN5SmsuT9stD6v0jN1z0hftg0FmRiCTxysU0Ihw%3D" alt="Damillora" width="100"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/8241184/39e18850e87a449e9c9a71acb3310ebd/3?token-time=2145916800&token-hash=gMq30aylxu5v3G8pRhWR5jeRBbYWEoRKjGbNeiCQz5g%3D" alt="Acid Chicken" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/8241184/39e18850e87a449e9c9a71acb3310ebd/3?token-time=2145916800&token-hash=gMq30aylxu5v3G8pRhWR5jeRBbYWEoRKjGbNeiCQz5g%3D" alt="Acid Chicken" width="100"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/4389829/9f709180ac714651a70f74a82f3ffdb9/2?token-time=2145916800&token-hash=zcwFxb2zopzWwksKVU1YpfAEjsl4yKT02aQ6yiAFRiQ%3D" alt="natalie" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/4389829/9f709180ac714651a70f74a82f3ffdb9/2?token-time=2145916800&token-hash=zcwFxb2zopzWwksKVU1YpfAEjsl4yKT02aQ6yiAFRiQ%3D" alt="natalie" width="100"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13034746/c711c7f58e204ecfbc2fd646bc8a4eee/1?token-time=2145916800&token-hash=5T8XcaAf9Zyzfg3QubR06s_kJZkArVEM2dwObrBVAU4%3D" alt="Hiratake" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13034746/c711c7f58e204ecfbc2fd646bc8a4eee/1?token-time=2145916800&token-hash=5T8XcaAf9Zyzfg3QubR06s_kJZkArVEM2dwObrBVAU4%3D" alt="Hiratake" width="100"></td>
|
||||||
@ -124,6 +125,7 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
|||||||
<td><a href="https://www.patreon.com/user?u=16542964">Takumi Sugita</a></td>
|
<td><a href="https://www.patreon.com/user?u=16542964">Takumi Sugita</a></td>
|
||||||
<td><a href="https://www.patreon.com/user?u=13039004">nemu</a></td>
|
<td><a href="https://www.patreon.com/user?u=13039004">nemu</a></td>
|
||||||
<td><a href="https://www.patreon.com/yukimochi">YUKIMOCHI</a></td>
|
<td><a href="https://www.patreon.com/yukimochi">YUKIMOCHI</a></td>
|
||||||
|
<td><a href="https://www.patreon.com/damillora">Damillora</a></td>
|
||||||
<td><a href="https://www.patreon.com/acid_chicken">Acid Chicken</a></td>
|
<td><a href="https://www.patreon.com/acid_chicken">Acid Chicken</a></td>
|
||||||
<td><a href="https://www.patreon.com/user?u=4389829">natalie</a></td>
|
<td><a href="https://www.patreon.com/user?u=4389829">natalie</a></td>
|
||||||
<td><a href="https://www.patreon.com/hiratake">Hiratake</a></td>
|
<td><a href="https://www.patreon.com/hiratake">Hiratake</a></td>
|
||||||
@ -140,7 +142,7 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
|||||||
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
|
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
|
||||||
</tr></table>
|
</tr></table>
|
||||||
|
|
||||||
**Last updated:** Sun, 03 Feb 2019 10:13:06 UTC
|
**Last updated:** Wed, 06 Feb 2019 18:18:05 UTC
|
||||||
<!-- PATREON_END -->
|
<!-- PATREON_END -->
|
||||||
|
|
||||||
:four_leaf_clover: Copyright
|
:four_leaf_clover: Copyright
|
||||||
|
@ -510,7 +510,11 @@ common/views/components/profile-editor.vue:
|
|||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
||||||
export: "エクスポート"
|
export: "エクスポート"
|
||||||
export-notes: "すべての投稿のエクスポート"
|
export-targets:
|
||||||
|
all-notes: "すべての投稿データ"
|
||||||
|
following-list: "フォロー"
|
||||||
|
mute-list: "ミュート"
|
||||||
|
blocking-list: "ブロック"
|
||||||
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
||||||
common/views/components/user-list-editor.vue:
|
common/views/components/user-list-editor.vue:
|
||||||
users: "ユーザー"
|
users: "ユーザー"
|
||||||
@ -1003,6 +1007,7 @@ admin/views/index.vue:
|
|||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
hashtags: "ハッシュタグ"
|
hashtags: "ハッシュタグ"
|
||||||
abuse: "スパム報告"
|
abuse: "スパム報告"
|
||||||
|
queue: "ジョブキュー"
|
||||||
back-to-misskey: "Misskeyに戻る"
|
back-to-misskey: "Misskeyに戻る"
|
||||||
admin/views/dashboard.vue:
|
admin/views/dashboard.vue:
|
||||||
dashboard: "ダッシュボード"
|
dashboard: "ダッシュボード"
|
||||||
@ -1012,6 +1017,9 @@ admin/views/dashboard.vue:
|
|||||||
instances: "インスタンス"
|
instances: "インスタンス"
|
||||||
this-instance: "このインスタンス"
|
this-instance: "このインスタンス"
|
||||||
federated: "連合"
|
federated: "連合"
|
||||||
|
admin/views/queue.vue:
|
||||||
|
operation: "操作"
|
||||||
|
remove-all-jobs: "すべてのジョブをクリア"
|
||||||
admin/views/abuse.vue:
|
admin/views/abuse.vue:
|
||||||
title: "スパム報告"
|
title: "スパム報告"
|
||||||
target: "対象"
|
target: "対象"
|
||||||
|
@ -510,7 +510,11 @@ common/views/components/profile-editor.vue:
|
|||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
||||||
export: "エクスポート"
|
export: "エクスポート"
|
||||||
export-notes: "すべての投稿のエクスポート"
|
export-targets:
|
||||||
|
all-notes: "すべての投稿データ"
|
||||||
|
following-list: "フォロー"
|
||||||
|
mute-list: "ミュート"
|
||||||
|
blocking-list: "ブロック"
|
||||||
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
||||||
common/views/components/user-list-editor.vue:
|
common/views/components/user-list-editor.vue:
|
||||||
users: "ユーザー"
|
users: "ユーザー"
|
||||||
@ -1003,6 +1007,7 @@ admin/views/index.vue:
|
|||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
hashtags: "ハッシュタグ"
|
hashtags: "ハッシュタグ"
|
||||||
abuse: "スパム報告"
|
abuse: "スパム報告"
|
||||||
|
queue: "ジョブキュー"
|
||||||
back-to-misskey: "Misskeyに戻る"
|
back-to-misskey: "Misskeyに戻る"
|
||||||
admin/views/dashboard.vue:
|
admin/views/dashboard.vue:
|
||||||
dashboard: "ダッシュボード"
|
dashboard: "ダッシュボード"
|
||||||
@ -1012,6 +1017,9 @@ admin/views/dashboard.vue:
|
|||||||
instances: "インスタンス"
|
instances: "インスタンス"
|
||||||
this-instance: "このインスタンス"
|
this-instance: "このインスタンス"
|
||||||
federated: "連合"
|
federated: "連合"
|
||||||
|
admin/views/queue.vue:
|
||||||
|
operation: "操作"
|
||||||
|
remove-all-jobs: "すべてのジョブをクリア"
|
||||||
admin/views/abuse.vue:
|
admin/views/abuse.vue:
|
||||||
title: "スパム報告"
|
title: "スパム報告"
|
||||||
target: "対象"
|
target: "対象"
|
||||||
|
@ -510,7 +510,11 @@ common/views/components/profile-editor.vue:
|
|||||||
email-verified: "Your email has been verified."
|
email-verified: "Your email has been verified."
|
||||||
email-not-verified: "Email address is not confirmed. Please check your inbox."
|
email-not-verified: "Email address is not confirmed. Please check your inbox."
|
||||||
export: "Export"
|
export: "Export"
|
||||||
export-notes: "Export all of your Notes"
|
export-targets:
|
||||||
|
all-notes: "All posted Notes"
|
||||||
|
following-list: "List of followers"
|
||||||
|
mute-list: "List of muted accounts"
|
||||||
|
blocking-list: "List of blocked accounts"
|
||||||
export-requested: "You have requested an export. This may take a while. After the export is complete, the resulting file will be added to the drive."
|
export-requested: "You have requested an export. This may take a while. After the export is complete, the resulting file will be added to the drive."
|
||||||
common/views/components/user-list-editor.vue:
|
common/views/components/user-list-editor.vue:
|
||||||
users: "User"
|
users: "User"
|
||||||
@ -1003,6 +1007,7 @@ admin/views/index.vue:
|
|||||||
announcements: "Announcements"
|
announcements: "Announcements"
|
||||||
hashtags: "Hashtags"
|
hashtags: "Hashtags"
|
||||||
abuse: "Abuse"
|
abuse: "Abuse"
|
||||||
|
queue: "Job Queue"
|
||||||
back-to-misskey: "Back to Misskey"
|
back-to-misskey: "Back to Misskey"
|
||||||
admin/views/dashboard.vue:
|
admin/views/dashboard.vue:
|
||||||
dashboard: "Dashboard"
|
dashboard: "Dashboard"
|
||||||
@ -1012,6 +1017,9 @@ admin/views/dashboard.vue:
|
|||||||
instances: "Instances"
|
instances: "Instances"
|
||||||
this-instance: "This instance"
|
this-instance: "This instance"
|
||||||
federated: "Federated"
|
federated: "Federated"
|
||||||
|
admin/views/queue.vue:
|
||||||
|
operation: "Action(s)"
|
||||||
|
remove-all-jobs: "すべてのジョブをクリア"
|
||||||
admin/views/abuse.vue:
|
admin/views/abuse.vue:
|
||||||
title: "Abuse"
|
title: "Abuse"
|
||||||
target: "Target"
|
target: "Target"
|
||||||
|
@ -510,7 +510,11 @@ common/views/components/profile-editor.vue:
|
|||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
||||||
export: "エクスポート"
|
export: "エクスポート"
|
||||||
export-notes: "すべての投稿のエクスポート"
|
export-targets:
|
||||||
|
all-notes: "すべての投稿データ"
|
||||||
|
following-list: "フォロー"
|
||||||
|
mute-list: "ミュート"
|
||||||
|
blocking-list: "ブロック"
|
||||||
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
||||||
common/views/components/user-list-editor.vue:
|
common/views/components/user-list-editor.vue:
|
||||||
users: "Usuarios"
|
users: "Usuarios"
|
||||||
@ -1003,6 +1007,7 @@ admin/views/index.vue:
|
|||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
hashtags: "Hashtags"
|
hashtags: "Hashtags"
|
||||||
abuse: "スパム報告"
|
abuse: "スパム報告"
|
||||||
|
queue: "ジョブキュー"
|
||||||
back-to-misskey: "Volver a Misskey"
|
back-to-misskey: "Volver a Misskey"
|
||||||
admin/views/dashboard.vue:
|
admin/views/dashboard.vue:
|
||||||
dashboard: "Panel de Control"
|
dashboard: "Panel de Control"
|
||||||
@ -1012,6 +1017,9 @@ admin/views/dashboard.vue:
|
|||||||
instances: "Instancias"
|
instances: "Instancias"
|
||||||
this-instance: "Esta instancia"
|
this-instance: "Esta instancia"
|
||||||
federated: "連合"
|
federated: "連合"
|
||||||
|
admin/views/queue.vue:
|
||||||
|
operation: "操作"
|
||||||
|
remove-all-jobs: "すべてのジョブをクリア"
|
||||||
admin/views/abuse.vue:
|
admin/views/abuse.vue:
|
||||||
title: "スパム報告"
|
title: "スパム報告"
|
||||||
target: "対象"
|
target: "対象"
|
||||||
|
@ -510,7 +510,11 @@ common/views/components/profile-editor.vue:
|
|||||||
email-verified: "L’adresse du courrier électronique a été vérifiée."
|
email-verified: "L’adresse du courrier électronique a été vérifiée."
|
||||||
email-not-verified: "Adresse de courriel n’est pas confirmée. Veuillez vérifier votre boite de réception."
|
email-not-verified: "Adresse de courriel n’est pas confirmée. Veuillez vérifier votre boite de réception."
|
||||||
export: "エクスポート"
|
export: "エクスポート"
|
||||||
export-notes: "すべての投稿のエクスポート"
|
export-targets:
|
||||||
|
all-notes: "すべての投稿データ"
|
||||||
|
following-list: "フォロー"
|
||||||
|
mute-list: "ミュート"
|
||||||
|
blocking-list: "ブロック"
|
||||||
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
||||||
common/views/components/user-list-editor.vue:
|
common/views/components/user-list-editor.vue:
|
||||||
users: "Utilisateur·rice"
|
users: "Utilisateur·rice"
|
||||||
@ -1003,6 +1007,7 @@ admin/views/index.vue:
|
|||||||
announcements: "Annonces"
|
announcements: "Annonces"
|
||||||
hashtags: "Hashtags"
|
hashtags: "Hashtags"
|
||||||
abuse: "Abus"
|
abuse: "Abus"
|
||||||
|
queue: "ジョブキュー"
|
||||||
back-to-misskey: "Retour vers Misskey"
|
back-to-misskey: "Retour vers Misskey"
|
||||||
admin/views/dashboard.vue:
|
admin/views/dashboard.vue:
|
||||||
dashboard: "Tableau de bord"
|
dashboard: "Tableau de bord"
|
||||||
@ -1012,6 +1017,9 @@ admin/views/dashboard.vue:
|
|||||||
instances: "Instances"
|
instances: "Instances"
|
||||||
this-instance: "Cette instance"
|
this-instance: "Cette instance"
|
||||||
federated: "Fédérées"
|
federated: "Fédérées"
|
||||||
|
admin/views/queue.vue:
|
||||||
|
operation: "操作"
|
||||||
|
remove-all-jobs: "すべてのジョブをクリア"
|
||||||
admin/views/abuse.vue:
|
admin/views/abuse.vue:
|
||||||
title: "Abus"
|
title: "Abus"
|
||||||
target: "Cible"
|
target: "Cible"
|
||||||
|
@ -510,7 +510,11 @@ common/views/components/profile-editor.vue:
|
|||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
||||||
export: "エクスポート"
|
export: "エクスポート"
|
||||||
export-notes: "すべての投稿のエクスポート"
|
export-targets:
|
||||||
|
all-notes: "すべての投稿データ"
|
||||||
|
following-list: "フォロー"
|
||||||
|
mute-list: "ミュート"
|
||||||
|
blocking-list: "ブロック"
|
||||||
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
||||||
common/views/components/user-list-editor.vue:
|
common/views/components/user-list-editor.vue:
|
||||||
users: "ユーザー"
|
users: "ユーザー"
|
||||||
@ -1003,6 +1007,7 @@ admin/views/index.vue:
|
|||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
hashtags: "ハッシュタグ"
|
hashtags: "ハッシュタグ"
|
||||||
abuse: "スパム報告"
|
abuse: "スパム報告"
|
||||||
|
queue: "ジョブキュー"
|
||||||
back-to-misskey: "Misskeyに戻る"
|
back-to-misskey: "Misskeyに戻る"
|
||||||
admin/views/dashboard.vue:
|
admin/views/dashboard.vue:
|
||||||
dashboard: "ダッシュボード"
|
dashboard: "ダッシュボード"
|
||||||
@ -1012,6 +1017,9 @@ admin/views/dashboard.vue:
|
|||||||
instances: "インスタンス"
|
instances: "インスタンス"
|
||||||
this-instance: "このインスタンス"
|
this-instance: "このインスタンス"
|
||||||
federated: "連合"
|
federated: "連合"
|
||||||
|
admin/views/queue.vue:
|
||||||
|
operation: "操作"
|
||||||
|
remove-all-jobs: "すべてのジョブをクリア"
|
||||||
admin/views/abuse.vue:
|
admin/views/abuse.vue:
|
||||||
title: "スパム報告"
|
title: "スパム報告"
|
||||||
target: "対象"
|
target: "対象"
|
||||||
|
@ -558,7 +558,11 @@ common/views/components/profile-editor.vue:
|
|||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
||||||
export: "エクスポート"
|
export: "エクスポート"
|
||||||
export-notes: "すべての投稿のエクスポート"
|
export-targets:
|
||||||
|
all-notes: "すべての投稿データ"
|
||||||
|
following-list: "フォロー"
|
||||||
|
mute-list: "ミュート"
|
||||||
|
blocking-list: "ブロック"
|
||||||
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
||||||
|
|
||||||
common/views/components/user-list-editor.vue:
|
common/views/components/user-list-editor.vue:
|
||||||
@ -1367,6 +1371,32 @@ admin/views/announcements.vue:
|
|||||||
admin/views/hashtags.vue:
|
admin/views/hashtags.vue:
|
||||||
hided-tags: "Hidden Tags"
|
hided-tags: "Hidden Tags"
|
||||||
|
|
||||||
|
admin/views/federation.vue:
|
||||||
|
federation: "連合"
|
||||||
|
host: "ホスト"
|
||||||
|
notes: "投稿"
|
||||||
|
users: "ユーザー"
|
||||||
|
following: "フォロー中"
|
||||||
|
followers: "フォロワー"
|
||||||
|
status: "ステータス"
|
||||||
|
latest-request-sent-at: "直近のリクエスト送信"
|
||||||
|
latest-request-received-at: "直近のリクエスト受信"
|
||||||
|
lookup: "照会"
|
||||||
|
instances: "インスタンス"
|
||||||
|
instance-not-registered: "そのインスタンスは登録されていません"
|
||||||
|
sort: "ソート"
|
||||||
|
sorts:
|
||||||
|
caughtAtAsc: "登録日時が古い順"
|
||||||
|
caughtAtDesc: "登録日時が新しい順"
|
||||||
|
notesAsc: "投稿が少ない順"
|
||||||
|
notesDesc: "投稿が多い順"
|
||||||
|
usersAsc: "ユーザーが少ない順"
|
||||||
|
usersDesc: "ユーザーが多い順"
|
||||||
|
followingAsc: "フォローが少ない順"
|
||||||
|
followingDesc: "フォローが多い順"
|
||||||
|
followersAsc: "フォロワーが少ない順"
|
||||||
|
followersDesc: "フォロワーが多い順"
|
||||||
|
|
||||||
desktop/views/pages/welcome.vue:
|
desktop/views/pages/welcome.vue:
|
||||||
about: "詳しく..."
|
about: "詳しく..."
|
||||||
gotit: "わかった"
|
gotit: "わかった"
|
||||||
|
@ -510,7 +510,11 @@ common/views/components/profile-editor.vue:
|
|||||||
email-verified: "このメールアドレスOKや!"
|
email-verified: "このメールアドレスOKや!"
|
||||||
email-not-verified: "メールアドレスが確認されとらん。メールボックスもっぺん見てくれへん?"
|
email-not-verified: "メールアドレスが確認されとらん。メールボックスもっぺん見てくれへん?"
|
||||||
export: "エクスポート"
|
export: "エクスポート"
|
||||||
export-notes: "すべての投稿のエクスポート"
|
export-targets:
|
||||||
|
all-notes: "すべての投稿データ"
|
||||||
|
following-list: "フォロー"
|
||||||
|
mute-list: "ミュート"
|
||||||
|
blocking-list: "ブロック"
|
||||||
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
||||||
common/views/components/user-list-editor.vue:
|
common/views/components/user-list-editor.vue:
|
||||||
users: "ユーザー"
|
users: "ユーザー"
|
||||||
@ -1003,6 +1007,7 @@ admin/views/index.vue:
|
|||||||
announcements: "知っといてや"
|
announcements: "知っといてや"
|
||||||
hashtags: "ハッシュタグ"
|
hashtags: "ハッシュタグ"
|
||||||
abuse: "スパム報告"
|
abuse: "スパム報告"
|
||||||
|
queue: "ジョブキュー"
|
||||||
back-to-misskey: "Misskeyに戻る"
|
back-to-misskey: "Misskeyに戻る"
|
||||||
admin/views/dashboard.vue:
|
admin/views/dashboard.vue:
|
||||||
dashboard: "ダッシュボード"
|
dashboard: "ダッシュボード"
|
||||||
@ -1012,6 +1017,9 @@ admin/views/dashboard.vue:
|
|||||||
instances: "インスタンス"
|
instances: "インスタンス"
|
||||||
this-instance: "ワイのインスタンス"
|
this-instance: "ワイのインスタンス"
|
||||||
federated: "連合"
|
federated: "連合"
|
||||||
|
admin/views/queue.vue:
|
||||||
|
operation: "操作"
|
||||||
|
remove-all-jobs: "すべてのジョブをクリア"
|
||||||
admin/views/abuse.vue:
|
admin/views/abuse.vue:
|
||||||
title: "スパム報告"
|
title: "スパム報告"
|
||||||
target: "対象"
|
target: "対象"
|
||||||
|
@ -510,7 +510,11 @@ common/views/components/profile-editor.vue:
|
|||||||
email-verified: "매일 주소가 확인되었습니다"
|
email-verified: "매일 주소가 확인되었습니다"
|
||||||
email-not-verified: "메일 주소가 확인되지 않았습니다. 받은 편지함을 확인하여 주시기 바랍니다."
|
email-not-verified: "메일 주소가 확인되지 않았습니다. 받은 편지함을 확인하여 주시기 바랍니다."
|
||||||
export: "エクスポート"
|
export: "エクスポート"
|
||||||
export-notes: "すべての投稿のエクスポート"
|
export-targets:
|
||||||
|
all-notes: "すべての投稿データ"
|
||||||
|
following-list: "フォロー"
|
||||||
|
mute-list: "ミュート"
|
||||||
|
blocking-list: "ブロック"
|
||||||
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
||||||
common/views/components/user-list-editor.vue:
|
common/views/components/user-list-editor.vue:
|
||||||
users: "사용자"
|
users: "사용자"
|
||||||
@ -1003,6 +1007,7 @@ admin/views/index.vue:
|
|||||||
announcements: "공지사항"
|
announcements: "공지사항"
|
||||||
hashtags: "해시태그"
|
hashtags: "해시태그"
|
||||||
abuse: "스팸 신고"
|
abuse: "스팸 신고"
|
||||||
|
queue: "ジョブキュー"
|
||||||
back-to-misskey: "Misskey로 돌아가기"
|
back-to-misskey: "Misskey로 돌아가기"
|
||||||
admin/views/dashboard.vue:
|
admin/views/dashboard.vue:
|
||||||
dashboard: "대시보드"
|
dashboard: "대시보드"
|
||||||
@ -1012,6 +1017,9 @@ admin/views/dashboard.vue:
|
|||||||
instances: "인스턴스"
|
instances: "인스턴스"
|
||||||
this-instance: "이 인스턴스"
|
this-instance: "이 인스턴스"
|
||||||
federated: "연합"
|
federated: "연합"
|
||||||
|
admin/views/queue.vue:
|
||||||
|
operation: "操作"
|
||||||
|
remove-all-jobs: "すべてのジョブをクリア"
|
||||||
admin/views/abuse.vue:
|
admin/views/abuse.vue:
|
||||||
title: "스팸 신고"
|
title: "스팸 신고"
|
||||||
target: "대상"
|
target: "대상"
|
||||||
|
@ -510,7 +510,11 @@ common/views/components/profile-editor.vue:
|
|||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
||||||
export: "エクスポート"
|
export: "エクスポート"
|
||||||
export-notes: "すべての投稿のエクスポート"
|
export-targets:
|
||||||
|
all-notes: "すべての投稿データ"
|
||||||
|
following-list: "フォロー"
|
||||||
|
mute-list: "ミュート"
|
||||||
|
blocking-list: "ブロック"
|
||||||
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
||||||
common/views/components/user-list-editor.vue:
|
common/views/components/user-list-editor.vue:
|
||||||
users: "ユーザー"
|
users: "ユーザー"
|
||||||
@ -1003,6 +1007,7 @@ admin/views/index.vue:
|
|||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
hashtags: "ハッシュタグ"
|
hashtags: "ハッシュタグ"
|
||||||
abuse: "スパム報告"
|
abuse: "スパム報告"
|
||||||
|
queue: "ジョブキュー"
|
||||||
back-to-misskey: "Misskeyに戻る"
|
back-to-misskey: "Misskeyに戻る"
|
||||||
admin/views/dashboard.vue:
|
admin/views/dashboard.vue:
|
||||||
dashboard: "ダッシュボード"
|
dashboard: "ダッシュボード"
|
||||||
@ -1012,6 +1017,9 @@ admin/views/dashboard.vue:
|
|||||||
instances: "インスタンス"
|
instances: "インスタンス"
|
||||||
this-instance: "このインスタンス"
|
this-instance: "このインスタンス"
|
||||||
federated: "連合"
|
federated: "連合"
|
||||||
|
admin/views/queue.vue:
|
||||||
|
operation: "操作"
|
||||||
|
remove-all-jobs: "すべてのジョブをクリア"
|
||||||
admin/views/abuse.vue:
|
admin/views/abuse.vue:
|
||||||
title: "スパム報告"
|
title: "スパム報告"
|
||||||
target: "対象"
|
target: "対象"
|
||||||
|
@ -510,7 +510,11 @@ common/views/components/profile-editor.vue:
|
|||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
||||||
export: "エクスポート"
|
export: "エクスポート"
|
||||||
export-notes: "すべての投稿のエクスポート"
|
export-targets:
|
||||||
|
all-notes: "すべての投稿データ"
|
||||||
|
following-list: "フォロー"
|
||||||
|
mute-list: "ミュート"
|
||||||
|
blocking-list: "ブロック"
|
||||||
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
||||||
common/views/components/user-list-editor.vue:
|
common/views/components/user-list-editor.vue:
|
||||||
users: "ユーザー"
|
users: "ユーザー"
|
||||||
@ -1003,6 +1007,7 @@ admin/views/index.vue:
|
|||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
hashtags: "ハッシュタグ"
|
hashtags: "ハッシュタグ"
|
||||||
abuse: "スパム報告"
|
abuse: "スパム報告"
|
||||||
|
queue: "ジョブキュー"
|
||||||
back-to-misskey: "Misskeyに戻る"
|
back-to-misskey: "Misskeyに戻る"
|
||||||
admin/views/dashboard.vue:
|
admin/views/dashboard.vue:
|
||||||
dashboard: "ダッシュボード"
|
dashboard: "ダッシュボード"
|
||||||
@ -1012,6 +1017,9 @@ admin/views/dashboard.vue:
|
|||||||
instances: "インスタンス"
|
instances: "インスタンス"
|
||||||
this-instance: "このインスタンス"
|
this-instance: "このインスタンス"
|
||||||
federated: "連合"
|
federated: "連合"
|
||||||
|
admin/views/queue.vue:
|
||||||
|
operation: "操作"
|
||||||
|
remove-all-jobs: "すべてのジョブをクリア"
|
||||||
admin/views/abuse.vue:
|
admin/views/abuse.vue:
|
||||||
title: "スパム報告"
|
title: "スパム報告"
|
||||||
target: "対象"
|
target: "対象"
|
||||||
|
@ -510,7 +510,11 @@ common/views/components/profile-editor.vue:
|
|||||||
email-verified: "Twój adres e-mail został zweryfikowany."
|
email-verified: "Twój adres e-mail został zweryfikowany."
|
||||||
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
||||||
export: "エクスポート"
|
export: "エクスポート"
|
||||||
export-notes: "すべての投稿のエクスポート"
|
export-targets:
|
||||||
|
all-notes: "すべての投稿データ"
|
||||||
|
following-list: "フォロー"
|
||||||
|
mute-list: "ミュート"
|
||||||
|
blocking-list: "ブロック"
|
||||||
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
||||||
common/views/components/user-list-editor.vue:
|
common/views/components/user-list-editor.vue:
|
||||||
users: "Użytkownicy"
|
users: "Użytkownicy"
|
||||||
@ -1003,6 +1007,7 @@ admin/views/index.vue:
|
|||||||
announcements: "Ogłoszenia"
|
announcements: "Ogłoszenia"
|
||||||
hashtags: "Hashtagi"
|
hashtags: "Hashtagi"
|
||||||
abuse: "スパム報告"
|
abuse: "スパム報告"
|
||||||
|
queue: "ジョブキュー"
|
||||||
back-to-misskey: "Misskeyに戻る"
|
back-to-misskey: "Misskeyに戻る"
|
||||||
admin/views/dashboard.vue:
|
admin/views/dashboard.vue:
|
||||||
dashboard: "ダッシュボード"
|
dashboard: "ダッシュボード"
|
||||||
@ -1012,6 +1017,9 @@ admin/views/dashboard.vue:
|
|||||||
instances: "インスタンス"
|
instances: "インスタンス"
|
||||||
this-instance: "このインスタンス"
|
this-instance: "このインスタンス"
|
||||||
federated: "連合"
|
federated: "連合"
|
||||||
|
admin/views/queue.vue:
|
||||||
|
operation: "操作"
|
||||||
|
remove-all-jobs: "すべてのジョブをクリア"
|
||||||
admin/views/abuse.vue:
|
admin/views/abuse.vue:
|
||||||
title: "スパム報告"
|
title: "スパム報告"
|
||||||
target: "対象"
|
target: "対象"
|
||||||
|
@ -510,7 +510,11 @@ common/views/components/profile-editor.vue:
|
|||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
||||||
export: "エクスポート"
|
export: "エクスポート"
|
||||||
export-notes: "すべての投稿のエクスポート"
|
export-targets:
|
||||||
|
all-notes: "すべての投稿データ"
|
||||||
|
following-list: "フォロー"
|
||||||
|
mute-list: "ミュート"
|
||||||
|
blocking-list: "ブロック"
|
||||||
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
||||||
common/views/components/user-list-editor.vue:
|
common/views/components/user-list-editor.vue:
|
||||||
users: "ユーザー"
|
users: "ユーザー"
|
||||||
@ -1003,6 +1007,7 @@ admin/views/index.vue:
|
|||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
hashtags: "ハッシュタグ"
|
hashtags: "ハッシュタグ"
|
||||||
abuse: "スパム報告"
|
abuse: "スパム報告"
|
||||||
|
queue: "ジョブキュー"
|
||||||
back-to-misskey: "Misskeyに戻る"
|
back-to-misskey: "Misskeyに戻る"
|
||||||
admin/views/dashboard.vue:
|
admin/views/dashboard.vue:
|
||||||
dashboard: "ダッシュボード"
|
dashboard: "ダッシュボード"
|
||||||
@ -1012,6 +1017,9 @@ admin/views/dashboard.vue:
|
|||||||
instances: "インスタンス"
|
instances: "インスタンス"
|
||||||
this-instance: "このインスタンス"
|
this-instance: "このインスタンス"
|
||||||
federated: "連合"
|
federated: "連合"
|
||||||
|
admin/views/queue.vue:
|
||||||
|
operation: "操作"
|
||||||
|
remove-all-jobs: "すべてのジョブをクリア"
|
||||||
admin/views/abuse.vue:
|
admin/views/abuse.vue:
|
||||||
title: "スパム報告"
|
title: "スパム報告"
|
||||||
target: "対象"
|
target: "対象"
|
||||||
|
@ -510,7 +510,11 @@ common/views/components/profile-editor.vue:
|
|||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
||||||
export: "エクスポート"
|
export: "エクスポート"
|
||||||
export-notes: "すべての投稿のエクスポート"
|
export-targets:
|
||||||
|
all-notes: "すべての投稿データ"
|
||||||
|
following-list: "フォロー"
|
||||||
|
mute-list: "ミュート"
|
||||||
|
blocking-list: "ブロック"
|
||||||
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
||||||
common/views/components/user-list-editor.vue:
|
common/views/components/user-list-editor.vue:
|
||||||
users: "ユーザー"
|
users: "ユーザー"
|
||||||
@ -1003,6 +1007,7 @@ admin/views/index.vue:
|
|||||||
announcements: "お知らせ"
|
announcements: "お知らせ"
|
||||||
hashtags: "ハッシュタグ"
|
hashtags: "ハッシュタグ"
|
||||||
abuse: "スパム報告"
|
abuse: "スパム報告"
|
||||||
|
queue: "ジョブキュー"
|
||||||
back-to-misskey: "Misskeyに戻る"
|
back-to-misskey: "Misskeyに戻る"
|
||||||
admin/views/dashboard.vue:
|
admin/views/dashboard.vue:
|
||||||
dashboard: "ダッシュボード"
|
dashboard: "ダッシュボード"
|
||||||
@ -1012,6 +1017,9 @@ admin/views/dashboard.vue:
|
|||||||
instances: "インスタンス"
|
instances: "インスタンス"
|
||||||
this-instance: "このインスタンス"
|
this-instance: "このインスタンス"
|
||||||
federated: "連合"
|
federated: "連合"
|
||||||
|
admin/views/queue.vue:
|
||||||
|
operation: "操作"
|
||||||
|
remove-all-jobs: "すべてのジョブをクリア"
|
||||||
admin/views/abuse.vue:
|
admin/views/abuse.vue:
|
||||||
title: "スパム報告"
|
title: "スパム報告"
|
||||||
target: "対象"
|
target: "対象"
|
||||||
|
@ -510,7 +510,11 @@ common/views/components/profile-editor.vue:
|
|||||||
email-verified: "电子邮件地址已验证"
|
email-verified: "电子邮件地址已验证"
|
||||||
email-not-verified: "邮件地址尚未验证。 请检查您的邮箱。"
|
email-not-verified: "邮件地址尚未验证。 请检查您的邮箱。"
|
||||||
export: "导出"
|
export: "导出"
|
||||||
export-notes: "导出所有帖子"
|
export-targets:
|
||||||
|
all-notes: "すべての投稿データ"
|
||||||
|
following-list: "フォロー"
|
||||||
|
mute-list: "ミュート"
|
||||||
|
blocking-list: "ブロック"
|
||||||
export-requested: "导出请求已提交。可能需要花一些时间。导出的文件将保存到网盘中。"
|
export-requested: "导出请求已提交。可能需要花一些时间。导出的文件将保存到网盘中。"
|
||||||
common/views/components/user-list-editor.vue:
|
common/views/components/user-list-editor.vue:
|
||||||
users: "用户"
|
users: "用户"
|
||||||
@ -1003,6 +1007,7 @@ admin/views/index.vue:
|
|||||||
announcements: "公告"
|
announcements: "公告"
|
||||||
hashtags: "标签"
|
hashtags: "标签"
|
||||||
abuse: "举报垃圾信息"
|
abuse: "举报垃圾信息"
|
||||||
|
queue: "ジョブキュー"
|
||||||
back-to-misskey: "返回 Misskey"
|
back-to-misskey: "返回 Misskey"
|
||||||
admin/views/dashboard.vue:
|
admin/views/dashboard.vue:
|
||||||
dashboard: "Dashboard"
|
dashboard: "Dashboard"
|
||||||
@ -1012,6 +1017,9 @@ admin/views/dashboard.vue:
|
|||||||
instances: "例子"
|
instances: "例子"
|
||||||
this-instance: "此实例"
|
this-instance: "此实例"
|
||||||
federated: "联合"
|
federated: "联合"
|
||||||
|
admin/views/queue.vue:
|
||||||
|
operation: "操作"
|
||||||
|
remove-all-jobs: "すべてのジョブをクリア"
|
||||||
admin/views/abuse.vue:
|
admin/views/abuse.vue:
|
||||||
title: "举报垃圾信息"
|
title: "举报垃圾信息"
|
||||||
target: "目标"
|
target: "目标"
|
||||||
|
14
package.json
14
package.json
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <i@syuilo.com>",
|
"author": "syuilo <i@syuilo.com>",
|
||||||
"version": "10.82.2",
|
"version": "10.82.4",
|
||||||
"clientVersion": "2.0.14142",
|
"clientVersion": "2.0.14193",
|
||||||
"codename": "nighthike",
|
"codename": "nighthike",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -28,7 +28,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "1.2.14",
|
"@fortawesome/fontawesome-svg-core": "1.2.14",
|
||||||
"@fortawesome/free-brands-svg-icons": "5.6.3",
|
"@fortawesome/free-brands-svg-icons": "5.7.1",
|
||||||
"@fortawesome/free-regular-svg-icons": "5.7.0",
|
"@fortawesome/free-regular-svg-icons": "5.7.0",
|
||||||
"@fortawesome/free-solid-svg-icons": "5.6.3",
|
"@fortawesome/free-solid-svg-icons": "5.6.3",
|
||||||
"@fortawesome/vue-fontawesome": "0.1.5",
|
"@fortawesome/vue-fontawesome": "0.1.5",
|
||||||
@ -99,7 +99,7 @@
|
|||||||
"@types/websocket": "0.0.40",
|
"@types/websocket": "0.0.40",
|
||||||
"@types/ws": "6.0.1",
|
"@types/ws": "6.0.1",
|
||||||
"animejs": "3.0.1",
|
"animejs": "3.0.1",
|
||||||
"apexcharts": "3.2.1",
|
"apexcharts": "3.2.2",
|
||||||
"autobind-decorator": "2.4.0",
|
"autobind-decorator": "2.4.0",
|
||||||
"autosize": "4.0.2",
|
"autosize": "4.0.2",
|
||||||
"autwh": "0.1.0",
|
"autwh": "0.1.0",
|
||||||
@ -223,7 +223,7 @@
|
|||||||
"tmp": "0.0.33",
|
"tmp": "0.0.33",
|
||||||
"ts-loader": "5.3.3",
|
"ts-loader": "5.3.3",
|
||||||
"ts-node": "7.0.1",
|
"ts-node": "7.0.1",
|
||||||
"tslint": "5.12.0",
|
"tslint": "5.12.1",
|
||||||
"tslint-sonarts": "1.9.0",
|
"tslint-sonarts": "1.9.0",
|
||||||
"typescript": "3.2.4",
|
"typescript": "3.2.4",
|
||||||
"typescript-eslint-parser": "21.0.2",
|
"typescript-eslint-parser": "21.0.2",
|
||||||
@ -232,7 +232,7 @@
|
|||||||
"uuid": "3.3.2",
|
"uuid": "3.3.2",
|
||||||
"v-animate-css": "0.0.3",
|
"v-animate-css": "0.0.3",
|
||||||
"video-thumbnail-generator": "1.1.3",
|
"video-thumbnail-generator": "1.1.3",
|
||||||
"vue": "2.6.2",
|
"vue": "2.6.3",
|
||||||
"vue-color": "2.7.0",
|
"vue-color": "2.7.0",
|
||||||
"vue-content-loading": "1.5.3",
|
"vue-content-loading": "1.5.3",
|
||||||
"vue-cropperjs": "3.0.0",
|
"vue-cropperjs": "3.0.0",
|
||||||
@ -245,7 +245,7 @@
|
|||||||
"vue-sequential-entrance": "1.1.3",
|
"vue-sequential-entrance": "1.1.3",
|
||||||
"vue-style-loader": "4.1.2",
|
"vue-style-loader": "4.1.2",
|
||||||
"vue-svg-inline-loader": "1.2.10",
|
"vue-svg-inline-loader": "1.2.10",
|
||||||
"vue-template-compiler": "2.6.2",
|
"vue-template-compiler": "2.6.3",
|
||||||
"vuedraggable": "2.17.0",
|
"vuedraggable": "2.17.0",
|
||||||
"vuewordcloud": "18.7.11",
|
"vuewordcloud": "18.7.11",
|
||||||
"vuex": "3.1.0",
|
"vuex": "3.1.0",
|
||||||
|
@ -10,11 +10,12 @@ program
|
|||||||
.option('--only-queue', 'Pocessing job queue only')
|
.option('--only-queue', 'Pocessing job queue only')
|
||||||
.option('--quiet', 'Suppress all logs')
|
.option('--quiet', 'Suppress all logs')
|
||||||
.option('--verbose', 'Enable all logs')
|
.option('--verbose', 'Enable all logs')
|
||||||
|
.option('--with-log-time', 'Include timestamp for each logs')
|
||||||
.option('--slow', 'Delay all requests (for debbuging)')
|
.option('--slow', 'Delay all requests (for debbuging)')
|
||||||
.option('--color', 'This option is a dummy for some external program\'s (e.g. forever) issue.')
|
.option('--color', 'This option is a dummy for some external program\'s (e.g. forever) issue.')
|
||||||
.parse(process.argv);
|
.parse(process.argv);
|
||||||
|
|
||||||
if (process.env.MK_DISABLE_AP_QUEUE) program.disableApQueue = true;
|
/*if (process.env.MK_DISABLE_AP_QUEUE)*/ program.disableApQueue = true;
|
||||||
if (process.env.MK_DISABLE_QUEUE) program.disableQueue = true;
|
if (process.env.MK_DISABLE_QUEUE) program.disableQueue = true;
|
||||||
if (process.env.MK_ONLY_QUEUE) program.onlyQueue = true;
|
if (process.env.MK_ONLY_QUEUE) program.onlyQueue = true;
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ export default Vue.extend({
|
|||||||
this.meta = meta;
|
this.meta = meta;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$root.api('instances', {
|
this.$root.api('federation/instances', {
|
||||||
sort: '+notes'
|
sort: '+notes'
|
||||||
}).then(instances => {
|
}).then(instances => {
|
||||||
for (const i of instances) {
|
for (const i of instances) {
|
||||||
|
170
src/client/app/admin/views/federation.vue
Normal file
170
src/client/app/admin/views/federation.vue
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<ui-card>
|
||||||
|
<div slot="title"><fa :icon="faTerminal"/> {{ $t('federation') }}</div>
|
||||||
|
<section class="fit-top">
|
||||||
|
<ui-input class="target" v-model="target" type="text" @enter="showInstance">
|
||||||
|
<span>{{ $t('host') }}</span>
|
||||||
|
</ui-input>
|
||||||
|
<ui-button @click="showInstance"><fa :icon="faSearch"/> {{ $t('lookup') }}</ui-button>
|
||||||
|
|
||||||
|
<div class="instance" v-if="instance">
|
||||||
|
<ui-input :value="instance.host" type="text" readonly>
|
||||||
|
<span>{{ $t('host') }}</span>
|
||||||
|
</ui-input>
|
||||||
|
<ui-horizon-group inputs>
|
||||||
|
<ui-input :value="instance.notesCount | number" type="text" readonly>
|
||||||
|
<span>{{ $t('notes') }}</span>
|
||||||
|
</ui-input>
|
||||||
|
<ui-input :value="instance.usersCount | number" type="text" readonly>
|
||||||
|
<span>{{ $t('users') }}</span>
|
||||||
|
</ui-input>
|
||||||
|
</ui-horizon-group>
|
||||||
|
<ui-horizon-group inputs>
|
||||||
|
<ui-input :value="instance.followingCount | number" type="text" readonly>
|
||||||
|
<span>{{ $t('following') }}</span>
|
||||||
|
</ui-input>
|
||||||
|
<ui-input :value="instance.followersCount | number" type="text" readonly>
|
||||||
|
<span>{{ $t('followers') }}</span>
|
||||||
|
</ui-input>
|
||||||
|
</ui-horizon-group>
|
||||||
|
<ui-horizon-group inputs>
|
||||||
|
<ui-input :value="instance.latestRequestSentAt" type="text" readonly>
|
||||||
|
<span>{{ $t('latest-request-sent-at') }}</span>
|
||||||
|
</ui-input>
|
||||||
|
<ui-input :value="instance.latestStatus" type="text" readonly>
|
||||||
|
<span>{{ $t('status') }}</span>
|
||||||
|
</ui-input>
|
||||||
|
</ui-horizon-group>
|
||||||
|
<ui-input :value="instance.latestRequestReceivedAt" type="text" readonly>
|
||||||
|
<span>{{ $t('latest-request-received-at') }}</span>
|
||||||
|
</ui-input>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</ui-card>
|
||||||
|
|
||||||
|
<ui-card>
|
||||||
|
<div slot="title"><fa :icon="faUsers"/> {{ $t('instances') }}</div>
|
||||||
|
<section class="fit-top">
|
||||||
|
<ui-horizon-group inputs>
|
||||||
|
<ui-select v-model="sort">
|
||||||
|
<span slot="label">{{ $t('sort') }}</span>
|
||||||
|
<option value="-caughtAt">{{ $t('sorts.caughtAtAsc') }}</option>
|
||||||
|
<option value="+caughtAt">{{ $t('sorts.caughtAtDesc') }}</option>
|
||||||
|
<option value="-notes">{{ $t('sorts.notesAsc') }}</option>
|
||||||
|
<option value="+notes">{{ $t('sorts.notesDesc') }}</option>
|
||||||
|
<option value="-users">{{ $t('sorts.usersAsc') }}</option>
|
||||||
|
<option value="+users">{{ $t('sorts.usersDesc') }}</option>
|
||||||
|
<option value="-following">{{ $t('sorts.followingAsc') }}</option>
|
||||||
|
<option value="+following">{{ $t('sorts.followingDesc') }}</option>
|
||||||
|
<option value="-followers">{{ $t('sorts.followersAsc') }}</option>
|
||||||
|
<option value="+followers">{{ $t('sorts.followersDesc') }}</option>
|
||||||
|
</ui-select>
|
||||||
|
</ui-horizon-group>
|
||||||
|
|
||||||
|
<div class="instances">
|
||||||
|
<header>
|
||||||
|
<span>{{ $t('host') }}</span>
|
||||||
|
<span>{{ $t('notes') }}</span>
|
||||||
|
<span>{{ $t('users') }}</span>
|
||||||
|
<span>{{ $t('following') }}</span>
|
||||||
|
<span>{{ $t('followers') }}</span>
|
||||||
|
<span>{{ $t('status') }}</span>
|
||||||
|
</header>
|
||||||
|
<div v-for="instance in instances">
|
||||||
|
<span>{{ instance.host }}</span>
|
||||||
|
<span>{{ instance.notesCount | number }}</span>
|
||||||
|
<span>{{ instance.usersCount | number }}</span>
|
||||||
|
<span>{{ instance.followingCount | number }}</span>
|
||||||
|
<span>{{ instance.followersCount | number }}</span>
|
||||||
|
<span>{{ instance.latestStatus }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</ui-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
import i18n from '../../i18n';
|
||||||
|
import { faGlobe, faTerminal, faSearch } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
i18n: i18n('admin/views/federation.vue'),
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
instance: null,
|
||||||
|
target: null,
|
||||||
|
sort: '+caughtAt',
|
||||||
|
limit: 50,
|
||||||
|
instances: [],
|
||||||
|
faGlobe, faTerminal, faSearch
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
sort() {
|
||||||
|
this.instances = [];
|
||||||
|
this.fetchInstances();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.fetchInstances();
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
showInstance() {
|
||||||
|
this.$root.api('federation/show-instance', {
|
||||||
|
host: this.target
|
||||||
|
}).then(instance => {
|
||||||
|
if (instance == null) {
|
||||||
|
this.$root.dialog({
|
||||||
|
type: 'error',
|
||||||
|
text: this.$t('instance-not-registered')
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.instance = instance;
|
||||||
|
this.target = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchInstances() {
|
||||||
|
this.$root.api('federation/instances', {
|
||||||
|
sort: this.sort
|
||||||
|
}).then(instances => {
|
||||||
|
this.instances = instances;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.target
|
||||||
|
margin-bottom 16px !important
|
||||||
|
|
||||||
|
.instances
|
||||||
|
width 100%
|
||||||
|
|
||||||
|
> header
|
||||||
|
display flex
|
||||||
|
|
||||||
|
> *
|
||||||
|
color var(--text)
|
||||||
|
font-weight bold
|
||||||
|
|
||||||
|
> div
|
||||||
|
display flex
|
||||||
|
|
||||||
|
> * > *
|
||||||
|
flex 1
|
||||||
|
overflow auto
|
||||||
|
|
||||||
|
&:first-child
|
||||||
|
min-width 200px
|
||||||
|
|
||||||
|
</style>
|
@ -24,7 +24,7 @@
|
|||||||
<li @click="nav('moderators')" :class="{ active: page == 'moderators' }"><fa :icon="faHeadset" fixed-width/>{{ $t('moderators') }}</li>
|
<li @click="nav('moderators')" :class="{ active: page == 'moderators' }"><fa :icon="faHeadset" fixed-width/>{{ $t('moderators') }}</li>
|
||||||
<li @click="nav('users')" :class="{ active: page == 'users' }"><fa icon="users" fixed-width/>{{ $t('users') }}</li>
|
<li @click="nav('users')" :class="{ active: page == 'users' }"><fa icon="users" fixed-width/>{{ $t('users') }}</li>
|
||||||
<li @click="nav('drive')" :class="{ active: page == 'drive' }"><fa icon="cloud" fixed-width/>{{ $t('@.drive') }}</li>
|
<li @click="nav('drive')" :class="{ active: page == 'drive' }"><fa icon="cloud" fixed-width/>{{ $t('@.drive') }}</li>
|
||||||
<!-- <li @click="nav('federation')" :class="{ active: page == 'federation' }"><fa :icon="faShareAlt" fixed-width/>{{ $t('federation') }}</li> -->
|
<li @click="nav('federation')" :class="{ active: page == 'federation' }"><fa :icon="faGlobe" fixed-width/>{{ $t('federation') }}</li>
|
||||||
<li @click="nav('emoji')" :class="{ active: page == 'emoji' }"><fa :icon="faGrin" fixed-width/>{{ $t('emoji') }}</li>
|
<li @click="nav('emoji')" :class="{ active: page == 'emoji' }"><fa :icon="faGrin" fixed-width/>{{ $t('emoji') }}</li>
|
||||||
<li @click="nav('announcements')" :class="{ active: page == 'announcements' }"><fa icon="broadcast-tower" fixed-width/>{{ $t('announcements') }}</li>
|
<li @click="nav('announcements')" :class="{ active: page == 'announcements' }"><fa icon="broadcast-tower" fixed-width/>{{ $t('announcements') }}</li>
|
||||||
<li @click="nav('hashtags')" :class="{ active: page == 'hashtags' }"><fa icon="hashtag" fixed-width/>{{ $t('hashtags') }}</li>
|
<li @click="nav('hashtags')" :class="{ active: page == 'hashtags' }"><fa icon="hashtag" fixed-width/>{{ $t('hashtags') }}</li>
|
||||||
@ -48,6 +48,7 @@
|
|||||||
<div v-if="page == 'announcements'"><x-announcements/></div>
|
<div v-if="page == 'announcements'"><x-announcements/></div>
|
||||||
<div v-if="page == 'hashtags'"><x-hashtags/></div>
|
<div v-if="page == 'hashtags'"><x-hashtags/></div>
|
||||||
<div v-if="page == 'drive'"><x-drive/></div>
|
<div v-if="page == 'drive'"><x-drive/></div>
|
||||||
|
<div v-if="page == 'federation'"><x-federation/></div>
|
||||||
<div v-if="page == 'abuse'"><x-abuse/></div>
|
<div v-if="page == 'abuse'"><x-abuse/></div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
@ -68,7 +69,9 @@ import XHashtags from "./hashtags.vue";
|
|||||||
import XUsers from "./users.vue";
|
import XUsers from "./users.vue";
|
||||||
import XDrive from "./drive.vue";
|
import XDrive from "./drive.vue";
|
||||||
import XAbuse from "./abuse.vue";
|
import XAbuse from "./abuse.vue";
|
||||||
import { faHeadset, faArrowLeft, faShareAlt, faExclamationCircle, faTasks } from '@fortawesome/free-solid-svg-icons';
|
import XFederation from "./federation.vue";
|
||||||
|
|
||||||
|
import { faHeadset, faArrowLeft, faGlobe, faExclamationCircle, faTasks } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faGrin } from '@fortawesome/free-regular-svg-icons';
|
import { faGrin } from '@fortawesome/free-regular-svg-icons';
|
||||||
|
|
||||||
// Detect the user agent
|
// Detect the user agent
|
||||||
@ -88,6 +91,7 @@ export default Vue.extend({
|
|||||||
XUsers,
|
XUsers,
|
||||||
XDrive,
|
XDrive,
|
||||||
XAbuse,
|
XAbuse,
|
||||||
|
XFederation,
|
||||||
},
|
},
|
||||||
provide: {
|
provide: {
|
||||||
isMobile
|
isMobile
|
||||||
@ -101,7 +105,7 @@ export default Vue.extend({
|
|||||||
faGrin,
|
faGrin,
|
||||||
faArrowLeft,
|
faArrowLeft,
|
||||||
faHeadset,
|
faHeadset,
|
||||||
faShareAlt,
|
faGlobe,
|
||||||
faExclamationCircle,
|
faExclamationCircle,
|
||||||
faTasks
|
faTasks
|
||||||
};
|
};
|
||||||
|
@ -420,7 +420,7 @@ export default Vue.extend({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> [data-icon]
|
> [data-icon]
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
@ -92,7 +92,13 @@
|
|||||||
<header>{{ $t('export') }}</header>
|
<header>{{ $t('export') }}</header>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<ui-button @click="exportNotes()">{{ $t('export-notes') }}</ui-button>
|
<ui-select v-model="exportTarget">
|
||||||
|
<option value="notes">{{ $t('export-targets.all-notes') }}</option>
|
||||||
|
<option value="following">{{ $t('export-targets.following-list') }}</option>
|
||||||
|
<option value="mute">{{ $t('export-targets.mute-list') }}</option>
|
||||||
|
<option value="blocking">{{ $t('export-targets.blocking-list') }}</option>
|
||||||
|
</ui-select>
|
||||||
|
<ui-button @click="doExport()"><fa :icon="faDownload"/> {{ $t('export') }}</ui-button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</ui-card>
|
</ui-card>
|
||||||
@ -105,6 +111,7 @@ import { apiUrl, host } from '../../../config';
|
|||||||
import { toUnicode } from 'punycode';
|
import { toUnicode } from 'punycode';
|
||||||
import langmap from 'langmap';
|
import langmap from 'langmap';
|
||||||
import { unique } from '../../../../../prelude/array';
|
import { unique } from '../../../../../prelude/array';
|
||||||
|
import { faDownload } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
i18n: i18n('common/views/components/profile-editor.vue'),
|
i18n: i18n('common/views/components/profile-editor.vue'),
|
||||||
@ -131,7 +138,9 @@ export default Vue.extend({
|
|||||||
autoAcceptFollowed: false,
|
autoAcceptFollowed: false,
|
||||||
saving: false,
|
saving: false,
|
||||||
avatarUploading: false,
|
avatarUploading: false,
|
||||||
bannerUploading: false
|
bannerUploading: false,
|
||||||
|
exportTarget: 'notes',
|
||||||
|
faDownload
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -262,8 +271,13 @@ export default Vue.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
exportNotes() {
|
doExport() {
|
||||||
this.$root.api('i/export-notes', {});
|
this.$root.api(
|
||||||
|
this.exportTarget == 'notes' ? 'i/export-notes' :
|
||||||
|
this.exportTarget == 'following' ? 'i/export-following' :
|
||||||
|
this.exportTarget == 'mute' ? 'i/export-mute' :
|
||||||
|
this.exportTarget == 'blocking' ? 'i/export-blocking' :
|
||||||
|
null, {});
|
||||||
|
|
||||||
this.$root.dialog({
|
this.$root.dialog({
|
||||||
type: 'info',
|
type: 'info',
|
||||||
|
@ -0,0 +1,147 @@
|
|||||||
|
<template>
|
||||||
|
<span
|
||||||
|
class="reaction"
|
||||||
|
:class="{ reacted: note.myReaction == reaction }"
|
||||||
|
@click="toggleReaction(reaction)"
|
||||||
|
v-if="count > 0"
|
||||||
|
v-particle="!isMe"
|
||||||
|
>
|
||||||
|
<mk-reaction-icon :reaction="reaction" ref="icon"/>
|
||||||
|
<span>{{ count }}</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
import Icon from './reaction-icon.vue';
|
||||||
|
import anime from 'animejs';
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
props: {
|
||||||
|
reaction: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
count: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
note: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
canToggle: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isMe(): boolean {
|
||||||
|
return this.$store.getters.isSignedIn && this.$store.state.i.id === this.note.userId;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
count() {
|
||||||
|
this.anime();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggleReaction() {
|
||||||
|
if (this.isMe) return;
|
||||||
|
if (!this.canToggle) return;
|
||||||
|
|
||||||
|
const oldReaction = this.note.myReaction;
|
||||||
|
if (oldReaction) {
|
||||||
|
this.$root.api('notes/reactions/delete', {
|
||||||
|
noteId: this.note.id
|
||||||
|
}).then(() => {
|
||||||
|
if (oldReaction !== this.reaction) {
|
||||||
|
this.$root.api('notes/reactions/create', {
|
||||||
|
noteId: this.note.id,
|
||||||
|
reaction: this.reaction
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.$root.api('notes/reactions/create', {
|
||||||
|
noteId: this.note.id,
|
||||||
|
reaction: this.reaction
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
anime() {
|
||||||
|
if (this.$store.state.device.reduceMotion) return;
|
||||||
|
if (document.hidden) return;
|
||||||
|
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const rect = this.$refs.icon.$el.getBoundingClientRect();
|
||||||
|
|
||||||
|
const x = rect.left;
|
||||||
|
const y = rect.top;
|
||||||
|
|
||||||
|
const icon = new Icon({
|
||||||
|
parent: this,
|
||||||
|
propsData: {
|
||||||
|
reaction: this.reaction
|
||||||
|
}
|
||||||
|
}).$mount();
|
||||||
|
|
||||||
|
icon.$el.style.position = 'absolute';
|
||||||
|
icon.$el.style.zIndex = 100;
|
||||||
|
icon.$el.style.top = (y + window.scrollY) + 'px';
|
||||||
|
icon.$el.style.left = (x + window.scrollX) + 'px';
|
||||||
|
icon.$el.style.fontSize = window.getComputedStyle(this.$refs.icon.$el).fontSize;
|
||||||
|
|
||||||
|
document.body.appendChild(icon.$el);
|
||||||
|
|
||||||
|
anime({
|
||||||
|
targets: icon.$el,
|
||||||
|
opacity: [1, 0],
|
||||||
|
translateY: [0, -64],
|
||||||
|
duration: 1000,
|
||||||
|
easing: 'linear',
|
||||||
|
complete: () => {
|
||||||
|
icon.destroyDom();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.reaction
|
||||||
|
display inline-block
|
||||||
|
height 32px
|
||||||
|
margin 2px
|
||||||
|
padding 0 6px
|
||||||
|
border-radius 4px
|
||||||
|
cursor pointer
|
||||||
|
|
||||||
|
*
|
||||||
|
user-select none
|
||||||
|
pointer-events none
|
||||||
|
|
||||||
|
&.reacted
|
||||||
|
background var(--primary)
|
||||||
|
|
||||||
|
> span
|
||||||
|
color var(--primaryForeground)
|
||||||
|
|
||||||
|
&:not(.reacted)
|
||||||
|
background var(--reactionViewerButtonBg)
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
background var(--reactionViewerButtonHoverBg)
|
||||||
|
|
||||||
|
> .mk-reaction-icon
|
||||||
|
font-size 1.4em
|
||||||
|
|
||||||
|
> span
|
||||||
|
font-size 1.1em
|
||||||
|
line-height 32px
|
||||||
|
vertical-align middle
|
||||||
|
color var(--text)
|
||||||
|
</style>
|
@ -1,139 +1,37 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mk-reactions-viewer" :class="{ isMe }">
|
<div class="mk-reactions-viewer" :class="{ isMe }">
|
||||||
<template v-if="reactions">
|
<x-reaction v-for="(count, reaction) in reactions" :reaction="reaction" :count="count" :note="note" :key="reaction"/>
|
||||||
<span :class="{ reacted: note.myReaction == 'like' }" @click="toggleReaction('like')" v-if="reactions.like" v-particle="!isMe"><mk-reaction-icon reaction="like" ref="like"/><span>{{ reactions.like }}</span></span>
|
|
||||||
<span :class="{ reacted: note.myReaction == 'love' }" @click="toggleReaction('love')" v-if="reactions.love" v-particle="!isMe"><mk-reaction-icon reaction="love" ref="love"/><span>{{ reactions.love }}</span></span>
|
|
||||||
<span :class="{ reacted: note.myReaction == 'laugh' }" @click="toggleReaction('laugh')" v-if="reactions.laugh" v-particle="!isMe"><mk-reaction-icon reaction="laugh" ref="laugh"/><span>{{ reactions.laugh }}</span></span>
|
|
||||||
<span :class="{ reacted: note.myReaction == 'hmm' }" @click="toggleReaction('hmm')" v-if="reactions.hmm" v-particle="!isMe"><mk-reaction-icon reaction="hmm" ref="hmm"/><span>{{ reactions.hmm }}</span></span>
|
|
||||||
<span :class="{ reacted: note.myReaction == 'surprise' }" @click="toggleReaction('surprise')" v-if="reactions.surprise" v-particle="!isMe"><mk-reaction-icon reaction="surprise" ref="surprise"/><span>{{ reactions.surprise }}</span></span>
|
|
||||||
<span :class="{ reacted: note.myReaction == 'congrats' }" @click="toggleReaction('congrats')" v-if="reactions.congrats" v-particle="!isMe"><mk-reaction-icon reaction="congrats" ref="congrats"/><span>{{ reactions.congrats }}</span></span>
|
|
||||||
<span :class="{ reacted: note.myReaction == 'angry' }" @click="toggleReaction('angry')" v-if="reactions.angry" v-particle="!isMe"><mk-reaction-icon reaction="angry" ref="angry"/><span>{{ reactions.angry }}</span></span>
|
|
||||||
<span :class="{ reacted: note.myReaction == 'confused' }" @click="toggleReaction('confused')" v-if="reactions.confused" v-particle="!isMe"><mk-reaction-icon reaction="confused" ref="confused"/><span>{{ reactions.confused }}</span></span>
|
|
||||||
<span :class="{ reacted: note.myReaction == 'rip' }" @click="toggleReaction('rip')" v-if="reactions.rip" v-particle="!isMe"><mk-reaction-icon reaction="rip" ref="rip"/><span>{{ reactions.rip }}</span></span>
|
|
||||||
<span :class="{ reacted: note.myReaction == 'pudding' }" @click="toggleReaction('pudding')" v-if="reactions.pudding" v-particle="!isMe"><mk-reaction-icon reaction="pudding" ref="pudding"/><span>{{ reactions.pudding }}</span></span>
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import Icon from './reaction-icon.vue';
|
import XReaction from './reactions-viewer.reaction.vue';
|
||||||
import anime from 'animejs';
|
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
|
components: {
|
||||||
|
XReaction
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
note: {
|
note: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
reactions(): any {
|
reactions(): any {
|
||||||
return this.note.reactionCounts;
|
return this.note.reactionCounts;
|
||||||
},
|
},
|
||||||
isMe(): boolean {
|
isMe(): boolean {
|
||||||
return this.$store.getters.isSignedIn && (this.$store.state.i.id === this.note.userId);
|
return this.$store.getters.isSignedIn && this.$store.state.i.id === this.note.userId;
|
||||||
}
|
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
'reactions.like'() {
|
|
||||||
this.anime('like');
|
|
||||||
},
|
},
|
||||||
'reactions.love'() {
|
|
||||||
this.anime('love');
|
|
||||||
},
|
|
||||||
'reactions.laugh'() {
|
|
||||||
this.anime('laugh');
|
|
||||||
},
|
|
||||||
'reactions.hmm'() {
|
|
||||||
this.anime('hmm');
|
|
||||||
},
|
|
||||||
'reactions.surprise'() {
|
|
||||||
this.anime('surprise');
|
|
||||||
},
|
|
||||||
'reactions.congrats'() {
|
|
||||||
this.anime('congrats');
|
|
||||||
},
|
|
||||||
'reactions.angry'() {
|
|
||||||
this.anime('angry');
|
|
||||||
},
|
|
||||||
'reactions.confused'() {
|
|
||||||
this.anime('confused');
|
|
||||||
},
|
|
||||||
'reactions.rip'() {
|
|
||||||
this.anime('rip');
|
|
||||||
},
|
|
||||||
'reactions.pudding'() {
|
|
||||||
this.anime('pudding');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
toggleReaction(reaction: string) {
|
|
||||||
if (this.isMe) return;
|
|
||||||
|
|
||||||
const oldReaction = this.note.myReaction;
|
|
||||||
if (oldReaction) {
|
|
||||||
this.$root.api('notes/reactions/delete', {
|
|
||||||
noteId: this.note.id
|
|
||||||
}).then(() => {
|
|
||||||
if (oldReaction !== reaction) {
|
|
||||||
this.$root.api('notes/reactions/create', {
|
|
||||||
noteId: this.note.id,
|
|
||||||
reaction: reaction
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.$root.api('notes/reactions/create', {
|
|
||||||
noteId: this.note.id,
|
|
||||||
reaction: reaction
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
anime(reaction: string) {
|
|
||||||
if (this.$store.state.device.reduceMotion) return;
|
|
||||||
if (document.hidden) return;
|
|
||||||
|
|
||||||
this.$nextTick(() => {
|
|
||||||
const rect = this.$refs[reaction].$el.getBoundingClientRect();
|
|
||||||
|
|
||||||
const x = rect.left;
|
|
||||||
const y = rect.top;
|
|
||||||
|
|
||||||
const icon = new Icon({
|
|
||||||
parent: this,
|
|
||||||
propsData: {
|
|
||||||
reaction: reaction
|
|
||||||
}
|
|
||||||
}).$mount();
|
|
||||||
|
|
||||||
icon.$el.style.position = 'absolute';
|
|
||||||
icon.$el.style.zIndex = 100;
|
|
||||||
icon.$el.style.top = (y + window.scrollY) + 'px';
|
|
||||||
icon.$el.style.left = (x + window.scrollX) + 'px';
|
|
||||||
icon.$el.style.fontSize = window.getComputedStyle(this.$refs[reaction].$el).fontSize;
|
|
||||||
|
|
||||||
document.body.appendChild(icon.$el);
|
|
||||||
|
|
||||||
anime({
|
|
||||||
targets: icon.$el,
|
|
||||||
opacity: [1, 0],
|
|
||||||
translateY: [0, -64],
|
|
||||||
duration: 1000,
|
|
||||||
easing: 'linear',
|
|
||||||
complete: () => {
|
|
||||||
icon.destroyDom();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
.mk-reactions-viewer
|
.mk-reactions-viewer
|
||||||
margin 6px 0
|
margin: 4px -2px
|
||||||
|
|
||||||
&:empty
|
&:empty
|
||||||
display none
|
display none
|
||||||
@ -144,38 +42,4 @@ export default Vue.extend({
|
|||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
background var(--reactionViewerButtonBg) !important
|
background var(--reactionViewerButtonBg) !important
|
||||||
|
|
||||||
> span
|
|
||||||
display inline-block
|
|
||||||
height 32px
|
|
||||||
margin-right 6px
|
|
||||||
padding 0 6px
|
|
||||||
border-radius 4px
|
|
||||||
cursor pointer
|
|
||||||
|
|
||||||
*
|
|
||||||
user-select none
|
|
||||||
pointer-events none
|
|
||||||
|
|
||||||
&.reacted
|
|
||||||
background var(--primary)
|
|
||||||
|
|
||||||
> span
|
|
||||||
color var(--primaryForeground)
|
|
||||||
|
|
||||||
&:not(.reacted)
|
|
||||||
background var(--reactionViewerButtonBg)
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
background var(--reactionViewerButtonHoverBg)
|
|
||||||
|
|
||||||
> .mk-reaction-icon
|
|
||||||
font-size 1.4em
|
|
||||||
|
|
||||||
> span
|
|
||||||
font-size 1.1em
|
|
||||||
line-height 32px
|
|
||||||
vertical-align middle
|
|
||||||
color var(--text)
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -74,7 +74,7 @@ export default Vue.extend({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> [data-icon]
|
> [data-icon]
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
@ -117,7 +117,7 @@ export default define({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> [data-icon]
|
> [data-icon]
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
@ -86,7 +86,7 @@ export default define({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> [data-icon]
|
> [data-icon]
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
@ -88,7 +88,7 @@ export default define({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> [data-icon]
|
> [data-icon]
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
@ -12,7 +12,7 @@ export const hostname = address.hostname;
|
|||||||
export const url = address.origin;
|
export const url = address.origin;
|
||||||
export const apiUrl = url + '/api';
|
export const apiUrl = url + '/api';
|
||||||
export const wsUrl = url.replace('http://', 'ws://').replace('https://', 'wss://') + '/streaming';
|
export const wsUrl = url.replace('http://', 'ws://').replace('https://', 'wss://') + '/streaming';
|
||||||
export const lang = localStorage.getItem('lang');
|
export const lang = localStorage.getItem('lang') || window.lang; // windowは後方互換性のため
|
||||||
export const langs = _LANGS_;
|
export const langs = _LANGS_;
|
||||||
export const locale = JSON.parse(localStorage.getItem('locale'));
|
export const locale = JSON.parse(localStorage.getItem('locale'));
|
||||||
export const copyright = _COPYRIGHT_;
|
export const copyright = _COPYRIGHT_;
|
||||||
|
@ -78,7 +78,7 @@ export default Vue.extend({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> [data-icon]
|
> [data-icon]
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
@ -120,13 +120,13 @@ export default Vue.extend({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> .fetching
|
> .fetching
|
||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> [data-icon]
|
> [data-icon]
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
@ -598,6 +598,7 @@ export default Vue.extend({
|
|||||||
padding 16px 0 0 0
|
padding 16px 0 0 0
|
||||||
overflow auto
|
overflow auto
|
||||||
z-index 1
|
z-index 1
|
||||||
|
font-size 15px
|
||||||
|
|
||||||
&.inWindow
|
&.inWindow
|
||||||
box-shadow var(--shadowRight)
|
box-shadow var(--shadowRight)
|
||||||
|
@ -218,6 +218,6 @@ export default Vue.extend({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -74,7 +74,7 @@ export default Vue.extend({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> i
|
> i
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
@ -66,7 +66,7 @@ export default Vue.extend({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> i
|
> i
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
@ -98,7 +98,7 @@ export default Vue.extend({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> i
|
> i
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
@ -132,7 +132,7 @@ export default Vue.extend({
|
|||||||
padding 0 12px
|
padding 0 12px
|
||||||
text-align center
|
text-align center
|
||||||
font-size 0.8em
|
font-size 0.8em
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> .instance
|
> .instance
|
||||||
box-shadow var(--shadow)
|
box-shadow var(--shadow)
|
||||||
|
@ -92,13 +92,13 @@ export default define({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> .fetching
|
> .fetching
|
||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> [data-icon]
|
> [data-icon]
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
@ -89,13 +89,13 @@ export default define({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> .fetching
|
> .fetching
|
||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> [data-icon]
|
> [data-icon]
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
@ -129,13 +129,13 @@ export default define({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> .fetching
|
> .fetching
|
||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> [data-icon]
|
> [data-icon]
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
@ -83,13 +83,13 @@ export default Vue.extend({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> .fetching
|
> .fetching
|
||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> [data-icon]
|
> [data-icon]
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
@ -88,6 +88,6 @@ export default Vue.extend({
|
|||||||
> .mk-time
|
> .mk-time
|
||||||
display inline-block
|
display inline-block
|
||||||
padding 8px
|
padding 8px
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -184,7 +184,7 @@ export default Vue.extend({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> .placeholder
|
> .placeholder
|
||||||
padding 16px
|
padding 16px
|
||||||
|
@ -171,6 +171,7 @@ export default Vue.extend({
|
|||||||
overflow auto
|
overflow auto
|
||||||
-webkit-overflow-scrolling touch
|
-webkit-overflow-scrolling touch
|
||||||
background var(--secondary)
|
background var(--secondary)
|
||||||
|
font-size 15px
|
||||||
|
|
||||||
.me
|
.me
|
||||||
display block
|
display block
|
||||||
|
@ -121,13 +121,13 @@ export default Vue.extend({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> .fetching
|
> .fetching
|
||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> [data-icon]
|
> [data-icon]
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
@ -57,7 +57,7 @@ export default Vue.extend({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> i
|
> i
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
@ -48,7 +48,7 @@ export default Vue.extend({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> i
|
> i
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
@ -52,7 +52,7 @@ export default Vue.extend({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> i
|
> i
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
@ -89,7 +89,7 @@ export default Vue.extend({
|
|||||||
margin 0
|
margin 0
|
||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
color #aaa
|
color var(--text)
|
||||||
|
|
||||||
> i
|
> i
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
@ -23,6 +23,7 @@ export const colorfulTheme: Theme = require('../theme/colorful.json5');
|
|||||||
export const rainyTheme: Theme = require('../theme/rainy.json5');
|
export const rainyTheme: Theme = require('../theme/rainy.json5');
|
||||||
export const mauveTheme: Theme = require('../theme/mauve.json5');
|
export const mauveTheme: Theme = require('../theme/mauve.json5');
|
||||||
export const grayTheme: Theme = require('../theme/gray.json5');
|
export const grayTheme: Theme = require('../theme/gray.json5');
|
||||||
|
export const tweetDeckTheme: Theme = require('../theme/tweet-deck.json5');
|
||||||
|
|
||||||
export const builtinThemes = [
|
export const builtinThemes = [
|
||||||
lightTheme,
|
lightTheme,
|
||||||
@ -38,6 +39,7 @@ export const builtinThemes = [
|
|||||||
rainyTheme,
|
rainyTheme,
|
||||||
mauveTheme,
|
mauveTheme,
|
||||||
grayTheme,
|
grayTheme,
|
||||||
|
tweetDeckTheme,
|
||||||
];
|
];
|
||||||
|
|
||||||
export function applyTheme(theme: Theme, persisted = true) {
|
export function applyTheme(theme: Theme, persisted = true) {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
id: '2b0a0654-cdb4-4c9a-8244-736b647d3c2a',
|
id: '2b0a0654-cdb4-4c9a-8244-736b647d3c2a',
|
||||||
|
|
||||||
name: 'Japanese Sushi Set',
|
name: 'Japanese Sushi Set',
|
||||||
author: 'noizenecio & syuilo',
|
author: 'Noizenecio',
|
||||||
|
|
||||||
base: 'dark',
|
base: 'dark',
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
id: '252b2caf-86c2-4c3f-a73f-e1fc1cfa5298',
|
id: '252b2caf-86c2-4c3f-a73f-e1fc1cfa5298',
|
||||||
|
|
||||||
name: 'Mauve',
|
name: 'Mauve',
|
||||||
author: 'とわこ & syuilo',
|
author: 'とわこ',
|
||||||
|
|
||||||
base: 'dark',
|
base: 'dark',
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
id: 'e9c8c01d-9c15-48d0-9b5c-3d00843b5b36',
|
id: 'e9c8c01d-9c15-48d0-9b5c-3d00843b5b36',
|
||||||
|
|
||||||
name: 'Lavender',
|
name: 'Lavender',
|
||||||
author: 'sokuyuku & syuilo',
|
author: 'sokuyuku',
|
||||||
|
|
||||||
base: 'light',
|
base: 'light',
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
name: 'Rainy',
|
name: 'Rainy',
|
||||||
author: 'syuilo',
|
author: 'syuilo',
|
||||||
|
desc: 'It\'s a rainy day.',
|
||||||
|
|
||||||
base: 'light',
|
base: 'light',
|
||||||
|
|
||||||
|
44
src/client/theme/tweet-deck.json5
Normal file
44
src/client/theme/tweet-deck.json5
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
name: 'Tweet Deck',
|
||||||
|
id: '06f82fb4-0dad-4d70-8a3f-56cae91e1163',
|
||||||
|
author: 'simirall',
|
||||||
|
desc: 'Tweet like a pro.',
|
||||||
|
base: 'dark',
|
||||||
|
vars: {
|
||||||
|
primary: '#1da1f2',
|
||||||
|
secondary: '#15202b',
|
||||||
|
text: '#fdfdfd',
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
bg: '#10171e',
|
||||||
|
faceHeader: '$secondary',
|
||||||
|
faceTextButton: '$primary',
|
||||||
|
renoteGradient: '$secondary',
|
||||||
|
renoteText: '#17bf63',
|
||||||
|
quoteBorder: '#38444d',
|
||||||
|
noteHeaderAdminFg: '$primary',
|
||||||
|
noteHeaderAdminBg: '$secondary',
|
||||||
|
noteActionsReplyHover: '$primary',
|
||||||
|
noteActionsRenoteHover: '#17bf63',
|
||||||
|
noteActionsReactionHover: '#e0245e',
|
||||||
|
calendarWeek: '$primary',
|
||||||
|
calendarSaturdayOrSunday: '#e0245e',
|
||||||
|
announcementsBg: '$secondary',
|
||||||
|
announcementsTitle: '$primary',
|
||||||
|
suspendedInfoBg: '$secondary',
|
||||||
|
suspendedInfoFg: '$primary',
|
||||||
|
remoteInfoBg: '$secondary',
|
||||||
|
remoteInfoFg: '#$primary',
|
||||||
|
desktopHeaderBg: '#1c2938',
|
||||||
|
desktopHeaderFg: '#a9adae',
|
||||||
|
desktopHeaderHoverFg: '#fff',
|
||||||
|
desktopPostFormTransparentButtonFg: '#a9adae',
|
||||||
|
desktopTimelineSrc: '$primary',
|
||||||
|
desktopTimelineSrcHover: '#fff',
|
||||||
|
deckAcrylicColumnBg: 'rgba(0, 0, 0, 0.0)',
|
||||||
|
reversiBannerGradientStart: '$primary',
|
||||||
|
reversiBannerGradientEnd: '$primary',
|
||||||
|
reversiGameEmptyCellMyTurn: ':lighten<5<$primary',
|
||||||
|
reversiGameEmptyCellCanPut: ':lighten<4<$primary',
|
||||||
|
},
|
||||||
|
}
|
@ -26,6 +26,7 @@ export default function load() {
|
|||||||
const mixin = {} as Mixin;
|
const mixin = {} as Mixin;
|
||||||
|
|
||||||
const url = validateUrl(config.url);
|
const url = validateUrl(config.url);
|
||||||
|
|
||||||
config.url = normalizeUrl(config.url);
|
config.url = normalizeUrl(config.url);
|
||||||
|
|
||||||
mixin.host = url.host;
|
mixin.host = url.host;
|
||||||
|
@ -26,7 +26,7 @@ import { showMachineInfo } from './misc/show-machine-info';
|
|||||||
|
|
||||||
const logger = new Logger('core', 'cyan');
|
const logger = new Logger('core', 'cyan');
|
||||||
const bootLogger = logger.createSubLogger('boot', 'magenta');
|
const bootLogger = logger.createSubLogger('boot', 'magenta');
|
||||||
const clusterLog = logger.createSubLogger('cluster', 'orange');
|
const clusterLogger = logger.createSubLogger('cluster', 'orange');
|
||||||
const ev = new Xev();
|
const ev = new Xev();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -249,19 +249,19 @@ function spawnWorker(): Promise<void> {
|
|||||||
|
|
||||||
// Listen new workers
|
// Listen new workers
|
||||||
cluster.on('fork', worker => {
|
cluster.on('fork', worker => {
|
||||||
clusterLog.debug(`Process forked: [${worker.id}]`);
|
clusterLogger.debug(`Process forked: [${worker.id}]`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen online workers
|
// Listen online workers
|
||||||
cluster.on('online', worker => {
|
cluster.on('online', worker => {
|
||||||
clusterLog.debug(`Process is now online: [${worker.id}]`);
|
clusterLogger.debug(`Process is now online: [${worker.id}]`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen for dying workers
|
// Listen for dying workers
|
||||||
cluster.on('exit', worker => {
|
cluster.on('exit', worker => {
|
||||||
// Replace the dead worker,
|
// Replace the dead worker,
|
||||||
// we're not sentimental
|
// we're not sentimental
|
||||||
clusterLog.error(chalk.red(`[${worker.id}] died :(`));
|
clusterLogger.error(chalk.red(`[${worker.id}] died :(`));
|
||||||
cluster.fork();
|
cluster.fork();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -28,7 +28,8 @@ export default class Logger {
|
|||||||
} else {
|
} else {
|
||||||
const time = dateformat(new Date(), 'HH:MM:ss');
|
const time = dateformat(new Date(), 'HH:MM:ss');
|
||||||
const process = cluster.isMaster ? '*' : cluster.worker.id;
|
const process = cluster.isMaster ? '*' : cluster.worker.id;
|
||||||
const log = `${chalk.gray(time)} ${level} ${process}\t[${domains.join(' ')}]\t${message}`;
|
let log = `${level} ${process}\t[${domains.join(' ')}]\t${message}`;
|
||||||
|
if (program.withLogTime) log = chalk.gray(time) + ' ' + log;
|
||||||
console.log(important ? chalk.bold(log) : log);
|
console.log(important ? chalk.bold(log) : log);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,4 +32,29 @@ export interface IInstance {
|
|||||||
* このインスタンスから受け取った投稿数
|
* このインスタンスから受け取った投稿数
|
||||||
*/
|
*/
|
||||||
notesCount: number;
|
notesCount: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* このインスタンスのユーザーからフォローされている、自インスタンスのユーザーの数
|
||||||
|
*/
|
||||||
|
followingCount: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* このインスタンスのユーザーをフォローしている、自インスタンスのユーザーの数
|
||||||
|
*/
|
||||||
|
followersCount: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 直近のリクエスト送信日時
|
||||||
|
*/
|
||||||
|
latestRequestSentAt?: Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 直近のリクエスト送信時のHTTPステータスコード
|
||||||
|
*/
|
||||||
|
latestStatus?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 直近のリクエスト受信日時
|
||||||
|
*/
|
||||||
|
latestRequestReceivedAt?: Date;
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,36 @@ export function createExportNotesJob(user: ILocalUser) {
|
|||||||
.save();
|
.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createExportFollowingJob(user: ILocalUser) {
|
||||||
|
if (!queueAvailable) throw 'queue unavailable';
|
||||||
|
|
||||||
|
return queue.createJob({
|
||||||
|
type: 'exportFollowing',
|
||||||
|
user: user
|
||||||
|
})
|
||||||
|
.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createExportMuteJob(user: ILocalUser) {
|
||||||
|
if (!queueAvailable) throw 'queue unavailable';
|
||||||
|
|
||||||
|
return queue.createJob({
|
||||||
|
type: 'exportMute',
|
||||||
|
user: user
|
||||||
|
})
|
||||||
|
.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createExportBlockingJob(user: ILocalUser) {
|
||||||
|
if (!queueAvailable) throw 'queue unavailable';
|
||||||
|
|
||||||
|
return queue.createJob({
|
||||||
|
type: 'exportBlocking',
|
||||||
|
user: user
|
||||||
|
})
|
||||||
|
.save();
|
||||||
|
}
|
||||||
|
|
||||||
export default function() {
|
export default function() {
|
||||||
if (queueAvailable && enableQueue) {
|
if (queueAvailable && enableQueue) {
|
||||||
queue.process(128, handler);
|
queue.process(128, handler);
|
||||||
|
89
src/queue/processors/export-blocking.ts
Normal file
89
src/queue/processors/export-blocking.ts
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import * as bq from 'bee-queue';
|
||||||
|
import * as tmp from 'tmp';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as mongo from 'mongodb';
|
||||||
|
|
||||||
|
import { queueLogger } from '../logger';
|
||||||
|
import addFile from '../../services/drive/add-file';
|
||||||
|
import User from '../../models/user';
|
||||||
|
import dateFormat = require('dateformat');
|
||||||
|
import Blocking from '../../models/blocking';
|
||||||
|
import config from '../../config';
|
||||||
|
|
||||||
|
const logger = queueLogger.createSubLogger('export-blocking');
|
||||||
|
|
||||||
|
export async function exportBlocking(job: bq.Job, done: any): Promise<void> {
|
||||||
|
logger.info(`Exporting blocking of ${job.data.user._id} ...`);
|
||||||
|
|
||||||
|
const user = await User.findOne({
|
||||||
|
_id: new mongo.ObjectID(job.data.user._id.toString())
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create temp file
|
||||||
|
const [path, cleanup] = await new Promise<[string, any]>((res, rej) => {
|
||||||
|
tmp.file((e, path, fd, cleanup) => {
|
||||||
|
if (e) return rej(e);
|
||||||
|
res([path, cleanup]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.info(`Temp file is ${path}`);
|
||||||
|
|
||||||
|
const stream = fs.createWriteStream(path, { flags: 'a' });
|
||||||
|
|
||||||
|
let exportedCount = 0;
|
||||||
|
let ended = false;
|
||||||
|
let cursor: any = null;
|
||||||
|
|
||||||
|
while (!ended) {
|
||||||
|
const blockings = await Blocking.find({
|
||||||
|
blockerId: user._id,
|
||||||
|
...(cursor ? { _id: { $gt: cursor } } : {})
|
||||||
|
}, {
|
||||||
|
limit: 100,
|
||||||
|
sort: {
|
||||||
|
_id: 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (blockings.length === 0) {
|
||||||
|
ended = true;
|
||||||
|
job.reportProgress(100);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = blockings[blockings.length - 1]._id;
|
||||||
|
|
||||||
|
for (const block of blockings) {
|
||||||
|
const u = await User.findOne({ _id: block.blockeeId }, { fields: { username: true, host: true } });
|
||||||
|
const content = u.host ? `${u.username}@${u.host}` : `${u.username}@${config.host}`;
|
||||||
|
await new Promise((res, rej) => {
|
||||||
|
stream.write(content + '\n', err => {
|
||||||
|
if (err) {
|
||||||
|
logger.error(err);
|
||||||
|
rej(err);
|
||||||
|
} else {
|
||||||
|
res();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
exportedCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const total = await Blocking.count({
|
||||||
|
blockerId: user._id,
|
||||||
|
});
|
||||||
|
|
||||||
|
job.reportProgress(exportedCount / total);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.end();
|
||||||
|
logger.succ(`Exported to: ${path}`);
|
||||||
|
|
||||||
|
const fileName = 'blocking-' + dateFormat(new Date(), 'yyyy-mm-dd-HH-MM-ss') + '.csv';
|
||||||
|
const driveFile = await addFile(user, path, fileName);
|
||||||
|
|
||||||
|
logger.succ(`Exported to: ${driveFile._id}`);
|
||||||
|
cleanup();
|
||||||
|
done();
|
||||||
|
}
|
89
src/queue/processors/export-following.ts
Normal file
89
src/queue/processors/export-following.ts
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import * as bq from 'bee-queue';
|
||||||
|
import * as tmp from 'tmp';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as mongo from 'mongodb';
|
||||||
|
|
||||||
|
import { queueLogger } from '../logger';
|
||||||
|
import addFile from '../../services/drive/add-file';
|
||||||
|
import User from '../../models/user';
|
||||||
|
import dateFormat = require('dateformat');
|
||||||
|
import Following from '../../models/following';
|
||||||
|
import config from '../../config';
|
||||||
|
|
||||||
|
const logger = queueLogger.createSubLogger('export-following');
|
||||||
|
|
||||||
|
export async function exportFollowing(job: bq.Job, done: any): Promise<void> {
|
||||||
|
logger.info(`Exporting following of ${job.data.user._id} ...`);
|
||||||
|
|
||||||
|
const user = await User.findOne({
|
||||||
|
_id: new mongo.ObjectID(job.data.user._id.toString())
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create temp file
|
||||||
|
const [path, cleanup] = await new Promise<[string, any]>((res, rej) => {
|
||||||
|
tmp.file((e, path, fd, cleanup) => {
|
||||||
|
if (e) return rej(e);
|
||||||
|
res([path, cleanup]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.info(`Temp file is ${path}`);
|
||||||
|
|
||||||
|
const stream = fs.createWriteStream(path, { flags: 'a' });
|
||||||
|
|
||||||
|
let exportedCount = 0;
|
||||||
|
let ended = false;
|
||||||
|
let cursor: any = null;
|
||||||
|
|
||||||
|
while (!ended) {
|
||||||
|
const followings = await Following.find({
|
||||||
|
followerId: user._id,
|
||||||
|
...(cursor ? { _id: { $gt: cursor } } : {})
|
||||||
|
}, {
|
||||||
|
limit: 100,
|
||||||
|
sort: {
|
||||||
|
_id: 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (followings.length === 0) {
|
||||||
|
ended = true;
|
||||||
|
job.reportProgress(100);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = followings[followings.length - 1]._id;
|
||||||
|
|
||||||
|
for (const following of followings) {
|
||||||
|
const u = await User.findOne({ _id: following.followeeId }, { fields: { username: true, host: true } });
|
||||||
|
const content = u.host ? `${u.username}@${u.host}` : `${u.username}@${config.host}`;
|
||||||
|
await new Promise((res, rej) => {
|
||||||
|
stream.write(content + '\n', err => {
|
||||||
|
if (err) {
|
||||||
|
logger.error(err);
|
||||||
|
rej(err);
|
||||||
|
} else {
|
||||||
|
res();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
exportedCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const total = await Following.count({
|
||||||
|
followerId: user._id,
|
||||||
|
});
|
||||||
|
|
||||||
|
job.reportProgress(exportedCount / total);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.end();
|
||||||
|
logger.succ(`Exported to: ${path}`);
|
||||||
|
|
||||||
|
const fileName = 'following-' + dateFormat(new Date(), 'yyyy-mm-dd-HH-MM-ss') + '.csv';
|
||||||
|
const driveFile = await addFile(user, path, fileName);
|
||||||
|
|
||||||
|
logger.succ(`Exported to: ${driveFile._id}`);
|
||||||
|
cleanup();
|
||||||
|
done();
|
||||||
|
}
|
89
src/queue/processors/export-mute.ts
Normal file
89
src/queue/processors/export-mute.ts
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import * as bq from 'bee-queue';
|
||||||
|
import * as tmp from 'tmp';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as mongo from 'mongodb';
|
||||||
|
|
||||||
|
import { queueLogger } from '../logger';
|
||||||
|
import addFile from '../../services/drive/add-file';
|
||||||
|
import User from '../../models/user';
|
||||||
|
import dateFormat = require('dateformat');
|
||||||
|
import Mute from '../../models/mute';
|
||||||
|
import config from '../../config';
|
||||||
|
|
||||||
|
const logger = queueLogger.createSubLogger('export-mute');
|
||||||
|
|
||||||
|
export async function exportMute(job: bq.Job, done: any): Promise<void> {
|
||||||
|
logger.info(`Exporting mute of ${job.data.user._id} ...`);
|
||||||
|
|
||||||
|
const user = await User.findOne({
|
||||||
|
_id: new mongo.ObjectID(job.data.user._id.toString())
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create temp file
|
||||||
|
const [path, cleanup] = await new Promise<[string, any]>((res, rej) => {
|
||||||
|
tmp.file((e, path, fd, cleanup) => {
|
||||||
|
if (e) return rej(e);
|
||||||
|
res([path, cleanup]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.info(`Temp file is ${path}`);
|
||||||
|
|
||||||
|
const stream = fs.createWriteStream(path, { flags: 'a' });
|
||||||
|
|
||||||
|
let exportedCount = 0;
|
||||||
|
let ended = false;
|
||||||
|
let cursor: any = null;
|
||||||
|
|
||||||
|
while (!ended) {
|
||||||
|
const mutes = await Mute.find({
|
||||||
|
muterId: user._id,
|
||||||
|
...(cursor ? { _id: { $gt: cursor } } : {})
|
||||||
|
}, {
|
||||||
|
limit: 100,
|
||||||
|
sort: {
|
||||||
|
_id: 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (mutes.length === 0) {
|
||||||
|
ended = true;
|
||||||
|
job.reportProgress(100);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = mutes[mutes.length - 1]._id;
|
||||||
|
|
||||||
|
for (const mute of mutes) {
|
||||||
|
const u = await User.findOne({ _id: mute.muteeId }, { fields: { username: true, host: true } });
|
||||||
|
const content = u.host ? `${u.username}@${u.host}` : `${u.username}@${config.host}`;
|
||||||
|
await new Promise((res, rej) => {
|
||||||
|
stream.write(content + '\n', err => {
|
||||||
|
if (err) {
|
||||||
|
logger.error(err);
|
||||||
|
rej(err);
|
||||||
|
} else {
|
||||||
|
res();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
exportedCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const total = await Mute.count({
|
||||||
|
muterId: user._id,
|
||||||
|
});
|
||||||
|
|
||||||
|
job.reportProgress(exportedCount / total);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.end();
|
||||||
|
logger.succ(`Exported to: ${path}`);
|
||||||
|
|
||||||
|
const fileName = 'mute-' + dateFormat(new Date(), 'yyyy-mm-dd-HH-MM-ss') + '.csv';
|
||||||
|
const driveFile = await addFile(user, path, fileName);
|
||||||
|
|
||||||
|
logger.succ(`Exported to: ${driveFile._id}`);
|
||||||
|
cleanup();
|
||||||
|
done();
|
||||||
|
}
|
@ -100,7 +100,7 @@ export async function exportNotes(job: bq.Job, done: any): Promise<void> {
|
|||||||
stream.end();
|
stream.end();
|
||||||
logger.succ(`Exported to: ${path}`);
|
logger.succ(`Exported to: ${path}`);
|
||||||
|
|
||||||
const fileName = dateFormat(new Date(), 'yyyy-mm-dd-HH-MM-ss') + '.json';
|
const fileName = 'notes-' + dateFormat(new Date(), 'yyyy-mm-dd-HH-MM-ss') + '.json';
|
||||||
const driveFile = await addFile(user, path, fileName);
|
const driveFile = await addFile(user, path, fileName);
|
||||||
|
|
||||||
logger.succ(`Exported to: ${driveFile._id}`);
|
logger.succ(`Exported to: ${driveFile._id}`);
|
||||||
|
@ -2,19 +2,43 @@ import * as bq from 'bee-queue';
|
|||||||
|
|
||||||
import request from '../../../remote/activitypub/request';
|
import request from '../../../remote/activitypub/request';
|
||||||
import { queueLogger } from '../../logger';
|
import { queueLogger } from '../../logger';
|
||||||
|
import { registerOrFetchInstanceDoc } from '../../../services/register-or-fetch-instance-doc';
|
||||||
|
import Instance from '../../../models/instance';
|
||||||
|
|
||||||
export default async (job: bq.Job, done: any): Promise<void> => {
|
export default async (job: bq.Job, done: any): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
await request(job.data.user, job.data.to, job.data.content);
|
await request(job.data.user, job.data.to, job.data.content);
|
||||||
|
|
||||||
|
// Update stats
|
||||||
|
registerOrFetchInstanceDoc(job.data.user.host).then(i => {
|
||||||
|
Instance.update({ _id: i._id }, {
|
||||||
|
$set: {
|
||||||
|
latestRequestSentAt: new Date(),
|
||||||
|
latestStatus: 200
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
done();
|
done();
|
||||||
} catch (res) {
|
} catch (res) {
|
||||||
|
// Update stats
|
||||||
|
registerOrFetchInstanceDoc(job.data.user.host).then(i => {
|
||||||
|
Instance.update({ _id: i._id }, {
|
||||||
|
$set: {
|
||||||
|
latestRequestSentAt: new Date(),
|
||||||
|
latestStatus: res != null && res.hasOwnProperty('statusCode') ? res.statusCode : null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
if (res != null && res.hasOwnProperty('statusCode')) {
|
if (res != null && res.hasOwnProperty('statusCode')) {
|
||||||
|
queueLogger.warn(`deliver failed: ${res.statusCode} ${res.statusMessage} to=${job.data.to}`);
|
||||||
|
|
||||||
if (res.statusCode >= 400 && res.statusCode < 500) {
|
if (res.statusCode >= 400 && res.statusCode < 500) {
|
||||||
// HTTPステータスコード4xxはクライアントエラーであり、それはつまり
|
// HTTPステータスコード4xxはクライアントエラーであり、それはつまり
|
||||||
// 何回再送しても成功することはないということなのでエラーにはしないでおく
|
// 何回再送しても成功することはないということなのでエラーにはしないでおく
|
||||||
done();
|
done();
|
||||||
} else {
|
} else {
|
||||||
queueLogger.warn(`deliver failed: ${res.statusCode} ${res.statusMessage} to=${job.data.to}`);
|
|
||||||
done(res.statusMessage);
|
done(res.statusMessage);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -8,6 +8,8 @@ import { toUnicode } from 'punycode';
|
|||||||
import { URL } from 'url';
|
import { URL } from 'url';
|
||||||
import { publishApLogStream } from '../../../services/stream';
|
import { publishApLogStream } from '../../../services/stream';
|
||||||
import Logger from '../../../misc/logger';
|
import Logger from '../../../misc/logger';
|
||||||
|
import { registerOrFetchInstanceDoc } from '../../../services/register-or-fetch-instance-doc';
|
||||||
|
import Instance from '../../../models/instance';
|
||||||
|
|
||||||
const logger = new Logger('inbox');
|
const logger = new Logger('inbox');
|
||||||
|
|
||||||
@ -101,6 +103,15 @@ export default async (job: bq.Job, done: any): Promise<void> => {
|
|||||||
});
|
});
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
// Update stats
|
||||||
|
registerOrFetchInstanceDoc(user.host).then(i => {
|
||||||
|
Instance.update({ _id: i._id }, {
|
||||||
|
$set: {
|
||||||
|
latestRequestReceivedAt: new Date()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// アクティビティを処理
|
// アクティビティを処理
|
||||||
try {
|
try {
|
||||||
await perform(user, activity);
|
await perform(user, activity);
|
||||||
|
@ -1,12 +1,18 @@
|
|||||||
import deliver from './http/deliver';
|
import deliver from './http/deliver';
|
||||||
import processInbox from './http/process-inbox';
|
import processInbox from './http/process-inbox';
|
||||||
import { exportNotes } from './export-notes';
|
import { exportNotes } from './export-notes';
|
||||||
|
import { exportFollowing } from './export-following';
|
||||||
|
import { exportMute } from './export-mute';
|
||||||
|
import { exportBlocking } from './export-blocking';
|
||||||
import { queueLogger } from '../logger';
|
import { queueLogger } from '../logger';
|
||||||
|
|
||||||
const handlers: any = {
|
const handlers: any = {
|
||||||
deliver,
|
deliver,
|
||||||
processInbox,
|
processInbox,
|
||||||
exportNotes,
|
exportNotes,
|
||||||
|
exportFollowing,
|
||||||
|
exportMute,
|
||||||
|
exportBlocking,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default (job: any, done: any) => {
|
export default (job: any, done: any) => {
|
||||||
|
@ -12,7 +12,7 @@ import { fromHtml } from '../../../mfm/fromHtml';
|
|||||||
import usersChart from '../../../chart/users';
|
import usersChart from '../../../chart/users';
|
||||||
import { URL } from 'url';
|
import { URL } from 'url';
|
||||||
import { resolveNote, extractEmojis } from './note';
|
import { resolveNote, extractEmojis } from './note';
|
||||||
import registerInstance from '../../../services/register-instance';
|
import { registerOrFetchInstanceDoc } from '../../../services/register-or-fetch-instance-doc';
|
||||||
import Instance from '../../../models/instance';
|
import Instance from '../../../models/instance';
|
||||||
import getDriveFileUrl from '../../../misc/get-drive-file-url';
|
import getDriveFileUrl from '../../../misc/get-drive-file-url';
|
||||||
import { IEmoji } from '../../../models/emoji';
|
import { IEmoji } from '../../../models/emoji';
|
||||||
@ -188,7 +188,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<IU
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register host
|
// Register host
|
||||||
registerInstance(host).then(i => {
|
registerOrFetchInstanceDoc(host).then(i => {
|
||||||
Instance.update({ _id: i._id }, {
|
Instance.update({ _id: i._id }, {
|
||||||
$inc: {
|
$inc: {
|
||||||
usersCount: 1
|
usersCount: 1
|
||||||
|
84
src/server/api/endpoints/federation/instances.ts
Normal file
84
src/server/api/endpoints/federation/instances.ts
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import $ from 'cafy';
|
||||||
|
import define from '../../define';
|
||||||
|
import Instance from '../../../../models/instance';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
requireCredential: false,
|
||||||
|
|
||||||
|
params: {
|
||||||
|
limit: {
|
||||||
|
validator: $.num.optional.range(1, 100),
|
||||||
|
default: 30
|
||||||
|
},
|
||||||
|
|
||||||
|
offset: {
|
||||||
|
validator: $.num.optional.min(0),
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
|
||||||
|
sort: {
|
||||||
|
validator: $.str.optional,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default define(meta, (ps, me) => new Promise(async (res, rej) => {
|
||||||
|
let sort;
|
||||||
|
|
||||||
|
if (ps.sort) {
|
||||||
|
if (ps.sort == '+notes') {
|
||||||
|
sort = {
|
||||||
|
notesCount: -1
|
||||||
|
};
|
||||||
|
} else if (ps.sort == '-notes') {
|
||||||
|
sort = {
|
||||||
|
notesCount: 1
|
||||||
|
};
|
||||||
|
} else if (ps.sort == '+users') {
|
||||||
|
sort = {
|
||||||
|
usersCount: -1
|
||||||
|
};
|
||||||
|
} else if (ps.sort == '-users') {
|
||||||
|
sort = {
|
||||||
|
usersCount: 1
|
||||||
|
};
|
||||||
|
} else if (ps.sort == '+following') {
|
||||||
|
sort = {
|
||||||
|
followingCount: -1
|
||||||
|
};
|
||||||
|
} else if (ps.sort == '-following') {
|
||||||
|
sort = {
|
||||||
|
followingCount: 1
|
||||||
|
};
|
||||||
|
} else if (ps.sort == '+followers') {
|
||||||
|
sort = {
|
||||||
|
followersCount: -1
|
||||||
|
};
|
||||||
|
} else if (ps.sort == '-followers') {
|
||||||
|
sort = {
|
||||||
|
followersCount: 1
|
||||||
|
};
|
||||||
|
} else if (ps.sort == '+caughtAt') {
|
||||||
|
sort = {
|
||||||
|
caughtAt: -1
|
||||||
|
};
|
||||||
|
} else if (ps.sort == '-caughtAt') {
|
||||||
|
sort = {
|
||||||
|
caughtAt: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sort = {
|
||||||
|
_id: -1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const instances = await Instance
|
||||||
|
.find({}, {
|
||||||
|
limit: ps.limit,
|
||||||
|
sort: sort,
|
||||||
|
skip: ps.offset
|
||||||
|
});
|
||||||
|
|
||||||
|
res(instances);
|
||||||
|
}));
|
20
src/server/api/endpoints/federation/show-instance.ts
Normal file
20
src/server/api/endpoints/federation/show-instance.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import $ from 'cafy';
|
||||||
|
import define from '../../define';
|
||||||
|
import Instance from '../../../../models/instance';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
requireCredential: false,
|
||||||
|
|
||||||
|
params: {
|
||||||
|
host: {
|
||||||
|
validator: $.str
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default define(meta, (ps, me) => new Promise(async (res, rej) => {
|
||||||
|
const instance = await Instance
|
||||||
|
.findOne({ host: ps.host });
|
||||||
|
|
||||||
|
res(instance);
|
||||||
|
}));
|
18
src/server/api/endpoints/i/export-blocking.ts
Normal file
18
src/server/api/endpoints/i/export-blocking.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import define from '../../define';
|
||||||
|
import { createExportBlockingJob } from '../../../../queue';
|
||||||
|
import ms = require('ms');
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
secure: true,
|
||||||
|
requireCredential: true,
|
||||||
|
limit: {
|
||||||
|
duration: ms('1hour'),
|
||||||
|
max: 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default define(meta, (ps, user) => new Promise(async (res, rej) => {
|
||||||
|
createExportBlockingJob(user);
|
||||||
|
|
||||||
|
res();
|
||||||
|
}));
|
18
src/server/api/endpoints/i/export-following.ts
Normal file
18
src/server/api/endpoints/i/export-following.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import define from '../../define';
|
||||||
|
import { createExportFollowingJob } from '../../../../queue';
|
||||||
|
import ms = require('ms');
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
secure: true,
|
||||||
|
requireCredential: true,
|
||||||
|
limit: {
|
||||||
|
duration: ms('1hour'),
|
||||||
|
max: 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default define(meta, (ps, user) => new Promise(async (res, rej) => {
|
||||||
|
createExportFollowingJob(user);
|
||||||
|
|
||||||
|
res();
|
||||||
|
}));
|
18
src/server/api/endpoints/i/export-mute.ts
Normal file
18
src/server/api/endpoints/i/export-mute.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import define from '../../define';
|
||||||
|
import { createExportMuteJob } from '../../../../queue';
|
||||||
|
import ms = require('ms');
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
secure: true,
|
||||||
|
requireCredential: true,
|
||||||
|
limit: {
|
||||||
|
duration: ms('1hour'),
|
||||||
|
max: 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default define(meta, (ps, user) => new Promise(async (res, rej) => {
|
||||||
|
createExportMuteJob(user);
|
||||||
|
|
||||||
|
res();
|
||||||
|
}));
|
@ -1,51 +0,0 @@
|
|||||||
import $ from 'cafy';
|
|
||||||
import define from '../define';
|
|
||||||
import Instance from '../../../models/instance';
|
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
requireCredential: false,
|
|
||||||
|
|
||||||
params: {
|
|
||||||
limit: {
|
|
||||||
validator: $.num.optional.range(1, 100),
|
|
||||||
default: 30
|
|
||||||
},
|
|
||||||
|
|
||||||
offset: {
|
|
||||||
validator: $.num.optional.min(0),
|
|
||||||
default: 0
|
|
||||||
},
|
|
||||||
|
|
||||||
sort: {
|
|
||||||
validator: $.str.optional.or('+notes|-notes'),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default define(meta, (ps, me) => new Promise(async (res, rej) => {
|
|
||||||
let _sort;
|
|
||||||
if (ps.sort) {
|
|
||||||
if (ps.sort == '+notes') {
|
|
||||||
_sort = {
|
|
||||||
notesCount: -1
|
|
||||||
};
|
|
||||||
} else if (ps.sort == '-notes') {
|
|
||||||
_sort = {
|
|
||||||
notesCount: 1
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_sort = {
|
|
||||||
_id: -1
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const instances = await Instance
|
|
||||||
.find({}, {
|
|
||||||
limit: ps.limit,
|
|
||||||
sort: _sort,
|
|
||||||
skip: ps.offset
|
|
||||||
});
|
|
||||||
|
|
||||||
res(instances);
|
|
||||||
}));
|
|
@ -143,7 +143,11 @@ router.get('/@:user', async (ctx, next) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
await ctx.render('user', { user });
|
const meta = await fetchMeta();
|
||||||
|
await ctx.render('user', {
|
||||||
|
user,
|
||||||
|
instanceName: meta.name
|
||||||
|
});
|
||||||
ctx.set('Cache-Control', 'public, max-age=180');
|
ctx.set('Cache-Control', 'public, max-age=180');
|
||||||
} else {
|
} else {
|
||||||
// リモートユーザーなので
|
// リモートユーザーなので
|
||||||
@ -179,9 +183,11 @@ router.get('/notes/:note', async ctx => {
|
|||||||
|
|
||||||
if (note) {
|
if (note) {
|
||||||
const _note = await packNote(note);
|
const _note = await packNote(note);
|
||||||
|
const meta = await fetchMeta();
|
||||||
await ctx.render('note', {
|
await ctx.render('note', {
|
||||||
note: _note,
|
note: _note,
|
||||||
summary: getNoteSummary(_note)
|
summary: getNoteSummary(_note),
|
||||||
|
instanceName: meta.name
|
||||||
});
|
});
|
||||||
|
|
||||||
if (['public', 'home'].includes(note.visibility)) {
|
if (['public', 'home'].includes(note.visibility)) {
|
||||||
|
@ -6,7 +6,7 @@ block vars
|
|||||||
- const url = `${config.url}/notes/${note.id}`;
|
- const url = `${config.url}/notes/${note.id}`;
|
||||||
|
|
||||||
block title
|
block title
|
||||||
= `${title} | ${config.name}`
|
= `${title} | ${instanceName}`
|
||||||
|
|
||||||
block desc
|
block desc
|
||||||
meta(name='description' content= summary)
|
meta(name='description' content= summary)
|
||||||
|
@ -6,7 +6,7 @@ block vars
|
|||||||
- const img = user.avatarUrl || null;
|
- const img = user.avatarUrl || null;
|
||||||
|
|
||||||
block title
|
block title
|
||||||
= `${title} | ${config.name}`
|
= `${title} | ${instanceName}`
|
||||||
|
|
||||||
block desc
|
block desc
|
||||||
meta(name='description' content= user.description)
|
meta(name='description' content= user.description)
|
||||||
|
@ -10,6 +10,8 @@ import renderReject from '../../remote/activitypub/renderer/reject';
|
|||||||
import { deliver } from '../../queue';
|
import { deliver } from '../../queue';
|
||||||
import createFollowRequest from './requests/create';
|
import createFollowRequest from './requests/create';
|
||||||
import perUserFollowingChart from '../../chart/per-user-following';
|
import perUserFollowingChart from '../../chart/per-user-following';
|
||||||
|
import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc';
|
||||||
|
import Instance from '../../models/instance';
|
||||||
|
|
||||||
export default async function(follower: IUser, followee: IUser, requestId?: string) {
|
export default async function(follower: IUser, followee: IUser, requestId?: string) {
|
||||||
// check blocking
|
// check blocking
|
||||||
@ -97,6 +99,32 @@ export default async function(follower: IUser, followee: IUser, requestId?: stri
|
|||||||
});
|
});
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
//#region Update instance stats
|
||||||
|
if (isRemoteUser(follower) && isLocalUser(followee)) {
|
||||||
|
registerOrFetchInstanceDoc(follower.host).then(i => {
|
||||||
|
Instance.update({ _id: i._id }, {
|
||||||
|
$inc: {
|
||||||
|
followingCount: 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
//perInstanceChart.newFollowing();
|
||||||
|
});
|
||||||
|
} else if (isLocalUser(follower) && isRemoteUser(followee)) {
|
||||||
|
registerOrFetchInstanceDoc(followee.host).then(i => {
|
||||||
|
Instance.update({ _id: i._id }, {
|
||||||
|
$inc: {
|
||||||
|
followersCount: 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
//perInstanceChart.newFollower();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
perUserFollowingChart.update(follower, followee, true);
|
perUserFollowingChart.update(follower, followee, true);
|
||||||
|
|
||||||
// Publish follow event
|
// Publish follow event
|
||||||
|
@ -27,7 +27,7 @@ import activeUsersChart from '../../chart/active-users';
|
|||||||
|
|
||||||
import { erase, concat } from '../../prelude/array';
|
import { erase, concat } from '../../prelude/array';
|
||||||
import insertNoteUnread from './unread';
|
import insertNoteUnread from './unread';
|
||||||
import registerInstance from '../register-instance';
|
import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc';
|
||||||
import Instance from '../../models/instance';
|
import Instance from '../../models/instance';
|
||||||
import extractMentions from '../../misc/extract-mentions';
|
import extractMentions from '../../misc/extract-mentions';
|
||||||
import extractEmojis from '../../misc/extract-emojis';
|
import extractEmojis from '../../misc/extract-emojis';
|
||||||
@ -222,7 +222,7 @@ export default async (user: IUser, data: Option, silent = false) => new Promise<
|
|||||||
|
|
||||||
// Register host
|
// Register host
|
||||||
if (isRemoteUser(user)) {
|
if (isRemoteUser(user)) {
|
||||||
registerInstance(user.host).then(i => {
|
registerOrFetchInstanceDoc(user.host).then(i => {
|
||||||
Instance.update({ _id: i._id }, {
|
Instance.update({ _id: i._id }, {
|
||||||
$inc: {
|
$inc: {
|
||||||
notesCount: 1
|
notesCount: 1
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import Instance, { IInstance } from '../models/instance';
|
import Instance, { IInstance } from '../models/instance';
|
||||||
import federationChart from '../chart/federation';
|
import federationChart from '../chart/federation';
|
||||||
|
|
||||||
export default async function(host: string): Promise<IInstance> {
|
export async function registerOrFetchInstanceDoc(host: string): Promise<IInstance> {
|
||||||
if (host == null) return null;
|
if (host == null) return null;
|
||||||
|
|
||||||
const index = await Instance.findOne({ host });
|
const index = await Instance.findOne({ host });
|
Reference in New Issue
Block a user