Compare commits
69 Commits
11.0.0-bet
...
11.0.1
Author | SHA1 | Date | |
---|---|---|---|
dd3f7834c3 | |||
f8cf18d880 | |||
2ac7e242b6 | |||
d8b604a94f | |||
a1f7b00981 | |||
b7ee42198c | |||
d66e4b7ff9 | |||
7f9789cf65 | |||
b41c18e033 | |||
3c73a7ec6d | |||
182c09d952 | |||
9fb86aed04 | |||
b8f7b13b05 | |||
1ee1d5b6d1 | |||
154c38c314 | |||
3c0626752a | |||
511ef77fb7 | |||
4df3ede500 | |||
e83c080af8 | |||
054220db70 | |||
97bff010a8 | |||
487a3079cd | |||
2d5158c680 | |||
837be06b72 | |||
7e0d8dd4d7 | |||
146fb23d7d | |||
61455ffe29 | |||
c267baafdc | |||
42248a306a | |||
694ec7ebe1 | |||
e3b3f8fac1 | |||
b390363b25 | |||
f6f8cdbcf2 | |||
f46f53b8a3 | |||
a2fcae4383 | |||
483f043768 | |||
f8e0f4f21f | |||
9c3613e96d | |||
d9cacdc86d | |||
aa3d2deeaa | |||
e64912545a | |||
b247be80cc | |||
343f2f1f33 | |||
2d590df900 | |||
ba56b2b9fd | |||
bf472b0c5e | |||
f7961f34c5 | |||
e369031a28 | |||
186d7bbfd9 | |||
60a11f8da5 | |||
1181fcdceb | |||
8cb9852058 | |||
53d46d1cbe | |||
275e1c8de9 | |||
d46eca4c87 | |||
2927fb1597 | |||
8c72e011d2 | |||
69662e24c3 | |||
96099ffe98 | |||
ae16b45c11 | |||
83b7010d6a | |||
71654cbe47 | |||
e8f96e848a | |||
251abf21d4 | |||
d103427932 | |||
592cdfa910 | |||
f2ad1a0406 | |||
82af9320c0 | |||
fceebf7388 |
@ -65,10 +65,10 @@ db:
|
|||||||
# ┌─────────────────────┐
|
# ┌─────────────────────┐
|
||||||
#───┘ Redis configuration └─────────────────────────────────────
|
#───┘ Redis configuration └─────────────────────────────────────
|
||||||
|
|
||||||
#redis:
|
redis:
|
||||||
# host: localhost
|
host: localhost
|
||||||
# port: 6379
|
port: 6379
|
||||||
# pass: example-pass
|
#pass: example-pass
|
||||||
|
|
||||||
# ┌─────────────────────────────┐
|
# ┌─────────────────────────────┐
|
||||||
#───┘ Elasticsearch configuration └─────────────────────────────
|
#───┘ Elasticsearch configuration └─────────────────────────────
|
||||||
@ -127,28 +127,12 @@ drive:
|
|||||||
# change it according to your preferences.
|
# change it according to your preferences.
|
||||||
|
|
||||||
# Available methods:
|
# Available methods:
|
||||||
# aid1 ... Use AID for ID generation (with random 1 char)
|
# aid ... Short, Millisecond accuracy
|
||||||
# aid2 ... Use AID for ID generation (with random 2 chars)
|
# meid ... Similar to ObjectID, Millisecond accuracy
|
||||||
# aid3 ... Use AID for ID generation (with random 3 chars)
|
# ulid ... Millisecond accuracy
|
||||||
# aid4 ... Use AID for ID generation (with random 4 chars)
|
# objectid ... This is left for backward compatibility
|
||||||
# ulid ... Use ulid for ID generation
|
|
||||||
# objectid ... This is left for backward compatibility.
|
|
||||||
|
|
||||||
# AID(n) is the original ID generation method.
|
id: 'aid'
|
||||||
# The trailing n represents the number of random characters that
|
|
||||||
# will be suffixed.
|
|
||||||
# The larger n is the safer. If n is small, the possibility of
|
|
||||||
# collision at the same time increases, but there are also
|
|
||||||
# advantages such as shortening of the URL.
|
|
||||||
|
|
||||||
# ULID: Universally Unique Lexicographically Sortable Identifier.
|
|
||||||
# for more details: https://github.com/ulid/spec
|
|
||||||
# * Normally, AID should be sufficient.
|
|
||||||
|
|
||||||
# ObjectID is the method used in previous versions of Misskey.
|
|
||||||
# * Choose this if you are migrating from a previous Misskey.
|
|
||||||
|
|
||||||
id: 'aid2'
|
|
||||||
|
|
||||||
# ┌─────────────────────┐
|
# ┌─────────────────────┐
|
||||||
#───┘ Other configuration └─────────────────────────────────────
|
#───┘ Other configuration └─────────────────────────────────────
|
||||||
|
21
CHANGELOG.md
21
CHANGELOG.md
@ -5,10 +5,16 @@ If you encounter any problems with updating, please try the following:
|
|||||||
1. `npm run clean` or `npm run cleanall`
|
1. `npm run clean` or `npm run cleanall`
|
||||||
2. Retry update (Don't forget `npm i`)
|
2. Retry update (Don't forget `npm i`)
|
||||||
|
|
||||||
11.0.0
|
11.0.1 (2019/04/15)
|
||||||
----------
|
-------------------
|
||||||
* データベースがMongoDBからPostgreSQLに変更されました
|
* 不要な依存関係を削除
|
||||||
|
|
||||||
|
11.0.0 daybreak (2019/04/14)
|
||||||
|
----------------------------
|
||||||
|
* **データベースがMongoDBからPostgreSQLに変更されました**
|
||||||
|
* **Redisが必須に**
|
||||||
* アカウントを完全に削除できるように
|
* アカウントを完全に削除できるように
|
||||||
|
* 投稿フォームで添付ファイルの閲覧注意を確認/設定できるように
|
||||||
* ミュート/ブロック時にそのユーザーの投稿のウォッチをすべて解除するように
|
* ミュート/ブロック時にそのユーザーの投稿のウォッチをすべて解除するように
|
||||||
* フォロー申請数が実際より1すくなくなる問題を修正
|
* フォロー申請数が実際より1すくなくなる問題を修正
|
||||||
* リストからアカウント削除したユーザーを削除できない問題を修正
|
* リストからアカウント削除したユーザーを削除できない問題を修正
|
||||||
@ -19,6 +25,15 @@ If you encounter any problems with updating, please try the following:
|
|||||||
### APIの破壊的変更
|
### APIの破壊的変更
|
||||||
* v10時点で deprecated だったパラメータなどを削除
|
* v10時点で deprecated だったパラメータなどを削除
|
||||||
* ユーザーリストの title が name に
|
* ユーザーリストの title が name に
|
||||||
|
* リバーシの対局の`settings`プロパティがなくなり、その中にあったプロパティがすべて上の階層に
|
||||||
|
* 例えば`game.settings.map`は`game.map`になる
|
||||||
|
|
||||||
|
### 既知の問題
|
||||||
|
* ユーザー認証無しでのアプリが作成できない
|
||||||
|
* 依存ライブラリの問題と思わるため、対応が難しい
|
||||||
|
|
||||||
|
### Migration
|
||||||
|
coming soon...
|
||||||
|
|
||||||
10.100.0
|
10.100.0
|
||||||
----------
|
----------
|
||||||
|
45
README.md
45
README.md
@ -101,30 +101,33 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
|||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
<!-- PATREON_START -->
|
<!-- PATREON_START -->
|
||||||
<table><tr>
|
<table><tr>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5888816/36da0f7c15954df0ab13f9abdf227f66/1?token-time=2145916800&token-hash=HGkZJ7s4bSaQVoOJ5q30mTWHTxDLiw1LuyaogKPLy24%3D" alt="Hiroshi Seki" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5888816/36da0f7c15954df0ab13f9abdf227f66/1.jpeg?token-time=2145916800&token-hash=at8QpJXJ8C0zINY_NmoMKv-MhXVoUK-YzTgaJPJzJYU%3D" alt="Hiroshi Seki" width="100"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12190916/fb7fa7983c14425f890369535b1506a4/3?token-time=2145916800&token-hash=gr7DF8BuwflHvNoP24He4aa-5j8_KycrAQe3fHwQIUE%3D" alt="weep" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12190916/fb7fa7983c14425f890369535b1506a4/3.png?token-time=2145916800&token-hash=oH_i7gJjNT7Ot6j9JiVwy7ZJIBqACVnzLqlz4YrDAZA%3D" alt="weep" width="100"></td>
|
||||||
<td><img src="https://c8.patreon.com/2/200/12059069" alt="naga_rus" width="100"></td>
|
<td><img src="https://c8.patreon.com/2/200/12059069" alt="naga_rus" width="100"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12913507/f7181eacafe8469a93033d85f5969c29/4?token-time=2145916800&token-hash=vZdDTTF-ahiKBjjgppS2ev4rkD8H7TTKkXXoxsucs6Y%3D" alt="Melilot" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13099460/43cecdbaa63a40d79bf50a96b9910b9d/1.jpe?token-time=2145916800&token-hash=bqwLTk0Wo0hUJJ8J5y7ii05bLzz-_CDA7Bo0Mp4RFU0%3D" alt="ne_moni" width="100"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5670915/ee175f0bfb6347ffa4ea101a8c097bff/1?token-time=2145916800&token-hash=ubqJzjhBQUo8Nw6h_8jMDlJ5ocIO46EflpiRkp2jIw4%3D" alt="osapon" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12913507/f7181eacafe8469a93033d85f5969c29/4.jpe?token-time=2145916800&token-hash=zEyJqVM7u9d8Ri-65fJYSJcWF1jBH1nJ5a3taRzrTmw%3D" alt="Melilot" width="100"></td>
|
||||||
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5670915/ee175f0bfb6347ffa4ea101a8c097bff/1.jpg?token-time=2145916800&token-hash=mPLM9CA-riFHx-myr3bLZJuH2xBRHA9se5VbHhLIOuA%3D" alt="osapon" width="100"></td>
|
||||||
<td><img src="https://c8.patreon.com/2/200/16869916" alt="見当かなみ" width="100"></td>
|
<td><img src="https://c8.patreon.com/2/200/16869916" alt="見当かなみ" width="100"></td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><a href="https://www.patreon.com/rane_hs">Hiroshi Seki</a></td>
|
<td><a href="https://www.patreon.com/rane_hs">Hiroshi Seki</a></td>
|
||||||
<td><a href="https://www.patreon.com/weepjp">weep</a></td>
|
<td><a href="https://www.patreon.com/weepjp">weep</a></td>
|
||||||
<td><a href="https://www.patreon.com/user?u=12059069">naga_rus</a></td>
|
<td><a href="https://www.patreon.com/user?u=12059069">naga_rus</a></td>
|
||||||
|
<td><a href="https://www.patreon.com/user?u=13099460">ne_moni</a></td>
|
||||||
<td><a href="https://www.patreon.com/user?u=12913507">Melilot</a></td>
|
<td><a href="https://www.patreon.com/user?u=12913507">Melilot</a></td>
|
||||||
<td><a href="https://www.patreon.com/osapon">osapon</a></td>
|
<td><a href="https://www.patreon.com/osapon">osapon</a></td>
|
||||||
<td><a href="https://www.patreon.com/user?u=16869916">見当かなみ</a></td>
|
<td><a href="https://www.patreon.com/user?u=16869916">見当かなみ</a></td>
|
||||||
</tr></table>
|
</tr></table>
|
||||||
<table><tr>
|
<table><tr>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12021162/963128bb8d14476dbd8407943db8f31a/1?token-time=2145916800&token-hash=1FlxS9MEgmNGH_RHUVHbO5hIXB5I1z0lvA33CTvYvjA%3D" alt="gutfuckllc" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12021162/963128bb8d14476dbd8407943db8f31a/1.png?token-time=2145916800&token-hash=FMV7cPKBD1TU2WTbl1jg6AcdKSvTb2BSFcDhgc-EO8w%3D" alt="gutfuckllc" width="100"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/11357794/923ce94cd8c44ba788ee931907881839/1?token-time=2145916800&token-hash=0xgcpqvFDqRcV_YIEhcPNVH7gs9sLg_BBnTJXCkN4ao%3D" alt="mydarkstar" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/11357794/923ce94cd8c44ba788ee931907881839/1.png?token-time=2145916800&token-hash=9nEQje_eMvUjq9a7L3uBqW-MQbS-rRMaMgd7UYVoFNM%3D" alt="mydarkstar" width="100"></td>
|
||||||
<td><img src="https://c8.patreon.com/2/200/12718187" alt="Peter G." width="100"></td>
|
<td><img src="https://c8.patreon.com/2/200/12718187" alt="Peter G." width="100"></td>
|
||||||
<td><img src="https://c8.patreon.com/2/200/18833336" alt="itiradi" width="100"></td>
|
<td><img src="https://c8.patreon.com/2/200/18833336" alt="itiradi" 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.jpe?token-time=2145916800&token-hash=UQRWf01TwHDV4Cls1K0YAOAjM29ssif7hLVq0ESQ0hs%3D" alt="nemu" width="100"></td>
|
||||||
<td><img src="https://c8.patreon.com/2/200/17866454" alt="sikyosyounin" width="100"></td>
|
<td><img src="https://c8.patreon.com/2/200/17866454" alt="sikyosyounin" 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.png?token-time=2145916800&token-hash=KjfQL8nf3AIf6WqzLshBYAyX44piAqOAZiYXgZS_H6A%3D" alt="YUKIMOCHI" width="100"></td>
|
||||||
<td><img src="https://c8.patreon.com/2/200/17463605" alt="Sampot" width="100"></td>
|
<td><img src="https://c8.patreon.com/2/200/17463605" alt="Sampot" width="100"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/17880724/311738c8a48f4a6b9443c2445a75adde/1?token-time=2145916800&token-hash=95p8VdGX45E8BitZR_eOcDlqCjumjzNLBPQJrJdeCpI%3D" alt="takimura" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13737140/1adf7835017d479280d90fe8d30aade2/1.png?token-time=2145916800&token-hash=0pdle8h5pDZrww0BDOjdz6zO-HudeGTh36a3qi1biVU%3D" alt="Satsuki Yanagi" width="100"></td>
|
||||||
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/17880724/311738c8a48f4a6b9443c2445a75adde/1.jpe?token-time=2145916800&token-hash=CPxGQhKIlEaa6WUcgbyHixyKEhakiw9RFdOhsIJBQ_o%3D" alt="takimura" width="100"></td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><a href="https://www.patreon.com/gutfuckllc">gutfuckllc</a></td>
|
<td><a href="https://www.patreon.com/gutfuckllc">gutfuckllc</a></td>
|
||||||
<td><a href="https://www.patreon.com/mydarkstar">mydarkstar</a></td>
|
<td><a href="https://www.patreon.com/mydarkstar">mydarkstar</a></td>
|
||||||
@ -134,18 +137,19 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
|||||||
<td><a href="https://www.patreon.com/user?u=17866454">sikyosyounin</a></td>
|
<td><a href="https://www.patreon.com/user?u=17866454">sikyosyounin</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/user?u=17463605">Sampot</a></td>
|
<td><a href="https://www.patreon.com/user?u=17463605">Sampot</a></td>
|
||||||
|
<td><a href="https://www.patreon.com/user?u=13737140">Satsuki Yanagi</a></td>
|
||||||
<td><a href="https://www.patreon.com/takimura">takimura</a></td>
|
<td><a href="https://www.patreon.com/takimura">takimura</a></td>
|
||||||
</tr></table>
|
</tr></table>
|
||||||
<table><tr>
|
<table><tr>
|
||||||
<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/17195955/be45e5e14c3e48b2bee0456c84e19df4/4.jpe?token-time=2145916800&token-hash=UslrPVM-8TXOe8AapuNiaFYjcIJgPNcU-fKpGbfGJNI%3D" alt="Damillora" width="100"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/16900731/935a10339daa4ede8e555903a0707060/1?token-time=2145916800&token-hash=3CrpqH-XtKs_NoIlSsTyVs8wCzP1WFCsG2xwps1IJq0%3D" alt="Atsuko Tominaga" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/16900731/935a10339daa4ede8e555903a0707060/1.png?token-time=2145916800&token-hash=c1XAS1qGBPxVdCvnICxtAUmx41mVkMG87h7cIRF9YYE%3D" alt="Atsuko Tominaga" width="100"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/4389829/9f709180ac714651a70f74a82f3ffdb9/3?token-time=2145916800&token-hash=-iJszBqgYBhsM5qMdA1knf9wvprhEfESzKfR2oh7mIA%3D" alt="natalie" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/4389829/9f709180ac714651a70f74a82f3ffdb9/3.png?token-time=2145916800&token-hash=FTm3WVom4dJ9NwWMU4OpCL_8Yc13WiwEbKrDPyTZTPs%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.jpe?token-time=2145916800&token-hash=EWxXhVbZYH7KB4IDT3joc8TbIg8zPO40x1r5IDn3R7c%3D" alt="Hiratake" width="100"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/18072312/98e894d960314fa7bc236a72a39488fe/1?token-time=2145916800&token-hash=D6QK3fPyqiYKJfOzc-QqaSSairUrWdjld-ewp2waj6s%3D" alt="Hekovic" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/18072312/98e894d960314fa7bc236a72a39488fe/1.jpe?token-time=2145916800&token-hash=qA8j97lIZNc-74AuZ0p4F3ms6sKPeKjtNt2vEuwpsyo%3D" alt="Hekovic" width="100"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb/1?token-time=2145916800&token-hash=Ksk_2l3gjPDbnzMUOCSW1E-hdPJsNs2tSR4_RAakRK8%3D" alt="dansup" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb/1.jpeg?token-time=2145916800&token-hash=L55UhJ0rcuNAH3w_ryeeGN4hC6taoOixyAhraEi0bzw%3D" alt="dansup" width="100"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/619786/32cf01444db24e578cd1982c197f6fc6/1?token-time=2145916800&token-hash=CXe9AqlZy9AsYfiWd3OBYVOzvODoN47Litz0Tu4BFpU%3D" alt="Gargron" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/619786/32cf01444db24e578cd1982c197f6fc6/1.jpeg?token-time=2145916800&token-hash=d8jBQLMOHD87KtXs5C9fk1o58DMF73pQ-dYH3uZJPBE%3D" alt="Gargron" width="100"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5731881/4b6038e6cda34c04b83a5fcce3806a93/1?token-time=2145916800&token-hash=xhR1n6NAAyEb-IUXLD6_dshkFa3mefU5ZZuk1L8qKTs%3D" alt="Nokotaro Takeda" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5731881/4b6038e6cda34c04b83a5fcce3806a93/1.png?token-time=2145916800&token-hash=hBayGfOmQH3kRMdNnDe4oCZD_9fsJWSt29xXR3KRMVk%3D" alt="Nokotaro Takeda" width="100"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12531784/93a45137841849329ba692da92ac7c60/1?token-time=2145916800&token-hash=uR-48MQ0A4j0irQSrCAQZJ-sJUSs_Fkihlg3-l59b7c%3D" alt="Takashi Shibuya" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12531784/93a45137841849329ba692da92ac7c60/1.jpeg?token-time=2145916800&token-hash=vGe7wXGqmA8Q7m-kDNb6fyGdwk-Dxk4F-ut8ZZu51RM%3D" alt="Takashi Shibuya" width="100"></td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><a href="https://www.patreon.com/damillora">Damillora</a></td>
|
<td><a href="https://www.patreon.com/damillora">Damillora</a></td>
|
||||||
<td><a href="https://www.patreon.com/user?u=16900731">Atsuko Tominaga</a></td>
|
<td><a href="https://www.patreon.com/user?u=16900731">Atsuko Tominaga</a></td>
|
||||||
@ -157,8 +161,11 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
|||||||
<td><a href="https://www.patreon.com/takenoko">Nokotaro Takeda</a></td>
|
<td><a href="https://www.patreon.com/takenoko">Nokotaro Takeda</a></td>
|
||||||
<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>
|
||||||
|
<table><tr>
|
||||||
|
</tr><tr>
|
||||||
|
</tr></table>
|
||||||
|
|
||||||
**Last updated:** Sun, 07 Apr 2019 19:21:08 UTC
|
**Last updated:** Sun, 14 Apr 2019 08:13:12 UTC
|
||||||
<!-- PATREON_END -->
|
<!-- PATREON_END -->
|
||||||
|
|
||||||
:four_leaf_clover: Copyright
|
:four_leaf_clover: Copyright
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
'targets': [
|
|
||||||
{
|
|
||||||
'target_name': 'crypto_key',
|
|
||||||
'sources': ['src/crypto_key.cc'],
|
|
||||||
'include_dirs': ['<!(node -e "require(\'nan\')")']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -6,7 +6,7 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
links:
|
links:
|
||||||
- db
|
- db
|
||||||
# - redis
|
- redis
|
||||||
# - es
|
# - es
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:3000:3000"
|
- "127.0.0.1:3000:3000"
|
||||||
@ -14,13 +14,13 @@ services:
|
|||||||
- internal_network
|
- internal_network
|
||||||
- external_network
|
- external_network
|
||||||
|
|
||||||
# redis:
|
redis:
|
||||||
# restart: always
|
restart: always
|
||||||
# image: redis:4.0-alpine
|
image: redis:4.0-alpine
|
||||||
# networks:
|
networks:
|
||||||
# - internal_network
|
- internal_network
|
||||||
# volumes:
|
volumes:
|
||||||
# - ./redis:/data
|
- ./redis:/data
|
||||||
|
|
||||||
db:
|
db:
|
||||||
restart: always
|
restart: always
|
||||||
|
@ -24,18 +24,13 @@ Please install and setup these softwares:
|
|||||||
#### Dependencies :package:
|
#### Dependencies :package:
|
||||||
* **[Node.js](https://nodejs.org/en/)** >= 11.7.0
|
* **[Node.js](https://nodejs.org/en/)** >= 11.7.0
|
||||||
* **[PostgreSQL](https://www.postgresql.org/)** >= 10
|
* **[PostgreSQL](https://www.postgresql.org/)** >= 10
|
||||||
|
* **[Redis](https://redis.io/)**
|
||||||
|
|
||||||
##### Optional
|
##### Optional
|
||||||
* [Redis](https://redis.io/)
|
|
||||||
* Redis is optional, but we strongly recommended to install it
|
|
||||||
* [Elasticsearch](https://www.elastic.co/) - required to enable the search feature
|
* [Elasticsearch](https://www.elastic.co/) - required to enable the search feature
|
||||||
* [FFmpeg](https://www.ffmpeg.org/)
|
* [FFmpeg](https://www.ffmpeg.org/)
|
||||||
|
|
||||||
*3.* Setup PostgreSQL
|
*3.* Install Misskey
|
||||||
----------------------------------------------------------------
|
|
||||||
:)
|
|
||||||
|
|
||||||
*4.* Install Misskey
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
1. `su - misskey` Connect to misskey user.
|
1. `su - misskey` Connect to misskey user.
|
||||||
2. `git clone -b master git://github.com/syuilo/misskey.git` Clone the misskey repo from master branch.
|
2. `git clone -b master git://github.com/syuilo/misskey.git` Clone the misskey repo from master branch.
|
||||||
@ -43,12 +38,12 @@ Please install and setup these softwares:
|
|||||||
4. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest)
|
4. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest)
|
||||||
5. `npm install` Install misskey dependencies.
|
5. `npm install` Install misskey dependencies.
|
||||||
|
|
||||||
*5.* Configure Misskey
|
*4.* Configure Misskey
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
1. `cp .config/example.yml .config/default.yml` Copy the `.config/example.yml` and rename it to `default.yml`.
|
1. `cp .config/example.yml .config/default.yml` Copy the `.config/example.yml` and rename it to `default.yml`.
|
||||||
2. Edit `default.yml`
|
2. Edit `default.yml`
|
||||||
|
|
||||||
*6.* Build Misskey
|
*5.* Build Misskey
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
||||||
Build misskey with the following:
|
Build misskey with the following:
|
||||||
@ -64,13 +59,13 @@ If you're still encountering errors about some modules, use node-gyp:
|
|||||||
3. `node-gyp build`
|
3. `node-gyp build`
|
||||||
4. `NODE_ENV=production npm run build`
|
4. `NODE_ENV=production npm run build`
|
||||||
|
|
||||||
*7.* Init DB
|
*6.* Init DB
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
``` shell
|
``` shell
|
||||||
npm run init
|
npm run init
|
||||||
```
|
```
|
||||||
|
|
||||||
*8.* That is it.
|
*7.* That is it.
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
Well done! Now, you have an environment that run to Misskey.
|
Well done! Now, you have an environment that run to Misskey.
|
||||||
|
|
||||||
|
@ -24,18 +24,13 @@ Installez les paquets suivants :
|
|||||||
#### Dépendences :package:
|
#### Dépendences :package:
|
||||||
* **[Node.js](https://nodejs.org/en/)** >= 11.7.0
|
* **[Node.js](https://nodejs.org/en/)** >= 11.7.0
|
||||||
* **[PostgreSQL](https://www.postgresql.org/)** >= 10
|
* **[PostgreSQL](https://www.postgresql.org/)** >= 10
|
||||||
|
* **[Redis](https://redis.io/)**
|
||||||
|
|
||||||
##### Optionnels
|
##### Optionnels
|
||||||
* [Redis](https://redis.io/)
|
|
||||||
* Redis est optionnel mais nous vous recommandons vivement de l'installer
|
|
||||||
* [Elasticsearch](https://www.elastic.co/) - requis pour pouvoir activer la fonctionnalité de recherche
|
* [Elasticsearch](https://www.elastic.co/) - requis pour pouvoir activer la fonctionnalité de recherche
|
||||||
* [FFmpeg](https://www.ffmpeg.org/)
|
* [FFmpeg](https://www.ffmpeg.org/)
|
||||||
|
|
||||||
*3.* Paramètrage de PostgreSQL
|
*3.* Installation de Misskey
|
||||||
----------------------------------------------------------------
|
|
||||||
:)
|
|
||||||
|
|
||||||
*4.* Installation de Misskey
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
1. `su - misskey` Basculez vers l'utilisateur misskey.
|
1. `su - misskey` Basculez vers l'utilisateur misskey.
|
||||||
2. `git clone -b master git://github.com/syuilo/misskey.git` Clonez la branche master du dépôt misskey.
|
2. `git clone -b master git://github.com/syuilo/misskey.git` Clonez la branche master du dépôt misskey.
|
||||||
@ -43,12 +38,12 @@ Installez les paquets suivants :
|
|||||||
4. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` Checkout sur le tag de la [version la plus récente](https://github.com/syuilo/misskey/releases/latest)
|
4. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` Checkout sur le tag de la [version la plus récente](https://github.com/syuilo/misskey/releases/latest)
|
||||||
5. `npm install` Installez les dépendances de misskey.
|
5. `npm install` Installez les dépendances de misskey.
|
||||||
|
|
||||||
*5.* Création du fichier de configuration
|
*4.* Création du fichier de configuration
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
1. `cp .config/example.yml .config/default.yml` Copiez le fichier `.config/example.yml` et renommez-le`default.yml`.
|
1. `cp .config/example.yml .config/default.yml` Copiez le fichier `.config/example.yml` et renommez-le`default.yml`.
|
||||||
2. Editez le fichier `default.yml`
|
2. Editez le fichier `default.yml`
|
||||||
|
|
||||||
*6.* Construction de Misskey
|
*5.* Construction de Misskey
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
||||||
Construisez Misskey comme ceci :
|
Construisez Misskey comme ceci :
|
||||||
@ -64,7 +59,7 @@ Si vous rencontrez des erreurs concernant certains modules, utilisez node-gyp:
|
|||||||
3. `node-gyp build`
|
3. `node-gyp build`
|
||||||
4. `NODE_ENV=production npm run build`
|
4. `NODE_ENV=production npm run build`
|
||||||
|
|
||||||
*7.* C'est tout.
|
*6.* C'est tout.
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
Excellent ! Maintenant, vous avez un environnement prêt pour lancer Misskey
|
Excellent ! Maintenant, vous avez un environnement prêt pour lancer Misskey
|
||||||
|
|
||||||
|
@ -24,25 +24,14 @@ adduser --disabled-password --disabled-login misskey
|
|||||||
#### 依存関係 :package:
|
#### 依存関係 :package:
|
||||||
* **[Node.js](https://nodejs.org/en/)** (11.7.0以上)
|
* **[Node.js](https://nodejs.org/en/)** (11.7.0以上)
|
||||||
* **[PostgreSQL](https://www.postgresql.org/)** (10以上)
|
* **[PostgreSQL](https://www.postgresql.org/)** (10以上)
|
||||||
|
* **[Redis](https://redis.io/)**
|
||||||
|
|
||||||
##### オプション
|
##### オプション
|
||||||
* [Redis](https://redis.io/)
|
|
||||||
* Redisはオプションですが、インストールすることを強く推奨します。
|
|
||||||
* インストールしなくていいのは、あなたのインスタンスが自分専用のときだけとお考えください。
|
|
||||||
* 具体的には、Redisをインストールしないと、次の事が出来なくなります:
|
|
||||||
* Misskeyプロセスを複数起動しての負荷分散
|
|
||||||
* レートリミット
|
|
||||||
* ジョブキュー
|
|
||||||
* Twitter連携
|
|
||||||
* [Elasticsearch](https://www.elastic.co/)
|
* [Elasticsearch](https://www.elastic.co/)
|
||||||
* 検索機能を有効にするためにはインストールが必要です。
|
* 検索機能を有効にするためにはインストールが必要です。
|
||||||
* [FFmpeg](https://www.ffmpeg.org/)
|
* [FFmpeg](https://www.ffmpeg.org/)
|
||||||
|
|
||||||
*3.* PostgreSQLの設定
|
*3.* Misskeyのインストール
|
||||||
----------------------------------------------------------------
|
|
||||||
:)
|
|
||||||
|
|
||||||
*4.* Misskeyのインストール
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
1. `su - misskey` misskeyユーザーを使用
|
1. `su - misskey` misskeyユーザーを使用
|
||||||
2. `git clone -b master git://github.com/syuilo/misskey.git` masterブランチからMisskeyレポジトリをクローン
|
2. `git clone -b master git://github.com/syuilo/misskey.git` masterブランチからMisskeyレポジトリをクローン
|
||||||
@ -50,12 +39,12 @@ adduser --disabled-password --disabled-login misskey
|
|||||||
4. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認
|
4. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認
|
||||||
5. `npm install` Misskeyの依存パッケージをインストール
|
5. `npm install` Misskeyの依存パッケージをインストール
|
||||||
|
|
||||||
*5.* 設定ファイルを作成する
|
*4.* 設定ファイルを作成する
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
1. `cp .config/example.yml .config/default.yml` `.config/example.yml`をコピーし名前を`default.yml`にする。
|
1. `cp .config/example.yml .config/default.yml` `.config/example.yml`をコピーし名前を`default.yml`にする。
|
||||||
2. `default.yml` を編集する。
|
2. `default.yml` を編集する。
|
||||||
|
|
||||||
*6.* Misskeyのビルド
|
*5.* Misskeyのビルド
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
||||||
次のコマンドでMisskeyをビルドしてください:
|
次のコマンドでMisskeyをビルドしてください:
|
||||||
@ -70,13 +59,13 @@ Debianをお使いであれば、`build-essential`パッケージをインスト
|
|||||||
3. `node-gyp build`
|
3. `node-gyp build`
|
||||||
4. `NODE_ENV=production npm run build`
|
4. `NODE_ENV=production npm run build`
|
||||||
|
|
||||||
*7.* データベースを初期化
|
*6.* データベースを初期化
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
``` shell
|
``` shell
|
||||||
npm run init
|
npm run init
|
||||||
```
|
```
|
||||||
|
|
||||||
*8.* 以上です!
|
*7.* 以上です!
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
お疲れ様でした。これでMisskeyを動かす準備は整いました。
|
お疲れ様でした。これでMisskeyを動かす準備は整いました。
|
||||||
|
|
||||||
|
@ -49,7 +49,6 @@ gulp.task('build:copy:views', () =>
|
|||||||
|
|
||||||
gulp.task('build:copy', gulp.parallel('build:copy:views', () =>
|
gulp.task('build:copy', gulp.parallel('build:copy:views', () =>
|
||||||
gulp.src([
|
gulp.src([
|
||||||
'./build/Release/crypto_key.node',
|
|
||||||
'./src/const.json',
|
'./src/const.json',
|
||||||
'./src/server/web/views/**/*',
|
'./src/server/web/views/**/*',
|
||||||
'./src/**/assets/**/*',
|
'./src/**/assets/**/*',
|
||||||
|
@ -20,7 +20,7 @@ common:
|
|||||||
outro: "Podívejte se na unikátní vlastnosti Misskey vlastníma očima! Pokud si myslíte, že tato instance není pro vás, zkuste jiné instance, neboť Misskey je decentralizovaná sociální síť, takže můžete snadno najít své přátele. Hodně štěstí a zábavy!"
|
outro: "Podívejte se na unikátní vlastnosti Misskey vlastníma očima! Pokud si myslíte, že tato instance není pro vás, zkuste jiné instance, neboť Misskey je decentralizovaná sociální síť, takže můžete snadno najít své přátele. Hodně štěstí a zábavy!"
|
||||||
adblock:
|
adblock:
|
||||||
detected: "Prosím vypněte svůj blokovač reklam"
|
detected: "Prosím vypněte svůj blokovač reklam"
|
||||||
warning: "<strong>Misskey nepoužívá reklamy</strong>, některé vlastnosti však mohou být nedostupné nebo mohou způsobovat chyby, pokud máte povolený blokovač reklam."
|
warning: "Některé vlastnosti mohou být nedostupné nebo mohou způsobovat chyby, pokud máte povolený blokovač reklam. <strong>Misskey nepoužívá reklamy</strong>."
|
||||||
application-authorization: "Autorizované aplikace"
|
application-authorization: "Autorizované aplikace"
|
||||||
close: "Zavřít"
|
close: "Zavřít"
|
||||||
do-not-copy-paste: "Prosím nezadávejte ani nevkládejte sem kód. Váš účet může být kompromitován."
|
do-not-copy-paste: "Prosím nezadávejte ani nevkládejte sem kód. Váš účet může být kompromitován."
|
||||||
@ -227,6 +227,7 @@ common:
|
|||||||
cancel: "Zrušit"
|
cancel: "Zrušit"
|
||||||
update-available-title: "Aktualizace k dispozici"
|
update-available-title: "Aktualizace k dispozici"
|
||||||
update-available: "Je k dispozici nová verze Misskey ({newer},vaše verze je {current}). Pro aplikování nové verze znovunačtěte stránku."
|
update-available: "Je k dispozici nová verze Misskey ({newer},vaše verze je {current}). Pro aplikování nové verze znovunačtěte stránku."
|
||||||
|
my-token-regenerated: "Váš token byl regenerován, proto budete odhlášen/a."
|
||||||
verified-user: "Ověřené účty"
|
verified-user: "Ověřené účty"
|
||||||
hide-password: "Skrýt heslo"
|
hide-password: "Skrýt heslo"
|
||||||
show-password: "Zobrazit heslo"
|
show-password: "Zobrazit heslo"
|
||||||
@ -281,12 +282,6 @@ common:
|
|||||||
auth/views/form.vue:
|
auth/views/form.vue:
|
||||||
share-access: "Chcete dovolit aplikaci <i>{name}</i> přístup k vašemu účtu?"
|
share-access: "Chcete dovolit aplikaci <i>{name}</i> přístup k vašemu účtu?"
|
||||||
permission-ask: "Tato aplikace vyžaduje následující oprávnění:"
|
permission-ask: "Tato aplikace vyžaduje následující oprávnění:"
|
||||||
account-read: "Zobrazit informace účtu"
|
|
||||||
note-write: "Odeslat."
|
|
||||||
following-write: "Sledovat a přestat sledovat"
|
|
||||||
drive-read: "Přečíst váš Disk"
|
|
||||||
notification-read: "Sledovat oznámení."
|
|
||||||
notification-write: "Zpravovat notifikace."
|
|
||||||
cancel: "Zrušit"
|
cancel: "Zrušit"
|
||||||
accept: "Povolit přístup"
|
accept: "Povolit přístup"
|
||||||
auth/views/index.vue:
|
auth/views/index.vue:
|
||||||
@ -302,6 +297,7 @@ common/views/pages/explore.vue:
|
|||||||
popular-tags: "Populární tagy"
|
popular-tags: "Populární tagy"
|
||||||
federated: "Z fedivesmíru"
|
federated: "Z fedivesmíru"
|
||||||
explore: "Prozkoumat {host}"
|
explore: "Prozkoumat {host}"
|
||||||
|
users-info: "Aktuálně je zde registrováno {users} uživatelů"
|
||||||
common/views/components/url-preview.vue:
|
common/views/components/url-preview.vue:
|
||||||
enable-player: "Otevřít v přehrávači"
|
enable-player: "Otevřít v přehrávači"
|
||||||
disable-player: "Zavřít přehrávač"
|
disable-player: "Zavřít přehrávač"
|
||||||
@ -354,19 +350,23 @@ common/views/components/connect-failed.troubleshooter.vue:
|
|||||||
no-network-desc: "Ujistěte se že jste připojeni k Internetu."
|
no-network-desc: "Ujistěte se že jste připojeni k Internetu."
|
||||||
no-internet: "Nejste připojeni k internetu"
|
no-internet: "Nejste připojeni k internetu"
|
||||||
no-internet-desc: "Jste připojen k síti, ale zdá se že stále chybí připojení k Internetu. Prosím zkontrolujte Vaše připojení k Internetu."
|
no-internet-desc: "Jste připojen k síti, ale zdá se že stále chybí připojení k Internetu. Prosím zkontrolujte Vaše připojení k Internetu."
|
||||||
|
no-server: "Nelze se připojit k serveru Misskey"
|
||||||
common/views/components/media-banner.vue:
|
common/views/components/media-banner.vue:
|
||||||
click-to-show: "Klikněte pro zobrazení"
|
click-to-show: "Klikněte pro zobrazení"
|
||||||
common/views/components/theme.vue:
|
common/views/components/theme.vue:
|
||||||
light-theme: "Šablona pro použití ve světlém vzhledu"
|
light-theme: "Motiv pro použití ve světlém vzhledu"
|
||||||
dark-theme: "Šablona pro použití v tmavém vzhledu"
|
dark-theme: "Motiv pro použití v tmavém vzhledu"
|
||||||
light-themes: "Světlý vzhled"
|
light-themes: "Světlý vzhled"
|
||||||
dark-themes: "Tmavý vzhled"
|
dark-themes: "Tmavý vzhled"
|
||||||
install-a-theme: "Nainstalovat šablonu"
|
install-a-theme: "Nainstalovat motiv"
|
||||||
theme-code: "Kód šablony"
|
theme-code: "Kód motivu"
|
||||||
install: "Nainstalovat"
|
install: "Nainstalovat"
|
||||||
installed: "\"{}\" byl nainstalován"
|
installed: "\"{}\" byl nainstalován"
|
||||||
create-a-theme: "Vytvořit motiv"
|
create-a-theme: "Vytvořit motiv"
|
||||||
|
save-created-theme: "Uložit motiv"
|
||||||
base-theme: "Základní vzhled"
|
base-theme: "Základní vzhled"
|
||||||
|
base-theme-light: "Světlý"
|
||||||
|
base-theme-dark: "Tmavý"
|
||||||
find-more-theme: "Najít další vzhledy"
|
find-more-theme: "Najít další vzhledy"
|
||||||
theme-name: "Jméno vzhledu"
|
theme-name: "Jméno vzhledu"
|
||||||
preview-created-theme: "Náhled"
|
preview-created-theme: "Náhled"
|
||||||
@ -435,6 +435,7 @@ common/views/components/user-menu.vue:
|
|||||||
unblock: "Odblokovat"
|
unblock: "Odblokovat"
|
||||||
push-to-list: "Přidat do seznamu"
|
push-to-list: "Přidat do seznamu"
|
||||||
select-list: "Vyberte seznam"
|
select-list: "Vyberte seznam"
|
||||||
|
report-abuse: "Nahlásit spam"
|
||||||
report-abuse-reported: "Problém byl nahlášen administrátorovi. Děkujeme za Vaší kooperaci."
|
report-abuse-reported: "Problém byl nahlášen administrátorovi. Děkujeme za Vaší kooperaci."
|
||||||
silence: "Ztlumit"
|
silence: "Ztlumit"
|
||||||
suspend: "Zmrazit"
|
suspend: "Zmrazit"
|
||||||
@ -793,8 +794,6 @@ desktop/views/components/settings.tags.vue:
|
|||||||
title: "Tagy"
|
title: "Tagy"
|
||||||
add: "Přidat"
|
add: "Přidat"
|
||||||
save: "Uložit"
|
save: "Uložit"
|
||||||
desktop/views/components/taskmanager.vue:
|
|
||||||
title: "Správce úloh"
|
|
||||||
desktop/views/components/timeline.vue:
|
desktop/views/components/timeline.vue:
|
||||||
home: "Domů"
|
home: "Domů"
|
||||||
local: "Lokální"
|
local: "Lokální"
|
||||||
@ -839,7 +838,7 @@ admin/views/index.vue:
|
|||||||
emoji: "Emoji"
|
emoji: "Emoji"
|
||||||
moderators: "Moderátoři"
|
moderators: "Moderátoři"
|
||||||
users: "Uživatelé"
|
users: "Uživatelé"
|
||||||
federation: "Federovaná"
|
federation: "Z fedivesmíru"
|
||||||
announcements: "Oznámení"
|
announcements: "Oznámení"
|
||||||
hashtags: "Hashtagy"
|
hashtags: "Hashtagy"
|
||||||
queue: "Fronta úloh"
|
queue: "Fronta úloh"
|
||||||
@ -851,7 +850,7 @@ admin/views/dashboard.vue:
|
|||||||
drive: "Disk"
|
drive: "Disk"
|
||||||
instances: "Instance"
|
instances: "Instance"
|
||||||
this-instance: "Tato instance"
|
this-instance: "Tato instance"
|
||||||
federated: "Federovaná"
|
federated: "Z fedivesmíru"
|
||||||
admin/views/abuse.vue:
|
admin/views/abuse.vue:
|
||||||
details: "Popis"
|
details: "Popis"
|
||||||
remove-report: "Odstranit"
|
remove-report: "Odstranit"
|
||||||
@ -1006,7 +1005,7 @@ admin/views/federation.vue:
|
|||||||
status: "Status"
|
status: "Status"
|
||||||
latest-request-received-at: "Poslední požadavek přijat"
|
latest-request-received-at: "Poslední požadavek přijat"
|
||||||
block: "Blokován"
|
block: "Blokován"
|
||||||
instances: "Federovaná"
|
instances: "Z fedivesmíru"
|
||||||
states:
|
states:
|
||||||
all: "Všechny"
|
all: "Všechny"
|
||||||
blocked: "Blokován"
|
blocked: "Blokován"
|
||||||
@ -1184,10 +1183,3 @@ deck/deck.user-column.vue:
|
|||||||
dev/views/new-app.vue:
|
dev/views/new-app.vue:
|
||||||
app-name-desc: "Jméno vaší aplikace"
|
app-name-desc: "Jméno vaší aplikace"
|
||||||
app-desc: "Stručný popis nebo představení vaší aplikace."
|
app-desc: "Stručný popis nebo představení vaší aplikace."
|
||||||
account-read: "Zobrazit informace účtu"
|
|
||||||
note-write: "Odeslat."
|
|
||||||
reaction-write: "Přidat nebo odebrat reakce."
|
|
||||||
following-write: "Sledovat a přestat sledovat"
|
|
||||||
drive-read: "Přečíst váš Disk"
|
|
||||||
notification-read: "Sledovat oznámení."
|
|
||||||
notification-write: "Zpravovat notifikace."
|
|
||||||
|
@ -7,6 +7,7 @@ common:
|
|||||||
about: "Danke, dass Du Misskey gefunden hast. Misskey ist eine <b>dezentralisierte Microblogging-Plattform</b>, welche auf der ganzen Welt verteilt ist. Da es innerhalb es Fediversums existiert (ein Universum, in dem verschiedene Soziale Netzwerke organisiert sind), ist es unmittelbar mit anderen sozialen Netzwerken verbunden. Warum nimmst du dir nicht einmal eine Auszeit von dem Trubel der Stadt und tauchst in das neue Internet hinein?"
|
about: "Danke, dass Du Misskey gefunden hast. Misskey ist eine <b>dezentralisierte Microblogging-Plattform</b>, welche auf der ganzen Welt verteilt ist. Da es innerhalb es Fediversums existiert (ein Universum, in dem verschiedene Soziale Netzwerke organisiert sind), ist es unmittelbar mit anderen sozialen Netzwerken verbunden. Warum nimmst du dir nicht einmal eine Auszeit von dem Trubel der Stadt und tauchst in das neue Internet hinein?"
|
||||||
intro:
|
intro:
|
||||||
title: "Was ist Misskey?"
|
title: "Was ist Misskey?"
|
||||||
|
about: "Misskey ist eine Quelloffene, <b>dezentralisierte microblogging Software</b>. Es bietet eine erweiterbare Benutzeroberfläche, verschiedenste Möglichkeiten auf Beiträge zu reagieren, kostenlosen Datenspeicher, und andere fortschrittliche Funktionen. Zusätzlich ist Misskey dazu in der Lage, sich mittels des Fediverse mit beliebig vielen anderen ActivityPub-kompatiblen Diensten zu verbinden. Wenn du zum Beispiel einen Betrag mit Misskey abschickst, wird dieser auch für Nutzer von Mastodon oder Pleroma sichtbar sein. So ähnlich wie eine Radioübertragung zwischen Planeten."
|
||||||
features: "Funktionen"
|
features: "Funktionen"
|
||||||
rich-contents: "Notizen"
|
rich-contents: "Notizen"
|
||||||
reaction: "Reaktionen"
|
reaction: "Reaktionen"
|
||||||
@ -138,13 +139,6 @@ common:
|
|||||||
auth/views/form.vue:
|
auth/views/form.vue:
|
||||||
share-access: "Erlaubst Du <i>{name}</i> auf deinen Account zuzugreifen?"
|
share-access: "Erlaubst Du <i>{name}</i> auf deinen Account zuzugreifen?"
|
||||||
permission-ask: "Diese Applikation benötigt folgende Berechtigungen:"
|
permission-ask: "Diese Applikation benötigt folgende Berechtigungen:"
|
||||||
account-read: "Accountinformationen anzeigen."
|
|
||||||
account-write: "Accountinformationen bearbeiten."
|
|
||||||
note-write: "Senden."
|
|
||||||
like-write: "Auf Beiträge reagieren."
|
|
||||||
following-write: "Folgen oder entfolgen."
|
|
||||||
notification-read: "Siehe deine Benachrichtigungen."
|
|
||||||
notification-write: "Benachrichtigungen verwalten."
|
|
||||||
cancel: "Abbrechen"
|
cancel: "Abbrechen"
|
||||||
accept: "Zugriff erlauben."
|
accept: "Zugriff erlauben."
|
||||||
auth/views/index.vue:
|
auth/views/index.vue:
|
||||||
@ -478,7 +472,6 @@ desktop/views/components/post-form.vue:
|
|||||||
posting: "Posting"
|
posting: "Posting"
|
||||||
attach-media-from-local: "Medien von deinem PC hinzufügen"
|
attach-media-from-local: "Medien von deinem PC hinzufügen"
|
||||||
attach-media-from-drive: "Medien von deinem Speicher hinzufügen"
|
attach-media-from-drive: "Medien von deinem Speicher hinzufügen"
|
||||||
attach-cancel: "Hinzufügen abbrechen"
|
|
||||||
create-poll: "Eine Abstimmung erstellen"
|
create-poll: "Eine Abstimmung erstellen"
|
||||||
text-remain: "{} Zeichen verbleibend"
|
text-remain: "{} Zeichen verbleibend"
|
||||||
visibility: "Sichtbarkeit"
|
visibility: "Sichtbarkeit"
|
||||||
@ -524,8 +517,6 @@ desktop/views/components/sub-note-content.vue:
|
|||||||
desktop/views/components/settings.tags.vue:
|
desktop/views/components/settings.tags.vue:
|
||||||
add: "Hinzufügen"
|
add: "Hinzufügen"
|
||||||
save: "Speichern"
|
save: "Speichern"
|
||||||
desktop/views/components/taskmanager.vue:
|
|
||||||
title: "Taskmanager"
|
|
||||||
desktop/views/components/timeline.vue:
|
desktop/views/components/timeline.vue:
|
||||||
home: "Home"
|
home: "Home"
|
||||||
local: "Lokal"
|
local: "Lokal"
|
||||||
@ -664,10 +655,3 @@ deck:
|
|||||||
rename: "Umbenennen"
|
rename: "Umbenennen"
|
||||||
deck/deck.user-column.vue:
|
deck/deck.user-column.vue:
|
||||||
activity: "Aktivität"
|
activity: "Aktivität"
|
||||||
dev/views/new-app.vue:
|
|
||||||
account-read: "Accountinformationen anzeigen."
|
|
||||||
account-write: "Accountinformationen bearbeiten."
|
|
||||||
note-write: "Senden."
|
|
||||||
following-write: "Folgen oder entfolgen."
|
|
||||||
notification-read: "Siehe deine Benachrichtigungen."
|
|
||||||
notification-write: "Benachrichtigungen verwalten."
|
|
||||||
|
@ -69,6 +69,11 @@ common:
|
|||||||
following: "Following"
|
following: "Following"
|
||||||
followers: "Followers"
|
followers: "Followers"
|
||||||
favorites: "Favorites"
|
favorites: "Favorites"
|
||||||
|
permissions:
|
||||||
|
'read:account': "View account information"
|
||||||
|
'write:account': "Update your account information"
|
||||||
|
'read:drive': "Browse the Drive"
|
||||||
|
'write:drive': "Work with the Drive"
|
||||||
empty-timeline-info:
|
empty-timeline-info:
|
||||||
follow-users-to-make-your-timeline: "Following users will show their posts in your timeline."
|
follow-users-to-make-your-timeline: "Following users will show their posts in your timeline."
|
||||||
explore: "Find users"
|
explore: "Find users"
|
||||||
@ -282,15 +287,6 @@ common:
|
|||||||
auth/views/form.vue:
|
auth/views/form.vue:
|
||||||
share-access: "Would you allow <i>{name}</i> to access your account?"
|
share-access: "Would you allow <i>{name}</i> to access your account?"
|
||||||
permission-ask: "This application requires the following permissions:"
|
permission-ask: "This application requires the following permissions:"
|
||||||
account-read: "View account information."
|
|
||||||
account-write: "Modify account information."
|
|
||||||
note-write: "Post."
|
|
||||||
like-write: "Express yourself about this post."
|
|
||||||
following-write: "Follow and unfollow."
|
|
||||||
drive-read: "Read your drive."
|
|
||||||
drive-write: "Upload/delete files in your drive."
|
|
||||||
notification-read: "Read your notifications."
|
|
||||||
notification-write: "Manage your notifications."
|
|
||||||
cancel: "Cancel"
|
cancel: "Cancel"
|
||||||
accept: "Allow access."
|
accept: "Allow access."
|
||||||
auth/views/index.vue:
|
auth/views/index.vue:
|
||||||
@ -877,7 +873,6 @@ desktop/views/components/post-form.vue:
|
|||||||
posting: "Posting"
|
posting: "Posting"
|
||||||
attach-media-from-local: "Attach media from your device"
|
attach-media-from-local: "Attach media from your device"
|
||||||
attach-media-from-drive: "Attach media from your Drive"
|
attach-media-from-drive: "Attach media from your Drive"
|
||||||
attach-cancel: "Cancel attachment"
|
|
||||||
insert-a-kao: "v('ω')v"
|
insert-a-kao: "v('ω')v"
|
||||||
create-poll: "Create a poll"
|
create-poll: "Create a poll"
|
||||||
text-remain: "{} characters remaining"
|
text-remain: "{} characters remaining"
|
||||||
@ -970,6 +965,10 @@ common/views/components/password-settings.vue:
|
|||||||
not-match: "The new passwords do not match"
|
not-match: "The new passwords do not match"
|
||||||
changed: "Password changed"
|
changed: "Password changed"
|
||||||
failed: "Failed to change password"
|
failed: "Failed to change password"
|
||||||
|
common/views/components/post-form-attaches.vue:
|
||||||
|
attach-cancel: "Remove Attachment"
|
||||||
|
mark-as-sensitive: "Mark as 'sensitive'"
|
||||||
|
unmark-as-sensitive: "Unmark as 'sensitive'"
|
||||||
desktop/views/components/sub-note-content.vue:
|
desktop/views/components/sub-note-content.vue:
|
||||||
private: "This post is private"
|
private: "This post is private"
|
||||||
deleted: "This post has been deleted"
|
deleted: "This post has been deleted"
|
||||||
@ -980,8 +979,6 @@ desktop/views/components/settings.tags.vue:
|
|||||||
query: "Query (optional)"
|
query: "Query (optional)"
|
||||||
add: "Add"
|
add: "Add"
|
||||||
save: "Save"
|
save: "Save"
|
||||||
desktop/views/components/taskmanager.vue:
|
|
||||||
title: "Task Manager"
|
|
||||||
desktop/views/components/timeline.vue:
|
desktop/views/components/timeline.vue:
|
||||||
home: "Home"
|
home: "Home"
|
||||||
local: "Local"
|
local: "Local"
|
||||||
@ -1115,11 +1112,6 @@ admin/views/instance.vue:
|
|||||||
save: "Save"
|
save: "Save"
|
||||||
saved: "Saved"
|
saved: "Saved"
|
||||||
user-recommendation-config: "Recommended users"
|
user-recommendation-config: "Recommended users"
|
||||||
enable-external-user-recommendation: "Enable external user recommendations"
|
|
||||||
external-user-recommendation-engine: "Engine"
|
|
||||||
external-user-recommendation-engine-desc: "Example : https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
|
|
||||||
external-user-recommendation-timeout: "Timeout"
|
|
||||||
external-user-recommendation-timeout-desc: "Number of milliseconds (ex. 300,000)"
|
|
||||||
email-config: "Email server settings"
|
email-config: "Email server settings"
|
||||||
email-config-info: "Used to confirm email and password reset etc."
|
email-config-info: "Used to confirm email and password reset etc."
|
||||||
enable-email: "Enable email delivery"
|
enable-email: "Enable email delivery"
|
||||||
@ -1632,12 +1624,3 @@ dev/views/new-app.vue:
|
|||||||
authority: "Permissions"
|
authority: "Permissions"
|
||||||
authority-desc: "Only the functions requested here can be accessed via the API."
|
authority-desc: "Only the functions requested here can be accessed via the API."
|
||||||
authority-warning: "You can change it even after creating the application, but if you give different permissions, all user keys associated at that time will be invalidated."
|
authority-warning: "You can change it even after creating the application, but if you give different permissions, all user keys associated at that time will be invalidated."
|
||||||
account-read: "View account information."
|
|
||||||
account-write: "Modify account information."
|
|
||||||
note-write: "Post."
|
|
||||||
reaction-write: "Add or remove reactions."
|
|
||||||
following-write: "Follow and unfollow."
|
|
||||||
drive-read: "Read the drive."
|
|
||||||
drive-write: "Upload/delete files in the drive."
|
|
||||||
notification-read: "Read your notifications."
|
|
||||||
notification-write: "Manage your notifications."
|
|
||||||
|
@ -169,15 +169,6 @@ common:
|
|||||||
you: "Tú"
|
you: "Tú"
|
||||||
auth/views/form.vue:
|
auth/views/form.vue:
|
||||||
permission-ask: "La aplicación requiere los siguientes permisos:"
|
permission-ask: "La aplicación requiere los siguientes permisos:"
|
||||||
account-read: "Viendo información de la cuenta:"
|
|
||||||
account-write: "Modificar información de la cuenta:"
|
|
||||||
note-write: "Publicación."
|
|
||||||
like-write: "Para reaccionar a las publicaciones."
|
|
||||||
following-write: "Seguir o dejar de seguir"
|
|
||||||
drive-read: "Leer tu unidad."
|
|
||||||
drive-write: "Cargar o borrar archivos de tu unidad."
|
|
||||||
notification-read: "Leer tus notificaciones."
|
|
||||||
notification-write: "Administrar tus notificaciones."
|
|
||||||
cancel: "Cancelar"
|
cancel: "Cancelar"
|
||||||
accept: "Garantizar acceso."
|
accept: "Garantizar acceso."
|
||||||
auth/views/index.vue:
|
auth/views/index.vue:
|
||||||
@ -631,7 +622,6 @@ desktop/views/components/post-form.vue:
|
|||||||
posting: "Publicando"
|
posting: "Publicando"
|
||||||
attach-media-from-local: "Agregar medios de tu dispositivo"
|
attach-media-from-local: "Agregar medios de tu dispositivo"
|
||||||
attach-media-from-drive: "Adjunta multimedia desde tu Disco"
|
attach-media-from-drive: "Adjunta multimedia desde tu Disco"
|
||||||
attach-cancel: "Quitar el archivo adjunto"
|
|
||||||
create-poll: "Crea una encuesta"
|
create-poll: "Crea una encuesta"
|
||||||
text-remain: "quedan {} caracteres"
|
text-remain: "quedan {} caracteres"
|
||||||
recent-tags: "Reciente"
|
recent-tags: "Reciente"
|
||||||
@ -697,6 +687,9 @@ common/views/components/mute-and-block.vue:
|
|||||||
mute: "Silenciar"
|
mute: "Silenciar"
|
||||||
block: "Bloquear"
|
block: "Bloquear"
|
||||||
save: "Guardar"
|
save: "Guardar"
|
||||||
|
common/views/components/post-form-attaches.vue:
|
||||||
|
mark-as-sensitive: "Marcar como 'sensible'"
|
||||||
|
unmark-as-sensitive: "Desmarcar como 'sensible'"
|
||||||
desktop/views/components/sub-note-content.vue:
|
desktop/views/components/sub-note-content.vue:
|
||||||
private: "Esta publicación es privada"
|
private: "Esta publicación es privada"
|
||||||
deleted: "Esta publicación ha sido removida"
|
deleted: "Esta publicación ha sido removida"
|
||||||
@ -708,7 +701,6 @@ desktop/views/components/settings.tags.vue:
|
|||||||
desktop/views/components/timeline.vue:
|
desktop/views/components/timeline.vue:
|
||||||
home: "Inicio"
|
home: "Inicio"
|
||||||
local: "Local"
|
local: "Local"
|
||||||
hybrid: "Social"
|
|
||||||
global: "Global"
|
global: "Global"
|
||||||
list: "Listas"
|
list: "Listas"
|
||||||
hashtag: "Hashtags"
|
hashtag: "Hashtags"
|
||||||
@ -768,7 +760,6 @@ admin/views/instance.vue:
|
|||||||
recaptcha-secret-key: "clave secreta reCAPTCHA"
|
recaptcha-secret-key: "clave secreta reCAPTCHA"
|
||||||
invite: "Invitar"
|
invite: "Invitar"
|
||||||
save: "Guardar"
|
save: "Guardar"
|
||||||
external-user-recommendation-timeout: "Tiempo de espera"
|
|
||||||
email: "Correo electrónico"
|
email: "Correo electrónico"
|
||||||
smtp-host: "Host SMTP"
|
smtp-host: "Host SMTP"
|
||||||
smtp-port: "Puerto SMTP"
|
smtp-port: "Puerto SMTP"
|
||||||
@ -898,7 +889,6 @@ mobile/views/pages/user-lists.vue:
|
|||||||
mobile/views/pages/home.vue:
|
mobile/views/pages/home.vue:
|
||||||
home: "Inicio"
|
home: "Inicio"
|
||||||
local: "Local"
|
local: "Local"
|
||||||
hybrid: "Social"
|
|
||||||
global: "Global"
|
global: "Global"
|
||||||
mobile/views/pages/widgets.vue:
|
mobile/views/pages/widgets.vue:
|
||||||
dashboard: "Panel de control"
|
dashboard: "Panel de control"
|
||||||
@ -921,7 +911,6 @@ mobile/views/pages/user/home.photos.vue:
|
|||||||
deck:
|
deck:
|
||||||
home: "Inicio"
|
home: "Inicio"
|
||||||
local: "Local"
|
local: "Local"
|
||||||
hybrid: "Social"
|
|
||||||
hashtag: "Etiquetas"
|
hashtag: "Etiquetas"
|
||||||
global: "Global"
|
global: "Global"
|
||||||
notifications: "Notificaciones"
|
notifications: "Notificaciones"
|
||||||
@ -929,12 +918,3 @@ deck:
|
|||||||
rename: "Renombrar"
|
rename: "Renombrar"
|
||||||
deck/deck.user-column.vue:
|
deck/deck.user-column.vue:
|
||||||
activity: "Actividad"
|
activity: "Actividad"
|
||||||
dev/views/new-app.vue:
|
|
||||||
account-read: "Viendo información de la cuenta:"
|
|
||||||
account-write: "Modificar información de la cuenta:"
|
|
||||||
note-write: "Publicación."
|
|
||||||
following-write: "Seguir o dejar de seguir"
|
|
||||||
drive-read: "Leer tu unidad."
|
|
||||||
drive-write: "Cargar o borrar archivos de tu unidad."
|
|
||||||
notification-read: "Leer tus notificaciones."
|
|
||||||
notification-write: "Administrar tus notificaciones."
|
|
||||||
|
@ -67,6 +67,11 @@ common:
|
|||||||
following: "Suit"
|
following: "Suit"
|
||||||
followers: "Abonné·e·s"
|
followers: "Abonné·e·s"
|
||||||
favorites: "Mettre cette note en favoris"
|
favorites: "Mettre cette note en favoris"
|
||||||
|
permissions:
|
||||||
|
'read:account': "Afficher les informations du compte"
|
||||||
|
'write:account': "Mettre à jour les informations de votre compte"
|
||||||
|
'read:drive': "Parcourir le Drive"
|
||||||
|
'write:drive': "Écrire sur le Drive"
|
||||||
empty-timeline-info:
|
empty-timeline-info:
|
||||||
follow-users-to-make-your-timeline: "Les utilisateurs suivants afficheront leurs publications sur votre fil."
|
follow-users-to-make-your-timeline: "Les utilisateurs suivants afficheront leurs publications sur votre fil."
|
||||||
explore: "Trouver des utilisateurs"
|
explore: "Trouver des utilisateurs"
|
||||||
@ -121,6 +126,7 @@ common:
|
|||||||
notification: "Notifications"
|
notification: "Notifications"
|
||||||
apps: "Applications"
|
apps: "Applications"
|
||||||
tags: "Hashtags"
|
tags: "Hashtags"
|
||||||
|
mute-and-block: "Silencer / Bloquer"
|
||||||
blocking: "En cours blocage"
|
blocking: "En cours blocage"
|
||||||
security: "Sécurité"
|
security: "Sécurité"
|
||||||
signin: "Historique des connexions"
|
signin: "Historique des connexions"
|
||||||
@ -134,6 +140,16 @@ common:
|
|||||||
remember-note-visibility: "Se souvenir du mode de visibilité de la publication"
|
remember-note-visibility: "Se souvenir du mode de visibilité de la publication"
|
||||||
web-search-engine: "Moteur de recherche Web"
|
web-search-engine: "Moteur de recherche Web"
|
||||||
web-search-engine-desc: "Exemple : https://www.google.com/?#q={{query}}"
|
web-search-engine-desc: "Exemple : https://www.google.com/?#q={{query}}"
|
||||||
|
keep-cw: "Maintenir l'avertissement de contenu"
|
||||||
|
i-like-sushi: "Je préfère les sushis plutôt que le pudding"
|
||||||
|
show-reversi-board-labels: "Afficher les étiquettes des lignes et colonnes dans Reversi"
|
||||||
|
use-avatar-reversi-stones: "Utiliser l’avatar comme pion dans Reversi"
|
||||||
|
disable-animated-mfm: "Désactiver les textes animés dans les publications"
|
||||||
|
disable-showing-animated-images: "Désactiver l'animation des images"
|
||||||
|
suggest-recent-hashtags: "Afficher les hashtags populaires dans le champs de saisie"
|
||||||
|
always-show-nsfw: "Toujours afficher les contenus sensibles"
|
||||||
|
always-mark-nsfw: "Toujours marquer les notes ayant des médias comme sensibles"
|
||||||
|
show-full-acct: "Afficher l’adresse complète de l’utilisateur"
|
||||||
show-via: "Afficher via"
|
show-via: "Afficher via"
|
||||||
reduce-motion: "Réduire les animations dans l’interface utilisateur"
|
reduce-motion: "Réduire les animations dans l’interface utilisateur"
|
||||||
this-setting-is-this-device-only: "Uniquement sur cet appareil"
|
this-setting-is-this-device-only: "Uniquement sur cet appareil"
|
||||||
@ -143,25 +159,69 @@ common:
|
|||||||
line-width-normal: "Normale"
|
line-width-normal: "Normale"
|
||||||
line-width-thick: "Épaisse"
|
line-width-thick: "Épaisse"
|
||||||
font-size: "Taille du texte"
|
font-size: "Taille du texte"
|
||||||
|
font-size-x-small: "Très petit"
|
||||||
|
font-size-small: "Petite"
|
||||||
font-size-medium: "Normale"
|
font-size-medium: "Normale"
|
||||||
|
font-size-large: "Grande"
|
||||||
font-size-x-large: "Large"
|
font-size-x-large: "Large"
|
||||||
|
deck-column-align: "Alignement des colonnes du Deck"
|
||||||
deck-column-align-center: "Centrer"
|
deck-column-align-center: "Centrer"
|
||||||
deck-column-align-left: "À gauche"
|
deck-column-align-left: "À gauche"
|
||||||
deck-column-align-flexible: "Flexible"
|
deck-column-align-flexible: "Flexible"
|
||||||
deck-column-width: "Largeur des colonnes du Deck"
|
deck-column-width: "Largeur des colonnes du Deck"
|
||||||
|
deck-column-width-narrow: "Étroite"
|
||||||
|
deck-column-width-narrower: "Légèrement étroite"
|
||||||
deck-column-width-normal: "Normale"
|
deck-column-width-normal: "Normale"
|
||||||
|
deck-column-width-wider: "Légèrement large"
|
||||||
|
deck-column-width-wide: "Large"
|
||||||
|
use-shadow: "Utiliser les ombres dans l'interface utilisateur"
|
||||||
|
rounded-corners: "Coins arrondis de l'interface utilisateur"
|
||||||
|
circle-icons: "Utiliser des icônes circulaires"
|
||||||
|
contrasted-acct: "Ajouter du contraste au nom de l’utilisateur"
|
||||||
|
wallpaper: "Image du fond d'écran"
|
||||||
|
choose-wallpaper: "Sélectionner un fond d'écran"
|
||||||
|
delete-wallpaper: "Supprimer le fond d'écran"
|
||||||
|
post-form-on-timeline: "Afficher le champs de saisie en haut du fil"
|
||||||
|
show-clock-on-header: "Afficher l'horloge sur le coté supérieur droit"
|
||||||
timeline: "Fil d’actualité"
|
timeline: "Fil d’actualité"
|
||||||
|
show-my-renotes: "Afficher mes republications dans le fil"
|
||||||
|
remain-deleted-note: "Continuer à afficher les notes supprimées"
|
||||||
|
sound: "Son"
|
||||||
|
enable-sounds: "Activer les sons"
|
||||||
|
enable-sounds-desc: "Jouer un son lorsque vous recevez un message/publication. Ce paramètre est sauvegardé dans le navigateur."
|
||||||
|
volume: "Volume"
|
||||||
|
test: "Test"
|
||||||
|
update: "Mise à jour de Misskey"
|
||||||
|
version: "Version actuelle :"
|
||||||
|
latest-version: "Dernière version :"
|
||||||
|
update-checking: "Recherche de mises à jour"
|
||||||
|
do-update: "Rechercher des mises à jour"
|
||||||
|
update-settings: "Paramètres avancés"
|
||||||
|
no-updates: "Aucune mise à jour disponible"
|
||||||
|
no-updates-desc: "Votre Misskey est à jour."
|
||||||
|
update-available: "Nouvelle version disponible !"
|
||||||
|
update-available-desc: "Les mises à jour seront appliquées une fois la page est rechargée."
|
||||||
|
advanced-settings: "Paramètres avancés"
|
||||||
|
debug-mode: "Activer le mode débogage"
|
||||||
|
debug-mode-desc: "Ce paramètre est stocké dans le navigateur."
|
||||||
|
navbar-position: "Position de la barre de navigation"
|
||||||
navbar-position-top: "en haut"
|
navbar-position-top: "en haut"
|
||||||
navbar-position-left: "À gauche"
|
navbar-position-left: "À gauche"
|
||||||
navbar-position-right: "à droite"
|
navbar-position-right: "à droite"
|
||||||
|
i-am-under-limited-internet: "J'ai un accès Internet limité"
|
||||||
|
post-style: "Style d'affichage des notes"
|
||||||
post-style-standard: "Standard"
|
post-style-standard: "Standard"
|
||||||
post-style-smart: "Intelligent"
|
post-style-smart: "Intelligent"
|
||||||
notification-position: "Afficher les notifications"
|
notification-position: "Afficher les notifications"
|
||||||
notification-position-bottom: "en bas"
|
notification-position-bottom: "en bas"
|
||||||
notification-position-top: "en haut"
|
notification-position-top: "en haut"
|
||||||
|
disable-via-mobile: "Enlever la mention publié via 'mobile'"
|
||||||
|
load-raw-images: "Afficher les photos jointes dans leur qualité originale"
|
||||||
|
load-remote-media: "Afficher les médias depuis le serveur distant"
|
||||||
search: "Recherche"
|
search: "Recherche"
|
||||||
delete: "Supprimer"
|
delete: "Supprimer"
|
||||||
loading: "Chargement en cours …"
|
loading: "Chargement en cours …"
|
||||||
|
ok: "Confirmer"
|
||||||
cancel: "Quitter"
|
cancel: "Quitter"
|
||||||
update-available-title: "Mise à jour disponible"
|
update-available-title: "Mise à jour disponible"
|
||||||
update-available: "Une nouvelle version de Misskey est disponible ({newer}, version actuelle: {current}). Veuillez recharger la page pour appliquer la mise à jour."
|
update-available: "Une nouvelle version de Misskey est disponible ({newer}, version actuelle: {current}). Veuillez recharger la page pour appliquer la mise à jour."
|
||||||
@ -176,7 +236,7 @@ common:
|
|||||||
view-on-remote: " Consulter le profil complet"
|
view-on-remote: " Consulter le profil complet"
|
||||||
renoted-by: "Renoté par {user}"
|
renoted-by: "Renoté par {user}"
|
||||||
no-notes: "Sans aucune note"
|
no-notes: "Sans aucune note"
|
||||||
turn-on-darkmode: "Basculer vers le mode nuit"
|
turn-on-darkmode: "Mode nuit"
|
||||||
turn-off-darkmode: "Mode jour"
|
turn-off-darkmode: "Mode jour"
|
||||||
error:
|
error:
|
||||||
title: "Une erreur est survenue"
|
title: "Une erreur est survenue"
|
||||||
@ -220,15 +280,6 @@ common:
|
|||||||
auth/views/form.vue:
|
auth/views/form.vue:
|
||||||
share-access: "Désirez-vous autoriser <i>{name}</i> à avoir accès à votre compte ?"
|
share-access: "Désirez-vous autoriser <i>{name}</i> à avoir accès à votre compte ?"
|
||||||
permission-ask: "Cette application nécessite les autorisations suivantes :"
|
permission-ask: "Cette application nécessite les autorisations suivantes :"
|
||||||
account-read: "Afficher les informations du compte."
|
|
||||||
account-write: "Modifications des informations du compte."
|
|
||||||
note-write: "Publier."
|
|
||||||
like-write: "Réagir aux publications."
|
|
||||||
following-write: "Suivre des comptes et se désabonner."
|
|
||||||
drive-read: "Lire votre Drive"
|
|
||||||
drive-write: "Téléverser/supprimer des fichiers dans votre Drive."
|
|
||||||
notification-read: "Lire vos notifications."
|
|
||||||
notification-write: "Gérer vos notifications."
|
|
||||||
cancel: "Annuler"
|
cancel: "Annuler"
|
||||||
accept: "Autoriser l’accès"
|
accept: "Autoriser l’accès"
|
||||||
auth/views/index.vue:
|
auth/views/index.vue:
|
||||||
@ -250,6 +301,8 @@ common/views/pages/explore.vue:
|
|||||||
federated: "Du Fédiverse"
|
federated: "Du Fédiverse"
|
||||||
explore: "Explorer {host}"
|
explore: "Explorer {host}"
|
||||||
users-info: "Actuellement, {users} utilisateurs se sont inscrit ici"
|
users-info: "Actuellement, {users} utilisateurs se sont inscrit ici"
|
||||||
|
common/views/components/url-preview.vue:
|
||||||
|
disable-player: "Fermer le lecteur"
|
||||||
common/views/components/user-list.vue:
|
common/views/components/user-list.vue:
|
||||||
no-users: "Il n'y a aucun utilisateur"
|
no-users: "Il n'y a aucun utilisateur"
|
||||||
common/views/components/games/reversi/reversi.vue:
|
common/views/components/games/reversi/reversi.vue:
|
||||||
@ -424,19 +477,32 @@ common/views/components/user-menu.vue:
|
|||||||
common/views/components/poll.vue:
|
common/views/components/poll.vue:
|
||||||
vote-to: "Voter pour '{}'"
|
vote-to: "Voter pour '{}'"
|
||||||
vote-count: "{} votes"
|
vote-count: "{} votes"
|
||||||
|
total-votes: "{} Total des votes"
|
||||||
vote: "Vote"
|
vote: "Vote"
|
||||||
show-result: "Montrer les résultats"
|
show-result: "Montrer les résultats"
|
||||||
voted: "Voté"
|
voted: "Voté"
|
||||||
|
closed: "Terminé"
|
||||||
|
remaining-days: "{d} jours, {h} heures restantes"
|
||||||
|
remaining-hours: "{h} heures et {m} minutes restantes"
|
||||||
|
remaining-minutes: "{m} minutes et {s} secondes restantes"
|
||||||
|
remaining-seconds: "{s} secondes restantes"
|
||||||
common/views/components/poll-editor.vue:
|
common/views/components/poll-editor.vue:
|
||||||
no-only-one-choice: "Vous devez saisir au moins deux choix."
|
no-only-one-choice: "Vous devez saisir au moins deux choix."
|
||||||
choice-n: "Choix {}"
|
choice-n: "Choix {}"
|
||||||
remove: "Supprimer ce choix"
|
remove: "Supprimer ce choix"
|
||||||
add: "+ Ajouter un choix"
|
add: "+ Ajouter un choix"
|
||||||
destroy: "Annuler ce sondage"
|
destroy: "Annuler ce sondage"
|
||||||
|
expiration: "Valide jusqu'à"
|
||||||
|
infinite: "Illimité"
|
||||||
|
at: "Choisir une date et une durée"
|
||||||
|
no-more: "Vous ne pouvez pas en ajouter davantage"
|
||||||
|
deadline-date: "Date d’échéance"
|
||||||
|
deadline-time: "Durée"
|
||||||
interval: "Durée"
|
interval: "Durée"
|
||||||
unit: "Unité"
|
unit: "Unité"
|
||||||
second: "secondes"
|
second: "secondes"
|
||||||
minute: "Minutes"
|
minute: "Minutes"
|
||||||
|
hour: "Heures"
|
||||||
day: "D"
|
day: "D"
|
||||||
common/views/components/reaction-picker.vue:
|
common/views/components/reaction-picker.vue:
|
||||||
choose-reaction: "Choisissez votre réaction"
|
choose-reaction: "Choisissez votre réaction"
|
||||||
@ -568,6 +634,7 @@ common/views/components/profile-editor.vue:
|
|||||||
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: "Exporter"
|
export: "Exporter"
|
||||||
import: "Importer"
|
import: "Importer"
|
||||||
|
export-and-import: "Exportation et importation"
|
||||||
export-targets:
|
export-targets:
|
||||||
all-notes: "Toutes les notes publiées"
|
all-notes: "Toutes les notes publiées"
|
||||||
following-list: "Liste des abonnements"
|
following-list: "Liste des abonnements"
|
||||||
@ -793,7 +860,6 @@ desktop/views/components/post-form.vue:
|
|||||||
posting: "Publication …"
|
posting: "Publication …"
|
||||||
attach-media-from-local: "Joindre un média depuis votre appareil"
|
attach-media-from-local: "Joindre un média depuis votre appareil"
|
||||||
attach-media-from-drive: "Joindre un média depuis votre Drive"
|
attach-media-from-drive: "Joindre un média depuis votre Drive"
|
||||||
attach-cancel: "Annuler le fichier attaché"
|
|
||||||
insert-a-kao: "v('ω')v"
|
insert-a-kao: "v('ω')v"
|
||||||
create-poll: "Créer un sondage"
|
create-poll: "Créer un sondage"
|
||||||
text-remain: "{} caractères restants"
|
text-remain: "{} caractères restants"
|
||||||
@ -886,6 +952,9 @@ common/views/components/password-settings.vue:
|
|||||||
not-match: "Les nouveaux mots de passe ne sont pas identiques"
|
not-match: "Les nouveaux mots de passe ne sont pas identiques"
|
||||||
changed: "Mot de passe modifié avec succès"
|
changed: "Mot de passe modifié avec succès"
|
||||||
failed: "Échec lors de la modification du mot de passe"
|
failed: "Échec lors de la modification du mot de passe"
|
||||||
|
common/views/components/post-form-attaches.vue:
|
||||||
|
mark-as-sensitive: "Marquer comme sensible"
|
||||||
|
unmark-as-sensitive: "Ne pas marquer comme sensible"
|
||||||
desktop/views/components/sub-note-content.vue:
|
desktop/views/components/sub-note-content.vue:
|
||||||
private: "cette publication est privée"
|
private: "cette publication est privée"
|
||||||
deleted: "cette publication a été supprimée"
|
deleted: "cette publication a été supprimée"
|
||||||
@ -896,8 +965,6 @@ desktop/views/components/settings.tags.vue:
|
|||||||
query: "Requête (optionnelle)"
|
query: "Requête (optionnelle)"
|
||||||
add: "Ajouter"
|
add: "Ajouter"
|
||||||
save: "Enregistrer"
|
save: "Enregistrer"
|
||||||
desktop/views/components/taskmanager.vue:
|
|
||||||
title: "Gestionnaire de tâches"
|
|
||||||
desktop/views/components/timeline.vue:
|
desktop/views/components/timeline.vue:
|
||||||
home: "Accueil"
|
home: "Accueil"
|
||||||
local: "Local"
|
local: "Local"
|
||||||
@ -958,6 +1025,7 @@ admin/views/index.vue:
|
|||||||
hashtags: "Hashtags"
|
hashtags: "Hashtags"
|
||||||
abuse: "Abus"
|
abuse: "Abus"
|
||||||
queue: "File d’attente"
|
queue: "File d’attente"
|
||||||
|
logs: "Journaux"
|
||||||
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"
|
||||||
@ -1026,11 +1094,6 @@ admin/views/instance.vue:
|
|||||||
save: "Sauvegarder"
|
save: "Sauvegarder"
|
||||||
saved: "Enregistré"
|
saved: "Enregistré"
|
||||||
user-recommendation-config: "Utilisateurs"
|
user-recommendation-config: "Utilisateurs"
|
||||||
enable-external-user-recommendation: "Activer la recommandation des utilisateurs distants"
|
|
||||||
external-user-recommendation-engine: "Moteur"
|
|
||||||
external-user-recommendation-engine-desc: "Exemple : https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
|
|
||||||
external-user-recommendation-timeout: "Délai d’expiration"
|
|
||||||
external-user-recommendation-timeout-desc: "En millisecondes (par exemple : 300000)"
|
|
||||||
email-config: "Paramètres du serveur de messagerie"
|
email-config: "Paramètres du serveur de messagerie"
|
||||||
email-config-info: "Utilisé pour confirmer votre adresse de courrier électronique et la réinitialisation de votre mot de passe."
|
email-config-info: "Utilisé pour confirmer votre adresse de courrier électronique et la réinitialisation de votre mot de passe."
|
||||||
enable-email: "Activation de la distribution du courrier"
|
enable-email: "Activation de la distribution du courrier"
|
||||||
@ -1199,6 +1262,7 @@ admin/views/federation.vue:
|
|||||||
marked-as-closed: "Marquées comme fermées"
|
marked-as-closed: "Marquées comme fermées"
|
||||||
lookup: "Recherche"
|
lookup: "Recherche"
|
||||||
instances: "Fédérées"
|
instances: "Fédérées"
|
||||||
|
instance-not-registered: "L’instance n’a pas encore été découverte"
|
||||||
sort: "Trier par"
|
sort: "Trier par"
|
||||||
sorts:
|
sorts:
|
||||||
caughtAtAsc: "Date d’inscription (Ascendant)"
|
caughtAtAsc: "Date d’inscription (Ascendant)"
|
||||||
@ -1206,6 +1270,7 @@ admin/views/federation.vue:
|
|||||||
lastCommunicatedAtAsc: "La date et l'heure des interactions plus anciennes"
|
lastCommunicatedAtAsc: "La date et l'heure des interactions plus anciennes"
|
||||||
lastCommunicatedAtDesc: "La date et l'heure des nouvelles interactions"
|
lastCommunicatedAtDesc: "La date et l'heure des nouvelles interactions"
|
||||||
notesDesc: "Description des notes"
|
notesDesc: "Description des notes"
|
||||||
|
usersAsc: "Peu d'abonnés"
|
||||||
followingAsc: "Les moins suivies"
|
followingAsc: "Les moins suivies"
|
||||||
followingDesc: "Ayant le plus d'abonné·e·s"
|
followingDesc: "Ayant le plus d'abonné·e·s"
|
||||||
followersAsc: "Ayant le moins d'abonné·e·s"
|
followersAsc: "Ayant le moins d'abonné·e·s"
|
||||||
@ -1530,12 +1595,3 @@ dev/views/new-app.vue:
|
|||||||
authority: "Autorisations "
|
authority: "Autorisations "
|
||||||
authority-desc: "Sont accessibles via l’API, uniquement les fonctionnalités demandées ici."
|
authority-desc: "Sont accessibles via l’API, uniquement les fonctionnalités demandées ici."
|
||||||
authority-warning: "Vous pouvez le changer même après avoir créé l'application, mais si vous attribuez une nouvelle permission, toutes les clés utilisateur associées seront dès lors invalides."
|
authority-warning: "Vous pouvez le changer même après avoir créé l'application, mais si vous attribuez une nouvelle permission, toutes les clés utilisateur associées seront dès lors invalides."
|
||||||
account-read: "Afficher les informations du compte"
|
|
||||||
account-write: "Modifications des informations du compte"
|
|
||||||
note-write: "Publications."
|
|
||||||
reaction-write: "Ajout et suppression de réactions."
|
|
||||||
following-write: "S’abonner et se désabonner."
|
|
||||||
drive-read: "Lecture du Drive."
|
|
||||||
drive-write: "Téléversement/suppression des fichiers de votre Lecteur."
|
|
||||||
notification-read: "Lire vos notifications."
|
|
||||||
notification-write: "Gestion de vos notifications."
|
|
||||||
|
@ -964,7 +964,6 @@ desktop/views/components/post-form.vue:
|
|||||||
posting: "投稿中"
|
posting: "投稿中"
|
||||||
attach-media-from-local: "PCからメディアを添付"
|
attach-media-from-local: "PCからメディアを添付"
|
||||||
attach-media-from-drive: "ドライブからメディアを添付"
|
attach-media-from-drive: "ドライブからメディアを添付"
|
||||||
attach-cancel: "添付取り消し"
|
|
||||||
insert-a-kao: "v('ω')v"
|
insert-a-kao: "v('ω')v"
|
||||||
create-poll: "アンケートを作成"
|
create-poll: "アンケートを作成"
|
||||||
text-remain: "残り{}文字"
|
text-remain: "残り{}文字"
|
||||||
@ -1070,6 +1069,11 @@ common/views/components/password-settings.vue:
|
|||||||
changed: "パスワードを変更しました"
|
changed: "パスワードを変更しました"
|
||||||
failed: "パスワード変更に失敗しました"
|
failed: "パスワード変更に失敗しました"
|
||||||
|
|
||||||
|
common/views/components/post-form-attaches.vue:
|
||||||
|
attach-cancel: "添付取り消し"
|
||||||
|
mark-as-sensitive: "閲覧注意に設定"
|
||||||
|
unmark-as-sensitive: "閲覧注意を解除"
|
||||||
|
|
||||||
desktop/views/components/sub-note-content.vue:
|
desktop/views/components/sub-note-content.vue:
|
||||||
private: "この投稿は非公開です"
|
private: "この投稿は非公開です"
|
||||||
deleted: "この投稿は削除されました"
|
deleted: "この投稿は削除されました"
|
||||||
|
@ -166,15 +166,6 @@ common:
|
|||||||
auth/views/form.vue:
|
auth/views/form.vue:
|
||||||
share-access: "あんたのアカウントに<i>{name}</i>がアクセスしようとしてるで?ええか?"
|
share-access: "あんたのアカウントに<i>{name}</i>がアクセスしようとしてるで?ええか?"
|
||||||
permission-ask: "このアプリは次の権限を要求してんで:"
|
permission-ask: "このアプリは次の権限を要求してんで:"
|
||||||
account-read: "アカウントの情報を見させてもらうで。"
|
|
||||||
account-write: "アカウントの情報を操作させてもらうで。"
|
|
||||||
note-write: "投稿させてもらうで。"
|
|
||||||
like-write: "いいねしたりいいね解除させてもらうで。"
|
|
||||||
following-write: "フォローしたりフォロー解除させてもらうで。"
|
|
||||||
drive-read: "ドライブを見させてもらうで。"
|
|
||||||
drive-write: "ドライブを操作させてもらうで。"
|
|
||||||
notification-read: "通知を見させてもらうで。"
|
|
||||||
notification-write: "通知を操作させてもらうで。"
|
|
||||||
cancel: "やめとくわ"
|
cancel: "やめとくわ"
|
||||||
accept: "アクセスを許可や!"
|
accept: "アクセスを許可や!"
|
||||||
auth/views/index.vue:
|
auth/views/index.vue:
|
||||||
@ -688,7 +679,6 @@ desktop/views/components/post-form.vue:
|
|||||||
posting: "投稿中"
|
posting: "投稿中"
|
||||||
attach-media-from-local: "PCからメディア持ってくる"
|
attach-media-from-local: "PCからメディア持ってくる"
|
||||||
attach-media-from-drive: "ドライブからメディア持ってくる"
|
attach-media-from-drive: "ドライブからメディア持ってくる"
|
||||||
attach-cancel: "くっつけるのやめよか"
|
|
||||||
create-poll: "アンケートを作成"
|
create-poll: "アンケートを作成"
|
||||||
text-remain: "残り{}文字"
|
text-remain: "残り{}文字"
|
||||||
recent-tags: "最近のタグ"
|
recent-tags: "最近のタグ"
|
||||||
@ -779,6 +769,9 @@ common/views/components/password-settings.vue:
|
|||||||
enter-new-password-again: "もっぺん入れてや"
|
enter-new-password-again: "もっぺん入れてや"
|
||||||
not-match: "パスワードがおうとらん"
|
not-match: "パスワードがおうとらん"
|
||||||
changed: "パスワード変えたわ"
|
changed: "パスワード変えたわ"
|
||||||
|
common/views/components/post-form-attaches.vue:
|
||||||
|
mark-as-sensitive: "見たらあかん感じにしとく"
|
||||||
|
unmark-as-sensitive: "やっぱ見せたるわ"
|
||||||
desktop/views/components/sub-note-content.vue:
|
desktop/views/components/sub-note-content.vue:
|
||||||
private: "この投稿は見せられへんわ"
|
private: "この投稿は見せられへんわ"
|
||||||
deleted: "この投稿なんか無くなってもうたわ"
|
deleted: "この投稿なんか無くなってもうたわ"
|
||||||
@ -787,12 +780,9 @@ desktop/views/components/sub-note-content.vue:
|
|||||||
desktop/views/components/settings.tags.vue:
|
desktop/views/components/settings.tags.vue:
|
||||||
add: "増やす"
|
add: "増やす"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
desktop/views/components/taskmanager.vue:
|
|
||||||
title: "タスクマネージャ"
|
|
||||||
desktop/views/components/timeline.vue:
|
desktop/views/components/timeline.vue:
|
||||||
home: "ホーム"
|
home: "ホーム"
|
||||||
local: "ローカル"
|
local: "ローカル"
|
||||||
hybrid: "ソーシャル"
|
|
||||||
global: "グローバル"
|
global: "グローバル"
|
||||||
mentions: "あんた宛て"
|
mentions: "あんた宛て"
|
||||||
messages: "ダイレクト投稿"
|
messages: "ダイレクト投稿"
|
||||||
@ -908,11 +898,6 @@ admin/views/instance.vue:
|
|||||||
save: "保存"
|
save: "保存"
|
||||||
saved: "保存したで!"
|
saved: "保存したで!"
|
||||||
user-recommendation-config: "このユーザーええで"
|
user-recommendation-config: "このユーザーええで"
|
||||||
enable-external-user-recommendation: "外部ユーザーレコメンデーションを使えるようにする"
|
|
||||||
external-user-recommendation-engine: "エンジン"
|
|
||||||
external-user-recommendation-engine-desc: "例: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
|
|
||||||
external-user-recommendation-timeout: "タイムアウト"
|
|
||||||
external-user-recommendation-timeout-desc: "ミリ秒単位 (例: 300000)"
|
|
||||||
email-config: "メールサーバーの設定"
|
email-config: "メールサーバーの設定"
|
||||||
email-config-info: "メールアドレス確認やパスワードリセットの際に使うで。"
|
email-config-info: "メールアドレス確認やパスワードリセットの際に使うで。"
|
||||||
enable-email: "メール配信を有効にする"
|
enable-email: "メール配信を有効にする"
|
||||||
@ -1174,7 +1159,6 @@ mobile/views/pages/following.vue:
|
|||||||
mobile/views/pages/home.vue:
|
mobile/views/pages/home.vue:
|
||||||
home: "ホーム"
|
home: "ホーム"
|
||||||
local: "ローカル"
|
local: "ローカル"
|
||||||
hybrid: "ソーシャル"
|
|
||||||
global: "グローバル"
|
global: "グローバル"
|
||||||
mentions: "あんた宛て"
|
mentions: "あんた宛て"
|
||||||
messages: "ダイレクト投稿"
|
messages: "ダイレクト投稿"
|
||||||
@ -1229,7 +1213,6 @@ deck:
|
|||||||
widgets: "ウィジェット"
|
widgets: "ウィジェット"
|
||||||
home: "ホーム"
|
home: "ホーム"
|
||||||
local: "ローカル"
|
local: "ローカル"
|
||||||
hybrid: "ソーシャル"
|
|
||||||
hashtag: "ハッシュタグ"
|
hashtag: "ハッシュタグ"
|
||||||
global: "グローバル"
|
global: "グローバル"
|
||||||
mentions: "あんた宛て"
|
mentions: "あんた宛て"
|
||||||
@ -1298,12 +1281,3 @@ dev/views/new-app.vue:
|
|||||||
authority: "権限"
|
authority: "権限"
|
||||||
authority-desc: "ここにチェックした機能しかAPIからアクセスできひんから気ぃつけてな"
|
authority-desc: "ここにチェックした機能しかAPIからアクセスできひんから気ぃつけてな"
|
||||||
authority-warning: "アプリ作った後でも変えれるけど、新しいやつ追加したらそん時関連付いてるユーザーキーは全部ほかされるで。"
|
authority-warning: "アプリ作った後でも変えれるけど、新しいやつ追加したらそん時関連付いてるユーザーキーは全部ほかされるで。"
|
||||||
account-read: "アカウントの情報見せて"
|
|
||||||
account-write: "アカウントの情報いじらせて"
|
|
||||||
note-write: "投稿させて"
|
|
||||||
reaction-write: "リアクションしたりそれをキャンセルさせて"
|
|
||||||
following-write: "フォローとかフォロー解除させて"
|
|
||||||
drive-read: "ドライブ見せて"
|
|
||||||
drive-write: "ドライブいじらせて"
|
|
||||||
notification-read: "通知見せて"
|
|
||||||
notification-write: "通知いじらせて"
|
|
||||||
|
@ -69,6 +69,11 @@ common:
|
|||||||
following: "팔로우 중"
|
following: "팔로우 중"
|
||||||
followers: "팔로워"
|
followers: "팔로워"
|
||||||
favorites: "즐겨찾기"
|
favorites: "즐겨찾기"
|
||||||
|
permissions:
|
||||||
|
'read:account': "계정 정보 보기"
|
||||||
|
'write:account': "계정 정보 변경"
|
||||||
|
'read:drive': "드라이브 보기"
|
||||||
|
'write:drive': "드라이브 수정"
|
||||||
empty-timeline-info:
|
empty-timeline-info:
|
||||||
follow-users-to-make-your-timeline: "사용자를 팔로우하면 글이 타임라인에 표시됩니다."
|
follow-users-to-make-your-timeline: "사용자를 팔로우하면 글이 타임라인에 표시됩니다."
|
||||||
explore: "사용자 탐색"
|
explore: "사용자 탐색"
|
||||||
@ -282,15 +287,6 @@ common:
|
|||||||
auth/views/form.vue:
|
auth/views/form.vue:
|
||||||
share-access: "<i>{name}</i>가 당신의 계정에 엑세스하도록 허용하시겠습니까?"
|
share-access: "<i>{name}</i>가 당신의 계정에 엑세스하도록 허용하시겠습니까?"
|
||||||
permission-ask: "이 앱은 다음의 권한을 요청합니다:"
|
permission-ask: "이 앱은 다음의 권한을 요청합니다:"
|
||||||
account-read: "계정 정보 보기."
|
|
||||||
account-write: "계정 정보의 수정."
|
|
||||||
note-write: "게시하기."
|
|
||||||
like-write: "좋아요 하거나 좋아요 해제하기."
|
|
||||||
following-write: "팔로우하거나 팔로우를 취소하기."
|
|
||||||
drive-read: "드라이브 보기."
|
|
||||||
drive-write: "드라이브의 수정."
|
|
||||||
notification-read: "알림 읽기."
|
|
||||||
notification-write: "알림 수정하기."
|
|
||||||
cancel: "취소"
|
cancel: "취소"
|
||||||
accept: "접근 권한 허용"
|
accept: "접근 권한 허용"
|
||||||
auth/views/index.vue:
|
auth/views/index.vue:
|
||||||
@ -877,7 +873,6 @@ desktop/views/components/post-form.vue:
|
|||||||
posting: "게시중"
|
posting: "게시중"
|
||||||
attach-media-from-local: "PC에서 미디어 첨부"
|
attach-media-from-local: "PC에서 미디어 첨부"
|
||||||
attach-media-from-drive: "드라이브에서 미디어 첨부"
|
attach-media-from-drive: "드라이브에서 미디어 첨부"
|
||||||
attach-cancel: "첨부 취소"
|
|
||||||
insert-a-kao: "v('ω')v"
|
insert-a-kao: "v('ω')v"
|
||||||
create-poll: "투표 만들기"
|
create-poll: "투표 만들기"
|
||||||
text-remain: "{}문자 남음"
|
text-remain: "{}문자 남음"
|
||||||
@ -970,6 +965,9 @@ common/views/components/password-settings.vue:
|
|||||||
not-match: "새 비밀번호가 일치하지 않습니다"
|
not-match: "새 비밀번호가 일치하지 않습니다"
|
||||||
changed: "비밀번호를 변경하였습니다"
|
changed: "비밀번호를 변경하였습니다"
|
||||||
failed: "비밀번호 변경을 실패하였습니다."
|
failed: "비밀번호 변경을 실패하였습니다."
|
||||||
|
common/views/components/post-form-attaches.vue:
|
||||||
|
mark-as-sensitive: "열람주의로 설정"
|
||||||
|
unmark-as-sensitive: "열람주의 해제"
|
||||||
desktop/views/components/sub-note-content.vue:
|
desktop/views/components/sub-note-content.vue:
|
||||||
private: "이 글은 비공개입니다"
|
private: "이 글은 비공개입니다"
|
||||||
deleted: "이 글은 삭제되었습니다"
|
deleted: "이 글은 삭제되었습니다"
|
||||||
@ -980,8 +978,6 @@ desktop/views/components/settings.tags.vue:
|
|||||||
query: "쿼리 (생략 가능)"
|
query: "쿼리 (생략 가능)"
|
||||||
add: "추가"
|
add: "추가"
|
||||||
save: "저장"
|
save: "저장"
|
||||||
desktop/views/components/taskmanager.vue:
|
|
||||||
title: "작업 관리자"
|
|
||||||
desktop/views/components/timeline.vue:
|
desktop/views/components/timeline.vue:
|
||||||
home: "홈"
|
home: "홈"
|
||||||
local: "로컬"
|
local: "로컬"
|
||||||
@ -1115,11 +1111,6 @@ admin/views/instance.vue:
|
|||||||
save: "저장"
|
save: "저장"
|
||||||
saved: "저장하였습니다"
|
saved: "저장하였습니다"
|
||||||
user-recommendation-config: "추천 사용자"
|
user-recommendation-config: "추천 사용자"
|
||||||
enable-external-user-recommendation: "외부 사용자 추천 활성화"
|
|
||||||
external-user-recommendation-engine: "엔진"
|
|
||||||
external-user-recommendation-engine-desc: "예: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
|
|
||||||
external-user-recommendation-timeout: "타임 아웃"
|
|
||||||
external-user-recommendation-timeout-desc: "밀리초 (예: 300000)"
|
|
||||||
email-config: "메일 서버 설정"
|
email-config: "메일 서버 설정"
|
||||||
email-config-info: "메일 주소 확인 혹은 비밀번호 재설정에 사용 됩니다."
|
email-config-info: "메일 주소 확인 혹은 비밀번호 재설정에 사용 됩니다."
|
||||||
enable-email: "메일 발신 활성화"
|
enable-email: "메일 발신 활성화"
|
||||||
@ -1632,12 +1623,3 @@ dev/views/new-app.vue:
|
|||||||
authority: "권한"
|
authority: "권한"
|
||||||
authority-desc: "이곳에서 요청한 권한에 한정하여 API로 액세스할 수 있습니다."
|
authority-desc: "이곳에서 요청한 권한에 한정하여 API로 액세스할 수 있습니다."
|
||||||
authority-warning: "앱을 생성한 뒤에도 변경할 수 있지만, 새로운 권한을 설정하는 경우 그 시점부터 예전에 발급받았던 유저 키는 모두 무효화됩니다."
|
authority-warning: "앱을 생성한 뒤에도 변경할 수 있지만, 새로운 권한을 설정하는 경우 그 시점부터 예전에 발급받았던 유저 키는 모두 무효화됩니다."
|
||||||
account-read: "계정 정보 보기."
|
|
||||||
account-write: "계정 정보 편집."
|
|
||||||
note-write: "글 쓰기."
|
|
||||||
reaction-write: "리액션을 하거나 리액션을 취소할 수 있음."
|
|
||||||
following-write: "팔로우하거나 팔로우 해제하기."
|
|
||||||
drive-read: "드라이브 보기."
|
|
||||||
drive-write: "드라이브를 조작."
|
|
||||||
notification-read: "알림 보기."
|
|
||||||
notification-write: "알림 조작."
|
|
||||||
|
@ -334,7 +334,6 @@ desktop/views/components/post-form.vue:
|
|||||||
posting: "Bezig met plaatsen"
|
posting: "Bezig met plaatsen"
|
||||||
attach-media-from-local: "Media bijvoegen van je computer"
|
attach-media-from-local: "Media bijvoegen van je computer"
|
||||||
attach-media-from-drive: "Media bijvoegen uit je Drive"
|
attach-media-from-drive: "Media bijvoegen uit je Drive"
|
||||||
attach-cancel: "Bijlage annuleren"
|
|
||||||
create-poll: "Peiling creëren"
|
create-poll: "Peiling creëren"
|
||||||
text-remain: "{} resterende tekens"
|
text-remain: "{} resterende tekens"
|
||||||
desktop/views/components/post-form-window.vue:
|
desktop/views/components/post-form-window.vue:
|
||||||
@ -384,8 +383,6 @@ desktop/views/components/sub-note-content.vue:
|
|||||||
poll: "Peilingen"
|
poll: "Peilingen"
|
||||||
desktop/views/components/settings.tags.vue:
|
desktop/views/components/settings.tags.vue:
|
||||||
add: "Toevoegen"
|
add: "Toevoegen"
|
||||||
desktop/views/components/taskmanager.vue:
|
|
||||||
title: "Taakbeheer"
|
|
||||||
desktop/views/components/timeline.vue:
|
desktop/views/components/timeline.vue:
|
||||||
home: "Startpagina"
|
home: "Startpagina"
|
||||||
local: "Lokaal"
|
local: "Lokaal"
|
||||||
|
@ -23,6 +23,7 @@ common:
|
|||||||
enter-password: "Wprowadź Hasło"
|
enter-password: "Wprowadź Hasło"
|
||||||
2fa: "Uwierzytelnienie dwuetapowe"
|
2fa: "Uwierzytelnienie dwuetapowe"
|
||||||
customize-home: "Dostosuj stronę główną"
|
customize-home: "Dostosuj stronę główną"
|
||||||
|
featured-notes: "Wyróżnienia"
|
||||||
dark-mode: "Tryb ciemny"
|
dark-mode: "Tryb ciemny"
|
||||||
signin: "Zaloguj się"
|
signin: "Zaloguj się"
|
||||||
signup: "Rejestracja"
|
signup: "Rejestracja"
|
||||||
@ -61,6 +62,8 @@ common:
|
|||||||
following: "Śledzisz"
|
following: "Śledzisz"
|
||||||
followers: "Śledzący"
|
followers: "Śledzący"
|
||||||
favorites: "Moje ulubione"
|
favorites: "Moje ulubione"
|
||||||
|
permissions:
|
||||||
|
'read:drive': "Wyświetl dysk"
|
||||||
empty-timeline-info:
|
empty-timeline-info:
|
||||||
explore: "Poznaj"
|
explore: "Poznaj"
|
||||||
weekday-short:
|
weekday-short:
|
||||||
@ -201,15 +204,6 @@ common:
|
|||||||
you: "Ty"
|
you: "Ty"
|
||||||
auth/views/form.vue:
|
auth/views/form.vue:
|
||||||
permission-ask: "Ta aplikacja wymaga następujących uprawnień:"
|
permission-ask: "Ta aplikacja wymaga następujących uprawnień:"
|
||||||
account-read: "Wyświetlanie informacji o koncie:"
|
|
||||||
account-write: "Modyfikowanie informacji o koncie:"
|
|
||||||
note-write: "Publikacja."
|
|
||||||
like-write: "Reagowanie na wpisy."
|
|
||||||
following-write: "Śledzenie i cofanie śledzenia."
|
|
||||||
drive-read: "Odczytywanie Twojego dysku."
|
|
||||||
drive-write: "Wysyłanie i usuwanie plików na Twoim dysku."
|
|
||||||
notification-read: "Odczytywanie Twoich powiadomień."
|
|
||||||
notification-write: "Zarządzanie Twoimi powiadomieniami."
|
|
||||||
cancel: "Anuluj"
|
cancel: "Anuluj"
|
||||||
accept: "Przyznaj dostęp."
|
accept: "Przyznaj dostęp."
|
||||||
auth/views/index.vue:
|
auth/views/index.vue:
|
||||||
@ -715,7 +709,6 @@ desktop/views/components/post-form.vue:
|
|||||||
posting: "Wysyłanie"
|
posting: "Wysyłanie"
|
||||||
attach-media-from-local: "Załącz zawartość multimedialną z komputera"
|
attach-media-from-local: "Załącz zawartość multimedialną z komputera"
|
||||||
attach-media-from-drive: "Załącz zawartość multimedialną z dysku"
|
attach-media-from-drive: "Załącz zawartość multimedialną z dysku"
|
||||||
attach-cancel: "Usuń załącznik"
|
|
||||||
insert-a-kao: "v('ω')v"
|
insert-a-kao: "v('ω')v"
|
||||||
create-poll: "Utwórz ankietę"
|
create-poll: "Utwórz ankietę"
|
||||||
text-remain: "pozostałe znaki: {}"
|
text-remain: "pozostałe znaki: {}"
|
||||||
@ -795,6 +788,9 @@ common/views/components/password-settings.vue:
|
|||||||
enter-current-password: "Wprowadź obecne hasło"
|
enter-current-password: "Wprowadź obecne hasło"
|
||||||
enter-new-password: "Wprowadź nowe hasło"
|
enter-new-password: "Wprowadź nowe hasło"
|
||||||
enter-new-password-again: "Wprowadź ponownie nowe hasło"
|
enter-new-password-again: "Wprowadź ponownie nowe hasło"
|
||||||
|
common/views/components/post-form-attaches.vue:
|
||||||
|
mark-as-sensitive: "Oznacz jako zawartość wrażliwą"
|
||||||
|
unmark-as-sensitive: "Cofnij oznaczenie jako zawartość wrażliwą"
|
||||||
desktop/views/components/sub-note-content.vue:
|
desktop/views/components/sub-note-content.vue:
|
||||||
private: "ten wpis jest prywatny"
|
private: "ten wpis jest prywatny"
|
||||||
deleted: "ten wpis został usunięty"
|
deleted: "ten wpis został usunięty"
|
||||||
@ -805,12 +801,9 @@ desktop/views/components/settings.tags.vue:
|
|||||||
query: "Zapytanie (opcjonalne)"
|
query: "Zapytanie (opcjonalne)"
|
||||||
add: "Dodaj"
|
add: "Dodaj"
|
||||||
save: "Zapisz"
|
save: "Zapisz"
|
||||||
desktop/views/components/taskmanager.vue:
|
|
||||||
title: "Menedżer zadań"
|
|
||||||
desktop/views/components/timeline.vue:
|
desktop/views/components/timeline.vue:
|
||||||
home: "Strona główna"
|
home: "Strona główna"
|
||||||
local: "Lokalne"
|
local: "Lokalne"
|
||||||
hybrid: "Społeczność"
|
|
||||||
global: "Globalne"
|
global: "Globalne"
|
||||||
mentions: "Wspomnienia"
|
mentions: "Wspomnienia"
|
||||||
messages: "Bezpośrednie wpisy"
|
messages: "Bezpośrednie wpisy"
|
||||||
@ -882,8 +875,6 @@ admin/views/instance.vue:
|
|||||||
save: "Zapisz"
|
save: "Zapisz"
|
||||||
saved: "Zapisano"
|
saved: "Zapisano"
|
||||||
user-recommendation-config: "Polecani użytkownicy"
|
user-recommendation-config: "Polecani użytkownicy"
|
||||||
external-user-recommendation-engine: "Silnik"
|
|
||||||
external-user-recommendation-engine-desc: "Np: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
|
|
||||||
email: "Adres e-mail"
|
email: "Adres e-mail"
|
||||||
admin/views/charts.vue:
|
admin/views/charts.vue:
|
||||||
notes: "Wpisy"
|
notes: "Wpisy"
|
||||||
@ -1119,7 +1110,6 @@ mobile/views/pages/signup.vue:
|
|||||||
mobile/views/pages/home.vue:
|
mobile/views/pages/home.vue:
|
||||||
home: "Strona główna"
|
home: "Strona główna"
|
||||||
local: "Lokalne"
|
local: "Lokalne"
|
||||||
hybrid: "Społeczność"
|
|
||||||
global: "Globalne"
|
global: "Globalne"
|
||||||
mentions: "Wspomnienia"
|
mentions: "Wspomnienia"
|
||||||
messages: "Bezpośrednie wpisy"
|
messages: "Bezpośrednie wpisy"
|
||||||
@ -1169,7 +1159,6 @@ deck:
|
|||||||
widgets: "Widżety"
|
widgets: "Widżety"
|
||||||
home: "Strona główna"
|
home: "Strona główna"
|
||||||
local: "Lokalne"
|
local: "Lokalne"
|
||||||
hybrid: "Społeczność"
|
|
||||||
hashtag: "Hashtag"
|
hashtag: "Hashtag"
|
||||||
global: "Globalne"
|
global: "Globalne"
|
||||||
mentions: "Wspomnienia"
|
mentions: "Wspomnienia"
|
||||||
@ -1224,11 +1213,3 @@ dev/views/apps.vue:
|
|||||||
dev/views/new-app.vue:
|
dev/views/new-app.vue:
|
||||||
app-name: "Nazwa Aplikacji"
|
app-name: "Nazwa Aplikacji"
|
||||||
authority: "Uprawnienia"
|
authority: "Uprawnienia"
|
||||||
account-read: "Wyświetlanie informacji o koncie:"
|
|
||||||
account-write: "Modyfikowanie informacji o koncie:"
|
|
||||||
note-write: "Publikacja."
|
|
||||||
following-write: "Śledzenie i cofanie śledzenia."
|
|
||||||
drive-read: "Odczytywanie Twojego dysku."
|
|
||||||
drive-write: "Wysyłanie i usuwanie plików na Twoim dysku."
|
|
||||||
notification-read: "Odczytywanie Twoich powiadomień."
|
|
||||||
notification-write: "Zarządzanie Twoimi powiadomieniami."
|
|
||||||
|
@ -119,9 +119,6 @@ common:
|
|||||||
you: "Você"
|
you: "Você"
|
||||||
auth/views/form.vue:
|
auth/views/form.vue:
|
||||||
permission-ask: "Este aplicativo precisa das seguintes permissões:"
|
permission-ask: "Este aplicativo precisa das seguintes permissões:"
|
||||||
account-read: "Ver informações da conta."
|
|
||||||
account-write: "Modificar informações da conta."
|
|
||||||
note-write: "Publicar"
|
|
||||||
cancel: "Cancelar"
|
cancel: "Cancelar"
|
||||||
accept: "Permitir acesso"
|
accept: "Permitir acesso"
|
||||||
auth/views/index.vue:
|
auth/views/index.vue:
|
||||||
@ -292,7 +289,3 @@ docs:
|
|||||||
description: "Descrição"
|
description: "Descrição"
|
||||||
dev/views/index.vue:
|
dev/views/index.vue:
|
||||||
manage-apps: "Gerenciar aplicativos"
|
manage-apps: "Gerenciar aplicativos"
|
||||||
dev/views/new-app.vue:
|
|
||||||
account-read: "Ver informações da conta."
|
|
||||||
account-write: "Modificar informações da conta."
|
|
||||||
note-write: "Publicar"
|
|
||||||
|
@ -69,6 +69,11 @@ common:
|
|||||||
following: "正在关注"
|
following: "正在关注"
|
||||||
followers: "关注者"
|
followers: "关注者"
|
||||||
favorites: "最爱"
|
favorites: "最爱"
|
||||||
|
permissions:
|
||||||
|
'read:account': "查看账户信息"
|
||||||
|
'write:account': "更改我的帐户信息"
|
||||||
|
'read:drive': "查看网盘"
|
||||||
|
'write:drive': "管理网盘文件"
|
||||||
empty-timeline-info:
|
empty-timeline-info:
|
||||||
follow-users-to-make-your-timeline: "关注其他用户时,帖子将显示在时间线中。"
|
follow-users-to-make-your-timeline: "关注其他用户时,帖子将显示在时间线中。"
|
||||||
explore: "查找用户"
|
explore: "查找用户"
|
||||||
@ -282,15 +287,6 @@ common:
|
|||||||
auth/views/form.vue:
|
auth/views/form.vue:
|
||||||
share-access: "您要允许<i>{name}</i>来访问您的账户吗?"
|
share-access: "您要允许<i>{name}</i>来访问您的账户吗?"
|
||||||
permission-ask: "这个应用程序需要以下权限:"
|
permission-ask: "这个应用程序需要以下权限:"
|
||||||
account-read: "查看账户信息"
|
|
||||||
account-write: "修改账户信息"
|
|
||||||
note-write: "投稿。"
|
|
||||||
like-write: "点赞或取消赞。"
|
|
||||||
following-write: "关注或取消关注。"
|
|
||||||
drive-read: "查看您的网盘"
|
|
||||||
drive-write: "管理网盘文件。"
|
|
||||||
notification-read: "查看通知。"
|
|
||||||
notification-write: "管理通知。"
|
|
||||||
cancel: "取消"
|
cancel: "取消"
|
||||||
accept: "允许访问。"
|
accept: "允许访问。"
|
||||||
auth/views/index.vue:
|
auth/views/index.vue:
|
||||||
@ -877,7 +873,6 @@ desktop/views/components/post-form.vue:
|
|||||||
posting: "发送中"
|
posting: "发送中"
|
||||||
attach-media-from-local: "从设备中添加媒体文件"
|
attach-media-from-local: "从设备中添加媒体文件"
|
||||||
attach-media-from-drive: "从网盘中添加媒体文件"
|
attach-media-from-drive: "从网盘中添加媒体文件"
|
||||||
attach-cancel: "删除附件"
|
|
||||||
insert-a-kao: "v('ω')v"
|
insert-a-kao: "v('ω')v"
|
||||||
create-poll: "创建一个投票"
|
create-poll: "创建一个投票"
|
||||||
text-remain: "还剩{}字"
|
text-remain: "还剩{}字"
|
||||||
@ -970,6 +965,9 @@ common/views/components/password-settings.vue:
|
|||||||
not-match: "新密码不匹配"
|
not-match: "新密码不匹配"
|
||||||
changed: "密码已更改"
|
changed: "密码已更改"
|
||||||
failed: "更改密码失败"
|
failed: "更改密码失败"
|
||||||
|
common/views/components/post-form-attaches.vue:
|
||||||
|
mark-as-sensitive: "标记为“敏感”"
|
||||||
|
unmark-as-sensitive: "取消标记为“敏感”"
|
||||||
desktop/views/components/sub-note-content.vue:
|
desktop/views/components/sub-note-content.vue:
|
||||||
private: "这个帖子是私密的"
|
private: "这个帖子是私密的"
|
||||||
deleted: "帖子已删除"
|
deleted: "帖子已删除"
|
||||||
@ -980,8 +978,6 @@ desktop/views/components/settings.tags.vue:
|
|||||||
query: "查询 (可选)"
|
query: "查询 (可选)"
|
||||||
add: "添加"
|
add: "添加"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
desktop/views/components/taskmanager.vue:
|
|
||||||
title: "任务管理器"
|
|
||||||
desktop/views/components/timeline.vue:
|
desktop/views/components/timeline.vue:
|
||||||
home: "首页"
|
home: "首页"
|
||||||
local: "本地"
|
local: "本地"
|
||||||
@ -1115,11 +1111,6 @@ admin/views/instance.vue:
|
|||||||
save: "保存"
|
save: "保存"
|
||||||
saved: "保存完毕"
|
saved: "保存完毕"
|
||||||
user-recommendation-config: "推荐用户"
|
user-recommendation-config: "推荐用户"
|
||||||
enable-external-user-recommendation: "启用外部用户推荐"
|
|
||||||
external-user-recommendation-engine: "引擎"
|
|
||||||
external-user-recommendation-engine-desc: "例如: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
|
|
||||||
external-user-recommendation-timeout: "超时"
|
|
||||||
external-user-recommendation-timeout-desc: "单位为毫秒 (例如:300000)"
|
|
||||||
email-config: "电子邮件服务器设置"
|
email-config: "电子邮件服务器设置"
|
||||||
email-config-info: "用于确认电子邮件和密码重置等。"
|
email-config-info: "用于确认电子邮件和密码重置等。"
|
||||||
enable-email: "启用电子邮件送递"
|
enable-email: "启用电子邮件送递"
|
||||||
@ -1503,7 +1494,7 @@ mobile/views/pages/following.vue:
|
|||||||
mobile/views/pages/home.vue:
|
mobile/views/pages/home.vue:
|
||||||
home: "首页"
|
home: "首页"
|
||||||
local: "Local"
|
local: "Local"
|
||||||
hybrid: "Social"
|
hybrid: "社交"
|
||||||
global: "Global"
|
global: "Global"
|
||||||
mentions: "Mentions"
|
mentions: "Mentions"
|
||||||
messages: "直接发布"
|
messages: "直接发布"
|
||||||
@ -1559,7 +1550,7 @@ deck:
|
|||||||
widgets: "小部件"
|
widgets: "小部件"
|
||||||
home: "首页"
|
home: "首页"
|
||||||
local: "Local"
|
local: "Local"
|
||||||
hybrid: "Social"
|
hybrid: "社交"
|
||||||
hashtag: "标签"
|
hashtag: "标签"
|
||||||
global: "Global"
|
global: "Global"
|
||||||
mentions: "Mentions"
|
mentions: "Mentions"
|
||||||
@ -1632,12 +1623,3 @@ dev/views/new-app.vue:
|
|||||||
authority: "权限"
|
authority: "权限"
|
||||||
authority-desc: "只能通过API访问此处请求的功能。"
|
authority-desc: "只能通过API访问此处请求的功能。"
|
||||||
authority-warning: "您可以在创建应用程序后对其进行更改,但如果您授予不同的权限,则当时关联的所有用户密钥都将失效。"
|
authority-warning: "您可以在创建应用程序后对其进行更改,但如果您授予不同的权限,则当时关联的所有用户密钥都将失效。"
|
||||||
account-read: "查看账户信息"
|
|
||||||
account-write: "修改账户信息"
|
|
||||||
note-write: "投稿。"
|
|
||||||
reaction-write: "添加或删除回应。"
|
|
||||||
following-write: "关注和不关注"
|
|
||||||
drive-read: "查看网盘"
|
|
||||||
drive-write: "管理网盘文件。"
|
|
||||||
notification-read: "阅读您的通知"
|
|
||||||
notification-write: "管理通知"
|
|
||||||
|
71
package.json
71
package.json
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <i@syuilo.com>",
|
"author": "syuilo <i@syuilo.com>",
|
||||||
"version": "11.0.0-beta.7",
|
"version": "11.0.1",
|
||||||
"codename": "daybreak",
|
"codename": "daybreak",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -12,8 +12,6 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node ./index.js",
|
"start": "node ./index.js",
|
||||||
"init": "node ./built/init.js",
|
"init": "node ./built/init.js",
|
||||||
"migrate": "node ./built/migrate.js",
|
|
||||||
"debug": "DEBUG=misskey:* node ./index.js",
|
|
||||||
"build": "webpack && gulp build",
|
"build": "webpack && gulp build",
|
||||||
"webpack": "webpack",
|
"webpack": "webpack",
|
||||||
"watch": "webpack --watch",
|
"watch": "webpack --watch",
|
||||||
@ -34,14 +32,13 @@
|
|||||||
"@prezzemolo/rap": "0.1.2",
|
"@prezzemolo/rap": "0.1.2",
|
||||||
"@prezzemolo/zip": "0.0.3",
|
"@prezzemolo/zip": "0.0.3",
|
||||||
"@types/bcryptjs": "2.4.2",
|
"@types/bcryptjs": "2.4.2",
|
||||||
"@types/bull": "3.5.8",
|
"@types/bull": "3.5.11",
|
||||||
"@types/chai-http": "3.0.5",
|
|
||||||
"@types/dateformat": "3.0.0",
|
"@types/dateformat": "3.0.0",
|
||||||
"@types/deep-equal": "1.0.1",
|
"@types/deep-equal": "1.0.1",
|
||||||
"@types/double-ended-queue": "2.1.0",
|
"@types/double-ended-queue": "2.1.0",
|
||||||
"@types/elasticsearch": "5.0.30",
|
"@types/elasticsearch": "5.0.32",
|
||||||
"@types/file-type": "10.6.0",
|
"@types/file-type": "10.9.1",
|
||||||
"@types/gulp": "4.0.5",
|
"@types/gulp": "4.0.6",
|
||||||
"@types/gulp-mocha": "0.0.32",
|
"@types/gulp-mocha": "0.0.32",
|
||||||
"@types/gulp-rename": "0.0.33",
|
"@types/gulp-rename": "0.0.33",
|
||||||
"@types/gulp-replace": "0.0.31",
|
"@types/gulp-replace": "0.0.31",
|
||||||
@ -49,19 +46,19 @@
|
|||||||
"@types/gulp-util": "3.0.34",
|
"@types/gulp-util": "3.0.34",
|
||||||
"@types/is-root": "1.0.0",
|
"@types/is-root": "1.0.0",
|
||||||
"@types/is-url": "1.2.28",
|
"@types/is-url": "1.2.28",
|
||||||
"@types/js-yaml": "3.12.0",
|
"@types/js-yaml": "3.12.1",
|
||||||
"@types/jsdom": "12.2.3",
|
"@types/jsdom": "12.2.3",
|
||||||
"@types/katex": "0.10.1",
|
"@types/katex": "0.10.1",
|
||||||
"@types/koa": "2.0.48",
|
"@types/koa": "2.0.48",
|
||||||
"@types/koa-bodyparser": "5.0.2",
|
"@types/koa-bodyparser": "5.0.2",
|
||||||
"@types/koa-compress": "2.0.8",
|
"@types/koa-compress": "2.0.9",
|
||||||
"@types/koa-cors": "0.0.0",
|
"@types/koa-cors": "0.0.0",
|
||||||
"@types/koa-favicon": "2.0.19",
|
"@types/koa-favicon": "2.0.19",
|
||||||
"@types/koa-logger": "3.1.1",
|
"@types/koa-logger": "3.1.1",
|
||||||
"@types/koa-mount": "3.0.1",
|
"@types/koa-mount": "3.0.1",
|
||||||
"@types/koa-multer": "1.0.0",
|
"@types/koa-multer": "1.0.0",
|
||||||
"@types/koa-router": "7.0.40",
|
"@types/koa-router": "7.0.40",
|
||||||
"@types/koa-send": "4.1.1",
|
"@types/koa-send": "4.1.2",
|
||||||
"@types/koa-views": "2.0.3",
|
"@types/koa-views": "2.0.3",
|
||||||
"@types/koa__cors": "2.2.3",
|
"@types/koa__cors": "2.2.3",
|
||||||
"@types/lolex": "3.1.1",
|
"@types/lolex": "3.1.1",
|
||||||
@ -69,37 +66,36 @@
|
|||||||
"@types/mocha": "5.2.6",
|
"@types/mocha": "5.2.6",
|
||||||
"@types/mongodb": "3.1.22",
|
"@types/mongodb": "3.1.22",
|
||||||
"@types/monk": "6.0.0",
|
"@types/monk": "6.0.0",
|
||||||
"@types/node": "11.10.4",
|
"@types/node": "11.13.4",
|
||||||
"@types/nodemailer": "4.6.6",
|
"@types/nodemailer": "4.6.7",
|
||||||
"@types/nprogress": "0.0.29",
|
"@types/nprogress": "0.0.29",
|
||||||
"@types/oauth": "0.9.1",
|
"@types/oauth": "0.9.1",
|
||||||
"@types/parse5": "5.0.0",
|
"@types/parse5": "5.0.0",
|
||||||
"@types/parsimmon": "1.10.0",
|
"@types/parsimmon": "1.10.0",
|
||||||
"@types/portscanner": "2.1.0",
|
"@types/portscanner": "2.1.0",
|
||||||
"@types/pug": "2.0.4",
|
"@types/pug": "2.0.4",
|
||||||
"@types/qrcode": "1.3.0",
|
"@types/qrcode": "1.3.2",
|
||||||
"@types/ratelimiter": "2.1.28",
|
"@types/ratelimiter": "2.1.28",
|
||||||
"@types/redis": "2.8.10",
|
"@types/redis": "2.8.12",
|
||||||
"@types/rename": "1.0.1",
|
"@types/rename": "1.0.1",
|
||||||
"@types/request": "2.48.1",
|
"@types/request": "2.48.1",
|
||||||
"@types/request-promise-native": "1.0.15",
|
"@types/request-promise-native": "1.0.15",
|
||||||
"@types/request-stats": "3.0.0",
|
"@types/request-stats": "3.0.0",
|
||||||
"@types/rimraf": "2.0.2",
|
"@types/rimraf": "2.0.2",
|
||||||
"@types/seedrandom": "2.4.27",
|
"@types/sharp": "0.22.1",
|
||||||
"@types/sharp": "0.21.2",
|
|
||||||
"@types/showdown": "1.9.2",
|
"@types/showdown": "1.9.2",
|
||||||
"@types/speakeasy": "2.0.4",
|
"@types/speakeasy": "2.0.4",
|
||||||
"@types/systeminformation": "3.23.1",
|
"@types/systeminformation": "3.23.1",
|
||||||
"@types/tinycolor2": "1.4.1",
|
"@types/tinycolor2": "1.4.1",
|
||||||
"@types/tmp": "0.0.33",
|
"@types/tmp": "0.1.0",
|
||||||
"@types/uuid": "3.4.4",
|
"@types/uuid": "3.4.4",
|
||||||
"@types/web-push": "3.3.0",
|
"@types/web-push": "3.3.0",
|
||||||
"@types/webpack": "4.4.24",
|
"@types/webpack": "4.4.27",
|
||||||
"@types/webpack-stream": "3.2.10",
|
"@types/webpack-stream": "3.2.10",
|
||||||
"@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.6.6",
|
"apexcharts": "3.6.7",
|
||||||
"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",
|
||||||
@ -108,7 +104,6 @@
|
|||||||
"bull": "3.7.0",
|
"bull": "3.7.0",
|
||||||
"cafy": "15.1.1",
|
"cafy": "15.1.1",
|
||||||
"chai": "4.2.0",
|
"chai": "4.2.0",
|
||||||
"chai-http": "4.2.1",
|
|
||||||
"chalk": "2.4.2",
|
"chalk": "2.4.2",
|
||||||
"cli-highlight": "2.1.0",
|
"cli-highlight": "2.1.0",
|
||||||
"commander": "2.20.0",
|
"commander": "2.20.0",
|
||||||
@ -122,11 +117,11 @@
|
|||||||
"double-ended-queue": "2.1.0-0",
|
"double-ended-queue": "2.1.0-0",
|
||||||
"elasticsearch": "15.4.1",
|
"elasticsearch": "15.4.1",
|
||||||
"emojilib": "2.4.0",
|
"emojilib": "2.4.0",
|
||||||
"eslint": "5.15.1",
|
"eslint": "5.16.0",
|
||||||
"eslint-plugin-vue": "5.2.2",
|
"eslint-plugin-vue": "5.2.2",
|
||||||
"eventemitter3": "3.1.0",
|
"eventemitter3": "3.1.0",
|
||||||
"feed": "2.0.4",
|
"feed": "2.0.4",
|
||||||
"file-type": "10.10.0",
|
"file-type": "10.11.0",
|
||||||
"fuckadblock": "3.2.1",
|
"fuckadblock": "3.2.1",
|
||||||
"gulp": "4.0.0",
|
"gulp": "4.0.0",
|
||||||
"gulp-cssnano": "2.1.3",
|
"gulp-cssnano": "2.1.3",
|
||||||
@ -137,19 +132,19 @@
|
|||||||
"gulp-sourcemaps": "2.6.5",
|
"gulp-sourcemaps": "2.6.5",
|
||||||
"gulp-stylus": "2.7.0",
|
"gulp-stylus": "2.7.0",
|
||||||
"gulp-tslint": "8.1.4",
|
"gulp-tslint": "8.1.4",
|
||||||
"gulp-typescript": "5.0.0",
|
"gulp-typescript": "5.0.1",
|
||||||
"gulp-uglify": "3.0.2",
|
"gulp-uglify": "3.0.2",
|
||||||
"gulp-util": "3.0.8",
|
"gulp-util": "3.0.8",
|
||||||
"hard-source-webpack-plugin": "0.13.1",
|
"hard-source-webpack-plugin": "0.13.1",
|
||||||
"html-minifier": "3.5.21",
|
"html-minifier": "4.0.0",
|
||||||
"http-signature": "1.2.0",
|
"http-signature": "1.2.0",
|
||||||
"insert-text-at-cursor": "0.1.2",
|
"insert-text-at-cursor": "0.2.0",
|
||||||
"is-root": "2.0.0",
|
"is-root": "2.0.0",
|
||||||
"is-svg": "4.0.0",
|
"is-svg": "4.1.0",
|
||||||
"js-yaml": "3.13.0",
|
"js-yaml": "3.13.1",
|
||||||
"jsdom": "14.0.0",
|
"jsdom": "14.0.0",
|
||||||
"json5": "2.1.0",
|
"json5": "2.1.0",
|
||||||
"json5-loader": "1.0.1",
|
"json5-loader": "2.0.0",
|
||||||
"katex": "0.10.1",
|
"katex": "0.10.1",
|
||||||
"koa": "2.7.0",
|
"koa": "2.7.0",
|
||||||
"koa-bodyparser": "4.2.1",
|
"koa-bodyparser": "4.2.1",
|
||||||
@ -168,16 +163,15 @@
|
|||||||
"lolex": "3.1.0",
|
"lolex": "3.1.0",
|
||||||
"lookup-dns-cache": "2.1.0",
|
"lookup-dns-cache": "2.1.0",
|
||||||
"minio": "7.0.5",
|
"minio": "7.0.5",
|
||||||
"mocha": "6.0.2",
|
"mocha": "6.1.3",
|
||||||
"moji": "0.5.1",
|
"moji": "0.5.1",
|
||||||
"moment": "2.24.0",
|
"moment": "2.24.0",
|
||||||
"mongodb": "3.2.3",
|
"mongodb": "3.2.3",
|
||||||
"monk": "6.0.6",
|
"monk": "6.0.6",
|
||||||
"ms": "2.1.1",
|
"ms": "2.1.1",
|
||||||
"nan": "2.12.1",
|
|
||||||
"nested-property": "0.0.7",
|
"nested-property": "0.0.7",
|
||||||
"node-fetch": "2.3.0",
|
"node-fetch": "2.3.0",
|
||||||
"nodemailer": "5.1.1",
|
"nodemailer": "6.1.0",
|
||||||
"nprogress": "0.2.0",
|
"nprogress": "0.2.0",
|
||||||
"object-assign-deep": "0.4.0",
|
"object-assign-deep": "0.4.0",
|
||||||
"os-utils": "0.0.14",
|
"os-utils": "0.0.14",
|
||||||
@ -208,7 +202,6 @@
|
|||||||
"rimraf": "2.6.3",
|
"rimraf": "2.6.3",
|
||||||
"rndstr": "1.0.0",
|
"rndstr": "1.0.0",
|
||||||
"s-age": "1.1.2",
|
"s-age": "1.1.2",
|
||||||
"seedrandom": "2.4.4",
|
|
||||||
"sharp": "0.22.0",
|
"sharp": "0.22.0",
|
||||||
"showdown": "1.9.0",
|
"showdown": "1.9.0",
|
||||||
"showdown-highlightjs-extension": "0.1.2",
|
"showdown-highlightjs-extension": "0.1.2",
|
||||||
@ -218,15 +211,15 @@
|
|||||||
"stylus": "0.54.5",
|
"stylus": "0.54.5",
|
||||||
"stylus-loader": "3.0.2",
|
"stylus-loader": "3.0.2",
|
||||||
"summaly": "2.2.0",
|
"summaly": "2.2.0",
|
||||||
"systeminformation": "4.0.16",
|
"systeminformation": "4.1.4",
|
||||||
"syuilo-password-strength": "0.0.1",
|
"syuilo-password-strength": "0.0.1",
|
||||||
"terser-webpack-plugin": "1.2.3",
|
"terser-webpack-plugin": "1.2.3",
|
||||||
"textarea-caret": "3.1.0",
|
"textarea-caret": "3.1.0",
|
||||||
"tinycolor2": "1.4.1",
|
"tinycolor2": "1.4.1",
|
||||||
"tmp": "0.0.33",
|
"tmp": "0.1.0",
|
||||||
"ts-loader": "5.3.3",
|
"ts-loader": "5.3.3",
|
||||||
"ts-node": "7.0.1",
|
"ts-node": "7.0.1",
|
||||||
"tslint": "5.13.1",
|
"tslint": "5.15.0",
|
||||||
"tslint-sonarts": "1.9.0",
|
"tslint-sonarts": "1.9.0",
|
||||||
"typeorm": "0.2.16-rc.1",
|
"typeorm": "0.2.16-rc.1",
|
||||||
"typescript": "3.3.3333",
|
"typescript": "3.3.3333",
|
||||||
@ -248,7 +241,7 @@
|
|||||||
"vue-loader": "15.7.0",
|
"vue-loader": "15.7.0",
|
||||||
"vue-marquee-text-component": "1.1.1",
|
"vue-marquee-text-component": "1.1.1",
|
||||||
"vue-prism-component": "1.1.1",
|
"vue-prism-component": "1.1.1",
|
||||||
"vue-router": "3.0.3",
|
"vue-router": "3.0.4",
|
||||||
"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.15",
|
"vue-svg-inline-loader": "1.2.15",
|
||||||
@ -258,8 +251,8 @@
|
|||||||
"vuex": "3.1.0",
|
"vuex": "3.1.0",
|
||||||
"vuex-persistedstate": "2.5.4",
|
"vuex-persistedstate": "2.5.4",
|
||||||
"web-push": "3.3.3",
|
"web-push": "3.3.3",
|
||||||
"webpack": "4.28.4",
|
"webpack": "4.30.0",
|
||||||
"webpack-cli": "3.2.3",
|
"webpack-cli": "3.3.0",
|
||||||
"websocket": "1.0.28",
|
"websocket": "1.0.28",
|
||||||
"ws": "6.2.1",
|
"ws": "6.2.1",
|
||||||
"xev": "2.0.1"
|
"xev": "2.0.1"
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
<div class="kidvdlkg" v-for="file in files">
|
<div class="kidvdlkg" v-for="file in files">
|
||||||
<div @click="file._open = !file._open">
|
<div @click="file._open = !file._open">
|
||||||
<div>
|
<div>
|
||||||
<div class="thumbnail" :style="thumbnail(file)"></div>
|
<x-file-thumbnail class="thumbnail" :file="file" fit="contain" @click="showFileMenu(file)"/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<header>
|
<header>
|
||||||
@ -75,10 +75,15 @@ import Vue from 'vue';
|
|||||||
import i18n from '../../i18n';
|
import i18n from '../../i18n';
|
||||||
import { faCloud, faTerminal, faSearch } from '@fortawesome/free-solid-svg-icons';
|
import { faCloud, faTerminal, faSearch } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faTrashAlt, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
|
import { faTrashAlt, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
|
||||||
|
import XFileThumbnail from '../../common/views/components/drive-file-thumbnail.vue';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
i18n: i18n('admin/views/drive.vue'),
|
i18n: i18n('admin/views/drive.vue'),
|
||||||
|
|
||||||
|
components: {
|
||||||
|
XFileThumbnail
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
file: null,
|
file: null,
|
||||||
@ -151,13 +156,6 @@ export default Vue.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
thumbnail(file: any): any {
|
|
||||||
return {
|
|
||||||
'background-color': file.properties.avgColor || 'transparent',
|
|
||||||
'background-image': `url(${file.thumbnailUrl})`
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
async del(file: any) {
|
async del(file: any) {
|
||||||
const process = async () => {
|
const process = async () => {
|
||||||
await this.$root.api('drive/files/delete', { fileId: file.id });
|
await this.$root.api('drive/files/delete', { fileId: file.id });
|
||||||
@ -179,9 +177,9 @@ export default Vue.extend({
|
|||||||
this.$root.api('drive/files/update', {
|
this.$root.api('drive/files/update', {
|
||||||
fileId: file.id,
|
fileId: file.id,
|
||||||
isSensitive: !file.isSensitive
|
isSensitive: !file.isSensitive
|
||||||
|
}).then(() => {
|
||||||
|
file.isSensitive = !file.isSensitive;
|
||||||
});
|
});
|
||||||
|
|
||||||
file.isSensitive = !file.isSensitive;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async show() {
|
async show() {
|
||||||
|
@ -105,9 +105,7 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
isThumbnailAvailable(): boolean {
|
isThumbnailAvailable(): boolean {
|
||||||
return this.file.thumbnailUrl
|
return this.file.thumbnailUrl
|
||||||
? this.file.thumbnailUrl.endsWith('?thumbnail')
|
? (this.is === 'image' || this.is === 'video')
|
||||||
? (this.is === 'image' || this.is === 'video')
|
|
||||||
: true
|
|
||||||
: false;
|
: false;
|
||||||
},
|
},
|
||||||
background(): string {
|
background(): string {
|
||||||
|
139
src/client/app/common/views/components/post-form-attaches.vue
Normal file
139
src/client/app/common/views/components/post-form-attaches.vue
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
<template>
|
||||||
|
<div class="skeikyzd" v-show="files.length != 0">
|
||||||
|
<x-draggable class="files" :list="files" :options="{ animation: 150 }">
|
||||||
|
<div v-for="file in files" :key="file.id" @click="showFileMenu(file, $event)" @contextmenu.prevent="showFileMenu(file, $event)">
|
||||||
|
<x-file-thumbnail :data-id="file.id" class="thumbnail" :file="file" fit="cover"/>
|
||||||
|
<img class="remove" @click.stop="detachMedia(file.id)" src="/assets/desktop/remove.png" :title="$t('attach-cancel')" alt=""/>
|
||||||
|
<div class="sensitive" v-if="file.isSensitive">
|
||||||
|
<fa class="icon" :icon="faExclamationTriangle"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</x-draggable>
|
||||||
|
<p class="remain">{{ 4 - files.length }}/4</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
import i18n from '../../../i18n';
|
||||||
|
import * as XDraggable from 'vuedraggable';
|
||||||
|
import XMenu from '../../../common/views/components/menu.vue';
|
||||||
|
import { faTimesCircle, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
|
||||||
|
import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import XFileThumbnail from './drive-file-thumbnail.vue'
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
i18n: i18n('common/views/components/post-form-attaches.vue'),
|
||||||
|
|
||||||
|
components: {
|
||||||
|
XDraggable,
|
||||||
|
XFileThumbnail
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
files: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
detachMediaFn: {
|
||||||
|
type: Object,
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
faExclamationTriangle
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
detachMedia(id) {
|
||||||
|
if (this.detachMediaFn) this.detachMediaFn(id)
|
||||||
|
else if (this.$parent.detachMedia) this.$parent.detachMedia(id)
|
||||||
|
},
|
||||||
|
toggleSensitive(file) {
|
||||||
|
this.$root.api('drive/files/update', {
|
||||||
|
fileId: file.id,
|
||||||
|
isSensitive: !file.isSensitive
|
||||||
|
}).then(() => {
|
||||||
|
file.isSensitive = !file.isSensitive;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
showFileMenu(file, ev: MouseEvent) {
|
||||||
|
this.$root.new(XMenu, {
|
||||||
|
items: [{
|
||||||
|
type: 'item',
|
||||||
|
text: file.isSensitive ? this.$t('unmark-as-sensitive') : this.$t('mark-as-sensitive'),
|
||||||
|
icon: file.isSensitive ? faEyeSlash : faEye,
|
||||||
|
action: () => { this.toggleSensitive(file) }
|
||||||
|
}, {
|
||||||
|
type: 'item',
|
||||||
|
text: this.$t('attach-cancel'),
|
||||||
|
icon: faTimesCircle,
|
||||||
|
action: () => { this.detachMedia(file.id) }
|
||||||
|
}],
|
||||||
|
source: ev.currentTarget || ev.target
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.skeikyzd
|
||||||
|
padding 4px
|
||||||
|
|
||||||
|
> .files
|
||||||
|
display flex
|
||||||
|
flex-wrap wrap
|
||||||
|
|
||||||
|
> div
|
||||||
|
width 64px
|
||||||
|
height 64px
|
||||||
|
margin 4px
|
||||||
|
cursor move
|
||||||
|
|
||||||
|
&:hover > .remove
|
||||||
|
display block
|
||||||
|
|
||||||
|
> .thumbnail
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
z-index 1
|
||||||
|
color var(--text)
|
||||||
|
|
||||||
|
> .remove
|
||||||
|
display none
|
||||||
|
position absolute
|
||||||
|
top -6px
|
||||||
|
right -6px
|
||||||
|
width 16px
|
||||||
|
height 16px
|
||||||
|
cursor pointer
|
||||||
|
z-index 1000
|
||||||
|
|
||||||
|
> .sensitive
|
||||||
|
display flex
|
||||||
|
position absolute
|
||||||
|
width 64px
|
||||||
|
height 64px
|
||||||
|
top 0
|
||||||
|
left 0
|
||||||
|
z-index 2
|
||||||
|
background rgba(17, 17, 17, .7)
|
||||||
|
color #fff
|
||||||
|
|
||||||
|
> .icon
|
||||||
|
margin auto
|
||||||
|
|
||||||
|
> .remain
|
||||||
|
display block
|
||||||
|
position absolute
|
||||||
|
top 8px
|
||||||
|
right 8px
|
||||||
|
margin 0
|
||||||
|
padding 0
|
||||||
|
color var(--primaryAlpha04)
|
||||||
|
|
||||||
|
</style>
|
@ -166,6 +166,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
append(note) {
|
append(note) {
|
||||||
this.notes.push(note);
|
this.notes.push(note);
|
||||||
|
this.cursor = this.notes[this.notes.length - 1].id
|
||||||
},
|
},
|
||||||
|
|
||||||
releaseQueue() {
|
releaseQueue() {
|
||||||
|
@ -85,7 +85,7 @@ export default Vue.extend({
|
|||||||
this.makePromise = cursor => this.$root.api('users/notes', {
|
this.makePromise = cursor => this.$root.api('users/notes', {
|
||||||
userId: this.user.id,
|
userId: this.user.id,
|
||||||
limit: fetchLimit + 1,
|
limit: fetchLimit + 1,
|
||||||
untilId: cursor ? cursor : undefined,
|
untilDate: cursor ? cursor : new Date().getTime() + 1000 * 86400 * 365,
|
||||||
withFiles: this.withFiles,
|
withFiles: this.withFiles,
|
||||||
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
||||||
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
|
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
|
||||||
|
@ -21,14 +21,7 @@
|
|||||||
<fa :icon="['far', 'laugh']"/>
|
<fa :icon="['far', 'laugh']"/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="files" v-show="files.length != 0">
|
<x-post-form-attaches class="files" :files="files" :detachMediaFn="detachMedia"/>
|
||||||
<x-draggable :list="files" :options="{ animation: 150 }">
|
|
||||||
<div v-for="file in files" :key="file.id">
|
|
||||||
<div class="img" :style="{ backgroundImage: `url(${file.thumbnailUrl})` }" :title="file.name"></div>
|
|
||||||
<img class="remove" @click="detachMedia(file.id)" src="/assets/desktop/remove.png" :title="$t('attach-cancel')" alt=""/>
|
|
||||||
</div>
|
|
||||||
</x-draggable>
|
|
||||||
</div>
|
|
||||||
<input ref="file" type="file" multiple="multiple" tabindex="-1" @change="onChangeFile"/>
|
<input ref="file" type="file" multiple="multiple" tabindex="-1" @change="onChangeFile"/>
|
||||||
<mk-uploader ref="uploader" @uploaded="attachMedia"/>
|
<mk-uploader ref="uploader" @uploaded="attachMedia"/>
|
||||||
<footer>
|
<footer>
|
||||||
@ -45,7 +38,7 @@
|
|||||||
import define from '../../../common/define-widget';
|
import define from '../../../common/define-widget';
|
||||||
import i18n from '../../../i18n';
|
import i18n from '../../../i18n';
|
||||||
import insertTextAtCursor from 'insert-text-at-cursor';
|
import insertTextAtCursor from 'insert-text-at-cursor';
|
||||||
import * as XDraggable from 'vuedraggable';
|
import XPostFormAttaches from '../components/post-form-attaches.vue';
|
||||||
|
|
||||||
export default define({
|
export default define({
|
||||||
name: 'post-form',
|
name: 'post-form',
|
||||||
@ -56,7 +49,7 @@ export default define({
|
|||||||
i18n: i18n('desktop/views/widgets/post-form.vue'),
|
i18n: i18n('desktop/views/widgets/post-form.vue'),
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
XDraggable
|
XPostFormAttaches
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
@ -249,38 +242,6 @@ export default define({
|
|||||||
& + .emoji
|
& + .emoji
|
||||||
opacity 0.7
|
opacity 0.7
|
||||||
|
|
||||||
> .files
|
|
||||||
> div
|
|
||||||
padding 4px
|
|
||||||
|
|
||||||
&:after
|
|
||||||
content ""
|
|
||||||
display block
|
|
||||||
clear both
|
|
||||||
|
|
||||||
> div
|
|
||||||
float left
|
|
||||||
border solid 4px transparent
|
|
||||||
cursor move
|
|
||||||
|
|
||||||
&:hover > .remove
|
|
||||||
display block
|
|
||||||
|
|
||||||
> .img
|
|
||||||
width 64px
|
|
||||||
height 64px
|
|
||||||
background-size cover
|
|
||||||
background-position center center
|
|
||||||
|
|
||||||
> .remove
|
|
||||||
display none
|
|
||||||
position absolute
|
|
||||||
top -6px
|
|
||||||
right -6px
|
|
||||||
width 16px
|
|
||||||
height 16px
|
|
||||||
cursor pointer
|
|
||||||
|
|
||||||
> input[type=file]
|
> input[type=file]
|
||||||
display none
|
display none
|
||||||
|
|
||||||
|
@ -769,7 +769,6 @@ export default Vue.extend({
|
|||||||
> .mk-uploader
|
> .mk-uploader
|
||||||
height 100px
|
height 100px
|
||||||
padding 16px
|
padding 16px
|
||||||
background #fff
|
|
||||||
|
|
||||||
> input
|
> input
|
||||||
display none
|
display none
|
||||||
|
@ -166,6 +166,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
append(note) {
|
append(note) {
|
||||||
this.notes.push(note);
|
this.notes.push(note);
|
||||||
|
this.cursor = this.notes[this.notes.length - 1].id
|
||||||
},
|
},
|
||||||
|
|
||||||
releaseQueue() {
|
releaseQueue() {
|
||||||
|
@ -27,15 +27,7 @@
|
|||||||
<button class="emoji" @click="emoji" ref="emoji">
|
<button class="emoji" @click="emoji" ref="emoji">
|
||||||
<fa :icon="['far', 'laugh']"/>
|
<fa :icon="['far', 'laugh']"/>
|
||||||
</button>
|
</button>
|
||||||
<div class="files" :class="{ with: poll }" v-show="files.length != 0">
|
<x-post-form-attaches class="files" :class="{ with: poll }" :files="files"/>
|
||||||
<x-draggable :list="files" :options="{ animation: 150 }">
|
|
||||||
<div v-for="file in files" :key="file.id">
|
|
||||||
<div class="img" :style="{ backgroundImage: `url(${file.thumbnailUrl})` }" :title="file.name"></div>
|
|
||||||
<img class="remove" @click="detachMedia(file.id)" src="/assets/desktop/remove.png" :title="$t('attach-cancel')" alt=""/>
|
|
||||||
</div>
|
|
||||||
</x-draggable>
|
|
||||||
<p class="remain">{{ 4 - files.length }}/4</p>
|
|
||||||
</div>
|
|
||||||
<mk-poll-editor v-if="poll" ref="poll" @destroyed="poll = false" @updated="onPollUpdate()"/>
|
<mk-poll-editor v-if="poll" ref="poll" @destroyed="poll = false" @updated="onPollUpdate()"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -65,7 +57,6 @@
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import i18n from '../../../i18n';
|
import i18n from '../../../i18n';
|
||||||
import insertTextAtCursor from 'insert-text-at-cursor';
|
import insertTextAtCursor from 'insert-text-at-cursor';
|
||||||
import * as XDraggable from 'vuedraggable';
|
|
||||||
import getFace from '../../../common/scripts/get-face';
|
import getFace from '../../../common/scripts/get-face';
|
||||||
import MkVisibilityChooser from '../../../common/views/components/visibility-chooser.vue';
|
import MkVisibilityChooser from '../../../common/views/components/visibility-chooser.vue';
|
||||||
import { parse } from '../../../../../mfm/parse';
|
import { parse } from '../../../../../mfm/parse';
|
||||||
@ -74,13 +65,14 @@ import { erase, unique } from '../../../../../prelude/array';
|
|||||||
import { length } from 'stringz';
|
import { length } from 'stringz';
|
||||||
import { toASCII } from 'punycode';
|
import { toASCII } from 'punycode';
|
||||||
import extractMentions from '../../../../../misc/extract-mentions';
|
import extractMentions from '../../../../../misc/extract-mentions';
|
||||||
|
import XPostFormAttaches from '../../../common/views/components/post-form-attaches.vue';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
i18n: i18n('desktop/views/components/post-form.vue'),
|
i18n: i18n('desktop/views/components/post-form.vue'),
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
XDraggable,
|
MkVisibilityChooser,
|
||||||
MkVisibilityChooser
|
XPostFormAttaches
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
@ -513,7 +505,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
kao() {
|
kao() {
|
||||||
this.text += getFace();
|
this.text += getFace();
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@ -618,46 +610,6 @@ export default Vue.extend({
|
|||||||
border-bottom solid 1px var(--primaryAlpha01) !important
|
border-bottom solid 1px var(--primaryAlpha01) !important
|
||||||
border-radius 0
|
border-radius 0
|
||||||
|
|
||||||
> .remain
|
|
||||||
display block
|
|
||||||
position absolute
|
|
||||||
top 8px
|
|
||||||
right 8px
|
|
||||||
margin 0
|
|
||||||
padding 0
|
|
||||||
color var(--primaryAlpha04)
|
|
||||||
|
|
||||||
> div
|
|
||||||
padding 4px
|
|
||||||
|
|
||||||
&:after
|
|
||||||
content ""
|
|
||||||
display block
|
|
||||||
clear both
|
|
||||||
|
|
||||||
> div
|
|
||||||
float left
|
|
||||||
border solid 4px transparent
|
|
||||||
cursor move
|
|
||||||
|
|
||||||
&:hover > .remove
|
|
||||||
display block
|
|
||||||
|
|
||||||
> .img
|
|
||||||
width 64px
|
|
||||||
height 64px
|
|
||||||
background-size cover
|
|
||||||
background-position center center
|
|
||||||
|
|
||||||
> .remove
|
|
||||||
display none
|
|
||||||
position absolute
|
|
||||||
top -6px
|
|
||||||
right -6px
|
|
||||||
width 16px
|
|
||||||
height 16px
|
|
||||||
cursor pointer
|
|
||||||
|
|
||||||
> .mk-poll-editor
|
> .mk-poll-editor
|
||||||
background var(--desktopPostFormTextareaBg)
|
background var(--desktopPostFormTextareaBg)
|
||||||
border solid 1px var(--primaryAlpha01)
|
border solid 1px var(--primaryAlpha01)
|
||||||
|
@ -36,7 +36,7 @@ export default Vue.extend({
|
|||||||
includeReplies: this.mode == 'with-replies',
|
includeReplies: this.mode == 'with-replies',
|
||||||
includeMyRenotes: this.mode != 'my-posts',
|
includeMyRenotes: this.mode != 'my-posts',
|
||||||
withFiles: this.mode == 'with-media',
|
withFiles: this.mode == 'with-media',
|
||||||
untilId: cursor ? cursor : undefined
|
untilDate: cursor ? cursor : new Date().getTime() + 1000 * 86400 * 365
|
||||||
}).then(notes => {
|
}).then(notes => {
|
||||||
if (notes.length == fetchLimit + 1) {
|
if (notes.length == fetchLimit + 1) {
|
||||||
notes.pop();
|
notes.pop();
|
||||||
|
@ -28,7 +28,7 @@ export default class MiOS extends EventEmitter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public get instanceName() {
|
public get instanceName() {
|
||||||
return this.meta ? this.meta.data.name : 'Misskey';
|
return this.meta ? (this.meta.data.name || 'Misskey') : 'Misskey';
|
||||||
}
|
}
|
||||||
|
|
||||||
private isMetaFetching = false;
|
private isMetaFetching = false;
|
||||||
|
@ -160,6 +160,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
append(note) {
|
append(note) {
|
||||||
this.notes.push(note);
|
this.notes.push(note);
|
||||||
|
this.cursor = this.notes[this.notes.length - 1].id
|
||||||
},
|
},
|
||||||
|
|
||||||
releaseQueue() {
|
releaseQueue() {
|
||||||
|
@ -21,13 +21,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<input v-show="useCw" ref="cw" v-model="cw" :placeholder="$t('annotations')" v-autocomplete="{ model: 'cw' }">
|
<input v-show="useCw" ref="cw" v-model="cw" :placeholder="$t('annotations')" v-autocomplete="{ model: 'cw' }">
|
||||||
<textarea v-model="text" ref="text" :disabled="posting" :placeholder="placeholder" v-autocomplete="{ model: 'text' }"></textarea>
|
<textarea v-model="text" ref="text" :disabled="posting" :placeholder="placeholder" v-autocomplete="{ model: 'text' }"></textarea>
|
||||||
<div class="attaches" v-show="files.length != 0">
|
<x-post-form-attaches class="attaches" :files="files"/>
|
||||||
<x-draggable class="files" :list="files" :options="{ animation: 150 }">
|
|
||||||
<div class="file" v-for="file in files" :key="file.id">
|
|
||||||
<div class="img" :style="`background-image: url(${file.thumbnailUrl})`" @click="detachMedia(file)"></div>
|
|
||||||
</div>
|
|
||||||
</x-draggable>
|
|
||||||
</div>
|
|
||||||
<mk-poll-editor v-if="poll" ref="poll" @destroyed="poll = false" @updated="onPollUpdate()"/>
|
<mk-poll-editor v-if="poll" ref="poll" @destroyed="poll = false" @updated="onPollUpdate()"/>
|
||||||
<mk-uploader ref="uploader" @uploaded="attachMedia" @change="onChangeUploadings"/>
|
<mk-uploader ref="uploader" @uploaded="attachMedia" @change="onChangeUploadings"/>
|
||||||
<footer>
|
<footer>
|
||||||
@ -57,7 +51,6 @@
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import i18n from '../../../i18n';
|
import i18n from '../../../i18n';
|
||||||
import insertTextAtCursor from 'insert-text-at-cursor';
|
import insertTextAtCursor from 'insert-text-at-cursor';
|
||||||
import * as XDraggable from 'vuedraggable';
|
|
||||||
import MkVisibilityChooser from '../../../common/views/components/visibility-chooser.vue';
|
import MkVisibilityChooser from '../../../common/views/components/visibility-chooser.vue';
|
||||||
import getFace from '../../../common/scripts/get-face';
|
import getFace from '../../../common/scripts/get-face';
|
||||||
import { parse } from '../../../../../mfm/parse';
|
import { parse } from '../../../../../mfm/parse';
|
||||||
@ -66,11 +59,12 @@ import { erase, unique } from '../../../../../prelude/array';
|
|||||||
import { length } from 'stringz';
|
import { length } from 'stringz';
|
||||||
import { toASCII } from 'punycode';
|
import { toASCII } from 'punycode';
|
||||||
import extractMentions from '../../../../../misc/extract-mentions';
|
import extractMentions from '../../../../../misc/extract-mentions';
|
||||||
|
import XPostFormAttaches from '../../../common/views/components/post-form-attaches.vue';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
i18n: i18n('mobile/views/components/post-form.vue'),
|
i18n: i18n('mobile/views/components/post-form.vue'),
|
||||||
components: {
|
components: {
|
||||||
XDraggable
|
XPostFormAttaches
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
@ -264,8 +258,8 @@ export default Vue.extend({
|
|||||||
this.$emit('change-attached-files', this.files);
|
this.$emit('change-attached-files', this.files);
|
||||||
},
|
},
|
||||||
|
|
||||||
detachMedia(file) {
|
detachMedia(id) {
|
||||||
this.files = this.files.filter(x => x.id != file.id);
|
this.files = this.files.filter(x => x.id != id);
|
||||||
this.$emit('change-attached-files', this.files);
|
this.$emit('change-attached-files', this.files);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -481,32 +475,6 @@ export default Vue.extend({
|
|||||||
min-width 100%
|
min-width 100%
|
||||||
min-height 80px
|
min-height 80px
|
||||||
|
|
||||||
> .attaches
|
|
||||||
|
|
||||||
> .files
|
|
||||||
display block
|
|
||||||
margin 0
|
|
||||||
padding 4px
|
|
||||||
list-style none
|
|
||||||
|
|
||||||
&:after
|
|
||||||
content ""
|
|
||||||
display block
|
|
||||||
clear both
|
|
||||||
|
|
||||||
> .file
|
|
||||||
display block
|
|
||||||
float left
|
|
||||||
margin 0
|
|
||||||
padding 0
|
|
||||||
border solid 4px transparent
|
|
||||||
|
|
||||||
> .img
|
|
||||||
width 64px
|
|
||||||
height 64px
|
|
||||||
background-size cover
|
|
||||||
background-position center center
|
|
||||||
|
|
||||||
> .mk-uploader
|
> .mk-uploader
|
||||||
margin 8px 0 0 0
|
margin 8px 0 0 0
|
||||||
padding 8px
|
padding 8px
|
||||||
|
@ -21,7 +21,7 @@ export default Vue.extend({
|
|||||||
userId: this.user.id,
|
userId: this.user.id,
|
||||||
limit: fetchLimit + 1,
|
limit: fetchLimit + 1,
|
||||||
withFiles: this.withMedia,
|
withFiles: this.withMedia,
|
||||||
untilId: cursor ? cursor : undefined
|
untilDate: cursor ? cursor : new Date().getTime() + 1000 * 86400 * 365
|
||||||
}).then(notes => {
|
}).then(notes => {
|
||||||
if (notes.length == fetchLimit + 1) {
|
if (notes.length == fetchLimit + 1) {
|
||||||
notes.pop();
|
notes.pop();
|
||||||
|
BIN
src/client/assets/thumbnail-not-available.png
Normal file
BIN
src/client/assets/thumbnail-not-available.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
@ -1,111 +0,0 @@
|
|||||||
#include <nan.h>
|
|
||||||
#include <openssl/bio.h>
|
|
||||||
#include <openssl/buffer.h>
|
|
||||||
#include <openssl/crypto.h>
|
|
||||||
#include <openssl/pem.h>
|
|
||||||
#include <openssl/rsa.h>
|
|
||||||
#include <openssl/x509.h>
|
|
||||||
|
|
||||||
NAN_METHOD(extractPublic)
|
|
||||||
{
|
|
||||||
const auto sourceString = info[0]->ToString(Nan::GetCurrentContext()).ToLocalChecked();
|
|
||||||
if (!sourceString->IsOneByte()) {
|
|
||||||
Nan::ThrowError("Malformed character found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t sourceLength = sourceString->Length();
|
|
||||||
const auto sourceBuf = new char[sourceLength];
|
|
||||||
|
|
||||||
Nan::DecodeWrite(sourceBuf, sourceLength, sourceString);
|
|
||||||
|
|
||||||
const auto source = BIO_new_mem_buf(sourceBuf, sourceLength);
|
|
||||||
if (source == nullptr) {
|
|
||||||
Nan::ThrowError("Memory allocation failed");
|
|
||||||
delete[] sourceBuf;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto rsa = PEM_read_bio_RSAPrivateKey(source, nullptr, nullptr, nullptr);
|
|
||||||
|
|
||||||
BIO_free(source);
|
|
||||||
delete[] sourceBuf;
|
|
||||||
|
|
||||||
if (rsa == nullptr) {
|
|
||||||
Nan::ThrowError("Decode failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto destination = BIO_new(BIO_s_mem());
|
|
||||||
if (destination == nullptr) {
|
|
||||||
Nan::ThrowError("Memory allocation failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto result = PEM_write_bio_RSAPublicKey(destination, rsa);
|
|
||||||
|
|
||||||
RSA_free(rsa);
|
|
||||||
|
|
||||||
if (result != 1) {
|
|
||||||
Nan::ThrowError("Public key extraction failed");
|
|
||||||
BIO_free(destination);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *pem;
|
|
||||||
const auto pemLength = BIO_get_mem_data(destination, &pem);
|
|
||||||
|
|
||||||
info.GetReturnValue().Set(Nan::Encode(pem, pemLength));
|
|
||||||
BIO_free(destination);
|
|
||||||
}
|
|
||||||
|
|
||||||
NAN_METHOD(generate)
|
|
||||||
{
|
|
||||||
const auto exponent = BN_new();
|
|
||||||
const auto mem = BIO_new(BIO_s_mem());
|
|
||||||
const auto rsa = RSA_new();
|
|
||||||
char *data;
|
|
||||||
long result;
|
|
||||||
|
|
||||||
if (exponent == nullptr || mem == nullptr || rsa == nullptr) {
|
|
||||||
Nan::ThrowError("Memory allocation failed");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = BN_set_word(exponent, 65537);
|
|
||||||
if (result != 1) {
|
|
||||||
Nan::ThrowError("Exponent setting failed");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = RSA_generate_key_ex(rsa, 2048, exponent, nullptr);
|
|
||||||
if (result != 1) {
|
|
||||||
Nan::ThrowError("Key generation failed");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = PEM_write_bio_RSAPrivateKey(mem, rsa, NULL, NULL, 0, NULL, NULL);
|
|
||||||
if (result != 1) {
|
|
||||||
Nan::ThrowError("Key export failed");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = BIO_get_mem_data(mem, &data);
|
|
||||||
info.GetReturnValue().Set(Nan::Encode(data, result));
|
|
||||||
|
|
||||||
done:
|
|
||||||
RSA_free(rsa);
|
|
||||||
BIO_free(mem);
|
|
||||||
BN_free(exponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
NAN_MODULE_INIT(InitAll)
|
|
||||||
{
|
|
||||||
Nan::Set(target, Nan::New<v8::String>("extractPublic").ToLocalChecked(),
|
|
||||||
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(extractPublic)).ToLocalChecked());
|
|
||||||
|
|
||||||
Nan::Set(target, Nan::New<v8::String>("generate").ToLocalChecked(),
|
|
||||||
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(generate)).ToLocalChecked());
|
|
||||||
}
|
|
||||||
|
|
||||||
NODE_MODULE(crypto_key, InitAll);
|
|
2
src/crypto_key.d.ts
vendored
2
src/crypto_key.d.ts
vendored
@ -1,2 +0,0 @@
|
|||||||
export function extractPublic(keypair: string): string;
|
|
||||||
export function generate(): string;
|
|
@ -56,20 +56,12 @@ function cpuUsage() {
|
|||||||
|
|
||||||
// MEMORY(excl buffer + cache) STAT
|
// MEMORY(excl buffer + cache) STAT
|
||||||
async function usedMem() {
|
async function usedMem() {
|
||||||
try {
|
const data = await sysUtils.mem();
|
||||||
const data = await sysUtils.mem();
|
return data.active;
|
||||||
return data.active;
|
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TOTAL MEMORY STAT
|
// TOTAL MEMORY STAT
|
||||||
async function totalMem() {
|
async function totalMem() {
|
||||||
try {
|
const data = await sysUtils.mem();
|
||||||
const data = await sysUtils.mem();
|
return data.total;
|
||||||
return data.total;
|
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import * as redis from 'redis';
|
import * as redis from 'redis';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
|
|
||||||
export default config.redis ? redis.createClient(
|
export default redis.createClient(
|
||||||
config.redis.port,
|
config.redis.port,
|
||||||
config.redis.host,
|
config.redis.host,
|
||||||
{
|
{
|
||||||
@ -9,4 +9,4 @@ export default config.redis ? redis.createClient(
|
|||||||
prefix: config.redis.prefix,
|
prefix: config.redis.prefix,
|
||||||
db: config.redis.db || 0
|
db: config.redis.db || 0
|
||||||
}
|
}
|
||||||
) : null;
|
);
|
||||||
|
502
src/migrate.ts
502
src/migrate.ts
@ -1,502 +0,0 @@
|
|||||||
process.env.NODE_ENV = 'production';
|
|
||||||
|
|
||||||
import monk from 'monk';
|
|
||||||
import * as mongo from 'mongodb';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import * as uuid from 'uuid';
|
|
||||||
import chalk from 'chalk';
|
|
||||||
import config from './config';
|
|
||||||
import { initDb } from './db/postgre';
|
|
||||||
import { User } from './models/entities/user';
|
|
||||||
import { getRepository } from 'typeorm';
|
|
||||||
import generateUserToken from './server/api/common/generate-native-user-token';
|
|
||||||
import { DriveFile } from './models/entities/drive-file';
|
|
||||||
import { DriveFolder } from './models/entities/drive-folder';
|
|
||||||
import { InternalStorage } from './services/drive/internal-storage';
|
|
||||||
import { createTemp } from './misc/create-temp';
|
|
||||||
import { Note } from './models/entities/note';
|
|
||||||
import { Following } from './models/entities/following';
|
|
||||||
import { Poll } from './models/entities/poll';
|
|
||||||
import { PollVote } from './models/entities/poll-vote';
|
|
||||||
import { NoteFavorite } from './models/entities/note-favorite';
|
|
||||||
import { NoteReaction } from './models/entities/note-reaction';
|
|
||||||
import { UserPublickey } from './models/entities/user-publickey';
|
|
||||||
import { UserKeypair } from './models/entities/user-keypair';
|
|
||||||
import { extractPublic } from './crypto_key';
|
|
||||||
import { Emoji } from './models/entities/emoji';
|
|
||||||
import { toPuny as _toPuny } from './misc/convert-host';
|
|
||||||
import { UserProfile } from './models/entities/user-profile';
|
|
||||||
|
|
||||||
function toPuny(x: string | null): string | null {
|
|
||||||
if (x == null) return null;
|
|
||||||
return _toPuny(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
const u = (config as any).mongodb.user ? encodeURIComponent((config as any).mongodb.user) : null;
|
|
||||||
const p = (config as any).mongodb.pass ? encodeURIComponent((config as any).mongodb.pass) : null;
|
|
||||||
|
|
||||||
const uri = `mongodb://${u && p ? `${u}:${p}@` : ''}${(config as any).mongodb.host}:${(config as any).mongodb.port}/${(config as any).mongodb.db}`;
|
|
||||||
|
|
||||||
const db = monk(uri);
|
|
||||||
let mdb: mongo.Db;
|
|
||||||
|
|
||||||
const test = false;
|
|
||||||
const limit = 500;
|
|
||||||
|
|
||||||
const nativeDbConn = async (): Promise<mongo.Db> => {
|
|
||||||
if (mdb) return mdb;
|
|
||||||
|
|
||||||
const db = await ((): Promise<mongo.Db> => new Promise((resolve, reject) => {
|
|
||||||
mongo.MongoClient.connect(uri, { useNewUrlParser: true }, (e: Error, client: any) => {
|
|
||||||
if (e) return reject(e);
|
|
||||||
resolve(client.db((config as any).mongodb.db));
|
|
||||||
});
|
|
||||||
}))();
|
|
||||||
|
|
||||||
mdb = db;
|
|
||||||
|
|
||||||
return db;
|
|
||||||
};
|
|
||||||
|
|
||||||
const _User = db.get<any>('users');
|
|
||||||
const _DriveFile = db.get<any>('driveFiles.files');
|
|
||||||
const _DriveFolder = db.get<any>('driveFolders');
|
|
||||||
const _Note = db.get<any>('notes');
|
|
||||||
const _Following = db.get<any>('following');
|
|
||||||
const _PollVote = db.get<any>('pollVotes');
|
|
||||||
const _Favorite = db.get<any>('favorites');
|
|
||||||
const _NoteReaction = db.get<any>('noteReactions');
|
|
||||||
const _Emoji = db.get<any>('emoji');
|
|
||||||
const getDriveFileBucket = async (): Promise<mongo.GridFSBucket> => {
|
|
||||||
const db = await nativeDbConn();
|
|
||||||
const bucket = new mongo.GridFSBucket(db, {
|
|
||||||
bucketName: 'driveFiles'
|
|
||||||
});
|
|
||||||
return bucket;
|
|
||||||
};
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
await initDb();
|
|
||||||
const Users = getRepository(User);
|
|
||||||
const UserProfiles = getRepository(UserProfile);
|
|
||||||
const DriveFiles = getRepository(DriveFile);
|
|
||||||
const DriveFolders = getRepository(DriveFolder);
|
|
||||||
const Notes = getRepository(Note);
|
|
||||||
const Followings = getRepository(Following);
|
|
||||||
const Polls = getRepository(Poll);
|
|
||||||
const PollVotes = getRepository(PollVote);
|
|
||||||
const NoteFavorites = getRepository(NoteFavorite);
|
|
||||||
const NoteReactions = getRepository(NoteReaction);
|
|
||||||
const UserPublickeys = getRepository(UserPublickey);
|
|
||||||
const UserKeypairs = getRepository(UserKeypair);
|
|
||||||
const Emojis = getRepository(Emoji);
|
|
||||||
|
|
||||||
async function migrateUser(user: any) {
|
|
||||||
await Users.save({
|
|
||||||
id: user._id.toHexString(),
|
|
||||||
createdAt: user.createdAt || new Date(),
|
|
||||||
username: user.username,
|
|
||||||
usernameLower: user.username.toLowerCase(),
|
|
||||||
host: toPuny(user.host),
|
|
||||||
token: generateUserToken(),
|
|
||||||
isAdmin: user.isAdmin || false,
|
|
||||||
name: user.name,
|
|
||||||
followersCount: user.followersCount || 0,
|
|
||||||
followingCount: user.followingCount || 0,
|
|
||||||
notesCount: user.notesCount || 0,
|
|
||||||
isBot: user.isBot || false,
|
|
||||||
isCat: user.isCat || false,
|
|
||||||
isVerified: user.isVerified || false,
|
|
||||||
inbox: user.inbox,
|
|
||||||
sharedInbox: user.sharedInbox,
|
|
||||||
uri: user.uri,
|
|
||||||
});
|
|
||||||
await UserProfiles.save({
|
|
||||||
userId: user._id.toHexString(),
|
|
||||||
description: user.description,
|
|
||||||
userHost: toPuny(user.host),
|
|
||||||
autoAcceptFollowed: true,
|
|
||||||
autoWatch: false,
|
|
||||||
password: user.password,
|
|
||||||
location: user.profile ? user.profile.location : null,
|
|
||||||
birthday: user.profile ? user.profile.birthday : null,
|
|
||||||
});
|
|
||||||
if (user.publicKey) {
|
|
||||||
await UserPublickeys.save({
|
|
||||||
userId: user._id.toHexString(),
|
|
||||||
keyId: user.publicKey.id,
|
|
||||||
keyPem: user.publicKey.publicKeyPem
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (user.keypair) {
|
|
||||||
await UserKeypairs.save({
|
|
||||||
userId: user._id.toHexString(),
|
|
||||||
publicKey: extractPublic(user.keypair),
|
|
||||||
privateKey: user.keypair,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function migrateFollowing(following: any) {
|
|
||||||
await Followings.save({
|
|
||||||
id: following._id.toHexString(),
|
|
||||||
createdAt: new Date(),
|
|
||||||
followerId: following.followerId.toHexString(),
|
|
||||||
followeeId: following.followeeId.toHexString(),
|
|
||||||
|
|
||||||
// 非正規化
|
|
||||||
followerHost: following._follower ? toPuny(following._follower.host) : null,
|
|
||||||
followerInbox: following._follower ? following._follower.inbox : null,
|
|
||||||
followerSharedInbox: following._follower ? following._follower.sharedInbox : null,
|
|
||||||
followeeHost: following._followee ? toPuny(following._followee.host) : null,
|
|
||||||
followeeInbox: following._followee ? following._followee.inbox : null,
|
|
||||||
followeeSharedInbox: following._followee ? following._followee.sharedInbo : null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function migrateDriveFolder(folder: any) {
|
|
||||||
await DriveFolders.save({
|
|
||||||
id: folder._id.toHexString(),
|
|
||||||
createdAt: folder.createdAt || new Date(),
|
|
||||||
name: folder.name,
|
|
||||||
parentId: folder.parentId ? folder.parentId.toHexString() : null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function migrateDriveFile(file: any) {
|
|
||||||
const user = await _User.findOne({
|
|
||||||
_id: file.metadata.userId
|
|
||||||
});
|
|
||||||
if (user == null) return;
|
|
||||||
if (file.metadata.storage && file.metadata.storage.key) { // when object storage
|
|
||||||
await DriveFiles.save({
|
|
||||||
id: file._id.toHexString(),
|
|
||||||
userId: user._id.toHexString(),
|
|
||||||
userHost: toPuny(user.host),
|
|
||||||
createdAt: file.uploadDate || new Date(),
|
|
||||||
md5: file.md5,
|
|
||||||
name: file.filename,
|
|
||||||
type: file.contentType,
|
|
||||||
properties: file.metadata.properties || {},
|
|
||||||
size: file.length,
|
|
||||||
url: file.metadata.url,
|
|
||||||
uri: file.metadata.uri,
|
|
||||||
accessKey: file.metadata.storage.key,
|
|
||||||
folderId: file.metadata.folderId ? file.metadata.folderId.toHexString() : null,
|
|
||||||
storedInternal: false,
|
|
||||||
isLink: false
|
|
||||||
});
|
|
||||||
} else if (!file.metadata.isLink) {
|
|
||||||
const [temp, clean] = await createTemp();
|
|
||||||
await new Promise(async (res, rej) => {
|
|
||||||
const bucket = await getDriveFileBucket();
|
|
||||||
const readable = bucket.openDownloadStream(file._id);
|
|
||||||
const dest = fs.createWriteStream(temp);
|
|
||||||
readable.pipe(dest);
|
|
||||||
readable.on('end', () => {
|
|
||||||
dest.end();
|
|
||||||
res();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const key = uuid.v4();
|
|
||||||
const url = InternalStorage.saveFromPath(key, temp);
|
|
||||||
await DriveFiles.save({
|
|
||||||
id: file._id.toHexString(),
|
|
||||||
userId: user._id.toHexString(),
|
|
||||||
userHost: toPuny(user.host),
|
|
||||||
createdAt: file.uploadDate || new Date(),
|
|
||||||
md5: file.md5,
|
|
||||||
name: file.filename,
|
|
||||||
type: file.contentType,
|
|
||||||
properties: file.metadata.properties,
|
|
||||||
size: file.length,
|
|
||||||
url: url,
|
|
||||||
uri: file.metadata.uri,
|
|
||||||
accessKey: key,
|
|
||||||
folderId: file.metadata.folderId ? file.metadata.folderId.toHexString() : null,
|
|
||||||
storedInternal: true,
|
|
||||||
isLink: false
|
|
||||||
});
|
|
||||||
clean();
|
|
||||||
} else {
|
|
||||||
await DriveFiles.save({
|
|
||||||
id: file._id.toHexString(),
|
|
||||||
userId: user._id.toHexString(),
|
|
||||||
userHost: toPuny(user.host),
|
|
||||||
createdAt: file.uploadDate || new Date(),
|
|
||||||
md5: file.md5,
|
|
||||||
name: file.filename,
|
|
||||||
type: file.contentType,
|
|
||||||
properties: file.metadata.properties,
|
|
||||||
size: file.length,
|
|
||||||
url: file.metadata.url,
|
|
||||||
uri: file.metadata.uri,
|
|
||||||
accessKey: null,
|
|
||||||
folderId: file.metadata.folderId ? file.metadata.folderId.toHexString() : null,
|
|
||||||
storedInternal: false,
|
|
||||||
isLink: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function migrateNote(note: any) {
|
|
||||||
await Notes.save({
|
|
||||||
id: note._id.toHexString(),
|
|
||||||
createdAt: note.createdAt || new Date(),
|
|
||||||
text: note.text,
|
|
||||||
cw: note.cw || null,
|
|
||||||
tags: note.tags || [],
|
|
||||||
userId: note.userId.toHexString(),
|
|
||||||
viaMobile: note.viaMobile || false,
|
|
||||||
geo: note.geo,
|
|
||||||
appId: null,
|
|
||||||
visibility: note.visibility || 'public',
|
|
||||||
visibleUserIds: note.visibleUserIds ? note.visibleUserIds.map((id: any) => id.toHexString()) : [],
|
|
||||||
replyId: note.replyId ? note.replyId.toHexString() : null,
|
|
||||||
renoteId: note.renoteId ? note.renoteId.toHexString() : null,
|
|
||||||
userHost: null,
|
|
||||||
fileIds: note.fileIds ? note.fileIds.map((id: any) => id.toHexString()) : [],
|
|
||||||
localOnly: note.localOnly || false,
|
|
||||||
hasPoll: note.poll != null
|
|
||||||
});
|
|
||||||
|
|
||||||
if (note.poll) {
|
|
||||||
await Polls.save({
|
|
||||||
noteId: note._id.toHexString(),
|
|
||||||
choices: note.poll.choices.map((x: any) => x.text),
|
|
||||||
expiresAt: note.poll.expiresAt,
|
|
||||||
multiple: note.poll.multiple,
|
|
||||||
votes: note.poll.choices.map((x: any) => x.votes),
|
|
||||||
noteVisibility: note.visibility,
|
|
||||||
userId: note.userId.toHexString(),
|
|
||||||
userHost: null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function migratePollVote(vote: any) {
|
|
||||||
await PollVotes.save({
|
|
||||||
id: vote._id.toHexString(),
|
|
||||||
createdAt: vote.createdAt,
|
|
||||||
noteId: vote.noteId.toHexString(),
|
|
||||||
userId: vote.userId.toHexString(),
|
|
||||||
choice: vote.choice
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function migrateNoteFavorite(favorite: any) {
|
|
||||||
await NoteFavorites.save({
|
|
||||||
id: favorite._id.toHexString(),
|
|
||||||
createdAt: favorite.createdAt,
|
|
||||||
noteId: favorite.noteId.toHexString(),
|
|
||||||
userId: favorite.userId.toHexString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function migrateNoteReaction(reaction: any) {
|
|
||||||
await NoteReactions.save({
|
|
||||||
id: reaction._id.toHexString(),
|
|
||||||
createdAt: reaction.createdAt,
|
|
||||||
noteId: reaction.noteId.toHexString(),
|
|
||||||
userId: reaction.userId.toHexString(),
|
|
||||||
reaction: reaction.reaction
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function reMigrateUser(user: any) {
|
|
||||||
const u = await _User.findOne({
|
|
||||||
_id: new mongo.ObjectId(user.id)
|
|
||||||
});
|
|
||||||
const avatar = u.avatarId ? await DriveFiles.findOne(u.avatarId.toHexString()) : null;
|
|
||||||
const banner = u.bannerId ? await DriveFiles.findOne(u.bannerId.toHexString()) : null;
|
|
||||||
await Users.update(user.id, {
|
|
||||||
avatarId: avatar ? avatar.id : null,
|
|
||||||
bannerId: banner ? banner.id : null,
|
|
||||||
avatarUrl: avatar ? avatar.url : null,
|
|
||||||
bannerUrl: banner ? banner.url : null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function migrateEmoji(emoji: any) {
|
|
||||||
await Emojis.save({
|
|
||||||
id: emoji._id.toHexString(),
|
|
||||||
updatedAt: emoji.createdAt,
|
|
||||||
aliases: emoji.aliases,
|
|
||||||
url: emoji.url,
|
|
||||||
uri: emoji.uri,
|
|
||||||
host: toPuny(emoji.host),
|
|
||||||
name: emoji.name
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let allUsersCount = await _User.count({
|
|
||||||
deletedAt: { $exists: false }
|
|
||||||
});
|
|
||||||
if (test && allUsersCount > limit) allUsersCount = limit;
|
|
||||||
for (let i = 0; i < allUsersCount; i++) {
|
|
||||||
const user = await _User.findOne({
|
|
||||||
deletedAt: { $exists: false }
|
|
||||||
}, {
|
|
||||||
skip: i
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
await migrateUser(user);
|
|
||||||
console.log(`USER (${i + 1}/${allUsersCount}) ${user._id} ${chalk.green('DONE')}`);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(`USER (${i + 1}/${allUsersCount}) ${user._id} ${chalk.red('ERR')}`);
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let allFollowingsCount = await _Following.count();
|
|
||||||
if (test && allFollowingsCount > limit) allFollowingsCount = limit;
|
|
||||||
for (let i = 0; i < allFollowingsCount; i++) {
|
|
||||||
const following = await _Following.findOne({}, {
|
|
||||||
skip: i
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
await migrateFollowing(following);
|
|
||||||
console.log(`FOLLOWING (${i + 1}/${allFollowingsCount}) ${following._id} ${chalk.green('DONE')}`);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(`FOLLOWING (${i + 1}/${allFollowingsCount}) ${following._id} ${chalk.red('ERR')}`);
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let allDriveFoldersCount = await _DriveFolder.count();
|
|
||||||
if (test && allDriveFoldersCount > limit) allDriveFoldersCount = limit;
|
|
||||||
for (let i = 0; i < allDriveFoldersCount; i++) {
|
|
||||||
const folder = await _DriveFolder.findOne({}, {
|
|
||||||
skip: i
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
await migrateDriveFolder(folder);
|
|
||||||
console.log(`FOLDER (${i + 1}/${allDriveFoldersCount}) ${folder._id} ${chalk.green('DONE')}`);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(`FOLDER (${i + 1}/${allDriveFoldersCount}) ${folder._id} ${chalk.red('ERR')}`);
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let allDriveFilesCount = await _DriveFile.count({
|
|
||||||
'metadata._user.host': null,
|
|
||||||
'metadata.deletedAt': { $exists: false }
|
|
||||||
});
|
|
||||||
if (test && allDriveFilesCount > limit) allDriveFilesCount = limit;
|
|
||||||
for (let i = 0; i < allDriveFilesCount; i++) {
|
|
||||||
const file = await _DriveFile.findOne({
|
|
||||||
'metadata._user.host': null,
|
|
||||||
'metadata.deletedAt': { $exists: false }
|
|
||||||
}, {
|
|
||||||
skip: i
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
await migrateDriveFile(file);
|
|
||||||
console.log(`FILE (${i + 1}/${allDriveFilesCount}) ${file._id} ${chalk.green('DONE')}`);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(`FILE (${i + 1}/${allDriveFilesCount}) ${file._id} ${chalk.red('ERR')}`);
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let allNotesCount = await _Note.count({
|
|
||||||
'_user.host': null,
|
|
||||||
'metadata.deletedAt': { $exists: false }
|
|
||||||
});
|
|
||||||
if (test && allNotesCount > limit) allNotesCount = limit;
|
|
||||||
for (let i = 0; i < allNotesCount; i++) {
|
|
||||||
const note = await _Note.findOne({
|
|
||||||
'_user.host': null,
|
|
||||||
'metadata.deletedAt': { $exists: false }
|
|
||||||
}, {
|
|
||||||
skip: i
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
await migrateNote(note);
|
|
||||||
console.log(`NOTE (${i + 1}/${allNotesCount}) ${note._id} ${chalk.green('DONE')}`);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(`NOTE (${i + 1}/${allNotesCount}) ${note._id} ${chalk.red('ERR')}`);
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let allPollVotesCount = await _PollVote.count();
|
|
||||||
if (test && allPollVotesCount > limit) allPollVotesCount = limit;
|
|
||||||
for (let i = 0; i < allPollVotesCount; i++) {
|
|
||||||
const vote = await _PollVote.findOne({}, {
|
|
||||||
skip: i
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
await migratePollVote(vote);
|
|
||||||
console.log(`VOTE (${i + 1}/${allPollVotesCount}) ${vote._id} ${chalk.green('DONE')}`);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(`VOTE (${i + 1}/${allPollVotesCount}) ${vote._id} ${chalk.red('ERR')}`);
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let allNoteFavoritesCount = await _Favorite.count();
|
|
||||||
if (test && allNoteFavoritesCount > limit) allNoteFavoritesCount = limit;
|
|
||||||
for (let i = 0; i < allNoteFavoritesCount; i++) {
|
|
||||||
const favorite = await _Favorite.findOne({}, {
|
|
||||||
skip: i
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
await migrateNoteFavorite(favorite);
|
|
||||||
console.log(`FAVORITE (${i + 1}/${allNoteFavoritesCount}) ${favorite._id} ${chalk.green('DONE')}`);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(`FAVORITE (${i + 1}/${allNoteFavoritesCount}) ${favorite._id} ${chalk.red('ERR')}`);
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let allNoteReactionsCount = await _NoteReaction.count();
|
|
||||||
if (test && allNoteReactionsCount > limit) allNoteReactionsCount = limit;
|
|
||||||
for (let i = 0; i < allNoteReactionsCount; i++) {
|
|
||||||
const reaction = await _NoteReaction.findOne({}, {
|
|
||||||
skip: i
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
await migrateNoteReaction(reaction);
|
|
||||||
console.log(`REACTION (${i + 1}/${allNoteReactionsCount}) ${reaction._id} ${chalk.green('DONE')}`);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(`REACTION (${i + 1}/${allNoteReactionsCount}) ${reaction._id} ${chalk.red('ERR')}`);
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let allActualUsersCount = await Users.count();
|
|
||||||
if (test && allActualUsersCount > limit) allActualUsersCount = limit;
|
|
||||||
for (let i = 0; i < allActualUsersCount; i++) {
|
|
||||||
const [user] = await Users.find({
|
|
||||||
take: 1,
|
|
||||||
skip: i
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
await reMigrateUser(user);
|
|
||||||
console.log(`RE:USER (${i + 1}/${allActualUsersCount}) ${user.id} ${chalk.green('DONE')}`);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(`RE:USER (${i + 1}/${allActualUsersCount}) ${user.id} ${chalk.red('ERR')}`);
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const allEmojisCount = await _Emoji.count();
|
|
||||||
for (let i = 0; i < allEmojisCount; i++) {
|
|
||||||
const emoji = await _Emoji.findOne({}, {
|
|
||||||
skip: i
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
await migrateEmoji(emoji);
|
|
||||||
console.log(`EMOJI (${i + 1}/${allEmojisCount}) ${emoji._id} ${chalk.green('DONE')}`);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(`EMOJI (${i + 1}/${allEmojisCount}) ${emoji._id} ${chalk.red('ERR')}`);
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('DONE :)');
|
|
||||||
}
|
|
||||||
|
|
||||||
main();
|
|
@ -1,26 +0,0 @@
|
|||||||
// AID
|
|
||||||
// 長さ8の[2000年1月1日からの経過ミリ秒をbase36でエンコードしたもの] + 長さnの[ランダムな文字列]
|
|
||||||
|
|
||||||
const CHARS = '0123456789abcdefghijklmnopqrstuvwxyz';
|
|
||||||
const TIME2000 = 946684800000;
|
|
||||||
|
|
||||||
function getTime(time: number) {
|
|
||||||
time = time - TIME2000;
|
|
||||||
if (time < 0) time = 0;
|
|
||||||
|
|
||||||
return time.toString(36);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRandom(length: number) {
|
|
||||||
let str = '';
|
|
||||||
|
|
||||||
for (let i = 0; i < length; i++) {
|
|
||||||
str += CHARS[Math.floor(Math.random() * CHARS.length)];
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function genAid(date: Date, rand: number): string {
|
|
||||||
return getTime(date.getTime()).padStart(8, CHARS[0]) + getRandom(rand);
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
// AID(Cheep)
|
|
||||||
// 長さ6の[2000年1月1日からの経過秒をbase36でエンコードしたもの] + 長さ3の[ランダムな文字列]
|
|
||||||
|
|
||||||
const CHARS = '0123456789abcdefghijklmnopqrstuvwxyz';
|
|
||||||
const TIME2000 = 946684800000;
|
|
||||||
|
|
||||||
function getTime(time: number) {
|
|
||||||
time = time - TIME2000;
|
|
||||||
if (time < 0) time = 0;
|
|
||||||
time = Math.floor(time / 1000);
|
|
||||||
return time.toString(36);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRandom() {
|
|
||||||
let str = '';
|
|
||||||
|
|
||||||
for (let i = 0; i < 3; i++) {
|
|
||||||
str += CHARS[Math.floor(Math.random() * CHARS.length)];
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function genAidc(date: Date): string {
|
|
||||||
return getTime(date.getTime()).padStart(6, CHARS[0]) + getRandom();
|
|
||||||
}
|
|
@ -19,3 +19,8 @@ export function extractDbHost(uri: string) {
|
|||||||
export function toPuny(host: string) {
|
export function toPuny(host: string) {
|
||||||
return toASCII(host.toLowerCase());
|
return toASCII(host.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toPunyNullable(host: string | null | undefined): string | null {
|
||||||
|
if (host == null) return null;
|
||||||
|
return toASCII(host.toLowerCase());
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { ulid } from 'ulid';
|
import { ulid } from 'ulid';
|
||||||
import { genAid } from './aid';
|
import { genAid } from './id/aid';
|
||||||
import { genAidc } from './aidc';
|
import { genMeid } from './id/meid';
|
||||||
import { genObjectId } from './object-id';
|
import { genObjectId } from './id/object-id';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
|
|
||||||
const metohd = config.id.toLowerCase();
|
const metohd = config.id.toLowerCase();
|
||||||
@ -10,13 +10,10 @@ export function genId(date?: Date): string {
|
|||||||
if (!date || (date > new Date())) date = new Date();
|
if (!date || (date > new Date())) date = new Date();
|
||||||
|
|
||||||
switch (metohd) {
|
switch (metohd) {
|
||||||
case 'aidc': return genAidc(date);
|
case 'aid': return genAid(date);
|
||||||
case 'aid1': return genAid(date, 1);
|
case 'meid': return genMeid(date);
|
||||||
case 'aid2': return genAid(date, 2);
|
|
||||||
case 'aid3': return genAid(date, 3);
|
|
||||||
case 'aid4': return genAid(date, 4);
|
|
||||||
case 'ulid': return ulid(date.getTime());
|
case 'ulid': return ulid(date.getTime());
|
||||||
case 'objectid': return genObjectId(date);
|
case 'objectid': return genObjectId(date);
|
||||||
default: throw 'unknown id generation method';
|
default: throw new Error('unknown id generation method');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
23
src/misc/id/aid.ts
Normal file
23
src/misc/id/aid.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// AID
|
||||||
|
// 長さ8の[2000年1月1日からの経過ミリ秒をbase36でエンコードしたもの] + 長さ2の[ノイズ文字列]
|
||||||
|
|
||||||
|
import * as cluster from 'cluster';
|
||||||
|
|
||||||
|
const TIME2000 = 946684800000;
|
||||||
|
let counter = process.pid + (cluster.isMaster ? 0 : cluster.worker.id);
|
||||||
|
|
||||||
|
function getTime(time: number) {
|
||||||
|
time = time - TIME2000;
|
||||||
|
if (time < 0) time = 0;
|
||||||
|
|
||||||
|
return time.toString(36).padStart(8, '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNoise() {
|
||||||
|
return counter.toString(36).padStart(2, '0').slice(-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function genAid(date: Date): string {
|
||||||
|
counter++;
|
||||||
|
return getTime(date.getTime()) + getNoise();
|
||||||
|
}
|
26
src/misc/id/meid.ts
Normal file
26
src/misc/id/meid.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
const CHARS = '0123456789abcdef';
|
||||||
|
|
||||||
|
function getTime(time: number) {
|
||||||
|
if (time < 0) time = 0;
|
||||||
|
if (time === 0) {
|
||||||
|
return CHARS[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
time += 0x800000000000;
|
||||||
|
|
||||||
|
return time.toString(16).padStart(12, CHARS[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRandom() {
|
||||||
|
let str = '';
|
||||||
|
|
||||||
|
for (let i = 0; i < 12; i++) {
|
||||||
|
str += CHARS[Math.floor(Math.random() * CHARS.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function genMeid(date: Date): string {
|
||||||
|
return 'f' + getTime(date.getTime()) + getRandom();
|
||||||
|
}
|
@ -8,7 +8,7 @@ function getTime(time: number) {
|
|||||||
|
|
||||||
time = Math.floor(time / 1000);
|
time = Math.floor(time / 1000);
|
||||||
|
|
||||||
return time.toString(16);
|
return time.toString(16).padStart(8, CHARS[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRandom() {
|
function getRandom() {
|
@ -20,7 +20,7 @@ export async function getFallbackReaction(): Promise<string> {
|
|||||||
return meta.useStarForReactionFallback ? 'star' : 'like';
|
return meta.useStarForReactionFallback ? 'star' : 'like';
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function toDbReaction(reaction: string, enableEmoji = true): Promise<string> {
|
export async function toDbReaction(reaction?: string | null, enableEmoji = true): Promise<string> {
|
||||||
if (reaction == null) return await getFallbackReaction();
|
if (reaction == null) return await getFallbackReaction();
|
||||||
|
|
||||||
// 既存の文字列リアクションはそのまま
|
// 既存の文字列リアクションはそのまま
|
||||||
|
@ -19,11 +19,15 @@ export class AuthSession {
|
|||||||
})
|
})
|
||||||
public token: string;
|
public token: string;
|
||||||
|
|
||||||
@Column(id())
|
@Column({
|
||||||
|
...id(),
|
||||||
|
nullable: true
|
||||||
|
})
|
||||||
public userId: User['id'];
|
public userId: User['id'];
|
||||||
|
|
||||||
@ManyToOne(type => User, {
|
@ManyToOne(type => User, {
|
||||||
onDelete: 'CASCADE'
|
onDelete: 'CASCADE',
|
||||||
|
nullable: true
|
||||||
})
|
})
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
public user: User | null;
|
public user: User | null;
|
||||||
|
@ -93,7 +93,7 @@ export class Meta {
|
|||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 512,
|
length: 512,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
default: 'https://ai.misskey.xyz/aiart/yubitun.png'
|
default: 'https://xn--931a.moe/aiart/yubitun.png'
|
||||||
})
|
})
|
||||||
public errorImageUrl: string | null;
|
public errorImageUrl: string | null;
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ export class Note {
|
|||||||
public uri: string | null;
|
public uri: string | null;
|
||||||
|
|
||||||
@Column('integer', {
|
@Column('integer', {
|
||||||
default: 0
|
default: 0, select: false
|
||||||
})
|
})
|
||||||
public score: number;
|
public score: number;
|
||||||
|
|
||||||
|
@ -18,12 +18,8 @@ export class DriveFileRepository extends Repository<DriveFile> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPublicUrl(file: DriveFile, thumbnail = false): string {
|
public getPublicUrl(file: DriveFile, thumbnail = false): string | null {
|
||||||
if (thumbnail) {
|
return thumbnail ? (file.thumbnailUrl || file.webpublicUrl || null) : (file.webpublicUrl || file.thumbnailUrl || file.url);
|
||||||
return file.thumbnailUrl || file.webpublicUrl || file.url;
|
|
||||||
} else {
|
|
||||||
return file.webpublicUrl || file.thumbnailUrl || file.url;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async clacDriveUsageOf(user: User['id'] | User): Promise<number> {
|
public async clacDriveUsageOf(user: User['id'] | User): Promise<number> {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { EntityRepository, Repository } from 'typeorm';
|
import { EntityRepository, Repository } from 'typeorm';
|
||||||
import { UserList } from '../entities/user-list';
|
import { UserList } from '../entities/user-list';
|
||||||
import { ensure } from '../../prelude/ensure';
|
import { ensure } from '../../prelude/ensure';
|
||||||
|
import { UserListJoinings } from '..';
|
||||||
|
|
||||||
@EntityRepository(UserList)
|
@EntityRepository(UserList)
|
||||||
export class UserListRepository extends Repository<UserList> {
|
export class UserListRepository extends Repository<UserList> {
|
||||||
@ -9,9 +10,14 @@ export class UserListRepository extends Repository<UserList> {
|
|||||||
) {
|
) {
|
||||||
const userList = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
const userList = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
|
||||||
|
|
||||||
|
const users = await UserListJoinings.find({
|
||||||
|
userListId: userList.id
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: userList.id,
|
id: userList.id,
|
||||||
name: userList.name
|
name: userList.name,
|
||||||
|
userIds: users.map(x => x.userId)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,6 +121,7 @@ export class UserRepository extends Repository<User> {
|
|||||||
updatedAt: user.updatedAt,
|
updatedAt: user.updatedAt,
|
||||||
bannerUrl: user.bannerUrl,
|
bannerUrl: user.bannerUrl,
|
||||||
bannerColor: user.bannerColor,
|
bannerColor: user.bannerColor,
|
||||||
|
isLocked: user.isLocked,
|
||||||
description: profile!.description,
|
description: profile!.description,
|
||||||
location: profile!.location,
|
location: profile!.location,
|
||||||
birthday: profile!.birthday,
|
birthday: profile!.birthday,
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
export function ensure<T>(x: T): NonNullable<T> {
|
export function ensure<T>(x: T): NonNullable<T> {
|
||||||
if (x == null) {
|
if (x == null) {
|
||||||
throw 'ぬるぽ';
|
throw new Error('ぬるぽ');
|
||||||
} else {
|
} else {
|
||||||
return x!;
|
return x!;
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
export interface Maybe<T> {
|
export interface IMaybe<T> {
|
||||||
isJust(): this is Just<T>;
|
isJust(): this is IJust<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Just<T> = Maybe<T> & {
|
export interface IJust<T> extends IMaybe<T> {
|
||||||
get(): T
|
get(): T;
|
||||||
};
|
}
|
||||||
|
|
||||||
export function just<T>(value: T): Just<T> {
|
export function just<T>(value: T): IJust<T> {
|
||||||
return {
|
return {
|
||||||
isJust: () => true,
|
isJust: () => true,
|
||||||
get: () => value
|
get: () => value
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function nothing<T>(): Maybe<T> {
|
export function nothing<T>(): IMaybe<T> {
|
||||||
return {
|
return {
|
||||||
isJust: () => false,
|
isJust: () => false,
|
||||||
};
|
};
|
||||||
|
@ -23,6 +23,14 @@ function initializeQueue(name: string) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderError(e: Error): any {
|
||||||
|
return {
|
||||||
|
stack: e.stack,
|
||||||
|
message: e.message,
|
||||||
|
name: e.name
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export const deliverQueue = initializeQueue('deliver');
|
export const deliverQueue = initializeQueue('deliver');
|
||||||
export const inboxQueue = initializeQueue('inbox');
|
export const inboxQueue = initializeQueue('inbox');
|
||||||
export const dbQueue = initializeQueue('db');
|
export const dbQueue = initializeQueue('db');
|
||||||
@ -34,16 +42,16 @@ deliverQueue
|
|||||||
.on('waiting', (jobId) => deliverLogger.debug(`waiting id=${jobId}`))
|
.on('waiting', (jobId) => deliverLogger.debug(`waiting id=${jobId}`))
|
||||||
.on('active', (job) => deliverLogger.debug(`active id=${job.id} to=${job.data.to}`))
|
.on('active', (job) => deliverLogger.debug(`active id=${job.id} to=${job.data.to}`))
|
||||||
.on('completed', (job, result) => deliverLogger.debug(`completed(${result}) id=${job.id} to=${job.data.to}`))
|
.on('completed', (job, result) => deliverLogger.debug(`completed(${result}) id=${job.id} to=${job.data.to}`))
|
||||||
.on('failed', (job, err) => deliverLogger.warn(`failed(${err}) id=${job.id} to=${job.data.to}`))
|
.on('failed', (job, err) => deliverLogger.warn(`failed(${err}) id=${job.id} to=${job.data.to}`, { job, e: renderError(err) }))
|
||||||
.on('error', (error) => deliverLogger.error(`error ${error}`))
|
.on('error', (job: any, err: Error) => deliverLogger.error(`error ${err}`, { job, e: renderError(err) }))
|
||||||
.on('stalled', (job) => deliverLogger.warn(`stalled id=${job.id} to=${job.data.to}`));
|
.on('stalled', (job) => deliverLogger.warn(`stalled id=${job.id} to=${job.data.to}`));
|
||||||
|
|
||||||
inboxQueue
|
inboxQueue
|
||||||
.on('waiting', (jobId) => inboxLogger.debug(`waiting id=${jobId}`))
|
.on('waiting', (jobId) => inboxLogger.debug(`waiting id=${jobId}`))
|
||||||
.on('active', (job) => inboxLogger.debug(`active id=${job.id}`))
|
.on('active', (job) => inboxLogger.debug(`active id=${job.id}`))
|
||||||
.on('completed', (job, result) => inboxLogger.debug(`completed(${result}) id=${job.id}`))
|
.on('completed', (job, result) => inboxLogger.debug(`completed(${result}) id=${job.id}`))
|
||||||
.on('failed', (job, err) => inboxLogger.warn(`failed(${err}) id=${job.id} activity=${job.data.activity ? job.data.activity.id : 'none'}`))
|
.on('failed', (job, err) => inboxLogger.warn(`failed(${err}) id=${job.id} activity=${job.data.activity ? job.data.activity.id : 'none'}`, { job, e: renderError(err) }))
|
||||||
.on('error', (error) => inboxLogger.error(`error ${error}`))
|
.on('error', (job: any, err: Error) => inboxLogger.error(`error ${err}`, { job, e: renderError(err) }))
|
||||||
.on('stalled', (job) => inboxLogger.warn(`stalled id=${job.id} activity=${job.data.activity ? job.data.activity.id : 'none'}`));
|
.on('stalled', (job) => inboxLogger.warn(`stalled id=${job.id} activity=${job.data.activity ? job.data.activity.id : 'none'}`));
|
||||||
|
|
||||||
export function deliver(user: ILocalUser, content: any, to: any) {
|
export function deliver(user: ILocalUser, content: any, to: any) {
|
||||||
|
@ -17,10 +17,9 @@ export async function deleteDriveFiles(job: Bull.Job, done: any): Promise<void>
|
|||||||
}
|
}
|
||||||
|
|
||||||
let deletedCount = 0;
|
let deletedCount = 0;
|
||||||
let ended = false;
|
|
||||||
let cursor: any = null;
|
let cursor: any = null;
|
||||||
|
|
||||||
while (!ended) {
|
while (true) {
|
||||||
const files = await DriveFiles.find({
|
const files = await DriveFiles.find({
|
||||||
where: {
|
where: {
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
@ -33,7 +32,6 @@ export async function deleteDriveFiles(job: Bull.Job, done: any): Promise<void>
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (files.length === 0) {
|
if (files.length === 0) {
|
||||||
ended = true;
|
|
||||||
job.progress(100);
|
job.progress(100);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -33,10 +33,9 @@ export async function exportBlocking(job: Bull.Job, done: any): Promise<void> {
|
|||||||
const stream = fs.createWriteStream(path, { flags: 'a' });
|
const stream = fs.createWriteStream(path, { flags: 'a' });
|
||||||
|
|
||||||
let exportedCount = 0;
|
let exportedCount = 0;
|
||||||
let ended = false;
|
|
||||||
let cursor: any = null;
|
let cursor: any = null;
|
||||||
|
|
||||||
while (!ended) {
|
while (true) {
|
||||||
const blockings = await Blockings.find({
|
const blockings = await Blockings.find({
|
||||||
where: {
|
where: {
|
||||||
blockerId: user.id,
|
blockerId: user.id,
|
||||||
@ -49,7 +48,6 @@ export async function exportBlocking(job: Bull.Job, done: any): Promise<void> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (blockings.length === 0) {
|
if (blockings.length === 0) {
|
||||||
ended = true;
|
|
||||||
job.progress(100);
|
job.progress(100);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -33,10 +33,9 @@ export async function exportFollowing(job: Bull.Job, done: any): Promise<void> {
|
|||||||
const stream = fs.createWriteStream(path, { flags: 'a' });
|
const stream = fs.createWriteStream(path, { flags: 'a' });
|
||||||
|
|
||||||
let exportedCount = 0;
|
let exportedCount = 0;
|
||||||
let ended = false;
|
|
||||||
let cursor: any = null;
|
let cursor: any = null;
|
||||||
|
|
||||||
while (!ended) {
|
while (true) {
|
||||||
const followings = await Followings.find({
|
const followings = await Followings.find({
|
||||||
where: {
|
where: {
|
||||||
followerId: user.id,
|
followerId: user.id,
|
||||||
@ -49,7 +48,6 @@ export async function exportFollowing(job: Bull.Job, done: any): Promise<void> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (followings.length === 0) {
|
if (followings.length === 0) {
|
||||||
ended = true;
|
|
||||||
job.progress(100);
|
job.progress(100);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -33,10 +33,9 @@ export async function exportMute(job: Bull.Job, done: any): Promise<void> {
|
|||||||
const stream = fs.createWriteStream(path, { flags: 'a' });
|
const stream = fs.createWriteStream(path, { flags: 'a' });
|
||||||
|
|
||||||
let exportedCount = 0;
|
let exportedCount = 0;
|
||||||
let ended = false;
|
|
||||||
let cursor: any = null;
|
let cursor: any = null;
|
||||||
|
|
||||||
while (!ended) {
|
while (true) {
|
||||||
const mutes = await Mutings.find({
|
const mutes = await Mutings.find({
|
||||||
where: {
|
where: {
|
||||||
muterId: user.id,
|
muterId: user.id,
|
||||||
@ -49,7 +48,6 @@ export async function exportMute(job: Bull.Job, done: any): Promise<void> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (mutes.length === 0) {
|
if (mutes.length === 0) {
|
||||||
ended = true;
|
|
||||||
job.progress(100);
|
job.progress(100);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -46,10 +46,9 @@ export async function exportNotes(job: Bull.Job, done: any): Promise<void> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let exportedNotesCount = 0;
|
let exportedNotesCount = 0;
|
||||||
let ended = false;
|
|
||||||
let cursor: any = null;
|
let cursor: any = null;
|
||||||
|
|
||||||
while (!ended) {
|
while (true) {
|
||||||
const notes = await Notes.find({
|
const notes = await Notes.find({
|
||||||
where: {
|
where: {
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
@ -62,7 +61,6 @@ export async function exportNotes(job: Bull.Job, done: any): Promise<void> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (notes.length === 0) {
|
if (notes.length === 0) {
|
||||||
ended = true;
|
|
||||||
job.progress(100);
|
job.progress(100);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ import { Instances, Users, UserPublickeys } from '../../models';
|
|||||||
import { instanceChart } from '../../services/chart';
|
import { instanceChart } from '../../services/chart';
|
||||||
import { UserPublickey } from '../../models/entities/user-publickey';
|
import { UserPublickey } from '../../models/entities/user-publickey';
|
||||||
import fetchMeta from '../../misc/fetch-meta';
|
import fetchMeta from '../../misc/fetch-meta';
|
||||||
import { toPuny } from '../../misc/convert-host';
|
import { toPuny, toPunyNullable } from '../../misc/convert-host';
|
||||||
import { validActor } from '../../remote/activitypub/type';
|
import { validActor } from '../../remote/activitypub/type';
|
||||||
import { ensure } from '../../prelude/ensure';
|
import { ensure } from '../../prelude/ensure';
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ export default async (job: Bull.Job): Promise<void> => {
|
|||||||
|
|
||||||
if (keyIdLower.startsWith('acct:')) {
|
if (keyIdLower.startsWith('acct:')) {
|
||||||
const acct = parseAcct(keyIdLower.slice('acct:'.length));
|
const acct = parseAcct(keyIdLower.slice('acct:'.length));
|
||||||
const host = acct.host ? toPuny(acct.host) : null;
|
const host = toPunyNullable(acct.host);
|
||||||
const username = toPuny(acct.username);
|
const username = toPuny(acct.username);
|
||||||
|
|
||||||
if (host === null) {
|
if (host === null) {
|
||||||
|
@ -6,7 +6,7 @@ import { Users } from '../../../../models';
|
|||||||
|
|
||||||
export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
|
export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
|
||||||
const id = typeof activity.actor == 'string' ? activity.actor : activity.actor.id;
|
const id = typeof activity.actor == 'string' ? activity.actor : activity.actor.id;
|
||||||
if (id == null) throw 'missing id';
|
if (id == null) throw new Error('missing id');
|
||||||
|
|
||||||
if (!id.startsWith(config.url + '/')) {
|
if (!id.startsWith(config.url + '/')) {
|
||||||
return;
|
return;
|
||||||
|
@ -9,7 +9,7 @@ const logger = apLogger;
|
|||||||
|
|
||||||
export default async (actor: IRemoteUser, activity: IBlock): Promise<void> => {
|
export default async (actor: IRemoteUser, activity: IBlock): Promise<void> => {
|
||||||
const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
|
const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
|
||||||
if (id == null) throw 'missing id';
|
if (id == null) throw new Error('missing id');
|
||||||
|
|
||||||
const uri = activity.id || activity;
|
const uri = activity.id || activity;
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import { Users } from '../../../models';
|
|||||||
|
|
||||||
export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
|
export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
|
||||||
const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
|
const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
|
||||||
if (id == null) throw 'missing id';
|
if (id == null) throw new Error('missing id');
|
||||||
|
|
||||||
if (!id.startsWith(config.url + '/')) {
|
if (!id.startsWith(config.url + '/')) {
|
||||||
return;
|
return;
|
||||||
|
@ -5,7 +5,7 @@ import { Notes } from '../../../models';
|
|||||||
|
|
||||||
export default async (actor: IRemoteUser, activity: ILike) => {
|
export default async (actor: IRemoteUser, activity: ILike) => {
|
||||||
const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
|
const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
|
||||||
if (id == null) throw 'missing id';
|
if (id == null) throw new Error('missing id');
|
||||||
|
|
||||||
// Transform:
|
// Transform:
|
||||||
// https://misskey.ex/notes/xxxx to
|
// https://misskey.ex/notes/xxxx to
|
||||||
|
@ -6,7 +6,7 @@ import { Users } from '../../../../models';
|
|||||||
|
|
||||||
export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
|
export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
|
||||||
const id = typeof activity.actor == 'string' ? activity.actor : activity.actor.id;
|
const id = typeof activity.actor == 'string' ? activity.actor : activity.actor.id;
|
||||||
if (id == null) throw 'missing id';
|
if (id == null) throw new Error('missing id');
|
||||||
|
|
||||||
if (!id.startsWith(config.url + '/')) {
|
if (!id.startsWith(config.url + '/')) {
|
||||||
return;
|
return;
|
||||||
|
@ -9,7 +9,7 @@ const logger = apLogger;
|
|||||||
|
|
||||||
export default async (actor: IRemoteUser, activity: IBlock): Promise<void> => {
|
export default async (actor: IRemoteUser, activity: IBlock): Promise<void> => {
|
||||||
const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
|
const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
|
||||||
if (id == null) throw 'missing id';
|
if (id == null) throw new Error('missing id');
|
||||||
|
|
||||||
const uri = activity.id || activity;
|
const uri = activity.id || activity;
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import { Users, FollowRequests, Followings } from '../../../../models';
|
|||||||
|
|
||||||
export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
|
export default async (actor: IRemoteUser, activity: IFollow): Promise<void> => {
|
||||||
const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
|
const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
|
||||||
if (id == null) throw 'missing id';
|
if (id == null) throw new Error('missing id');
|
||||||
|
|
||||||
if (!id.startsWith(config.url + '/')) {
|
if (!id.startsWith(config.url + '/')) {
|
||||||
return;
|
return;
|
||||||
|
@ -8,13 +8,13 @@ import { Notes } from '../../../../models';
|
|||||||
*/
|
*/
|
||||||
export default async (actor: IRemoteUser, activity: ILike): Promise<void> => {
|
export default async (actor: IRemoteUser, activity: ILike): Promise<void> => {
|
||||||
const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
|
const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
|
||||||
if (id == null) throw 'missing id';
|
if (id == null) throw new Error('missing id');
|
||||||
|
|
||||||
const noteId = id.split('/').pop();
|
const noteId = id.split('/').pop();
|
||||||
|
|
||||||
const note = await Notes.findOne(noteId);
|
const note = await Notes.findOne(noteId);
|
||||||
if (note == null) {
|
if (note == null) {
|
||||||
throw 'note not found';
|
throw new Error('note not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await deleteReaction(actor, note);
|
await deleteReaction(actor, note);
|
||||||
|
@ -32,7 +32,7 @@ const logger = apLogger;
|
|||||||
*/
|
*/
|
||||||
export async function fetchNote(value: string | IObject, resolver?: Resolver): Promise<Note | null> {
|
export async function fetchNote(value: string | IObject, resolver?: Resolver): Promise<Note | null> {
|
||||||
const uri = typeof value == 'string' ? value : value.id;
|
const uri = typeof value == 'string' ? value : value.id;
|
||||||
if (uri == null) throw 'missing uri';
|
if (uri == null) throw new Error('missing uri');
|
||||||
|
|
||||||
// URIがこのサーバーを指しているならデータベースからフェッチ
|
// URIがこのサーバーを指しているならデータベースからフェッチ
|
||||||
if (uri.startsWith(config.url + '/')) {
|
if (uri.startsWith(config.url + '/')) {
|
||||||
@ -67,7 +67,7 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
|||||||
value: value,
|
value: value,
|
||||||
object: object
|
object: object
|
||||||
});
|
});
|
||||||
throw 'invalid note';
|
throw new Error('invalid note');
|
||||||
}
|
}
|
||||||
|
|
||||||
const note: INote = object;
|
const note: INote = object;
|
||||||
@ -81,7 +81,7 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
|||||||
|
|
||||||
// 投稿者が凍結されていたらスキップ
|
// 投稿者が凍結されていたらスキップ
|
||||||
if (actor.isSuspended) {
|
if (actor.isSuspended) {
|
||||||
throw 'actor has been suspended';
|
throw new Error('actor has been suspended');
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region Visibility
|
//#region Visibility
|
||||||
@ -120,13 +120,15 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
|||||||
: [];
|
: [];
|
||||||
|
|
||||||
// リプライ
|
// リプライ
|
||||||
const reply: Note | undefined | null = note.inReplyTo
|
const reply: Note | null = note.inReplyTo
|
||||||
? await resolveNote(note.inReplyTo, resolver).catch(e => {
|
? await resolveNote(note.inReplyTo, resolver).then(x => {
|
||||||
// 4xxの場合はリプライしてないことにする
|
if (x == null) {
|
||||||
if (e.statusCode >= 400 && e.statusCode < 500) {
|
logger.warn(`Specified inReplyTo, but nout found`);
|
||||||
logger.warn(`Ignored inReplyTo ${note.inReplyTo} - ${e.statusCode} `);
|
throw new Error('inReplyTo not found');
|
||||||
return null;
|
} else {
|
||||||
|
return x;
|
||||||
}
|
}
|
||||||
|
}).catch(e => {
|
||||||
logger.warn(`Error in inReplyTo ${note.inReplyTo} - ${e.statusCode || e}`);
|
logger.warn(`Error in inReplyTo ${note.inReplyTo} - ${e.statusCode || e}`);
|
||||||
throw e;
|
throw e;
|
||||||
})
|
})
|
||||||
@ -150,11 +152,11 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
|||||||
const cw = note.summary === '' ? null : note.summary;
|
const cw = note.summary === '' ? null : note.summary;
|
||||||
|
|
||||||
// テキストのパース
|
// テキストのパース
|
||||||
const text = note._misskey_content || fromHtml(note.content);
|
const text = note._misskey_content || (note.content ? fromHtml(note.content) : null);
|
||||||
|
|
||||||
// vote
|
// vote
|
||||||
if (reply && reply.hasPoll) {
|
if (reply && reply.hasPoll) {
|
||||||
const poll = await Polls.findOne({ noteId: reply.id }).then(ensure);
|
const poll = await Polls.findOne(reply.id).then(ensure);
|
||||||
|
|
||||||
const tryCreateVote = async (name: string, index: number): Promise<null> => {
|
const tryCreateVote = async (name: string, index: number): Promise<null> => {
|
||||||
if (poll.expiresAt && Date.now() > new Date(poll.expiresAt).getTime()) {
|
if (poll.expiresAt && Date.now() > new Date(poll.expiresAt).getTime()) {
|
||||||
@ -228,7 +230,7 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
|||||||
*/
|
*/
|
||||||
export async function resolveNote(value: string | IObject, resolver?: Resolver): Promise<Note | null> {
|
export async function resolveNote(value: string | IObject, resolver?: Resolver): Promise<Note | null> {
|
||||||
const uri = typeof value == 'string' ? value : value.id;
|
const uri = typeof value == 'string' ? value : value.id;
|
||||||
if (uri == null) throw 'missing uri';
|
if (uri == null) throw new Error('missing uri');
|
||||||
|
|
||||||
// ブロックしてたら中断
|
// ブロックしてたら中断
|
||||||
// TODO: いちいちデータベースにアクセスするのはコスト高そうなのでどっかにキャッシュしておく
|
// TODO: いちいちデータベースにアクセスするのはコスト高そうなのでどっかにキャッシュしておく
|
||||||
@ -250,7 +252,7 @@ export async function resolveNote(value: string | IObject, resolver?: Resolver):
|
|||||||
if (e.name === 'duplicated') {
|
if (e.name === 'duplicated') {
|
||||||
return fetchNote(uri).then(note => {
|
return fetchNote(uri).then(note => {
|
||||||
if (note == null) {
|
if (note == null) {
|
||||||
throw 'something happened';
|
throw new Error('something happened');
|
||||||
} else {
|
} else {
|
||||||
return note;
|
return note;
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ function validatePerson(x: any, uri: string) {
|
|||||||
* Misskeyに対象のPersonが登録されていればそれを返します。
|
* Misskeyに対象のPersonが登録されていればそれを返します。
|
||||||
*/
|
*/
|
||||||
export async function fetchPerson(uri: string, resolver?: Resolver): Promise<User | null> {
|
export async function fetchPerson(uri: string, resolver?: Resolver): Promise<User | null> {
|
||||||
if (typeof uri !== 'string') throw 'uri is not string';
|
if (typeof uri !== 'string') throw new Error('uri is not string');
|
||||||
|
|
||||||
// URIがこのサーバーを指しているならデータベースからフェッチ
|
// URIがこのサーバーを指しているならデータベースからフェッチ
|
||||||
if (uri.startsWith(config.url + '/')) {
|
if (uri.startsWith(config.url + '/')) {
|
||||||
@ -111,7 +111,7 @@ export async function fetchPerson(uri: string, resolver?: Resolver): Promise<Use
|
|||||||
* Personを作成します。
|
* Personを作成します。
|
||||||
*/
|
*/
|
||||||
export async function createPerson(uri: string, resolver?: Resolver): Promise<User> {
|
export async function createPerson(uri: string, resolver?: Resolver): Promise<User> {
|
||||||
if (typeof uri !== 'string') throw 'uri is not string';
|
if (typeof uri !== 'string') throw new Error('uri is not string');
|
||||||
|
|
||||||
if (resolver == null) resolver = new Resolver();
|
if (resolver == null) resolver = new Resolver();
|
||||||
|
|
||||||
@ -256,7 +256,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<Us
|
|||||||
* @param hint Hint of Person object (この値が正当なPersonの場合、Remote resolveをせずに更新に利用します)
|
* @param hint Hint of Person object (この値が正当なPersonの場合、Remote resolveをせずに更新に利用します)
|
||||||
*/
|
*/
|
||||||
export async function updatePerson(uri: string, resolver?: Resolver | null, hint?: object): Promise<void> {
|
export async function updatePerson(uri: string, resolver?: Resolver | null, hint?: object): Promise<void> {
|
||||||
if (typeof uri !== 'string') throw 'uri is not string';
|
if (typeof uri !== 'string') throw new Error('uri is not string');
|
||||||
|
|
||||||
// URIがこのサーバーを指しているならスキップ
|
// URIがこのサーバーを指しているならスキップ
|
||||||
if (uri.startsWith(config.url + '/')) {
|
if (uri.startsWith(config.url + '/')) {
|
||||||
@ -380,7 +380,7 @@ export async function updatePerson(uri: string, resolver?: Resolver | null, hint
|
|||||||
* リモートサーバーからフェッチしてMisskeyに登録しそれを返します。
|
* リモートサーバーからフェッチしてMisskeyに登録しそれを返します。
|
||||||
*/
|
*/
|
||||||
export async function resolvePerson(uri: string, resolver?: Resolver): Promise<User> {
|
export async function resolvePerson(uri: string, resolver?: Resolver): Promise<User> {
|
||||||
if (typeof uri !== 'string') throw 'uri is not string';
|
if (typeof uri !== 'string') throw new Error('uri is not string');
|
||||||
|
|
||||||
//#region このサーバーに既に登録されていたらそれを返す
|
//#region このサーバーに既に登録されていたらそれを返す
|
||||||
const exist = await fetchPerson(uri);
|
const exist = await fetchPerson(uri);
|
||||||
|
@ -11,7 +11,7 @@ export async function extractPollFromQuestion(source: string | IQuestion): Promi
|
|||||||
const expiresAt = question.endTime ? new Date(question.endTime) : null;
|
const expiresAt = question.endTime ? new Date(question.endTime) : null;
|
||||||
|
|
||||||
if (multiple && !question.anyOf) {
|
if (multiple && !question.anyOf) {
|
||||||
throw 'invalid question';
|
throw new Error('invalid question');
|
||||||
}
|
}
|
||||||
|
|
||||||
const choices = question[multiple ? 'anyOf' : 'oneOf']!
|
const choices = question[multiple ? 'anyOf' : 'oneOf']!
|
||||||
@ -37,14 +37,14 @@ export async function updateQuestion(value: any) {
|
|||||||
const uri = typeof value == 'string' ? value : value.id;
|
const uri = typeof value == 'string' ? value : value.id;
|
||||||
|
|
||||||
// URIがこのサーバーを指しているならスキップ
|
// URIがこのサーバーを指しているならスキップ
|
||||||
if (uri.startsWith(config.url + '/')) throw 'uri points local';
|
if (uri.startsWith(config.url + '/')) throw new Error('uri points local');
|
||||||
|
|
||||||
//#region このサーバーに既に登録されているか
|
//#region このサーバーに既に登録されているか
|
||||||
const note = await Notes.findOne({ uri });
|
const note = await Notes.findOne({ uri });
|
||||||
if (note == null) throw 'Question is not registed';
|
if (note == null) throw new Error('Question is not registed');
|
||||||
|
|
||||||
const poll = await Polls.findOne({ noteId: note.id });
|
const poll = await Polls.findOne({ noteId: note.id });
|
||||||
if (poll == null) throw 'Question is not registed';
|
if (poll == null) throw new Error('Question is not registed');
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
// resolve new Question object
|
// resolve new Question object
|
||||||
@ -52,7 +52,7 @@ export async function updateQuestion(value: any) {
|
|||||||
const question = await resolver.resolve(value) as IQuestion;
|
const question = await resolver.resolve(value) as IQuestion;
|
||||||
apLogger.debug(`fetched question: ${JSON.stringify(question, null, 2)}`);
|
apLogger.debug(`fetched question: ${JSON.stringify(question, null, 2)}`);
|
||||||
|
|
||||||
if (question.type !== 'Question') throw 'object is not a Question';
|
if (question.type !== 'Question') throw new Error('object is not a Question');
|
||||||
|
|
||||||
const apChoices = question.oneOf || question.anyOf;
|
const apChoices = question.oneOf || question.anyOf;
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ export default async (user: ILocalUser, url: string, object: any) => {
|
|||||||
userId: user.id
|
userId: user.id
|
||||||
}).then(ensure);
|
}).then(ensure);
|
||||||
|
|
||||||
const _ = new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
const req = request({
|
const req = request({
|
||||||
protocol,
|
protocol,
|
||||||
hostname: addr,
|
hostname: addr,
|
||||||
@ -88,8 +88,6 @@ export default async (user: ILocalUser, url: string, object: any) => {
|
|||||||
req.end(data);
|
req.end(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
await _;
|
|
||||||
|
|
||||||
//#region Log
|
//#region Log
|
||||||
publishApLogStream({
|
publishApLogStream({
|
||||||
direction: 'out',
|
direction: 'out',
|
||||||
|
@ -12,7 +12,7 @@ export interface IObject {
|
|||||||
attachment?: any[];
|
attachment?: any[];
|
||||||
inReplyTo?: any;
|
inReplyTo?: any;
|
||||||
replies?: ICollection;
|
replies?: ICollection;
|
||||||
content: string;
|
content?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
startTime?: Date;
|
startTime?: Date;
|
||||||
endTime?: Date;
|
endTime?: Date;
|
||||||
@ -44,16 +44,16 @@ export interface IOrderedCollection extends IObject {
|
|||||||
|
|
||||||
export interface INote extends IObject {
|
export interface INote extends IObject {
|
||||||
type: 'Note' | 'Question';
|
type: 'Note' | 'Question';
|
||||||
_misskey_content: string;
|
_misskey_content?: string;
|
||||||
_misskey_quote: string;
|
_misskey_quote?: string;
|
||||||
_misskey_question: string;
|
_misskey_question?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IQuestion extends IObject {
|
export interface IQuestion extends IObject {
|
||||||
type: 'Note' | 'Question';
|
type: 'Note' | 'Question';
|
||||||
_misskey_content: string;
|
_misskey_content?: string;
|
||||||
_misskey_quote: string;
|
_misskey_quote?: string;
|
||||||
_misskey_question: string;
|
_misskey_question?: string;
|
||||||
oneOf?: IQuestionChoice[];
|
oneOf?: IQuestionChoice[];
|
||||||
anyOf?: IQuestionChoice[];
|
anyOf?: IQuestionChoice[];
|
||||||
endTime?: Date;
|
endTime?: Date;
|
||||||
@ -129,7 +129,7 @@ export interface IRemove extends IActivity {
|
|||||||
|
|
||||||
export interface ILike extends IActivity {
|
export interface ILike extends IActivity {
|
||||||
type: 'Like';
|
type: 'Like';
|
||||||
_misskey_reaction: string;
|
_misskey_reaction?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IAnnounce extends IActivity {
|
export interface IAnnounce extends IActivity {
|
||||||
|
@ -17,7 +17,7 @@ export async function resolveUser(username: string, host: string | null, option?
|
|||||||
logger.info(`return local user: ${usernameLower}`);
|
logger.info(`return local user: ${usernameLower}`);
|
||||||
return await Users.findOne({ usernameLower, host: null }).then(u => {
|
return await Users.findOne({ usernameLower, host: null }).then(u => {
|
||||||
if (u == null) {
|
if (u == null) {
|
||||||
throw 'user not found';
|
throw new Error('user not found');
|
||||||
} else {
|
} else {
|
||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
@ -30,7 +30,7 @@ export async function resolveUser(username: string, host: string | null, option?
|
|||||||
logger.info(`return local user: ${usernameLower}`);
|
logger.info(`return local user: ${usernameLower}`);
|
||||||
return await Users.findOne({ usernameLower, host: null }).then(u => {
|
return await Users.findOne({ usernameLower, host: null }).then(u => {
|
||||||
if (u == null) {
|
if (u == null) {
|
||||||
throw 'user not found';
|
throw new Error('user not found');
|
||||||
} else {
|
} else {
|
||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
@ -78,7 +78,7 @@ export async function resolveUser(username: string, host: string | null, option?
|
|||||||
logger.info(`return resynced remote user: ${acctLower}`);
|
logger.info(`return resynced remote user: ${acctLower}`);
|
||||||
return await Users.findOne({ uri: self.href }).then(u => {
|
return await Users.findOne({ uri: self.href }).then(u => {
|
||||||
if (u == null) {
|
if (u == null) {
|
||||||
throw 'user not found';
|
throw new Error('user not found');
|
||||||
} else {
|
} else {
|
||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ export default async (token: string): Promise<[User | null | undefined, App | nu
|
|||||||
.findOne({ token });
|
.findOne({ token });
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
throw 'user not found';
|
throw new Error('user not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
return [user, null];
|
return [user, null];
|
||||||
@ -24,7 +24,7 @@ export default async (token: string): Promise<[User | null | undefined, App | nu
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (accessToken == null) {
|
if (accessToken == null) {
|
||||||
throw 'invalid signature';
|
throw new Error('invalid signature');
|
||||||
}
|
}
|
||||||
|
|
||||||
const app = await Apps
|
const app = await Apps
|
||||||
|
@ -36,7 +36,7 @@ export async function getRemoteUser(userId: User['id']) {
|
|||||||
const user = await getUser(userId);
|
const user = await getUser(userId);
|
||||||
|
|
||||||
if (!Users.isRemoteUser(user)) {
|
if (!Users.isRemoteUser(user)) {
|
||||||
throw 'user is not a remote user';
|
throw new Error('user is not a remote user');
|
||||||
}
|
}
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
@ -49,7 +49,7 @@ export async function getLocalUser(userId: User['id']) {
|
|||||||
const user = await getUser(userId);
|
const user = await getUser(userId);
|
||||||
|
|
||||||
if (!Users.isLocalUser(user)) {
|
if (!Users.isLocalUser(user)) {
|
||||||
throw 'user is not a local user';
|
throw new Error('user is not a local user');
|
||||||
}
|
}
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import $ from 'cafy';
|
import $ from 'cafy';
|
||||||
import define from '../../../define';
|
import define from '../../../define';
|
||||||
import { Emojis } from '../../../../../models';
|
import { Emojis } from '../../../../../models';
|
||||||
import { toPuny } from '../../../../../misc/convert-host';
|
import { toPunyNullable } from '../../../../../misc/convert-host';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
desc: {
|
desc: {
|
||||||
@ -23,7 +23,7 @@ export const meta = {
|
|||||||
|
|
||||||
export default define(meta, async (ps) => {
|
export default define(meta, async (ps) => {
|
||||||
const emojis = await Emojis.find({
|
const emojis = await Emojis.find({
|
||||||
host: ps.host ? toPuny(ps.host) : null
|
host: toPunyNullable(ps.host)
|
||||||
});
|
});
|
||||||
|
|
||||||
return emojis.map(e => ({
|
return emojis.map(e => ({
|
||||||
|
@ -57,13 +57,10 @@ export default define(meta, async (ps) => {
|
|||||||
let i = 0;
|
let i = 0;
|
||||||
for (const subDomain of subDomains) {
|
for (const subDomain of subDomains) {
|
||||||
const p = `blackSubDomain_${subDomain}_${i}`;
|
const p = `blackSubDomain_${subDomain}_${i}`;
|
||||||
if (i === subDomains.length - 1) {
|
// 全体で否定できないのでド・モルガンの法則で
|
||||||
// SQL is 1 based, so we need '+ 1'
|
// !(P && Q) を !P || !Q で表す
|
||||||
qb.andWhere(`log.domain[${i + 1}] != :${p}`, { [p]: subDomain });
|
// SQL is 1 based, so we need '+ 1'
|
||||||
} else {
|
qb.orWhere(`log.domain[${i + 1}] != :${p}`, { [p]: subDomain });
|
||||||
// SQL is 1 based, so we need '+ 1'
|
|
||||||
qb.andWhere(`log.domain[${i + 1}] = :${p}`, { [p]: subDomain });
|
|
||||||
}
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ export default define(meta, async (ps, user) => {
|
|||||||
const app = await Apps.save({
|
const app = await Apps.save({
|
||||||
id: genId(),
|
id: genId(),
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
userId: user && user.id,
|
userId: user ? user.id : null,
|
||||||
name: ps.name,
|
name: ps.name,
|
||||||
description: ps.description,
|
description: ps.description,
|
||||||
permission: ps.permission,
|
permission: ps.permission,
|
||||||
|
@ -71,6 +71,4 @@ export default define(meta, async (ps, user) => {
|
|||||||
await AuthSessions.update(session.id, {
|
await AuthSessions.update(session.id, {
|
||||||
userId: user.id
|
userId: user.id
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
|
||||||
});
|
});
|
||||||
|
@ -35,6 +35,7 @@ export default define(meta, async (ps, user) => {
|
|||||||
const day = 1000 * 60 * 60 * 24 * 3; // 3日前まで
|
const day = 1000 * 60 * 60 * 24 * 3; // 3日前まで
|
||||||
|
|
||||||
const query = Notes.createQueryBuilder('note')
|
const query = Notes.createQueryBuilder('note')
|
||||||
|
.where('note.userHost IS NULL')
|
||||||
.andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) })
|
.andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) })
|
||||||
.andWhere(`note.visibility = 'public'`)
|
.andWhere(`note.visibility = 'public'`)
|
||||||
.leftJoinAndSelect('note.user', 'user');
|
.leftJoinAndSelect('note.user', 'user');
|
||||||
|
@ -124,7 +124,7 @@ export default define(meta, async (ps, user) => {
|
|||||||
|
|
||||||
// Increment votes count
|
// Increment votes count
|
||||||
const index = ps.choice + 1; // In SQL, array index is 1 based
|
const index = ps.choice + 1; // In SQL, array index is 1 based
|
||||||
await Polls.query(`UPDATE poll SET votes[${index}] = votes[${index}] + 1 WHERE noteId = '${poll.noteId}'`);
|
await Polls.query(`UPDATE poll SET votes[${index}] = votes[${index}] + 1 WHERE "noteId" = '${poll.noteId}'`);
|
||||||
|
|
||||||
publishNoteStream(note.id, 'pollVoted', {
|
publishNoteStream(note.id, 'pollVoted', {
|
||||||
choice: ps.choice,
|
choice: ps.choice,
|
||||||
|
@ -4,7 +4,7 @@ import define from '../../define';
|
|||||||
import { ApiError } from '../../error';
|
import { ApiError } from '../../error';
|
||||||
import { Users, Followings } from '../../../../models';
|
import { Users, Followings } from '../../../../models';
|
||||||
import { makePaginationQuery } from '../../common/make-pagination-query';
|
import { makePaginationQuery } from '../../common/make-pagination-query';
|
||||||
import { toPuny } from '../../../../misc/convert-host';
|
import { toPunyNullable } from '../../../../misc/convert-host';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
desc: {
|
desc: {
|
||||||
@ -66,7 +66,7 @@ export const meta = {
|
|||||||
export default define(meta, async (ps, me) => {
|
export default define(meta, async (ps, me) => {
|
||||||
const user = await Users.findOne(ps.userId != null
|
const user = await Users.findOne(ps.userId != null
|
||||||
? { id: ps.userId }
|
? { id: ps.userId }
|
||||||
: { usernameLower: ps.username!.toLowerCase(), host: toPuny(ps.host!) });
|
: { usernameLower: ps.username!.toLowerCase(), host: toPunyNullable(ps.host) });
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
throw new ApiError(meta.errors.noSuchUser);
|
throw new ApiError(meta.errors.noSuchUser);
|
||||||
|
@ -4,7 +4,7 @@ import define from '../../define';
|
|||||||
import { ApiError } from '../../error';
|
import { ApiError } from '../../error';
|
||||||
import { Users, Followings } from '../../../../models';
|
import { Users, Followings } from '../../../../models';
|
||||||
import { makePaginationQuery } from '../../common/make-pagination-query';
|
import { makePaginationQuery } from '../../common/make-pagination-query';
|
||||||
import { toPuny } from '../../../../misc/convert-host';
|
import { toPunyNullable } from '../../../../misc/convert-host';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
desc: {
|
desc: {
|
||||||
@ -66,7 +66,7 @@ export const meta = {
|
|||||||
export default define(meta, async (ps, me) => {
|
export default define(meta, async (ps, me) => {
|
||||||
const user = await Users.findOne(ps.userId != null
|
const user = await Users.findOne(ps.userId != null
|
||||||
? { id: ps.userId }
|
? { id: ps.userId }
|
||||||
: { usernameLower: ps.username!.toLowerCase(), host: toPuny(ps.host!) });
|
: { usernameLower: ps.username!.toLowerCase(), host: toPunyNullable(ps.host) });
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
throw new ApiError(meta.errors.noSuchUser);
|
throw new ApiError(meta.errors.noSuchUser);
|
||||||
|
@ -8,12 +8,6 @@ import Logger from '../../services/logger';
|
|||||||
const logger = new Logger('limiter');
|
const logger = new Logger('limiter');
|
||||||
|
|
||||||
export default (endpoint: IEndpoint, user: User) => new Promise((ok, reject) => {
|
export default (endpoint: IEndpoint, user: User) => new Promise((ok, reject) => {
|
||||||
// Redisがインストールされてない場合は常に許可
|
|
||||||
if (limiterDB == null) {
|
|
||||||
ok();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const limitation = endpoint.meta.limit!;
|
const limitation = endpoint.meta.limit!;
|
||||||
|
|
||||||
const key = limitation.hasOwnProperty('key')
|
const key = limitation.hasOwnProperty('key')
|
||||||
|
@ -10,7 +10,7 @@ import { genId } from '../../../misc/gen-id';
|
|||||||
import { usersChart } from '../../../services/chart';
|
import { usersChart } from '../../../services/chart';
|
||||||
import { User } from '../../../models/entities/user';
|
import { User } from '../../../models/entities/user';
|
||||||
import { UserKeypair } from '../../../models/entities/user-keypair';
|
import { UserKeypair } from '../../../models/entities/user-keypair';
|
||||||
import { toPuny } from '../../../misc/convert-host';
|
import { toPunyNullable } from '../../../misc/convert-host';
|
||||||
import { UserProfile } from '../../../models/entities/user-profile';
|
import { UserProfile } from '../../../models/entities/user-profile';
|
||||||
import { getConnection } from 'typeorm';
|
import { getConnection } from 'typeorm';
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ export default async (ctx: Koa.BaseContext) => {
|
|||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
username: username,
|
username: username,
|
||||||
usernameLower: username.toLowerCase(),
|
usernameLower: username.toLowerCase(),
|
||||||
host: host ? toPuny(host) : null,
|
host: toPunyNullable(host),
|
||||||
token: secret,
|
token: secret,
|
||||||
isAdmin: config.autoAdmin && usersCount === 0,
|
isAdmin: config.autoAdmin && usersCount === 0,
|
||||||
}));
|
}));
|
||||||
|
@ -83,8 +83,6 @@ async function getOAuth2() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
router.get('/connect/discord', async ctx => {
|
router.get('/connect/discord', async ctx => {
|
||||||
if (redis == null) return;
|
|
||||||
|
|
||||||
if (!compareOrigin(ctx)) {
|
if (!compareOrigin(ctx)) {
|
||||||
ctx.throw(400, 'invalid origin');
|
ctx.throw(400, 'invalid origin');
|
||||||
return;
|
return;
|
||||||
@ -110,8 +108,6 @@ router.get('/connect/discord', async ctx => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.get('/signin/discord', async ctx => {
|
router.get('/signin/discord', async ctx => {
|
||||||
if (redis == null) return;
|
|
||||||
|
|
||||||
const sessid = uuid();
|
const sessid = uuid();
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
@ -138,8 +134,6 @@ router.get('/signin/discord', async ctx => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.get('/dc/cb', async ctx => {
|
router.get('/dc/cb', async ctx => {
|
||||||
if (redis == null) return;
|
|
||||||
|
|
||||||
const userToken = getUserToken(ctx);
|
const userToken = getUserToken(ctx);
|
||||||
|
|
||||||
const oauth2 = await getOAuth2();
|
const oauth2 = await getOAuth2();
|
||||||
@ -160,7 +154,7 @@ router.get('/dc/cb', async ctx => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { redirect_uri, state } = await new Promise<any>((res, rej) => {
|
const { redirect_uri, state } = await new Promise<any>((res, rej) => {
|
||||||
redis!.get(sessid, async (_, state) => {
|
redis.get(sessid, async (_, state) => {
|
||||||
res(JSON.parse(state));
|
res(JSON.parse(state));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -241,7 +235,7 @@ router.get('/dc/cb', async ctx => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { redirect_uri, state } = await new Promise<any>((res, rej) => {
|
const { redirect_uri, state } = await new Promise<any>((res, rej) => {
|
||||||
redis!.get(userToken, async (_, state) => {
|
redis.get(userToken, async (_, state) => {
|
||||||
res(JSON.parse(state));
|
res(JSON.parse(state));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -80,8 +80,6 @@ async function getOath2() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
router.get('/connect/github', async ctx => {
|
router.get('/connect/github', async ctx => {
|
||||||
if (redis == null) return;
|
|
||||||
|
|
||||||
if (!compareOrigin(ctx)) {
|
if (!compareOrigin(ctx)) {
|
||||||
ctx.throw(400, 'invalid origin');
|
ctx.throw(400, 'invalid origin');
|
||||||
return;
|
return;
|
||||||
@ -106,8 +104,6 @@ router.get('/connect/github', async ctx => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.get('/signin/github', async ctx => {
|
router.get('/signin/github', async ctx => {
|
||||||
if (redis == null) return;
|
|
||||||
|
|
||||||
const sessid = uuid();
|
const sessid = uuid();
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
@ -133,8 +129,6 @@ router.get('/signin/github', async ctx => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.get('/gh/cb', async ctx => {
|
router.get('/gh/cb', async ctx => {
|
||||||
if (redis == null) return;
|
|
||||||
|
|
||||||
const userToken = getUserToken(ctx);
|
const userToken = getUserToken(ctx);
|
||||||
|
|
||||||
const oauth2 = await getOath2();
|
const oauth2 = await getOath2();
|
||||||
@ -155,7 +149,7 @@ router.get('/gh/cb', async ctx => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { redirect_uri, state } = await new Promise<any>((res, rej) => {
|
const { redirect_uri, state } = await new Promise<any>((res, rej) => {
|
||||||
redis!.get(sessid, async (_, state) => {
|
redis.get(sessid, async (_, state) => {
|
||||||
res(JSON.parse(state));
|
res(JSON.parse(state));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -222,7 +216,7 @@ router.get('/gh/cb', async ctx => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { redirect_uri, state } = await new Promise<any>((res, rej) => {
|
const { redirect_uri, state } = await new Promise<any>((res, rej) => {
|
||||||
redis!.get(userToken, async (_, state) => {
|
redis.get(userToken, async (_, state) => {
|
||||||
res(JSON.parse(state));
|
res(JSON.parse(state));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -79,8 +79,6 @@ async function getTwAuth() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
router.get('/connect/twitter', async ctx => {
|
router.get('/connect/twitter', async ctx => {
|
||||||
if (redis == null) return;
|
|
||||||
|
|
||||||
if (!compareOrigin(ctx)) {
|
if (!compareOrigin(ctx)) {
|
||||||
ctx.throw(400, 'invalid origin');
|
ctx.throw(400, 'invalid origin');
|
||||||
return;
|
return;
|
||||||
@ -99,8 +97,6 @@ router.get('/connect/twitter', async ctx => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.get('/signin/twitter', async ctx => {
|
router.get('/signin/twitter', async ctx => {
|
||||||
if (redis == null) return;
|
|
||||||
|
|
||||||
const twAuth = await getTwAuth();
|
const twAuth = await getTwAuth();
|
||||||
const twCtx = await twAuth!.begin();
|
const twCtx = await twAuth!.begin();
|
||||||
|
|
||||||
@ -122,8 +118,6 @@ router.get('/signin/twitter', async ctx => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.get('/tw/cb', async ctx => {
|
router.get('/tw/cb', async ctx => {
|
||||||
if (redis == null) return;
|
|
||||||
|
|
||||||
const userToken = getUserToken(ctx);
|
const userToken = getUserToken(ctx);
|
||||||
|
|
||||||
const twAuth = await getTwAuth();
|
const twAuth = await getTwAuth();
|
||||||
@ -137,7 +131,7 @@ router.get('/tw/cb', async ctx => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const get = new Promise<any>((res, rej) => {
|
const get = new Promise<any>((res, rej) => {
|
||||||
redis!.get(sessid, async (_, twCtx) => {
|
redis.get(sessid, async (_, twCtx) => {
|
||||||
res(twCtx);
|
res(twCtx);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -170,7 +164,7 @@ router.get('/tw/cb', async ctx => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const get = new Promise<any>((res, rej) => {
|
const get = new Promise<any>((res, rej) => {
|
||||||
redis!.get(userToken, async (_, twCtx) => {
|
redis.get(userToken, async (_, twCtx) => {
|
||||||
res(twCtx);
|
res(twCtx);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -43,7 +43,7 @@ export default class extends Channel {
|
|||||||
if (this.user == null) return;
|
if (this.user == null) return;
|
||||||
|
|
||||||
const game = await ReversiGames.findOne(this.gameId!);
|
const game = await ReversiGames.findOne(this.gameId!);
|
||||||
if (game == null) throw 'game not found';
|
if (game == null) throw new Error('game not found');
|
||||||
|
|
||||||
if (game.isStarted) return;
|
if (game.isStarted) return;
|
||||||
if ((game.user1Id !== this.user.id) && (game.user2Id !== this.user.id)) return;
|
if ((game.user1Id !== this.user.id) && (game.user2Id !== this.user.id)) return;
|
||||||
@ -67,7 +67,7 @@ export default class extends Channel {
|
|||||||
if (this.user == null) return;
|
if (this.user == null) return;
|
||||||
|
|
||||||
const game = await ReversiGames.findOne(this.gameId!);
|
const game = await ReversiGames.findOne(this.gameId!);
|
||||||
if (game == null) throw 'game not found';
|
if (game == null) throw new Error('game not found');
|
||||||
|
|
||||||
if (game.isStarted) return;
|
if (game.isStarted) return;
|
||||||
if ((game.user1Id !== this.user.id) && (game.user2Id !== this.user.id)) return;
|
if ((game.user1Id !== this.user.id) && (game.user2Id !== this.user.id)) return;
|
||||||
@ -91,7 +91,7 @@ export default class extends Channel {
|
|||||||
if (this.user == null) return;
|
if (this.user == null) return;
|
||||||
|
|
||||||
const game = await ReversiGames.findOne(this.gameId!);
|
const game = await ReversiGames.findOne(this.gameId!);
|
||||||
if (game == null) throw 'game not found';
|
if (game == null) throw new Error('game not found');
|
||||||
|
|
||||||
if (game.isStarted) return;
|
if (game.isStarted) return;
|
||||||
if ((game.user1Id !== this.user.id) && (game.user2Id !== this.user.id)) return;
|
if ((game.user1Id !== this.user.id) && (game.user2Id !== this.user.id)) return;
|
||||||
@ -135,7 +135,7 @@ export default class extends Channel {
|
|||||||
if (this.user == null) return;
|
if (this.user == null) return;
|
||||||
|
|
||||||
const game = await ReversiGames.findOne(this.gameId!);
|
const game = await ReversiGames.findOne(this.gameId!);
|
||||||
if (game == null) throw 'game not found';
|
if (game == null) throw new Error('game not found');
|
||||||
|
|
||||||
if (game.isStarted) return;
|
if (game.isStarted) return;
|
||||||
|
|
||||||
@ -237,7 +237,7 @@ export default class extends Channel {
|
|||||||
if (this.user == null) return;
|
if (this.user == null) return;
|
||||||
|
|
||||||
const game = await ReversiGames.findOne(this.gameId!);
|
const game = await ReversiGames.findOne(this.gameId!);
|
||||||
if (game == null) throw 'game not found';
|
if (game == null) throw new Error('game not found');
|
||||||
|
|
||||||
if (!game.isStarted) return;
|
if (!game.isStarted) return;
|
||||||
if (game.isEnded) return;
|
if (game.isEnded) return;
|
||||||
@ -304,7 +304,7 @@ export default class extends Channel {
|
|||||||
@autobind
|
@autobind
|
||||||
private async check(crc32: string) {
|
private async check(crc32: string) {
|
||||||
const game = await ReversiGames.findOne(this.gameId!);
|
const game = await ReversiGames.findOne(this.gameId!);
|
||||||
if (game == null) throw 'game not found';
|
if (game == null) throw new Error('game not found');
|
||||||
|
|
||||||
if (!game.isStarted) return;
|
if (!game.isStarted) return;
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import * as http from 'http';
|
import * as http from 'http';
|
||||||
import * as websocket from 'websocket';
|
import * as websocket from 'websocket';
|
||||||
import * as redis from 'redis';
|
import * as redis from 'redis';
|
||||||
import Xev from 'xev';
|
|
||||||
|
|
||||||
import MainStreamConnection from './stream';
|
import MainStreamConnection from './stream';
|
||||||
import { ParsedUrlQuery } from 'querystring';
|
import { ParsedUrlQuery } from 'querystring';
|
||||||
@ -23,28 +22,24 @@ module.exports = (server: http.Server) => {
|
|||||||
|
|
||||||
let ev: EventEmitter;
|
let ev: EventEmitter;
|
||||||
|
|
||||||
if (config.redis) {
|
// Connect to Redis
|
||||||
// Connect to Redis
|
const subscriber = redis.createClient(
|
||||||
const subscriber = redis.createClient(
|
config.redis.port, config.redis.host);
|
||||||
config.redis.port, config.redis.host);
|
|
||||||
|
|
||||||
subscriber.subscribe('misskey');
|
subscriber.subscribe('misskey');
|
||||||
|
|
||||||
ev = new EventEmitter();
|
ev = new EventEmitter();
|
||||||
|
|
||||||
subscriber.on('message', async (_, data) => {
|
subscriber.on('message', async (_, data) => {
|
||||||
const obj = JSON.parse(data);
|
const obj = JSON.parse(data);
|
||||||
|
|
||||||
ev.emit(obj.channel, obj.message);
|
ev.emit(obj.channel, obj.message);
|
||||||
});
|
});
|
||||||
|
|
||||||
connection.once('close', () => {
|
connection.once('close', () => {
|
||||||
subscriber.unsubscribe();
|
subscriber.unsubscribe();
|
||||||
subscriber.quit();
|
subscriber.quit();
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
ev = new Xev();
|
|
||||||
}
|
|
||||||
|
|
||||||
const main = new MainStreamConnection(connection, ev, user, app);
|
const main = new MainStreamConnection(connection, ev, user, app);
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ export default async function(user: User) {
|
|||||||
date: note.createdAt,
|
date: note.createdAt,
|
||||||
description: note.cw || undefined,
|
description: note.cw || undefined,
|
||||||
content: note.text || undefined,
|
content: note.text || undefined,
|
||||||
image: file ? DriveFiles.getPublicUrl(file) : undefined
|
image: file ? DriveFiles.getPublicUrl(file) || undefined : undefined
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,13 +201,20 @@ async function upload(key: string, stream: fs.ReadStream | Buffer, type: string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function deleteOldFile(user: IRemoteUser) {
|
async function deleteOldFile(user: IRemoteUser) {
|
||||||
const oldFile = await DriveFiles.createQueryBuilder()
|
const q = DriveFiles.createQueryBuilder('file')
|
||||||
.select('file')
|
.where('file.userId = :userId', { userId: user.id });
|
||||||
.where('file.id != :avatarId', { avatarId: user.avatarId })
|
|
||||||
.andWhere('file.id != :bannerId', { bannerId: user.bannerId })
|
if (user.avatarId) {
|
||||||
.andWhere('file.userId = :userId', { userId: user.id })
|
q.andWhere('file.id != :avatarId', { avatarId: user.avatarId });
|
||||||
.orderBy('file.id', 'DESC')
|
}
|
||||||
.getOne();
|
|
||||||
|
if (user.bannerId) {
|
||||||
|
q.andWhere('file.id != :bannerId', { bannerId: user.bannerId })
|
||||||
|
}
|
||||||
|
|
||||||
|
q.orderBy('file.id', 'DESC');
|
||||||
|
|
||||||
|
const oldFile = await q.getOne();
|
||||||
|
|
||||||
if (oldFile) {
|
if (oldFile) {
|
||||||
delFile(oldFile, true);
|
delFile(oldFile, true);
|
||||||
@ -297,7 +304,7 @@ export default async function(
|
|||||||
// If usage limit exceeded
|
// If usage limit exceeded
|
||||||
if (usage + size > driveCapacity) {
|
if (usage + size > driveCapacity) {
|
||||||
if (Users.isLocalUser(user)) {
|
if (Users.isLocalUser(user)) {
|
||||||
throw 'no-free-space';
|
throw new Error('no-free-space');
|
||||||
} else {
|
} else {
|
||||||
// (アバターまたはバナーを含まず)最も古いファイルを削除する
|
// (アバターまたはバナーを含まず)最も古いファイルを削除する
|
||||||
deleteOldFile(user as IRemoteUser);
|
deleteOldFile(user as IRemoteUser);
|
||||||
@ -316,7 +323,7 @@ export default async function(
|
|||||||
userId: user.id
|
userId: user.id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (driveFolder == null) throw 'folder-not-found';
|
if (driveFolder == null) throw new Error('folder-not-found');
|
||||||
|
|
||||||
return driveFolder;
|
return driveFolder;
|
||||||
};
|
};
|
||||||
|
@ -78,7 +78,7 @@ export async function removePinned(user: User, noteId: Note['id']) {
|
|||||||
|
|
||||||
export async function deliverPinnedChange(userId: User['id'], noteId: Note['id'], isAddition: boolean) {
|
export async function deliverPinnedChange(userId: User['id'], noteId: Note['id'], isAddition: boolean) {
|
||||||
const user = await Users.findOne(userId);
|
const user = await Users.findOne(userId);
|
||||||
if (user == null) throw 'user not found';
|
if (user == null) throw new Error('user not found');
|
||||||
|
|
||||||
if (!Users.isLocalUser(user)) return;
|
if (!Users.isLocalUser(user)) return;
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import { renderPerson } from '../../remote/activitypub/renderer/person';
|
|||||||
|
|
||||||
export async function publishToFollowers(userId: User['id']) {
|
export async function publishToFollowers(userId: User['id']) {
|
||||||
const user = await Users.findOne(userId);
|
const user = await Users.findOne(userId);
|
||||||
if (user == null) throw 'user not found';
|
if (user == null) throw new Error('user not found');
|
||||||
|
|
||||||
const followers = await Followings.find({
|
const followers = await Followings.find({
|
||||||
followeeId: user.id
|
followeeId: user.id
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user