Compare commits
52 Commits
Author | SHA1 | Date | |
---|---|---|---|
532ef744f4 | |||
27a961814b | |||
5a5b65e9bf | |||
96673ad610 | |||
a9025aea0d | |||
f38ab0b973 | |||
150dac00cf | |||
bcb1a9c5d3 | |||
2e55aea584 | |||
4f5a3f0df5 | |||
e265b538cc | |||
b186504718 | |||
fc27890f13 | |||
a583939767 | |||
52e3bcfd29 | |||
85d29a3f9d | |||
18944d389d | |||
e90ac5d6a4 | |||
cb9a6ae774 | |||
3ef09aa6b2 | |||
4db22e45a2 | |||
f966d0b32c | |||
ba3879a95a | |||
c6cef0162d | |||
6d09aa86e9 | |||
b711f0f9c6 | |||
8fefb3a4c9 | |||
400cdf0f26 | |||
bce8c5a315 | |||
f44dc2dd05 | |||
df950d2fc5 | |||
5e1f804dd1 | |||
15de89f2f9 | |||
df647a415c | |||
fc66231f8e | |||
71df3e1566 | |||
168c22fc98 | |||
792ec23d7a | |||
ff625253ce | |||
8c872c6b22 | |||
541f5bc0a6 | |||
77ff7b9df0 | |||
203cc5075e | |||
7abfcd06da | |||
724f81c7f3 | |||
4d2e98af7b | |||
08221fdda7 | |||
c0f72970b9 | |||
18bc4a49e8 | |||
f90b6dbed4 | |||
d2d991ff34 | |||
190a5e175b |
@ -5,12 +5,6 @@ executors:
|
||||
working_directory: /tmp/workspace
|
||||
docker:
|
||||
- image: misskey/ci:latest
|
||||
- image: circleci/mongo:latest
|
||||
with-redis:
|
||||
working_directory: /tmp/workspace
|
||||
docker:
|
||||
- image: misskey/ci:latest
|
||||
- image: circleci/mongo:latest
|
||||
- image: circleci/redis:latest
|
||||
docker:
|
||||
working_directory: /tmp/workspace
|
||||
|
41
CHANGELOG.md
41
CHANGELOG.md
@ -5,6 +5,47 @@ If you encounter any problems with updating, please try the following:
|
||||
1. `npm run clean` or `npm run cleanall`
|
||||
2. Retry update (Don't forget `npm i`)
|
||||
|
||||
11.1.4 (2019/04/17)
|
||||
-------------------
|
||||
### Fixes
|
||||
* タイムライン取得時に削除されたファイルを添付している投稿が含まれているとサーバーでエラーになる問題を修正
|
||||
* 管理画面のインスタンスメニューで変更前の設定が読み込まれないことがある問題を修正
|
||||
* 猫ではないのに猫のままで表示される問題を修正
|
||||
* admin/driveのアイコンがずれてる問題を修正
|
||||
* チャートで大きな数値を扱えない問題を修正
|
||||
* UIの修正
|
||||
|
||||
11.1.3 (2019/04/16)
|
||||
-------------------
|
||||
### Fixes
|
||||
* アプリからAPIにリクエストするときにランダムなユーザーがリクエストしたことになる問題を修正
|
||||
|
||||
11.1.2 (2019/04/15)
|
||||
-------------------
|
||||
### Fixes
|
||||
* 画像描画の依存関係を変更
|
||||
* リモートユーザーのファイルを削除するときに古い方からではなく新しい方から削除されるのを修正
|
||||
* リアクションしてないのにリアクションしたことになる問題を修正
|
||||
* APIドキュメントの修正
|
||||
|
||||
11.1.1 (2019/04/15)
|
||||
-------------------
|
||||
### Fixes
|
||||
* Metaタグの application-name を Misskey で固定するように修正
|
||||
* トークメッセージが既読にならない問題を修正
|
||||
* デフォルトでHTLを表示するように
|
||||
|
||||
11.1.0 (2019/04/15)
|
||||
-------------------
|
||||
### Improvements
|
||||
* アイコン未設定時にランダムな画像を表示するように
|
||||
* 管理者やモデレーターはレートリミット無効に
|
||||
|
||||
### Fixes
|
||||
* メンションの「あなた」インジケーターが表示されない問題を修正
|
||||
* ブロックAPIでエラーが発生する問題を修正
|
||||
* プッシュ通知の購読に失敗する問題を修正
|
||||
|
||||
11.0.3 (2019/04/15)
|
||||
-------------------
|
||||
### Fixes
|
||||
|
@ -140,7 +140,7 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||
</tr></table>
|
||||
<table><tr>
|
||||
<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.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/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/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.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.jpe?token-time=2145916800&token-hash=qA8j97lIZNc-74AuZ0p4F3ms6sKPeKjtNt2vEuwpsyo%3D" alt="Hekovic" width="100"></td>
|
||||
@ -163,7 +163,7 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
||||
</tr><tr>
|
||||
</tr></table>
|
||||
|
||||
**Last updated:** Mon, 15 Apr 2019 01:59:07 UTC
|
||||
**Last updated:** Mon, 15 Apr 2019 12:07:08 UTC
|
||||
<!-- PATREON_END -->
|
||||
|
||||
:four_leaf_clover: Copyright
|
||||
|
@ -9,9 +9,17 @@ This guide describes how to install and setup Misskey with Docker.
|
||||
|
||||
*1.* Download Misskey
|
||||
----------------------------------------------------------------
|
||||
1. `git clone -b master git://github.com/syuilo/misskey.git` Clone Misskey repository's master branch.
|
||||
2. `cd misskey` Move to misskey directory.
|
||||
3. `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) tag.
|
||||
1. Clone Misskey repository's master branch.
|
||||
|
||||
`git clone -b master git://github.com/syuilo/misskey.git`
|
||||
|
||||
2. Move to misskey directory.
|
||||
|
||||
`cd misskey`
|
||||
|
||||
3. Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest) tag.
|
||||
|
||||
`git checkout master`
|
||||
|
||||
*2.* Configure Misskey
|
||||
----------------------------------------------------------------
|
||||
@ -57,7 +65,13 @@ Build misskey with the following:
|
||||
|
||||
`docker-compose build`
|
||||
|
||||
*5.* That is it.
|
||||
*5.* Init DB
|
||||
----------------------------------------------------------------
|
||||
``` shell
|
||||
docker-compose run --rm web npm run init
|
||||
```
|
||||
|
||||
*6.* That is it.
|
||||
----------------------------------------------------------------
|
||||
Well done! Now you have an environment to run Misskey.
|
||||
|
||||
@ -65,9 +79,9 @@ Well done! Now you have an environment to run Misskey.
|
||||
Just `docker-compose up -d`. GLHF!
|
||||
|
||||
### How to update your Misskey server to the latest version
|
||||
1. `git fetch`
|
||||
2. `git stash`
|
||||
3. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)`
|
||||
1. `git stash`
|
||||
2. `git checkout master`
|
||||
3. `git pull`
|
||||
4. `git stash pop`
|
||||
5. `docker-compose build`
|
||||
6. Check [ChangeLog](../CHANGELOG.md) for migration information
|
||||
|
@ -10,9 +10,17 @@ Ce guide explique comment installer et configurer Misskey avec Docker.
|
||||
|
||||
*1.* Télécharger Misskey
|
||||
----------------------------------------------------------------
|
||||
1. `git clone -b master git://github.com/syuilo/misskey.git` Clone le dépôt de Misskey sur la branche master.
|
||||
2. `cd misskey` Naviguez dans le dossier du dépôt.
|
||||
3. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` Checkout sur le tag de la [dernière version](https://github.com/syuilo/misskey/releases/latest).
|
||||
1. Clone le dépôt de Misskey sur la branche master.
|
||||
|
||||
`git clone -b master git://github.com/syuilo/misskey.git`
|
||||
|
||||
2. Naviguez dans le dossier du dépôt.
|
||||
|
||||
`cd misskey`
|
||||
|
||||
3. Checkout sur le tag de la [dernière version](https://github.com/syuilo/misskey/releases/latest).
|
||||
|
||||
`git checkout master`
|
||||
|
||||
*2.* Configuration de Misskey
|
||||
----------------------------------------------------------------
|
||||
@ -38,9 +46,9 @@ Parfait, Vous avez un environnement prêt pour démarrer Misskey.
|
||||
Utilisez la commande `docker-compose up -d`. GLHF!
|
||||
|
||||
### How to update your Misskey server to the latest version
|
||||
1. `git fetch`
|
||||
2. `git stash`
|
||||
3. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)`
|
||||
1. `git stash`
|
||||
2. `git checkout master`
|
||||
3. `git pull`
|
||||
4. `git stash pop`
|
||||
5. `docker-compose build`
|
||||
6. Consultez le [ChangeLog](../CHANGELOG.md) pour avoir les éventuelles informations de migration
|
||||
@ -52,14 +60,28 @@ Utilisez la commande `docker-compose up -d`. GLHF!
|
||||
### Configuration d'ElasticSearch (pour la fonction de recherche)
|
||||
*1.* Préparation de l'environnement
|
||||
----------------------------------------------------------------
|
||||
1. `mkdir elasticsearch && chown 1000:1000 elasticsearch` Permet de créer le dossier d'accueil de la base ElasticSearch aves les bons droits
|
||||
2. `sysctl -w vm.max_map_count=262144` Augmente la valeur max du paramètre map_count du système (valeur minimum pour pouvoir lancer ES)
|
||||
1. Permet de créer le dossier d'accueil de la base ElasticSearch aves les bons droits
|
||||
|
||||
`mkdir elasticsearch && chown 1000:1000 elasticsearch`
|
||||
|
||||
2. Augmente la valeur max du paramètre map_count du système (valeur minimum pour pouvoir lancer ES)
|
||||
|
||||
`sysctl -w vm.max_map_count=262144`
|
||||
|
||||
*2.* Après lancement du docker-compose, initialisation de la base ElasticSearch
|
||||
----------------------------------------------------------------
|
||||
1. `docker-compose -it web /bin/sh` Connexion dans le conteneur web
|
||||
2. `apk add curl` Ajout du paquet curl
|
||||
3. `curl -X PUT "es:9200/misskey" -H 'Content-Type: application/json' -d'{ "settings" : { "index" : { } }}'` Création de la base ES
|
||||
1. Connexion dans le conteneur web
|
||||
|
||||
`docker-compose -it web /bin/sh`
|
||||
|
||||
2. Ajout du paquet curl
|
||||
|
||||
`apk add curl`
|
||||
|
||||
3. Création de la base ES
|
||||
|
||||
`curl -X PUT "es:9200/misskey" -H 'Content-Type: application/json' -d'{ "settings" : { "index" : { } }}'`
|
||||
|
||||
4. `exit`
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
@ -9,9 +9,17 @@ Dockerを使ったMisskey構築方法
|
||||
|
||||
*1.* Misskeyのダウンロード
|
||||
----------------------------------------------------------------
|
||||
1. `git clone -b master git://github.com/syuilo/misskey.git` masterブランチからMisskeyレポジトリをクローン
|
||||
2. `cd misskey` misskeyディレクトリに移動
|
||||
3. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認
|
||||
1. masterブランチからMisskeyレポジトリをクローン
|
||||
|
||||
`git clone -b master git://github.com/syuilo/misskey.git`
|
||||
|
||||
2. misskeyディレクトリに移動
|
||||
|
||||
`cd misskey`
|
||||
|
||||
3. [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認
|
||||
|
||||
`git checkout master`
|
||||
|
||||
*2.* 設定ファイルの作成と編集
|
||||
----------------------------------------------------------------
|
||||
@ -57,7 +65,13 @@ cp docker_example.env docker.env
|
||||
|
||||
`docker-compose build`
|
||||
|
||||
*5.* 以上です!
|
||||
*5.* データベースを初期化
|
||||
----------------------------------------------------------------
|
||||
``` shell
|
||||
docker-compose run --rm web npm run init
|
||||
```
|
||||
|
||||
*6.* 以上です!
|
||||
----------------------------------------------------------------
|
||||
お疲れ様でした。これでMisskeyを動かす準備は整いました。
|
||||
|
||||
@ -65,9 +79,9 @@ cp docker_example.env docker.env
|
||||
`docker-compose up -d`するだけです。GLHF!
|
||||
|
||||
### Misskeyを最新バージョンにアップデートする方法:
|
||||
1. `git fetch`
|
||||
2. `git stash`
|
||||
3. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)`
|
||||
1. `git stash`
|
||||
2. `git checkout master`
|
||||
3. `git pull`
|
||||
4. `git stash pop`
|
||||
5. `docker-compose build`
|
||||
6. [ChangeLog](../CHANGELOG.md)でマイグレーション情報を確認する
|
||||
|
@ -32,15 +32,32 @@ Please install and setup these softwares:
|
||||
|
||||
*3.* Install Misskey
|
||||
----------------------------------------------------------------
|
||||
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.
|
||||
3. `cd misskey` Navigate to misskey directory
|
||||
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.
|
||||
1. Connect to misskey user.
|
||||
|
||||
`su - misskey`
|
||||
|
||||
2. Clone the misskey repo from master branch.
|
||||
|
||||
`git clone -b master git://github.com/syuilo/misskey.git`
|
||||
|
||||
3. Navigate to misskey directory
|
||||
|
||||
`cd misskey`
|
||||
|
||||
4. Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest)
|
||||
|
||||
`git checkout master`
|
||||
|
||||
5. Install misskey dependencies.
|
||||
|
||||
`npm install`
|
||||
|
||||
*4.* Configure Misskey
|
||||
----------------------------------------------------------------
|
||||
1. `cp .config/example.yml .config/default.yml` Copy the `.config/example.yml` and rename it to `default.yml`.
|
||||
1. Copy the `.config/example.yml` and rename it to `default.yml`.
|
||||
|
||||
`cp .config/example.yml .config/default.yml`
|
||||
|
||||
2. Edit `default.yml`
|
||||
|
||||
*5.* Build Misskey
|
||||
@ -74,7 +91,10 @@ Just `NODE_ENV=production npm start`. GLHF!
|
||||
|
||||
### Launch with systemd
|
||||
|
||||
1. Create a systemd service here: `/etc/systemd/system/misskey.service`
|
||||
1. Create a systemd service here
|
||||
|
||||
`/etc/systemd/system/misskey.service`
|
||||
|
||||
2. Edit it, and paste this and save:
|
||||
|
||||
```
|
||||
@ -97,14 +117,19 @@ Restart=always
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
3. `systemctl daemon-reload ; systemctl enable misskey` Reload systemd and enable the misskey service.
|
||||
4. `systemctl start misskey` Start the misskey service.
|
||||
3. Reload systemd and enable the misskey service.
|
||||
|
||||
`systemctl daemon-reload ; systemctl enable misskey`
|
||||
|
||||
4. Start the misskey service.
|
||||
|
||||
`systemctl start misskey`
|
||||
|
||||
You can check if the service is running with `systemctl status misskey`.
|
||||
|
||||
### How to update your Misskey server to the latest version
|
||||
1. `git fetch`
|
||||
2. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)`
|
||||
1. `git checkout master`
|
||||
2. `git pull`
|
||||
3. `npm install`
|
||||
4. `NODE_ENV=production npm run build`
|
||||
5. Check [ChangeLog](../CHANGELOG.md) for migration information
|
||||
|
@ -32,15 +32,32 @@ Installez les paquets suivants :
|
||||
|
||||
*3.* Installation de 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.
|
||||
3. `cd misskey` Accédez au dossier misskey.
|
||||
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.
|
||||
1. Basculez vers l'utilisateur misskey.
|
||||
|
||||
`su - misskey`
|
||||
|
||||
2. Clonez la branche master du dépôt misskey.
|
||||
|
||||
`git clone -b master git://github.com/syuilo/misskey.git`
|
||||
|
||||
3. Accédez au dossier misskey.
|
||||
|
||||
`cd misskey`
|
||||
|
||||
4. Checkout sur le tag de la [version la plus récente](https://github.com/syuilo/misskey/releases/latest)
|
||||
|
||||
`git checkout master`
|
||||
|
||||
5. Installez les dépendances de misskey.
|
||||
|
||||
`npm install`
|
||||
|
||||
*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. Copiez le fichier `.config/example.yml` et renommez-le`default.yml`.
|
||||
|
||||
`cp .config/example.yml .config/default.yml`
|
||||
|
||||
2. Editez le fichier `default.yml`
|
||||
|
||||
*5.* Construction de Misskey
|
||||
@ -68,7 +85,10 @@ Lancez tout simplement `NODE_ENV=production npm start`. Bonne chance et amusez-v
|
||||
|
||||
### Démarrage avec systemd
|
||||
|
||||
1. Créez un service systemd sur : `/etc/systemd/system/misskey.service`
|
||||
1. Créez un service systemd sur
|
||||
|
||||
`/etc/systemd/system/misskey.service`
|
||||
|
||||
2. Editez-le puis copiez et coller ceci dans le fichier :
|
||||
|
||||
```
|
||||
@ -91,14 +111,19 @@ Restart=always
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
3. `systemctl daemon-reload ; systemctl enable misskey` Redémarre systemd et active le service misskey.
|
||||
4. `systemctl start misskey` Démarre le service misskey.
|
||||
3. Redémarre systemd et active le service misskey.
|
||||
|
||||
`systemctl daemon-reload ; systemctl enable misskey`
|
||||
|
||||
4. Démarre le service misskey.
|
||||
|
||||
`systemctl start misskey`
|
||||
|
||||
Vous pouvez vérifier si le service a démarré en utilisant la commande `systemctl status misskey`.
|
||||
|
||||
### Méthode de mise à jour vers la plus récente version de Misskey
|
||||
1. `git fetch`
|
||||
2. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)`
|
||||
1. `git checkout master`
|
||||
2. `git pull`
|
||||
3. `npm install`
|
||||
4. `NODE_ENV=production npm run build`
|
||||
5. Consultez [ChangeLog](../CHANGELOG.md) pour les information de migration.
|
||||
|
@ -33,15 +33,32 @@ adduser --disabled-password --disabled-login misskey
|
||||
|
||||
*3.* Misskeyのインストール
|
||||
----------------------------------------------------------------
|
||||
1. `su - misskey` misskeyユーザーを使用
|
||||
2. `git clone -b master git://github.com/syuilo/misskey.git` masterブランチからMisskeyレポジトリをクローン
|
||||
3. `cd misskey` 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)を確認
|
||||
5. `npm install` Misskeyの依存パッケージをインストール
|
||||
1. misskeyユーザーを使用
|
||||
|
||||
`su - misskey`
|
||||
|
||||
2. masterブランチからMisskeyレポジトリをクローン
|
||||
|
||||
`git clone -b master git://github.com/syuilo/misskey.git`
|
||||
|
||||
3. misskeyディレクトリに移動
|
||||
|
||||
`cd misskey`
|
||||
|
||||
4. [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認
|
||||
|
||||
`git checkout master`
|
||||
|
||||
5. Misskeyの依存パッケージをインストール
|
||||
|
||||
`npm install`
|
||||
|
||||
*4.* 設定ファイルを作成する
|
||||
----------------------------------------------------------------
|
||||
1. `cp .config/example.yml .config/default.yml` `.config/example.yml`をコピーし名前を`default.yml`にする。
|
||||
1. `.config/example.yml`をコピーし名前を`default.yml`にする。
|
||||
|
||||
`cp .config/example.yml .config/default.yml`
|
||||
|
||||
2. `default.yml` を編集する。
|
||||
|
||||
*5.* Misskeyのビルド
|
||||
@ -73,7 +90,10 @@ npm run init
|
||||
`NODE_ENV=production npm start`するだけです。GLHF!
|
||||
|
||||
### systemdを用いた起動
|
||||
1. systemdサービスのファイルを作成: `/etc/systemd/system/misskey.service`
|
||||
1. systemdサービスのファイルを作成
|
||||
|
||||
`/etc/systemd/system/misskey.service`
|
||||
|
||||
2. エディタで開き、以下のコードを貼り付けて保存:
|
||||
|
||||
```
|
||||
@ -95,16 +115,22 @@ Restart=always
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
CentOSで1024以下のポートを使用してMisskeyを使用する場合は`ExecStart=/usr/bin/sudo /usr/bin/npm start`に変更する必要があります。
|
||||
|
||||
3. `systemctl daemon-reload ; systemctl enable misskey` systemdを再読み込みしmisskeyサービスを有効化
|
||||
4. `systemctl start misskey` misskeyサービスの起動
|
||||
3. systemdを再読み込みしmisskeyサービスを有効化
|
||||
|
||||
`systemctl daemon-reload ; systemctl enable misskey`
|
||||
|
||||
4. misskeyサービスの起動
|
||||
|
||||
`systemctl start misskey`
|
||||
|
||||
`systemctl status misskey`と入力すると、サービスの状態を調べることができます。
|
||||
|
||||
### Misskeyを最新バージョンにアップデートする方法:
|
||||
1. `git fetch`
|
||||
2. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)`
|
||||
1. `git checkout master`
|
||||
2. `git pull`
|
||||
3. `npm install`
|
||||
4. `NODE_ENV=production npm run build`
|
||||
5. [ChangeLog](../CHANGELOG.md)でマイグレーション情報を確認する
|
||||
|
@ -313,6 +313,7 @@ common:
|
||||
nav: "ナビゲーション"
|
||||
tips: "ヒント"
|
||||
hashtags: "ハッシュタグ"
|
||||
queue: "キュー"
|
||||
|
||||
dev: "アプリの作成に失敗しました。再度お試しください。"
|
||||
ai-chan-kawaii: "藍ちゃかわいい"
|
||||
@ -1549,6 +1550,7 @@ desktop/views/widgets/polls.vue:
|
||||
desktop/views/widgets/post-form.vue:
|
||||
title: "投稿"
|
||||
note: "投稿"
|
||||
something-happened: "何らかの事情で投稿できませんでした。"
|
||||
|
||||
desktop/views/widgets/profile.vue:
|
||||
update-banner: "クリックでバナー編集"
|
||||
@ -1641,7 +1643,7 @@ mobile/views/components/post-form.vue:
|
||||
quote-placeholder: "この投稿を引用... (オプション)"
|
||||
reply-placeholder: "この投稿への返信..."
|
||||
cw-placeholder: "内容への注釈 (オプション)"
|
||||
location-alert: "お使いの端末は位置情報に対応していません"
|
||||
geolocation-alert: "お使いの端末は位置情報に対応していません"
|
||||
error: "エラー"
|
||||
username-prompt: "ユーザー名を入力してください"
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"author": "syuilo <i@syuilo.com>",
|
||||
"version": "11.0.3",
|
||||
"version": "11.1.4",
|
||||
"codename": "daybreak",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -64,8 +64,6 @@
|
||||
"@types/lolex": "3.1.1",
|
||||
"@types/minio": "7.0.1",
|
||||
"@types/mocha": "5.2.6",
|
||||
"@types/mongodb": "3.1.22",
|
||||
"@types/monk": "6.0.0",
|
||||
"@types/node": "11.13.4",
|
||||
"@types/nodemailer": "4.6.7",
|
||||
"@types/nprogress": "0.0.29",
|
||||
@ -75,6 +73,7 @@
|
||||
"@types/portscanner": "2.1.0",
|
||||
"@types/pug": "2.0.4",
|
||||
"@types/qrcode": "1.3.2",
|
||||
"@types/random-seed": "0.3.3",
|
||||
"@types/ratelimiter": "2.1.28",
|
||||
"@types/redis": "2.8.12",
|
||||
"@types/rename": "1.0.1",
|
||||
@ -166,8 +165,6 @@
|
||||
"mocha": "6.1.3",
|
||||
"moji": "0.5.1",
|
||||
"moment": "2.24.0",
|
||||
"mongodb": "3.2.3",
|
||||
"monk": "6.0.6",
|
||||
"ms": "2.1.1",
|
||||
"nested-property": "0.0.7",
|
||||
"node-fetch": "2.3.0",
|
||||
@ -187,7 +184,9 @@
|
||||
"promise-sequential": "1.1.1",
|
||||
"pug": "2.0.3",
|
||||
"punycode": "2.1.1",
|
||||
"pureimage": "0.1.6",
|
||||
"qrcode": "1.3.3",
|
||||
"random-seed": "0.3.0",
|
||||
"randomcolor": "0.5.4",
|
||||
"ratelimiter": "3.3.0",
|
||||
"recaptcha-promise": "0.1.3",
|
||||
|
@ -242,7 +242,7 @@ export default Vue.extend({
|
||||
|
||||
> div:nth-child(1)
|
||||
> .thumbnail
|
||||
display block
|
||||
display flex
|
||||
width 64px
|
||||
height 64px
|
||||
background-size cover
|
||||
|
@ -195,7 +195,7 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
created() {
|
||||
this.$root.getMeta().then(meta => {
|
||||
this.$root.getMeta(true).then(meta => {
|
||||
this.maintainerName = meta.maintainerName;
|
||||
this.maintainerEmail = meta.maintainerEmail;
|
||||
this.disableRegistration = meta.disableRegistration;
|
||||
|
@ -134,7 +134,7 @@ export default (opts: Opts = {}) => ({
|
||||
},
|
||||
|
||||
reactDirectly(reaction) {
|
||||
(this.$root.api('notes/reactions/create', {
|
||||
this.$root.api('notes/reactions/create', {
|
||||
noteId: this.appearNote.id,
|
||||
reaction: reaction
|
||||
});
|
||||
|
@ -36,7 +36,9 @@ export default Vue.extend({
|
||||
return this.host === localHost ? `@${this.username}` : `@${this.username}@${toUnicode(this.host)}`;
|
||||
},
|
||||
isMe(): boolean {
|
||||
return this.$store.getters.isSignedIn && this.canonical.toLowerCase() === `@${this.$store.state.i.username}@${toUnicode(localHost)}`.toLowerCase();
|
||||
return this.$store.getters.isSignedIn && (
|
||||
`@${this.username}@${toUnicode(this.host)}` === `@${this.$store.state.i.username}@${toUnicode(localHost)}`.toLowerCase()
|
||||
);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -85,7 +85,10 @@ export default Vue.extend({
|
||||
}
|
||||
} else {
|
||||
if (items[0].kind == 'file') {
|
||||
alert(this.$t('only-one-file-attached'));
|
||||
this.$root.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('only-one-file-attached')
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -107,7 +110,10 @@ export default Vue.extend({
|
||||
return;
|
||||
} else if (e.dataTransfer.files.length > 1) {
|
||||
e.preventDefault();
|
||||
alert(this.$t('only-one-file-attached'));
|
||||
this.$root.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('only-one-file-attached')
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,10 @@ export default Vue.extend({
|
||||
this.form.upload(e.dataTransfer.files[0]);
|
||||
return;
|
||||
} else if (e.dataTransfer.files.length > 1) {
|
||||
alert(this.$t('only-one-file-attached'));
|
||||
this.$root.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('only-one-file-attached')
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="skeikyzd" v-show="files.length != 0">
|
||||
<x-draggable class="files" :list="files" :options="{ animation: 150 }">
|
||||
<x-draggable class="files" :list="files" 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=""/>
|
||||
|
@ -84,7 +84,7 @@
|
||||
<ui-info v-else warn>{{ $t('email-not-verified') }}</ui-info>
|
||||
</template>
|
||||
<ui-input v-model="email" type="email"><span>{{ $t('email-address') }}</span></ui-input>
|
||||
<ui-button @click="updateEmail()"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
|
||||
<ui-button @click="updateEmail()" :disabled="email === $store.state.i.email"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
@ -542,8 +542,8 @@ export default Vue.extend({
|
||||
this.latestVersion = newer;
|
||||
if (newer == null) {
|
||||
this.$root.dialog({
|
||||
title: this.$t('no-updates'),
|
||||
text: this.$t('no-updates-desc')
|
||||
title: this.$t('@._settings.no-updates'),
|
||||
text: this.$t('@._settings.no-updates-desc')
|
||||
});
|
||||
} else {
|
||||
this.$root.dialog({
|
||||
|
@ -79,7 +79,10 @@ export default Vue.extend({
|
||||
localStorage.setItem('i', res.i);
|
||||
location.reload();
|
||||
}).catch(() => {
|
||||
alert(this.$t('login-failed'));
|
||||
this.$root.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('login-failed')
|
||||
});
|
||||
this.signing = false;
|
||||
});
|
||||
}
|
||||
|
@ -153,7 +153,10 @@ export default Vue.extend({
|
||||
location.href = '/';
|
||||
});
|
||||
}).catch(() => {
|
||||
alert(this.$t('some-error'));
|
||||
this.$root.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('some-error')
|
||||
});
|
||||
|
||||
if (this.meta.enableRecaptcha) {
|
||||
(window as any).grecaptcha.reset();
|
||||
|
@ -21,7 +21,7 @@
|
||||
<option value="users">{{ $t('@.widgets.users') }}</option>
|
||||
<option value="polls">{{ $t('@.widgets.polls') }}</option>
|
||||
<option value="post-form">{{ $t('@.widgets.post-form') }}</option>
|
||||
<option value="messaging">{{ $t('@.widgets.messaging') }}</option>
|
||||
<option value="messaging">{{ $t('@.messaging') }}</option>
|
||||
<option value="memo">{{ $t('@.widgets.memo') }}</option>
|
||||
<option value="hashtags">{{ $t('@.widgets.hashtags') }}</option>
|
||||
<option value="posts-monitor">{{ $t('@.widgets.posts-monitor') }}</option>
|
||||
@ -33,7 +33,7 @@
|
||||
</header>
|
||||
<x-draggable
|
||||
:list="column.widgets"
|
||||
:options="{ animation: 150 }"
|
||||
animation="150"
|
||||
@sort="onWidgetSort"
|
||||
>
|
||||
<div v-for="widget in column.widgets" class="customize-container" :key="widget.id" @contextmenu.stop.prevent="widgetFunc(widget.id)">
|
||||
|
@ -188,7 +188,10 @@ export default define({
|
||||
}).then(data => {
|
||||
this.clear();
|
||||
}).catch(err => {
|
||||
alert('Something happened');
|
||||
this.$root.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('something-happened')
|
||||
});
|
||||
}).then(() => {
|
||||
this.posting = false;
|
||||
this.$nextTick(() => {
|
||||
|
@ -161,7 +161,10 @@ export default Vue.extend({
|
||||
});
|
||||
break;
|
||||
default:
|
||||
alert(this.$t('unhandled-error'));
|
||||
this.$root.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('unhandled-error')
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -320,7 +320,10 @@ export default Vue.extend({
|
||||
});
|
||||
break;
|
||||
default:
|
||||
alert(this.$t('unhandled-error'));
|
||||
this.$root.dialog({
|
||||
type: 'error',
|
||||
text: this.$t('unhandled-error')
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -364,7 +364,10 @@ export default Vue.extend({
|
||||
|
||||
setGeo() {
|
||||
if (navigator.geolocation == null) {
|
||||
alert(this.$t('geolocation-alert'));
|
||||
this.$root.dialog({
|
||||
type: 'warning',
|
||||
text: this.$t('geolocation-alert')
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@ -372,7 +375,11 @@ export default Vue.extend({
|
||||
this.geo = pos.coords;
|
||||
this.$emit('geo-attached', this.geo);
|
||||
}, err => {
|
||||
alert(`%i18n:@error%: ${err.message}`);
|
||||
this.$root.dialog({
|
||||
type: 'error',
|
||||
title: this.$t('error')
|
||||
text: err.message
|
||||
});
|
||||
}, {
|
||||
enableHighAccuracy: true
|
||||
});
|
||||
|
@ -34,7 +34,7 @@
|
||||
<button @click="addWidget">{{ $t('add') }}</button>
|
||||
</div>
|
||||
<div class="trash">
|
||||
<x-draggable v-model="trash" :options="{ group: 'x' }" @add="onTrash"></x-draggable>
|
||||
<x-draggable v-model="trash" group="x" @add="onTrash"></x-draggable>
|
||||
<p>{{ $t('@.trash') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -45,7 +45,8 @@
|
||||
:list="widgets[place]"
|
||||
:class="place"
|
||||
:data-place="place"
|
||||
:options="{ group: 'x', animation: 150 }"
|
||||
group="x"
|
||||
animation="150"
|
||||
@sort="onWidgetSort"
|
||||
:key="place"
|
||||
>
|
||||
|
@ -88,8 +88,6 @@ export default Vue.extend({
|
||||
} else if (this.src == 'tag') {
|
||||
this.tagTl = this.$store.state.device.tl.arg;
|
||||
}
|
||||
} else if (this.$store.state.i.followingCount == 0) {
|
||||
this.src = 'hybrid';
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -34,7 +34,7 @@ export default Vue.extend({
|
||||
document.title = title;
|
||||
},
|
||||
onOpenFolder(folder) {
|
||||
const title = folder.name + ' | %i18n:@title%';
|
||||
const title = `${folder.name} | ${this.$t('title')}`;
|
||||
|
||||
// Rewrite URL
|
||||
history.pushState(null, title, `/i/drive/folder/${folder.id}`);
|
||||
|
@ -4,7 +4,7 @@ import { EventEmitter } from 'eventemitter3';
|
||||
import * as uuid from 'uuid';
|
||||
|
||||
import initStore from './store';
|
||||
import { apiUrl, version } from './config';
|
||||
import { apiUrl, version, locale } from './config';
|
||||
import Progress from './common/scripts/loading';
|
||||
|
||||
import Err from './common/views/components/connect-failed.vue';
|
||||
@ -281,7 +281,7 @@ export default class MiOS extends EventEmitter {
|
||||
// トークンが再生成されたとき
|
||||
// このままではMisskeyが利用できないので強制的にサインアウトさせる
|
||||
main.on('myTokenRegenerated', () => {
|
||||
alert('%i18n:common.my-token-regenerated%');
|
||||
alert(locale['common']['my-token-regenerated'])
|
||||
this.signout();
|
||||
});
|
||||
}
|
||||
|
@ -136,7 +136,10 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
showCreatedAt() {
|
||||
alert(new Date(this.file.createdAt).toLocaleString());
|
||||
this.$root.dialog({
|
||||
type: 'info',
|
||||
text: (new Date(this.file.createdAt)).toLocaleString()
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -150,11 +153,13 @@ export default Vue.extend({
|
||||
|
||||
> .preview
|
||||
width fit-content
|
||||
width -moz-fit-content
|
||||
max-width 100%
|
||||
margin 0 auto
|
||||
box-shadow 1px 1px 4px rgba(#000, 0.2)
|
||||
overflow hidden
|
||||
color var(--driveFileIcon)
|
||||
justify-content center
|
||||
|
||||
> footer
|
||||
padding 8px 8px 0 8px
|
||||
|
@ -283,14 +283,21 @@ export default Vue.extend({
|
||||
|
||||
setGeo() {
|
||||
if (navigator.geolocation == null) {
|
||||
alert(this.$t('location-alert'));
|
||||
this.$root.dialog({
|
||||
type: 'warning',
|
||||
text: this.$t('geolocation-alert')
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
navigator.geolocation.getCurrentPosition(pos => {
|
||||
this.geo = pos.coords;
|
||||
}, err => {
|
||||
alert(`%i18n:@error%: ${err.message}`);
|
||||
this.$root.dialog({
|
||||
type: 'error',
|
||||
title: this.$t('error')
|
||||
text: err.message
|
||||
});
|
||||
}, {
|
||||
enableHighAccuracy: true
|
||||
});
|
||||
|
@ -32,7 +32,7 @@ export default Vue.extend({
|
||||
this.fetch();
|
||||
},
|
||||
mounted() {
|
||||
document.title = `${this.$root.instanceName} | %i18n:@notifications%`;
|
||||
document.title = `${this.$root.instanceName} | ${this.$t('@.favorites')}`;
|
||||
},
|
||||
methods: {
|
||||
fetch() {
|
||||
|
@ -15,7 +15,7 @@ export default Vue.extend({
|
||||
XReversi: () => import('../../../../common/views/components/games/reversi/reversi.vue').then(m => m.default)
|
||||
},
|
||||
mounted() {
|
||||
document.title = `${this.$root.instanceName} %i18n:@reversi%`;
|
||||
document.title = `${this.$root.instanceName} | ${this.$t('reversi')}`;
|
||||
},
|
||||
methods: {
|
||||
nav(game, actualNav) {
|
||||
|
@ -130,8 +130,6 @@ export default Vue.extend({
|
||||
} else if (this.src == 'tag') {
|
||||
this.tagTl = this.$store.state.device.tl.arg;
|
||||
}
|
||||
} else if (this.$store.state.i.followingCount == 0) {
|
||||
this.src = 'hybrid';
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -50,7 +50,7 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
document.title = `%i18n:@search%: ${this.q} | ${this.$root.instanceName}`;
|
||||
document.title = `${this.$t('search')}: ${this.q} | ${this.$root.instanceName}`;
|
||||
},
|
||||
methods: {
|
||||
inited() {
|
||||
|
@ -29,7 +29,8 @@
|
||||
</header>
|
||||
<x-draggable
|
||||
:list="widgets"
|
||||
:options="{ handle: '.handle', animation: 150 }"
|
||||
handle=".handle"
|
||||
animation="150"
|
||||
@sort="onWidgetSort"
|
||||
>
|
||||
<div v-for="widget in widgets" class="customize-container" :key="widget.id">
|
||||
@ -106,7 +107,10 @@ export default Vue.extend({
|
||||
|
||||
methods: {
|
||||
hint() {
|
||||
alert(this.$t('widgets-hints'));
|
||||
this.$root.dialog({
|
||||
type: 'info',
|
||||
text: this.$t('widgets-hints')
|
||||
});
|
||||
},
|
||||
|
||||
widgetFunc(id) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
@charset 'utf-8'
|
||||
@charset "utf-8"
|
||||
|
||||
/*
|
||||
::selection
|
||||
|
@ -130,12 +130,14 @@ Misskeyのストリームに接続しただけでは、まだリアルタイム
|
||||
```json
|
||||
{
|
||||
type: 'api',
|
||||
body: {
|
||||
id: 'xxxxxxxxxxxxxxxx',
|
||||
endpoint: 'notes/create',
|
||||
data: {
|
||||
text: 'yee haw!'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
ここで、
|
||||
|
@ -1,14 +1,21 @@
|
||||
import { Meta } from '../models/entities/meta';
|
||||
import { Metas } from '../models';
|
||||
import { genId } from './gen-id';
|
||||
import { getConnection } from 'typeorm';
|
||||
|
||||
export default async function(): Promise<Meta> {
|
||||
const meta = await Metas.findOne();
|
||||
return await getConnection().transaction(async transactionalEntityManager => {
|
||||
// バグでレコードが複数出来てしまっている可能性があるので新しいIDを優先する
|
||||
const meta = await transactionalEntityManager.findOne(Meta, {
|
||||
order: {
|
||||
id: 'DESC'
|
||||
}
|
||||
});
|
||||
|
||||
if (meta) {
|
||||
return meta;
|
||||
} else {
|
||||
return Metas.save({
|
||||
id: genId(),
|
||||
} as Meta);
|
||||
return await transactionalEntityManager.save(Meta, {
|
||||
id: 'x'
|
||||
}) as Meta;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
90
src/misc/gen-avatar.ts
Normal file
90
src/misc/gen-avatar.ts
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Random avatar generator
|
||||
*/
|
||||
|
||||
const p = require('pureimage');
|
||||
import * as gen from 'random-seed';
|
||||
import { WriteStream } from 'fs';
|
||||
|
||||
const size = 256; // px
|
||||
const n = 5; // resolution
|
||||
const margin = (size / n) / 1.5;
|
||||
const colors = [
|
||||
'#e57373',
|
||||
'#F06292',
|
||||
'#BA68C8',
|
||||
'#9575CD',
|
||||
'#7986CB',
|
||||
'#64B5F6',
|
||||
'#4FC3F7',
|
||||
'#4DD0E1',
|
||||
'#4DB6AC',
|
||||
'#81C784',
|
||||
'#8BC34A',
|
||||
'#AFB42B',
|
||||
'#F57F17',
|
||||
'#FF5722',
|
||||
'#795548',
|
||||
'#455A64',
|
||||
];
|
||||
const bg = '#e9e9e9';
|
||||
|
||||
const actualSize = size - (margin * 2);
|
||||
const cellSize = actualSize / n;
|
||||
const sideN = Math.floor(n / 2);
|
||||
|
||||
/**
|
||||
* Generate buffer of random avatar by seed
|
||||
*/
|
||||
export function genAvatar(seed: string, stream: WriteStream): Promise<void> {
|
||||
const rand = gen.create(seed);
|
||||
const canvas = p.make(size, size);
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
ctx.fillStyle = bg;
|
||||
ctx.beginPath();
|
||||
ctx.fillRect(0, 0, size, size);
|
||||
|
||||
ctx.fillStyle = colors[rand(colors.length)];
|
||||
|
||||
// side bitmap (filled by false)
|
||||
const side: boolean[][] = new Array(sideN);
|
||||
for (let i = 0; i < side.length; i++) {
|
||||
side[i] = new Array(n).fill(false);
|
||||
}
|
||||
|
||||
// 1*n (filled by false)
|
||||
const center: boolean[] = new Array(n).fill(false);
|
||||
|
||||
// tslint:disable-next-line:prefer-for-of
|
||||
for (let x = 0; x < side.length; x++) {
|
||||
for (let y = 0; y < side[x].length; y++) {
|
||||
side[x][y] = rand(3) === 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < center.length; i++) {
|
||||
center[i] = rand(3) === 0;
|
||||
}
|
||||
|
||||
// Draw
|
||||
for (let x = 0; x < n; x++) {
|
||||
for (let y = 0; y < n; y++) {
|
||||
const isXCenter = x === ((n - 1) / 2);
|
||||
if (isXCenter && !center[y]) continue;
|
||||
|
||||
const isLeftSide = x < ((n - 1) / 2);
|
||||
if (isLeftSide && !side[x][y]) continue;
|
||||
|
||||
const isRightSide = x > ((n - 1) / 2);
|
||||
if (isRightSide && !side[sideN - (x - sideN)][y]) continue;
|
||||
|
||||
const actualX = margin + (cellSize * x);
|
||||
const actualY = margin + (cellSize * y);
|
||||
ctx.beginPath();
|
||||
ctx.fillRect(actualX, actualY, cellSize, cellSize);
|
||||
}
|
||||
}
|
||||
|
||||
return p.encodePNGToStream(canvas, stream);
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { Entity, PrimaryColumn, Index, Column, ManyToOne, JoinColumn, RelationId } from 'typeorm';
|
||||
import { Entity, PrimaryColumn, Index, Column, ManyToOne, JoinColumn } from 'typeorm';
|
||||
import { User } from './user';
|
||||
import { App } from './app';
|
||||
import { id } from '../id';
|
||||
@ -25,7 +25,8 @@ export class AccessToken {
|
||||
})
|
||||
public hash: string;
|
||||
|
||||
@RelationId((self: AccessToken) => self.user)
|
||||
@Index()
|
||||
@Column(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(type => User, {
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { Entity, Column, PrimaryColumn } from 'typeorm';
|
||||
import { id } from '../id';
|
||||
|
||||
@Entity()
|
||||
export class Meta {
|
||||
@PrimaryColumn(id())
|
||||
@PrimaryColumn({
|
||||
type: 'varchar',
|
||||
length: 32
|
||||
})
|
||||
public id: string;
|
||||
|
||||
@Column('varchar', {
|
||||
|
@ -93,12 +93,12 @@ export class Note {
|
||||
})
|
||||
public localOnly: boolean;
|
||||
|
||||
@Column('integer', {
|
||||
@Column('smallint', {
|
||||
default: 0
|
||||
})
|
||||
public renoteCount: number;
|
||||
|
||||
@Column('integer', {
|
||||
@Column('smallint', {
|
||||
default: 0
|
||||
})
|
||||
public repliesCount: number;
|
||||
@ -129,12 +129,14 @@ export class Note {
|
||||
})
|
||||
public score: number;
|
||||
|
||||
@Index()
|
||||
@Column({
|
||||
...id(),
|
||||
array: true, default: '{}'
|
||||
})
|
||||
public fileIds: DriveFile['id'][];
|
||||
|
||||
@Index()
|
||||
@Column('varchar', {
|
||||
length: 256, array: true, default: '{}'
|
||||
})
|
||||
|
@ -103,7 +103,7 @@ export class NoteRepository extends Repository<Note> {
|
||||
const host = note.userHost;
|
||||
|
||||
async function populatePoll() {
|
||||
const poll = await Polls.findOne({ noteId: note.id }).then(ensure);
|
||||
const poll = await Polls.findOne(note.id).then(ensure);
|
||||
const choices = poll.choices.map(c => ({
|
||||
text: c,
|
||||
votes: poll.votes[poll.choices.indexOf(c)],
|
||||
|
@ -3,6 +3,7 @@ import { User, ILocalUser, IRemoteUser } from '../entities/user';
|
||||
import { Emojis, Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles } from '..';
|
||||
import rap from '@prezzemolo/rap';
|
||||
import { ensure } from '../../prelude/ensure';
|
||||
import config from '../../config';
|
||||
|
||||
@EntityRepository(User)
|
||||
export class UserRepository extends Repository<User> {
|
||||
@ -83,17 +84,19 @@ export class UserRepository extends Repository<User> {
|
||||
const pins = opts.detail ? await UserNotePinings.find({ userId: user.id }) : [];
|
||||
const profile = opts.detail ? await UserProfiles.findOne({ userId: user.id }).then(ensure) : null;
|
||||
|
||||
const falsy = opts.detail ? false : undefined;
|
||||
|
||||
return await rap({
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
username: user.username,
|
||||
host: user.host,
|
||||
avatarUrl: user.avatarUrl,
|
||||
avatarUrl: user.avatarUrl ? user.avatarUrl : config.url + '/avatar/' + user.id,
|
||||
avatarColor: user.avatarColor,
|
||||
isAdmin: user.isAdmin || undefined,
|
||||
isBot: user.isBot || undefined,
|
||||
isCat: user.isCat || undefined,
|
||||
isVerified: user.isVerified || undefined,
|
||||
isAdmin: user.isAdmin || falsy,
|
||||
isBot: user.isBot || falsy,
|
||||
isCat: user.isCat || falsy,
|
||||
isVerified: user.isVerified || falsy,
|
||||
|
||||
// カスタム絵文字添付
|
||||
emojis: user.emojis.length > 0 ? Emojis.find({
|
||||
@ -122,7 +125,7 @@ export class UserRepository extends Repository<User> {
|
||||
bannerUrl: user.bannerUrl,
|
||||
bannerColor: user.bannerColor,
|
||||
isLocked: user.isLocked,
|
||||
isModerator: user.isModerator || undefined,
|
||||
isModerator: user.isModerator || falsy,
|
||||
description: profile!.description,
|
||||
location: profile!.location,
|
||||
birthday: profile!.birthday,
|
||||
|
@ -31,7 +31,9 @@ export default async (token: string): Promise<[User | null | undefined, App | nu
|
||||
.findOne(accessToken.appId);
|
||||
|
||||
const user = await Users
|
||||
.findOne(accessToken.userId);
|
||||
.findOne({
|
||||
id: accessToken.userId // findOne(accessToken.userId) のように書かないのは後方互換性のため
|
||||
});
|
||||
|
||||
return [user, app];
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ export default async (endpoint: string, user: User | null | undefined, app: App
|
||||
});
|
||||
}
|
||||
|
||||
if (ep.meta.requireCredential && ep.meta.limit) {
|
||||
if (ep.meta.requireCredential && ep.meta.limit && !user!.isAdmin && !user!.isModerator) {
|
||||
// Rate limit
|
||||
await limiter(ep, user!).catch(e => {
|
||||
throw new ApiError({
|
||||
|
@ -1,3 +1,3 @@
|
||||
import rndstr from 'rndstr';
|
||||
|
||||
export default () => `0${rndstr('a-zA-Z0-9', 15)}`;
|
||||
export default () => rndstr('a-zA-Z0-9', 16);
|
||||
|
@ -1 +1 @@
|
||||
export default (token: string) => token.startsWith('0');
|
||||
export default (token: string) => token.length === 16;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import $ from 'cafy';
|
||||
import define from '../../define';
|
||||
import { Metas } from '../../../../models';
|
||||
import { getConnection } from 'typeorm';
|
||||
import { Meta } from '../../../../models/entities/meta';
|
||||
|
||||
export const meta = {
|
||||
@ -505,11 +505,17 @@ export default define(meta, async (ps) => {
|
||||
set.swPrivateKey = ps.swPrivateKey;
|
||||
}
|
||||
|
||||
const meta = await Metas.findOne();
|
||||
|
||||
if (meta) {
|
||||
await Metas.update(meta.id, set);
|
||||
} else {
|
||||
await Metas.save(set);
|
||||
await getConnection().transaction(async transactionalEntityManager => {
|
||||
const meta = await transactionalEntityManager.findOne(Meta, {
|
||||
order: {
|
||||
id: 'DESC'
|
||||
}
|
||||
});
|
||||
|
||||
if (meta) {
|
||||
await transactionalEntityManager.update(Meta, meta.id, set);
|
||||
} else {
|
||||
await transactionalEntityManager.save(Meta, set);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -10,24 +10,68 @@ export const meta = {
|
||||
|
||||
requireCredential: false,
|
||||
|
||||
desc: {
|
||||
'ja-JP': 'アプリを作成します。',
|
||||
'en-US': 'Create a application.'
|
||||
},
|
||||
|
||||
params: {
|
||||
name: {
|
||||
validator: $.str
|
||||
validator: $.str,
|
||||
desc: {
|
||||
'ja-JP': 'アプリの名前',
|
||||
'en-US': 'Name of application'
|
||||
}
|
||||
},
|
||||
|
||||
description: {
|
||||
validator: $.str
|
||||
validator: $.str,
|
||||
desc: {
|
||||
'ja-JP': 'アプリの説明',
|
||||
'en-US': 'Description of application'
|
||||
}
|
||||
},
|
||||
|
||||
permission: {
|
||||
validator: $.arr($.str).unique()
|
||||
validator: $.arr($.str).unique(),
|
||||
desc: {
|
||||
'ja-JP': 'このアプリに割り当てる権限(権限については"Permissions"を参照)',
|
||||
'en-US': 'Permissions assigned to this app (see "Permissions" for the permissions)'
|
||||
}
|
||||
},
|
||||
|
||||
// TODO: Check it is valid url
|
||||
callbackUrl: {
|
||||
validator: $.optional.nullable.str,
|
||||
default: null as any
|
||||
default: null as any,
|
||||
desc: {
|
||||
'ja-JP': 'アプリ認証時にコールバックするURL',
|
||||
'en-US': 'URL to call back at app authentication'
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
description: 'アプリケーションのID'
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
description: 'アプリケーションの名前'
|
||||
},
|
||||
callbackUrl: {
|
||||
type: 'string',
|
||||
nullable: true,
|
||||
description: 'コールバックするURL'
|
||||
},
|
||||
secret: {
|
||||
type: 'string',
|
||||
description: 'アプリケーションのシークレットキー'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -39,7 +39,7 @@ export default define(meta, async (ps, user) => {
|
||||
}
|
||||
|
||||
// Generate access token
|
||||
const accessToken = '1' + rndstr('a-zA-Z0-9', 15);
|
||||
const accessToken = rndstr('a-zA-Z0-9', 32);
|
||||
|
||||
// Fetch exist access token
|
||||
const exist = await AccessTokens.findOne({
|
||||
|
@ -11,6 +11,11 @@ export const meta = {
|
||||
|
||||
requireCredential: false,
|
||||
|
||||
desc: {
|
||||
'ja-JP': 'アプリを認証するためのトークンを作成します。',
|
||||
'en-US': 'Generate a token for authorize application.'
|
||||
},
|
||||
|
||||
params: {
|
||||
appSecret: {
|
||||
validator: $.str,
|
||||
|
@ -5,7 +5,7 @@ import create from '../../../../services/blocking/create';
|
||||
import define from '../../define';
|
||||
import { ApiError } from '../../error';
|
||||
import { getUser } from '../../common/getters';
|
||||
import { Blockings, NoteWatchings } from '../../../../models';
|
||||
import { Blockings, NoteWatchings, Users } from '../../../../models';
|
||||
|
||||
export const meta = {
|
||||
stability: 'stable',
|
||||
@ -89,5 +89,5 @@ export default define(meta, async (ps, user) => {
|
||||
noteUserId: blockee.id
|
||||
});
|
||||
|
||||
return await Blockings.pack(blockee.id, user);
|
||||
return await Users.pack(blockee.id, user);
|
||||
});
|
||||
|
@ -5,7 +5,7 @@ import deleteBlocking from '../../../../services/blocking/delete';
|
||||
import define from '../../define';
|
||||
import { ApiError } from '../../error';
|
||||
import { getUser } from '../../common/getters';
|
||||
import { Blockings } from '../../../../models';
|
||||
import { Blockings, Users } from '../../../../models';
|
||||
|
||||
export const meta = {
|
||||
stability: 'stable',
|
||||
@ -84,5 +84,5 @@ export default define(meta, async (ps, user) => {
|
||||
// Delete blocking
|
||||
await deleteBlocking(blocker, blockee);
|
||||
|
||||
return await Blockings.pack(blockee.id, user);
|
||||
return await Users.pack(blockee.id, user);
|
||||
});
|
||||
|
@ -238,8 +238,6 @@ export default define(meta, async (ps, user, app) => {
|
||||
userId: user.id
|
||||
})
|
||||
))).filter(file => file != null) as DriveFile[];
|
||||
|
||||
files = files;
|
||||
}
|
||||
|
||||
let renote: Note | undefined;
|
||||
|
@ -27,7 +27,6 @@ export const meta = {
|
||||
export default define(meta, async (ps, user) => {
|
||||
// if already subscribed
|
||||
const exist = await SwSubscriptions.findOne({
|
||||
createdAt: new Date(),
|
||||
userId: user.id,
|
||||
endpoint: ps.endpoint,
|
||||
auth: ps.auth,
|
||||
@ -45,6 +44,7 @@ export default define(meta, async (ps, user) => {
|
||||
|
||||
await SwSubscriptions.save({
|
||||
id: genId(),
|
||||
createdAt: new Date(),
|
||||
userId: user.id,
|
||||
endpoint: ps.endpoint,
|
||||
auth: ps.auth,
|
||||
|
@ -196,5 +196,5 @@ export default define(meta, async (ps, me) => {
|
||||
|
||||
const timeline = await query.take(ps.limit!).getMany();
|
||||
|
||||
return await Notes.packMany(timeline, user);
|
||||
return await Notes.packMany(timeline, me);
|
||||
});
|
||||
|
@ -23,7 +23,7 @@ export default class extends Channel {
|
||||
public onMessage(type: string, body: any) {
|
||||
switch (type) {
|
||||
case 'read':
|
||||
read(this.user!.id, this.otherpartyId, body.id);
|
||||
read(this.user!.id, this.otherpartyId, [body.id]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.2 KiB |
@ -21,12 +21,6 @@ app.use(async (ctx, next) => {
|
||||
// Init router
|
||||
const router = new Router();
|
||||
|
||||
router.get('/default-avatar.jpg', ctx => {
|
||||
const file = fs.createReadStream(`${__dirname}/assets/avatar.jpg`);
|
||||
ctx.set('Content-Type', 'image/jpeg');
|
||||
ctx.body = file;
|
||||
});
|
||||
|
||||
router.get('/app-default.jpg', ctx => {
|
||||
const file = fs.createReadStream(`${__dirname}/assets/dummy.png`);
|
||||
ctx.set('Content-Type', 'image/jpeg');
|
||||
|
@ -25,6 +25,8 @@ import Logger from '../services/logger';
|
||||
import { program } from '../argv';
|
||||
import { UserProfiles } from '../models';
|
||||
import { networkChart } from '../services/chart';
|
||||
import { genAvatar } from '../misc/gen-avatar';
|
||||
import { createTemp } from '../misc/create-temp';
|
||||
|
||||
export const serverLogger = new Logger('server', 'gray', false);
|
||||
|
||||
@ -72,6 +74,13 @@ router.use(activityPub.routes());
|
||||
router.use(nodeinfo.routes());
|
||||
router.use(wellKnown.routes());
|
||||
|
||||
router.get('/avatar/:x', async ctx => {
|
||||
const [temp] = await createTemp();
|
||||
await genAvatar(ctx.params.x, fs.createWriteStream(temp));
|
||||
ctx.set('Content-Type', 'image/png');
|
||||
ctx.body = fs.createReadStream(temp);
|
||||
});
|
||||
|
||||
router.get('/verify-email/:code', async ctx => {
|
||||
const profile = await UserProfiles.findOne({
|
||||
emailVerifyCode: ctx.params.code
|
||||
|
@ -8,7 +8,7 @@ html
|
||||
|
||||
head
|
||||
meta(charset='utf-8')
|
||||
meta(name='application-name' content= title || 'Misskey')
|
||||
meta(name='application-name' content='Misskey')
|
||||
meta(name='referrer' content='origin')
|
||||
meta(name='theme-color' content='#105779')
|
||||
meta(property='og:site_name' content= title || 'Misskey')
|
||||
|
@ -79,7 +79,7 @@ export default abstract class Chart<T extends Record<string, any>> {
|
||||
flatColumns(v.properties, p);
|
||||
} else {
|
||||
columns[this.columnPrefix + p] = {
|
||||
type: 'integer',
|
||||
type: 'bigint',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -209,10 +209,10 @@ async function deleteOldFile(user: IRemoteUser) {
|
||||
}
|
||||
|
||||
if (user.bannerId) {
|
||||
q.andWhere('file.id != :bannerId', { bannerId: user.bannerId })
|
||||
q.andWhere('file.id != :bannerId', { bannerId: user.bannerId });
|
||||
}
|
||||
|
||||
q.orderBy('file.id', 'DESC');
|
||||
q.orderBy('file.id', 'ASC');
|
||||
|
||||
const oldFile = await q.getOne();
|
||||
|
||||
|
@ -2,7 +2,7 @@ import * as Minio from 'minio';
|
||||
import config from '../../config';
|
||||
import { DriveFile } from '../../models/entities/drive-file';
|
||||
import { InternalStorage } from './internal-storage';
|
||||
import { DriveFiles, Instances } from '../../models';
|
||||
import { DriveFiles, Instances, Notes } from '../../models';
|
||||
import { driveChart, perUserDriveChart, instanceChart } from '../chart';
|
||||
|
||||
export default async function(file: DriveFile, isExpired = false) {
|
||||
@ -40,6 +40,11 @@ export default async function(file: DriveFile, isExpired = false) {
|
||||
});
|
||||
} else {
|
||||
DriveFiles.delete(file.id);
|
||||
|
||||
// TODO: トランザクション
|
||||
Notes.createQueryBuilder().delete()
|
||||
.where(':id = ANY(fileIds)', { id: file.id })
|
||||
.execute();
|
||||
}
|
||||
|
||||
// 統計を更新
|
||||
|
Reference in New Issue
Block a user