Merge branch 'develop'
This commit is contained in:
commit
796252357e
|
@ -84,40 +84,54 @@ redis:
|
||||||
drive:
|
drive:
|
||||||
storage: 'fs'
|
storage: 'fs'
|
||||||
|
|
||||||
# OR
|
# OR
|
||||||
|
|
||||||
# storage: 'minio'
|
#drive:
|
||||||
# bucket:
|
# storage: 'minio'
|
||||||
# prefix:
|
# bucket:
|
||||||
# config:
|
# prefix:
|
||||||
# endPoint:
|
# config:
|
||||||
# port:
|
# endPoint:
|
||||||
# useSSL:
|
# port:
|
||||||
# accessKey:
|
# useSSL:
|
||||||
# secretKey:
|
# accessKey:
|
||||||
|
# secretKey:
|
||||||
|
|
||||||
# S3 example
|
# S3/GCS example
|
||||||
# storage: 'minio'
|
#
|
||||||
# bucket: bucket-name
|
# * Replace <endpoint> to
|
||||||
# prefix: files
|
# S3: see https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region
|
||||||
# config:
|
# GCS: use 'storage.googleapis.com'
|
||||||
# endPoint: s3-us-west-2.amazonaws.com
|
#
|
||||||
# region: us-west-2
|
# * Replace <region> to
|
||||||
# useSSL: true
|
# S3: see https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region
|
||||||
# accessKey: XXX
|
# GCS: not needed (just delete the region line)
|
||||||
# secretKey: YYY
|
#
|
||||||
|
#drive:
|
||||||
|
# storage: 'minio'
|
||||||
|
# bucket: bucket-name
|
||||||
|
# prefix: files
|
||||||
|
# baseUrl: https://bucket-name.<endpoint>
|
||||||
|
# config:
|
||||||
|
# endPoint: <endpoint>
|
||||||
|
# region: <region>
|
||||||
|
# useSSL: true
|
||||||
|
# accessKey: XXX
|
||||||
|
# secretKey: YYY
|
||||||
|
|
||||||
# S3 example (with CDN, custom domain)
|
# S3/GCS example (with CDN, custom domain)
|
||||||
# storage: 'minio'
|
#
|
||||||
# bucket: drive.example.com
|
#drive:
|
||||||
# prefix: files
|
# storage: 'minio'
|
||||||
# baseUrl: https://drive.example.com
|
# bucket: drive.example.com
|
||||||
# config:
|
# prefix: files
|
||||||
# endPoint: s3-us-west-2.amazonaws.com
|
# baseUrl: https://drive.example.com
|
||||||
# region: us-west-2
|
# config:
|
||||||
# useSSL: true
|
# endPoint: <endpoint>
|
||||||
# accessKey: XXX
|
# region: <region>
|
||||||
# secretKey: YYY
|
# useSSL: true
|
||||||
|
# accessKey: XXX
|
||||||
|
# secretKey: YYY
|
||||||
|
|
||||||
# ┌───────────────┐
|
# ┌───────────────┐
|
||||||
#───┘ ID generation └───────────────────────────────────────────
|
#───┘ ID generation └───────────────────────────────────────────
|
||||||
|
|
20
CHANGELOG.md
20
CHANGELOG.md
|
@ -73,6 +73,26 @@ mongodb:
|
||||||
8. master ブランチに戻す
|
8. master ブランチに戻す
|
||||||
9. enjoy
|
9. enjoy
|
||||||
|
|
||||||
|
11.12.0 (2019/05/10)
|
||||||
|
--------------------
|
||||||
|
### 注意
|
||||||
|
このアップデートを適用した後、プロセスを起動(もしくは再起動)する前に[マイグレーション](#migration)の手順を実行してください
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* インスタンス運営者がおすすめアカウントを設定できるように
|
||||||
|
* MisskeyPagesでNAME環境変数がNULLにならないように
|
||||||
|
* MisskeyPagesにNULL環境変数を追加
|
||||||
|
* MisskeyPagesで変数を並べ替えられるように
|
||||||
|
* MisskeyPagesのテキストのリスト内で変数埋め込みできるように
|
||||||
|
* 自分の指定した投稿のRenoteを全て解除するAPIを追加
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Noteをpull取得した時にhost名がvalidateされていない問題を修正
|
||||||
|
* みつけるで人気のタグが表示されない問題を修正
|
||||||
|
|
||||||
|
### その他
|
||||||
|
* アカウントのisVerifiedフラグを廃止
|
||||||
|
|
||||||
11.11.2 (2019/05/07)
|
11.11.2 (2019/05/07)
|
||||||
--------------------
|
--------------------
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|
12
README.md
12
README.md
|
@ -105,6 +105,7 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||||
<table><tr>
|
<table><tr>
|
||||||
<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/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.png?token-time=2145916800&token-hash=oH_i7gJjNT7Ot6j9JiVwy7ZJIBqACVnzLqlz4YrDAZA%3D" alt="weepjp" 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="weepjp" width="100"></td>
|
||||||
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/19045173/cb91c0f345c24d4ebfd05f19906d5e26/1.png?token-time=2145916800&token-hash=o_zKBytJs_AxHwSYw_5R8eD0eSJe3RoTR3kR3Q0syN0%3D" alt="kiritan" 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/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/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/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://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>
|
||||||
|
@ -112,6 +113,7 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||||
</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">weepjp</a></td>
|
<td><a href="https://www.patreon.com/weepjp">weepjp</a></td>
|
||||||
|
<td><a href="https://www.patreon.com/user?u=19045173">kiritan</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=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>
|
||||||
|
@ -127,7 +129,6 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||||
<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://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/19356899/496b4681d33b4520bd7688e0fd19c04d/2.jpeg?token-time=2145916800&token-hash=_sTj3dUBOhn9qwiJ7F19Qd-yWWfUqJC_0jG1h0agEqQ%3D" alt="sheeta.s" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/19356899/496b4681d33b4520bd7688e0fd19c04d/2.jpeg?token-time=2145916800&token-hash=_sTj3dUBOhn9qwiJ7F19Qd-yWWfUqJC_0jG1h0agEqQ%3D" alt="sheeta.s" 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>
|
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><a href="https://www.patreon.com/Yuzulia">YuzuRyo61</a></td>
|
<td><a href="https://www.patreon.com/Yuzulia">YuzuRyo61</a></td>
|
||||||
<td><a href="https://www.patreon.com/gutfuckllc">gutfuckllc</a></td>
|
<td><a href="https://www.patreon.com/gutfuckllc">gutfuckllc</a></td>
|
||||||
|
@ -138,9 +139,9 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||||
<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=19356899">sheeta.s</a></td>
|
<td><a href="https://www.patreon.com/user?u=19356899">sheeta.s</a></td>
|
||||||
<td><a href="https://www.patreon.com/user?u=13737140">Satsuki Yanagi</a></td>
|
|
||||||
</tr></table>
|
</tr></table>
|
||||||
<table><tr>
|
<table><tr>
|
||||||
|
<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>
|
<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>
|
||||||
<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/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/83884b38afc74d4cbe83c30a13b10edd/1.png?token-time=2145916800&token-hash=R5Tog8RWg0rguRoCIoir3lThokrdPvs8Utfikhc0nhY%3D" alt="Atsuko Tominaga" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/16900731/83884b38afc74d4cbe83c30a13b10edd/1.png?token-time=2145916800&token-hash=R5Tog8RWg0rguRoCIoir3lThokrdPvs8Utfikhc0nhY%3D" alt="Atsuko Tominaga" width="100"></td>
|
||||||
|
@ -149,8 +150,8 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/2384390/5681180e1efb46a8b28e0e8d4c8b9037/1.jpg?token-time=2145916800&token-hash=SJcMy-Q1BcS940-LFUVOMfR7-5SgrzsEQGhYb3yowFk%3D" alt="CG" width="100"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/2384390/5681180e1efb46a8b28e0e8d4c8b9037/1.jpg?token-time=2145916800&token-hash=SJcMy-Q1BcS940-LFUVOMfR7-5SgrzsEQGhYb3yowFk%3D" alt="CG" 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/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.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/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.jpeg?token-time=2145916800&token-hash=d8jBQLMOHD87KtXs5C9fk1o58DMF73pQ-dYH3uZJPBE%3D" alt="Gargron" width="100"></td>
|
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
|
<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>
|
||||||
<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>
|
||||||
|
@ -159,17 +160,18 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||||
<td><a href="https://www.patreon.com/Corset">CG</a></td>
|
<td><a href="https://www.patreon.com/Corset">CG</a></td>
|
||||||
<td><a href="https://www.patreon.com/hekovic">Hekovic</a></td>
|
<td><a href="https://www.patreon.com/hekovic">Hekovic</a></td>
|
||||||
<td><a href="https://www.patreon.com/dansup">dansup</a></td>
|
<td><a href="https://www.patreon.com/dansup">dansup</a></td>
|
||||||
<td><a href="https://www.patreon.com/mastodon">Gargron</a></td>
|
|
||||||
</tr></table>
|
</tr></table>
|
||||||
<table><tr>
|
<table><tr>
|
||||||
|
<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.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/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.jpeg?token-time=2145916800&token-hash=vGe7wXGqmA8Q7m-kDNb6fyGdwk-Dxk4F-ut8ZZu51RM%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/mastodon">Gargron</a></td>
|
||||||
<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>
|
||||||
|
|
||||||
**Last updated:** Fri, 03 May 2019 05:33:07 UTC
|
**Last updated:** Tue, 07 May 2019 11:55:07 UTC
|
||||||
<!-- PATREON_END -->
|
<!-- PATREON_END -->
|
||||||
|
|
||||||
:four_leaf_clover: Copyright
|
:four_leaf_clover: Copyright
|
||||||
|
|
|
@ -263,7 +263,6 @@ common:
|
||||||
update-available-title: "更新があります"
|
update-available-title: "更新があります"
|
||||||
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
|
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
|
||||||
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
|
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
|
||||||
verified-user: "公式アカウント"
|
|
||||||
hide-password: "パスワードを隠す"
|
hide-password: "パスワードを隠す"
|
||||||
show-password: "パスワードを表示する"
|
show-password: "パスワードを表示する"
|
||||||
|
|
||||||
|
@ -339,7 +338,7 @@ auth/views/index.vue:
|
||||||
sign-in: "サインインしてください"
|
sign-in: "サインインしてください"
|
||||||
|
|
||||||
common/views/pages/explore.vue:
|
common/views/pages/explore.vue:
|
||||||
verified-users: "公式アカウント"
|
pinned-users: "ピン留めされたユーザー"
|
||||||
popular-users: "人気のユーザー"
|
popular-users: "人気のユーザー"
|
||||||
recently-updated-users: "最近投稿したユーザー"
|
recently-updated-users: "最近投稿したユーザー"
|
||||||
recently-registered-users: "新規ユーザー"
|
recently-registered-users: "新規ユーザー"
|
||||||
|
@ -1264,7 +1263,7 @@ admin/views/instance.vue:
|
||||||
invite: "招待"
|
invite: "招待"
|
||||||
save: "保存"
|
save: "保存"
|
||||||
saved: "保存しました"
|
saved: "保存しました"
|
||||||
user-recommendation-config: "おすすめユーザー"
|
pinned-users: "ピン留めユーザー"
|
||||||
email-config: "メールサーバーの設定"
|
email-config: "メールサーバーの設定"
|
||||||
email-config-info: "メールアドレス確認やパスワードリセットの際に使われます。"
|
email-config-info: "メールアドレス確認やパスワードリセットの際に使われます。"
|
||||||
enable-email: "メール配信を有効にする"
|
enable-email: "メール配信を有効にする"
|
||||||
|
@ -1351,12 +1350,6 @@ admin/views/users.vue:
|
||||||
silence-confirm: "サイレンスしますか?"
|
silence-confirm: "サイレンスしますか?"
|
||||||
unmake-silence: "サイレンスの解除"
|
unmake-silence: "サイレンスの解除"
|
||||||
unsilence-confirm: "サイレンスを解除しますか?"
|
unsilence-confirm: "サイレンスを解除しますか?"
|
||||||
verify: "公式アカウントにする"
|
|
||||||
verify-confirm: "公式アカウントにしますか?"
|
|
||||||
verified: "公式アカウントにしました"
|
|
||||||
unverify: "公式アカウントを解除する"
|
|
||||||
unverify-confirm: "公式アカウントを解除しますか?"
|
|
||||||
unverified: "公式アカウントを解除しました"
|
|
||||||
update-remote-user: "リモートユーザー情報の更新"
|
update-remote-user: "リモートユーザー情報の更新"
|
||||||
remote-user-updated: "リモートユーザー情報を更新しました"
|
remote-user-updated: "リモートユーザー情報を更新しました"
|
||||||
users:
|
users:
|
||||||
|
@ -1373,7 +1366,6 @@ admin/views/users.vue:
|
||||||
admin: "管理者"
|
admin: "管理者"
|
||||||
moderator: "モデレーター"
|
moderator: "モデレーター"
|
||||||
adminOrModerator: "管理者+モデレーター"
|
adminOrModerator: "管理者+モデレーター"
|
||||||
verified: "公式アカウント"
|
|
||||||
silenced: "サイレンス済み"
|
silenced: "サイレンス済み"
|
||||||
suspended: "凍結済み"
|
suspended: "凍結済み"
|
||||||
origin:
|
origin:
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||||
|
|
||||||
|
export class PinnedUsers1557476068003 implements MigrationInterface {
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<any> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" ADD "pinnedUsers" character varying(256) array NOT NULL DEFAULT '{}'::varchar[]`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<any> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "pinnedUsers"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <i@syuilo.com>",
|
"author": "syuilo <i@syuilo.com>",
|
||||||
"version": "11.11.2",
|
"version": "11.12.0",
|
||||||
"codename": "daybreak",
|
"codename": "daybreak",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -82,6 +82,14 @@
|
||||||
</section>
|
</section>
|
||||||
</ui-card>
|
</ui-card>
|
||||||
|
|
||||||
|
<ui-card>
|
||||||
|
<template #title>{{ $t('pinned-users') }}</template>
|
||||||
|
<section>
|
||||||
|
<ui-textarea v-model="pinnedUsers"></ui-textarea>
|
||||||
|
<ui-button @click="updateMeta">{{ $t('save') }}</ui-button>
|
||||||
|
</section>
|
||||||
|
</ui-card>
|
||||||
|
|
||||||
<ui-card>
|
<ui-card>
|
||||||
<template #title>{{ $t('invite') }}</template>
|
<template #title>{{ $t('invite') }}</template>
|
||||||
<section>
|
<section>
|
||||||
|
@ -190,6 +198,7 @@ export default Vue.extend({
|
||||||
enableServiceWorker: false,
|
enableServiceWorker: false,
|
||||||
swPublicKey: null,
|
swPublicKey: null,
|
||||||
swPrivateKey: null,
|
swPrivateKey: null,
|
||||||
|
pinnedUsers: [],
|
||||||
faHeadset, faShieldAlt, faGhost, faUserPlus, farEnvelope, faBolt
|
faHeadset, faShieldAlt, faGhost, faUserPlus, farEnvelope, faBolt
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -239,6 +248,7 @@ export default Vue.extend({
|
||||||
this.enableServiceWorker = meta.enableServiceWorker;
|
this.enableServiceWorker = meta.enableServiceWorker;
|
||||||
this.swPublicKey = meta.swPublickey;
|
this.swPublicKey = meta.swPublickey;
|
||||||
this.swPrivateKey = meta.swPrivateKey;
|
this.swPrivateKey = meta.swPrivateKey;
|
||||||
|
this.pinnedUsers = meta.pinnedUsers.join('\n');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -297,7 +307,8 @@ export default Vue.extend({
|
||||||
smtpPass: this.smtpAuth ? this.smtpPass : '',
|
smtpPass: this.smtpAuth ? this.smtpPass : '',
|
||||||
enableServiceWorker: this.enableServiceWorker,
|
enableServiceWorker: this.enableServiceWorker,
|
||||||
swPublicKey: this.swPublicKey,
|
swPublicKey: this.swPublicKey,
|
||||||
swPrivateKey: this.swPrivateKey
|
swPrivateKey: this.swPrivateKey,
|
||||||
|
pinnedUsers: this.pinnedUsers.split('\n')
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.$root.dialog({
|
this.$root.dialog({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
<span class="username">@{{ user | acct }}</span>
|
<span class="username">@{{ user | acct }}</span>
|
||||||
<span class="is-admin" v-if="user.isAdmin">admin</span>
|
<span class="is-admin" v-if="user.isAdmin">admin</span>
|
||||||
<span class="is-moderator" v-if="user.isModerator">moderator</span>
|
<span class="is-moderator" v-if="user.isModerator">moderator</span>
|
||||||
<span class="is-verified" v-if="user.isVerified" :title="$t('@.verified-user')"><fa icon="star"/></span>
|
|
||||||
<span class="is-silenced" v-if="user.isSilenced" :title="$t('@.silenced-user')"><fa :icon="faMicrophoneSlash"/></span>
|
<span class="is-silenced" v-if="user.isSilenced" :title="$t('@.silenced-user')"><fa :icon="faMicrophoneSlash"/></span>
|
||||||
<span class="is-suspended" v-if="user.isSuspended" :title="$t('@.suspended-user')"><fa :icon="faSnowflake"/></span>
|
<span class="is-suspended" v-if="user.isSuspended" :title="$t('@.suspended-user')"><fa :icon="faSnowflake"/></span>
|
||||||
</header>
|
</header>
|
||||||
|
@ -77,7 +76,6 @@ export default Vue.extend({
|
||||||
background var(--noteHeaderAdminBg)
|
background var(--noteHeaderAdminBg)
|
||||||
color var(--noteHeaderAdminFg)
|
color var(--noteHeaderAdminFg)
|
||||||
|
|
||||||
> .is-verified
|
|
||||||
> .is-silenced
|
> .is-silenced
|
||||||
> .is-suspended
|
> .is-suspended
|
||||||
margin 0 0 0 .5em
|
margin 0 0 0 .5em
|
||||||
|
|
|
@ -12,10 +12,6 @@
|
||||||
<x-user :user='user'/>
|
<x-user :user='user'/>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<ui-button @click="resetPassword"><fa :icon="faKey"/> {{ $t('reset-password') }}</ui-button>
|
<ui-button @click="resetPassword"><fa :icon="faKey"/> {{ $t('reset-password') }}</ui-button>
|
||||||
<ui-horizon-group>
|
|
||||||
<ui-button @click="verifyUser" :disabled="verifying"><fa :icon="faCertificate"/> {{ $t('verify') }}</ui-button>
|
|
||||||
<ui-button @click="unverifyUser" :disabled="unverifying">{{ $t('unverify') }}</ui-button>
|
|
||||||
</ui-horizon-group>
|
|
||||||
<ui-horizon-group>
|
<ui-horizon-group>
|
||||||
<ui-button @click="silenceUser"><fa :icon="faMicrophoneSlash"/> {{ $t('make-silence') }}</ui-button>
|
<ui-button @click="silenceUser"><fa :icon="faMicrophoneSlash"/> {{ $t('make-silence') }}</ui-button>
|
||||||
<ui-button @click="unsilenceUser">{{ $t('unmake-silence') }}</ui-button>
|
<ui-button @click="unsilenceUser">{{ $t('unmake-silence') }}</ui-button>
|
||||||
|
@ -47,7 +43,6 @@
|
||||||
<option value="all">{{ $t('users.state.all') }}</option>
|
<option value="all">{{ $t('users.state.all') }}</option>
|
||||||
<option value="admin">{{ $t('users.state.admin') }}</option>
|
<option value="admin">{{ $t('users.state.admin') }}</option>
|
||||||
<option value="moderator">{{ $t('users.state.moderator') }}</option>
|
<option value="moderator">{{ $t('users.state.moderator') }}</option>
|
||||||
<option value="verified">{{ $t('users.state.verified') }}</option>
|
|
||||||
<option value="silenced">{{ $t('users.state.silenced') }}</option>
|
<option value="silenced">{{ $t('users.state.silenced') }}</option>
|
||||||
<option value="suspended">{{ $t('users.state.suspended') }}</option>
|
<option value="suspended">{{ $t('users.state.suspended') }}</option>
|
||||||
</ui-select>
|
</ui-select>
|
||||||
|
@ -71,7 +66,7 @@
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import i18n from '../../i18n';
|
import i18n from '../../i18n';
|
||||||
import parseAcct from "../../../../misc/acct/parse";
|
import parseAcct from "../../../../misc/acct/parse";
|
||||||
import { faCertificate, faUsers, faTerminal, faSearch, faKey, faSync, faMicrophoneSlash } from '@fortawesome/free-solid-svg-icons';
|
import { faUsers, faTerminal, faSearch, faKey, faSync, faMicrophoneSlash } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faSnowflake } from '@fortawesome/free-regular-svg-icons';
|
import { faSnowflake } from '@fortawesome/free-regular-svg-icons';
|
||||||
import XUser from './users.user.vue';
|
import XUser from './users.user.vue';
|
||||||
|
|
||||||
|
@ -84,8 +79,6 @@ export default Vue.extend({
|
||||||
return {
|
return {
|
||||||
user: null,
|
user: null,
|
||||||
target: null,
|
target: null,
|
||||||
verifying: false,
|
|
||||||
unverifying: false,
|
|
||||||
suspending: false,
|
suspending: false,
|
||||||
unsuspending: false,
|
unsuspending: false,
|
||||||
sort: '+createdAt',
|
sort: '+createdAt',
|
||||||
|
@ -95,7 +88,7 @@ export default Vue.extend({
|
||||||
offset: 0,
|
offset: 0,
|
||||||
users: [],
|
users: [],
|
||||||
existMore: false,
|
existMore: false,
|
||||||
faTerminal, faCertificate, faUsers, faSnowflake, faSearch, faKey, faSync, faMicrophoneSlash
|
faTerminal, faUsers, faSnowflake, faSearch, faKey, faSync, faMicrophoneSlash
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -181,56 +174,6 @@ export default Vue.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
async verifyUser() {
|
|
||||||
if (!await this.getConfirmed(this.$t('verify-confirm'))) return;
|
|
||||||
|
|
||||||
this.verifying = true;
|
|
||||||
|
|
||||||
const process = async () => {
|
|
||||||
await this.$root.api('admin/verify-user', { userId: this.user.id });
|
|
||||||
this.$root.dialog({
|
|
||||||
type: 'success',
|
|
||||||
text: this.$t('verified')
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
await process().catch(e => {
|
|
||||||
this.$root.dialog({
|
|
||||||
type: 'error',
|
|
||||||
text: e.toString()
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.verifying = false;
|
|
||||||
|
|
||||||
this.refreshUser();
|
|
||||||
},
|
|
||||||
|
|
||||||
async unverifyUser() {
|
|
||||||
if (!await this.getConfirmed(this.$t('unverify-confirm'))) return;
|
|
||||||
|
|
||||||
this.unverifying = true;
|
|
||||||
|
|
||||||
const process = async () => {
|
|
||||||
await this.$root.api('admin/unverify-user', { userId: this.user.id });
|
|
||||||
this.$root.dialog({
|
|
||||||
type: 'success',
|
|
||||||
text: this.$t('unverified')
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
await process().catch(e => {
|
|
||||||
this.$root.dialog({
|
|
||||||
type: 'error',
|
|
||||||
text: e.toString()
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.unverifying = false;
|
|
||||||
|
|
||||||
this.refreshUser();
|
|
||||||
},
|
|
||||||
|
|
||||||
async silenceUser() {
|
async silenceUser() {
|
||||||
if (!await this.getConfirmed(this.$t('silence-confirm'))) return;
|
if (!await this.getConfirmed(this.$t('silence-confirm'))) return;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
<span class="is-bot" v-if="note.user.isBot">bot</span>
|
<span class="is-bot" v-if="note.user.isBot">bot</span>
|
||||||
<span class="is-cat" v-if="note.user.isCat">cat</span>
|
<span class="is-cat" v-if="note.user.isCat">cat</span>
|
||||||
<span class="username"><mk-acct :user="note.user"/></span>
|
<span class="username"><mk-acct :user="note.user"/></span>
|
||||||
<span class="is-verified" v-if="note.user.isVerified" :title="$t('@.verified-user')"><fa icon="star"/></span>
|
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<span class="app" v-if="note.app && !mini && $store.state.settings.showVia">via <b>{{ note.app.name }}</b></span>
|
<span class="app" v-if="note.app && !mini && $store.state.settings.showVia">via <b>{{ note.app.name }}</b></span>
|
||||||
<span class="mobile" v-if="note.viaMobile"><fa icon="mobile-alt"/></span>
|
<span class="mobile" v-if="note.viaMobile"><fa icon="mobile-alt"/></span>
|
||||||
|
@ -95,10 +94,6 @@ export default Vue.extend({
|
||||||
color var(--noteHeaderAcct)
|
color var(--noteHeaderAcct)
|
||||||
flex-shrink 2147483647
|
flex-shrink 2147483647
|
||||||
|
|
||||||
> .is-verified
|
|
||||||
margin 0 .5em 0 0
|
|
||||||
color #4dabf7
|
|
||||||
|
|
||||||
> .info
|
> .info
|
||||||
margin-left auto
|
margin-left auto
|
||||||
font-size 0.9em
|
font-size 0.9em
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<x-container :removable="removable" @remove="() => $emit('remove')" :error="error" :warn="warn">
|
<x-container :removable="removable" @remove="() => $emit('remove')" :error="error" :warn="warn" :draggable="draggable">
|
||||||
<template #header><fa v-if="icon" :icon="icon"/> <template v-if="title">{{ title }} <span class="turmquns" v-if="typeText">({{ typeText }})</span></template><template v-else-if="typeText">{{ typeText }}</template></template>
|
<template #header><fa v-if="icon" :icon="icon"/> <template v-if="title">{{ title }} <span class="turmquns" v-if="typeText">({{ typeText }})</span></template><template v-else-if="typeText">{{ typeText }}</template></template>
|
||||||
<template #func>
|
<template #func>
|
||||||
<button @click="changeType()">
|
<button @click="changeType()">
|
||||||
|
@ -93,6 +93,10 @@ export default Vue.extend({
|
||||||
fnSlots: {
|
fnSlots: {
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
|
draggable: {
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
|
|
@ -53,9 +53,8 @@
|
||||||
<ui-container :body-togglable="true">
|
<ui-container :body-togglable="true">
|
||||||
<template #header><fa :icon="faMagic"/> {{ $t('variables') }}</template>
|
<template #header><fa :icon="faMagic"/> {{ $t('variables') }}</template>
|
||||||
<div class="qmuvgica">
|
<div class="qmuvgica">
|
||||||
<div class="variables" v-show="variables.length > 0">
|
<x-draggable tag="div" class="variables" v-show="variables.length > 0" :list="variables" handle=".drag-handle" :group="{ name: 'variables' }" animation="150" swap-threshold="0.5">
|
||||||
<template v-for="variable in variables">
|
<x-variable v-for="variable in variables"
|
||||||
<x-variable
|
|
||||||
:value="variable"
|
:value="variable"
|
||||||
:removable="true"
|
:removable="true"
|
||||||
@input="v => updateVariable(v)"
|
@input="v => updateVariable(v)"
|
||||||
|
@ -64,9 +63,9 @@
|
||||||
:ai-script="aiScript"
|
:ai-script="aiScript"
|
||||||
:name="variable.name"
|
:name="variable.name"
|
||||||
:title="variable.name"
|
:title="variable.name"
|
||||||
|
:draggable="true"
|
||||||
/>
|
/>
|
||||||
</template>
|
</x-draggable>
|
||||||
</div>
|
|
||||||
|
|
||||||
<ui-button @click="addVariable()" class="add" v-if="!readonly"><fa :icon="faPlus"/></ui-button>
|
<ui-button @click="addVariable()" class="add" v-if="!readonly"><fa :icon="faPlus"/></ui-button>
|
||||||
|
|
||||||
|
@ -92,6 +91,7 @@
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
|
import * as XDraggable from 'vuedraggable';
|
||||||
import { faICursor, faPlus, faMagic, faCog, faCode, faExternalLinkSquareAlt } from '@fortawesome/free-solid-svg-icons';
|
import { faICursor, faPlus, faMagic, faCog, faCode, faExternalLinkSquareAlt } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faSave, faStickyNote, faTrashAlt } from '@fortawesome/free-regular-svg-icons';
|
import { faSave, faStickyNote, faTrashAlt } from '@fortawesome/free-regular-svg-icons';
|
||||||
import i18n from '../../../../i18n';
|
import i18n from '../../../../i18n';
|
||||||
|
@ -107,7 +107,7 @@ export default Vue.extend({
|
||||||
i18n: i18n('pages'),
|
i18n: i18n('pages'),
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
XVariable, XBlocks
|
XDraggable, XVariable, XBlocks
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
<template #header><fa :icon="faHashtag" fixed-width/>{{ $t('popular-tags') }}</template>
|
<template #header><fa :icon="faHashtag" fixed-width/>{{ $t('popular-tags') }}</template>
|
||||||
|
|
||||||
<div class="vxjfqztj">
|
<div class="vxjfqztj">
|
||||||
<router-link v-for="tag in tagsLocal" :to="`/explore/tags/${tag.name}`" :key="'local:' + tag.name" class="local">{{ tag.name }}</router-link>
|
<router-link v-for="tag in tagsLocal" :to="`/explore/tags/${tag.tag}`" :key="'local:' + tag.tag" class="local">{{ tag.tag }}</router-link>
|
||||||
<router-link v-for="tag in tagsRemote" :to="`/explore/tags/${tag.name}`" :key="'remote:' + tag.name">{{ tag.name }}</router-link>
|
<router-link v-for="tag in tagsRemote" :to="`/explore/tags/${tag.tag}`" :key="'remote:' + tag.tag">{{ tag.tag }}</router-link>
|
||||||
</div>
|
</div>
|
||||||
</ui-container>
|
</ui-container>
|
||||||
|
|
||||||
|
@ -26,8 +26,8 @@
|
||||||
</mk-user-list>
|
</mk-user-list>
|
||||||
|
|
||||||
<template v-if="tag == null">
|
<template v-if="tag == null">
|
||||||
<mk-user-list :make-promise="verifiedUsers">
|
<mk-user-list :make-promise="pinnedUsers">
|
||||||
<fa :icon="faBookmark" fixed-width/>{{ $t('verified-users') }}
|
<fa :icon="faBookmark" fixed-width/>{{ $t('pinned-users') }}
|
||||||
</mk-user-list>
|
</mk-user-list>
|
||||||
<mk-user-list :make-promise="popularUsers">
|
<mk-user-list :make-promise="popularUsers">
|
||||||
<fa :icon="faChartLine" fixed-width/>{{ $t('popular-users') }}
|
<fa :icon="faChartLine" fixed-width/>{{ $t('popular-users') }}
|
||||||
|
@ -60,12 +60,7 @@ export default Vue.extend({
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
verifiedUsers: () => this.$root.api('users', {
|
pinnedUsers: () => this.$root.api('pinned-users'),
|
||||||
state: 'verified',
|
|
||||||
origin: 'local',
|
|
||||||
sort: '+follower',
|
|
||||||
limit: 10
|
|
||||||
}),
|
|
||||||
popularUsers: () => this.$root.api('users', {
|
popularUsers: () => this.$root.api('users', {
|
||||||
state: 'alive',
|
state: 'alive',
|
||||||
origin: 'local',
|
origin: 'local',
|
||||||
|
|
|
@ -31,7 +31,7 @@ export class ASEvaluator {
|
||||||
VERSION: opts.version,
|
VERSION: opts.version,
|
||||||
URL: opts.page ? `${opts.url}/@${opts.page.user.username}/pages/${opts.page.name}` : '',
|
URL: opts.page ? `${opts.url}/@${opts.page.user.username}/pages/${opts.page.name}` : '',
|
||||||
LOGIN: opts.visitor != null,
|
LOGIN: opts.visitor != null,
|
||||||
NAME: opts.visitor ? opts.visitor.name : '',
|
NAME: opts.visitor ? opts.visitor.name || opts.visitor.username : '',
|
||||||
USERNAME: opts.visitor ? opts.visitor.username : '',
|
USERNAME: opts.visitor ? opts.visitor.username : '',
|
||||||
USERID: opts.visitor ? opts.visitor.id : '',
|
USERID: opts.visitor ? opts.visitor.id : '',
|
||||||
NOTES_COUNT: opts.visitor ? opts.visitor.notesCount : 0,
|
NOTES_COUNT: opts.visitor ? opts.visitor.notesCount : 0,
|
||||||
|
@ -42,7 +42,8 @@ export class ASEvaluator {
|
||||||
MY_FOLLOWERS_COUNT: opts.user ? opts.user.followersCount : 0,
|
MY_FOLLOWERS_COUNT: opts.user ? opts.user.followersCount : 0,
|
||||||
MY_FOLLOWING_COUNT: opts.user ? opts.user.followingCount : 0,
|
MY_FOLLOWING_COUNT: opts.user ? opts.user.followingCount : 0,
|
||||||
SEED: opts.randomSeed ? opts.randomSeed : '',
|
SEED: opts.randomSeed ? opts.randomSeed : '',
|
||||||
YMD: `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`
|
YMD: `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`,
|
||||||
|
NULL: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +105,7 @@ export class ASEvaluator {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block.type === 'textList') {
|
if (block.type === 'textList') {
|
||||||
return block.value.trim().split('\n');
|
return this.interpolate(block.value || '', scope).trim().split('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block.type === 'ref') {
|
if (block.type === 'ref') {
|
||||||
|
|
|
@ -127,6 +127,7 @@ export const envVarsDef: Record<string, Type> = {
|
||||||
MY_FOLLOWING_COUNT: 'number',
|
MY_FOLLOWING_COUNT: 'number',
|
||||||
SEED: null,
|
SEED: null,
|
||||||
YMD: 'string',
|
YMD: 'string',
|
||||||
|
NULL: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function isLiteralBlock(v: Block) {
|
export function isLiteralBlock(v: Block) {
|
||||||
|
|
|
@ -69,6 +69,11 @@ export class Meta {
|
||||||
})
|
})
|
||||||
public langs: string[];
|
public langs: string[];
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 256, array: true, default: '{}'
|
||||||
|
})
|
||||||
|
public pinnedUsers: string[];
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256, array: true, default: '{}'
|
length: 256, array: true, default: '{}'
|
||||||
})
|
})
|
||||||
|
|
|
@ -157,11 +157,6 @@ export class User {
|
||||||
})
|
})
|
||||||
public isModerator: boolean;
|
public isModerator: boolean;
|
||||||
|
|
||||||
@Column('boolean', {
|
|
||||||
default: false,
|
|
||||||
})
|
|
||||||
public isVerified: boolean;
|
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 128, array: true, default: '{}'
|
length: 128, array: true, default: '{}'
|
||||||
})
|
})
|
||||||
|
|
|
@ -87,7 +87,6 @@ export class UserRepository extends Repository<User> {
|
||||||
isAdmin: user.isAdmin || falsy,
|
isAdmin: user.isAdmin || falsy,
|
||||||
isBot: user.isBot || falsy,
|
isBot: user.isBot || falsy,
|
||||||
isCat: user.isCat || falsy,
|
isCat: user.isCat || falsy,
|
||||||
isVerified: user.isVerified || falsy,
|
|
||||||
|
|
||||||
// カスタム絵文字添付
|
// カスタム絵文字添付
|
||||||
emojis: user.emojis.length > 0 ? Emojis.find({
|
emojis: user.emojis.length > 0 ? Emojis.find({
|
||||||
|
@ -369,10 +368,6 @@ export const packedUserSchema = {
|
||||||
nullable: bool.false, optional: bool.true,
|
nullable: bool.false, optional: bool.true,
|
||||||
description: 'Whether this account is a moderator.'
|
description: 'Whether this account is a moderator.'
|
||||||
},
|
},
|
||||||
isVerified: {
|
|
||||||
type: types.boolean,
|
|
||||||
nullable: bool.false, optional: bool.true,
|
|
||||||
},
|
|
||||||
isLocked: {
|
isLocked: {
|
||||||
type: types.boolean,
|
type: types.boolean,
|
||||||
nullable: bool.false, optional: bool.true,
|
nullable: bool.false, optional: bool.true,
|
||||||
|
|
|
@ -25,6 +25,28 @@ import { ensure } from '../../../prelude/ensure';
|
||||||
|
|
||||||
const logger = apLogger;
|
const logger = apLogger;
|
||||||
|
|
||||||
|
export function validateNote(object: any, uri: string) {
|
||||||
|
const expectHost = extractDbHost(uri);
|
||||||
|
|
||||||
|
if (object == null) {
|
||||||
|
return new Error('invalid Note: object is null');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!['Note', 'Question', 'Article'].includes(object.type)) {
|
||||||
|
return new Error(`invalid Note: invalied object type ${object.type}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (object.id && extractDbHost(object.id) !== expectHost) {
|
||||||
|
return new Error(`invalid Note: id has different host. expected: ${expectHost}, actual: ${extractDbHost(object.id)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (object.attributedTo && extractDbHost(object.attributedTo) !== expectHost) {
|
||||||
|
return new Error(`invalid Note: attributedTo has different host. expected: ${expectHost}, actual: ${extractDbHost(object.attributedTo)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Noteをフェッチします。
|
* Noteをフェッチします。
|
||||||
*
|
*
|
||||||
|
@ -59,8 +81,10 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
|
||||||
|
|
||||||
const object: any = await resolver.resolve(value);
|
const object: any = await resolver.resolve(value);
|
||||||
|
|
||||||
if (!object || !['Note', 'Question', 'Article'].includes(object.type)) {
|
const entryUri = value.id || value;
|
||||||
logger.error(`invalid note: ${value}`, {
|
const err = validateNote(object, entryUri);
|
||||||
|
if (err) {
|
||||||
|
logger.error(`${err.message}`, {
|
||||||
resolver: {
|
resolver: {
|
||||||
history: resolver.getHistory()
|
history: resolver.getHistory()
|
||||||
},
|
},
|
||||||
|
|
|
@ -36,7 +36,6 @@ export const meta = {
|
||||||
'admin',
|
'admin',
|
||||||
'moderator',
|
'moderator',
|
||||||
'adminOrModerator',
|
'adminOrModerator',
|
||||||
'verified',
|
|
||||||
'silenced',
|
'silenced',
|
||||||
'suspended',
|
'suspended',
|
||||||
]),
|
]),
|
||||||
|
@ -61,7 +60,6 @@ export default define(meta, async (ps, me) => {
|
||||||
case 'admin': query.where('user.isAdmin = TRUE'); break;
|
case 'admin': query.where('user.isAdmin = TRUE'); break;
|
||||||
case 'moderator': query.where('user.isModerator = TRUE'); break;
|
case 'moderator': query.where('user.isModerator = TRUE'); break;
|
||||||
case 'adminOrModerator': query.where('user.isAdmin = TRUE OR isModerator = TRUE'); break;
|
case 'adminOrModerator': query.where('user.isAdmin = TRUE OR isModerator = TRUE'); break;
|
||||||
case 'verified': query.where('user.isVerified = TRUE'); break;
|
|
||||||
case 'alive': query.where('user.updatedAt > :date', { date: new Date(Date.now() - 1000 * 60 * 60 * 24 * 5) }); break;
|
case 'alive': query.where('user.updatedAt > :date', { date: new Date(Date.now() - 1000 * 60 * 60 * 24 * 5) }); break;
|
||||||
case 'silenced': query.where('user.isSilenced = TRUE'); break;
|
case 'silenced': query.where('user.isSilenced = TRUE'); break;
|
||||||
case 'suspended': query.where('user.isSuspended = TRUE'); break;
|
case 'suspended': query.where('user.isSuspended = TRUE'); break;
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
import $ from 'cafy';
|
|
||||||
import { ID } from '../../../../misc/cafy-id';
|
|
||||||
import define from '../../define';
|
|
||||||
import { Users } from '../../../../models';
|
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
desc: {
|
|
||||||
'ja-JP': '指定したユーザーの公式アカウントを解除します。',
|
|
||||||
'en-US': 'Mark a user as unverified.'
|
|
||||||
},
|
|
||||||
|
|
||||||
tags: ['admin'],
|
|
||||||
|
|
||||||
requireCredential: true,
|
|
||||||
requireModerator: true,
|
|
||||||
|
|
||||||
params: {
|
|
||||||
userId: {
|
|
||||||
validator: $.type(ID),
|
|
||||||
desc: {
|
|
||||||
'ja-JP': '対象のユーザーID',
|
|
||||||
'en-US': 'The user ID which you want to unverify'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default define(meta, async (ps) => {
|
|
||||||
const user = await Users.findOne(ps.userId as string);
|
|
||||||
|
|
||||||
if (user == null) {
|
|
||||||
throw new Error('user not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
await Users.update(user.id, {
|
|
||||||
isVerified: false
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -56,6 +56,13 @@ export const meta = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
pinnedUsers: {
|
||||||
|
validator: $.optional.nullable.arr($.str),
|
||||||
|
desc: {
|
||||||
|
'ja-JP': 'ピン留めユーザー'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
hiddenTags: {
|
hiddenTags: {
|
||||||
validator: $.optional.nullable.arr($.str),
|
validator: $.optional.nullable.arr($.str),
|
||||||
desc: {
|
desc: {
|
||||||
|
@ -353,6 +360,10 @@ export default define(meta, async (ps) => {
|
||||||
set.useStarForReactionFallback = ps.useStarForReactionFallback;
|
set.useStarForReactionFallback = ps.useStarForReactionFallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(ps.pinnedUsers)) {
|
||||||
|
set.pinnedUsers = ps.pinnedUsers;
|
||||||
|
}
|
||||||
|
|
||||||
if (Array.isArray(ps.hiddenTags)) {
|
if (Array.isArray(ps.hiddenTags)) {
|
||||||
set.hiddenTags = ps.hiddenTags;
|
set.hiddenTags = ps.hiddenTags;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
import $ from 'cafy';
|
|
||||||
import { ID } from '../../../../misc/cafy-id';
|
|
||||||
import define from '../../define';
|
|
||||||
import { Users } from '../../../../models';
|
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
desc: {
|
|
||||||
'ja-JP': '指定したユーザーを公式アカウントにします。',
|
|
||||||
'en-US': 'Mark a user as verified.'
|
|
||||||
},
|
|
||||||
|
|
||||||
tags: ['admin'],
|
|
||||||
|
|
||||||
requireCredential: true,
|
|
||||||
requireModerator: true,
|
|
||||||
|
|
||||||
params: {
|
|
||||||
userId: {
|
|
||||||
validator: $.type(ID),
|
|
||||||
desc: {
|
|
||||||
'ja-JP': '対象のユーザーID',
|
|
||||||
'en-US': 'The user ID which you want to verify'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default define(meta, async (ps) => {
|
|
||||||
const user = await Users.findOne(ps.userId as string);
|
|
||||||
|
|
||||||
if (user == null) {
|
|
||||||
throw new Error('user not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
await Users.update(user.id, {
|
|
||||||
isVerified: true
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -160,6 +160,7 @@ export default define(meta, async (ps, me) => {
|
||||||
|
|
||||||
if (me && (me.isAdmin || me.isModerator)) {
|
if (me && (me.isAdmin || me.isModerator)) {
|
||||||
response.useStarForReactionFallback = instance.useStarForReactionFallback;
|
response.useStarForReactionFallback = instance.useStarForReactionFallback;
|
||||||
|
response.pinnedUsers = instance.pinnedUsers;
|
||||||
response.hiddenTags = instance.hiddenTags;
|
response.hiddenTags = instance.hiddenTags;
|
||||||
response.recaptchaSecretKey = instance.recaptchaSecretKey;
|
response.recaptchaSecretKey = instance.recaptchaSecretKey;
|
||||||
response.proxyAccount = instance.proxyAccount;
|
response.proxyAccount = instance.proxyAccount;
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
import $ from 'cafy';
|
||||||
|
import { ID } from '../../../../misc/cafy-id';
|
||||||
|
import deleteNote from '../../../../services/note/delete';
|
||||||
|
import define from '../../define';
|
||||||
|
import * as ms from 'ms';
|
||||||
|
import { getNote } from '../../common/getters';
|
||||||
|
import { ApiError } from '../../error';
|
||||||
|
import { Notes } from '../../../../models';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
desc: {
|
||||||
|
'ja-JP': '指定した投稿のRenoteを解除します。',
|
||||||
|
},
|
||||||
|
|
||||||
|
tags: ['notes'],
|
||||||
|
|
||||||
|
requireCredential: true,
|
||||||
|
|
||||||
|
kind: 'write:notes',
|
||||||
|
|
||||||
|
limit: {
|
||||||
|
duration: ms('1hour'),
|
||||||
|
max: 300,
|
||||||
|
minInterval: ms('1sec')
|
||||||
|
},
|
||||||
|
|
||||||
|
params: {
|
||||||
|
noteId: {
|
||||||
|
validator: $.type(ID),
|
||||||
|
desc: {
|
||||||
|
'ja-JP': '対象の投稿のID',
|
||||||
|
'en-US': 'Target note ID.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
errors: {
|
||||||
|
noSuchNote: {
|
||||||
|
message: 'No such note.',
|
||||||
|
code: 'NO_SUCH_NOTE',
|
||||||
|
id: 'efd4a259-2442-496b-8dd7-b255aa1a160f'
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default define(meta, async (ps, user) => {
|
||||||
|
const note = await getNote(ps.noteId).catch(e => {
|
||||||
|
if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
|
||||||
|
throw e;
|
||||||
|
});
|
||||||
|
|
||||||
|
const renotes = await Notes.find({
|
||||||
|
userId: user.id,
|
||||||
|
renoteId: note.id
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const note of renotes) {
|
||||||
|
deleteNote(user, note);
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,33 @@
|
||||||
|
import define from '../define';
|
||||||
|
import { Users } from '../../../models';
|
||||||
|
import { types, bool } from '../../../misc/schema';
|
||||||
|
import { fetchMeta } from '../../../misc/fetch-meta';
|
||||||
|
import parseAcct from '../../../misc/acct/parse';
|
||||||
|
import { User } from '../../../models/entities/user';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
tags: ['users'],
|
||||||
|
|
||||||
|
requireCredential: false,
|
||||||
|
|
||||||
|
params: {
|
||||||
|
},
|
||||||
|
|
||||||
|
res: {
|
||||||
|
type: types.array,
|
||||||
|
optional: bool.false, nullable: bool.false,
|
||||||
|
items: {
|
||||||
|
type: types.object,
|
||||||
|
optional: bool.false, nullable: bool.false,
|
||||||
|
ref: 'User',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default define(meta, async (ps, me) => {
|
||||||
|
const meta = await fetchMeta();
|
||||||
|
|
||||||
|
const users = await Promise.all(meta.pinnedUsers.map(acct => Users.findOne(parseAcct(acct))));
|
||||||
|
|
||||||
|
return await Users.packMany(users.filter(x => x !== undefined) as User[], me, { detail: true });
|
||||||
|
});
|
|
@ -37,7 +37,6 @@ export const meta = {
|
||||||
'admin',
|
'admin',
|
||||||
'moderator',
|
'moderator',
|
||||||
'adminOrModerator',
|
'adminOrModerator',
|
||||||
'verified',
|
|
||||||
'alive'
|
'alive'
|
||||||
]),
|
]),
|
||||||
default: 'all'
|
default: 'all'
|
||||||
|
@ -71,7 +70,6 @@ export default define(meta, async (ps, me) => {
|
||||||
case 'admin': query.where('user.isAdmin = TRUE'); break;
|
case 'admin': query.where('user.isAdmin = TRUE'); break;
|
||||||
case 'moderator': query.where('user.isModerator = TRUE'); break;
|
case 'moderator': query.where('user.isModerator = TRUE'); break;
|
||||||
case 'adminOrModerator': query.where('user.isAdmin = TRUE OR isModerator = TRUE'); break;
|
case 'adminOrModerator': query.where('user.isAdmin = TRUE OR isModerator = TRUE'); break;
|
||||||
case 'verified': query.where('user.isVerified = TRUE'); break;
|
|
||||||
case 'alive': query.where('user.updatedAt > :date', { date: new Date(Date.now() - 1000 * 60 * 60 * 24 * 5) }); break;
|
case 'alive': query.where('user.updatedAt > :date', { date: new Date(Date.now() - 1000 * 60 * 60 * 24 * 5) }); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue