Compare commits

...

29 Commits

Author SHA1 Message Date
14b16b4733 10.77.0 2019-01-16 14:58:05 +09:00
256c216dfb インスタンス情報ページに各種タイムラインの有効/無効を表示 2019-01-16 14:57:01 +09:00
13cee2b4f5 Resolve #3896 2019-01-16 14:54:14 +09:00
eb45eeb1ae [Client] Resolve #3895 2019-01-16 14:46:54 +09:00
3154350b64 10.76.0 2019-01-16 11:41:40 +09:00
519c9c4499 インスタンス情報ページにユーザー数と投稿数を追加 2019-01-16 03:36:25 +09:00
c2f6b09969 disableLocalTimeline機能を強化
* ストリームだけではなくAPIも無効に
* モデレーターは無効の場合でも見れるように
* グローバルタイムラインも無効に(連合数が少ないインスタンスではグローバルタイムラインは実質的にローカルタイムラインと同一なので)
2019-01-16 02:30:55 +09:00
c8e2b22942 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-01-15 18:28:31 +09:00
f433182c4c Revert "Resolve #3813 (#3814)"
This reverts commit 96515c4544.
2019-01-15 18:28:11 +09:00
957392aaae Update minio requirement from 7.0.2 to 7.0.3 (#3888)
Updates the requirements on [minio](https://github.com/minio/minio-js) to permit the latest version.
- [Release notes](https://github.com/minio/minio-js/releases)
- [Commits](https://github.com/minio/minio-js/commits/7.0.3)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-01-15 10:41:16 +09:00
bd8d06e133 Update vue-i18n requirement from 8.6.0 to 8.7.0 (#3889)
Updates the requirements on [vue-i18n](https://github.com/kazupon/vue-i18n) to permit the latest version.
- [Release notes](https://github.com/kazupon/vue-i18n/releases)
- [Changelog](https://github.com/kazupon/vue-i18n/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/kazupon/vue-i18n/commits/v8.7.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-01-15 10:40:04 +09:00
c617b60f70 Correct some weird french translations in the docs. (#3884)
* Correct some weird french translations

* Update docker.fr.md

* Update setup.fr.md

* Update setup.fr.md

* Update docker.fr.md

* Update setup.fr.md
2019-01-14 06:08:33 +09:00
018837db0b Support SVG (#3883)
* Update add-file.ts

* Update package.json

* Revert "Update add-file.ts"

This reverts commit ba0fe83b54a44493447208dfb3cc304a60df6fdd.

* Update add-file.ts

* Update package.json

* Update add-file.ts

* Update add-file.ts

* Create image.svg

* Update api.ts
2019-01-13 18:21:10 +09:00
00d5fdfc13 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-01-12 19:31:03 +09:00
2debb0c2ca Provide instance description in info page 2019-01-12 19:30:56 +09:00
148d6737cc Grammatical Fixes (#3844)
Updated the README to read more naturally for English speakers.
2019-01-12 14:34:00 +09:00
c15cb8d28c Update chalk requirement from 2.4.1 to 2.4.2 (#3855)
Updates the requirements on [chalk](https://github.com/chalk/chalk) to permit the latest version.
- [Release notes](https://github.com/chalk/chalk/releases)
- [Commits](https://github.com/chalk/chalk/commits/v2.4.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-01-12 14:33:23 +09:00
1d5471db70 Update webpack-cli requirement from 3.1.2 to 3.2.1 (#3850)
Updates the requirements on [webpack-cli](https://github.com/webpack/webpack-cli) to permit the latest version.
- [Release notes](https://github.com/webpack/webpack-cli/releases)
- [Changelog](https://github.com/webpack/webpack-cli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-cli/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-01-12 14:32:42 +09:00
086b83c1fe Merge pull request #3851 from syuilo/dependabot/npm_and_yarn/eslint-5.12.0
Update eslint requirement from 5.11.1 to 5.12.0
2019-01-12 14:32:29 +09:00
c509e0b86c Update ts-loader requirement from 5.3.1 to 5.3.3 (#3854)
Updates the requirements on [ts-loader](https://github.com/TypeStrong/ts-loader) to permit the latest version.
- [Release notes](https://github.com/TypeStrong/ts-loader/releases)
- [Changelog](https://github.com/TypeStrong/ts-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TypeStrong/ts-loader/commits/v5.3.3)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-01-12 14:32:20 +09:00
e8a1ad9823 Update chai-http requirement from 4.2.0 to 4.2.1 (#3856)
Updates the requirements on [chai-http](https://github.com/chaijs/chai-http) to permit the latest version.
- [Release notes](https://github.com/chaijs/chai-http/releases)
- [Changelog](https://github.com/chaijs/chai-http/blob/master/History.md)
- [Commits](https://github.com/chaijs/chai-http/commits/4.2.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-01-12 14:32:11 +09:00
6446b1cfb1 Update cssnano requirement from 4.1.7 to 4.1.8 (#3880)
Updates the requirements on [cssnano](https://github.com/cssnano/cssnano) to permit the latest version.
- [Release notes](https://github.com/cssnano/cssnano/releases)
- [Commits](https://github.com/cssnano/cssnano/commits/v4.1.8)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-01-12 14:32:03 +09:00
2b9216c441 Merge pull request #3866 from syuilo/dependabot/npm_and_yarn/@types/mongodb-3.1.18
Update @types/mongodb requirement from 3.1.14 to 3.1.18
2019-01-12 14:31:52 +09:00
28656a701f Merge pull request #3857 from syuilo/dependabot/npm_and_yarn/@types/showdown-1.9.1
Update @types/showdown requirement from 1.9.0 to 1.9.1
2019-01-12 14:31:43 +09:00
cd628eaf54 [MFM] Better hashtag parsing: Ignore trailing colon 2019-01-12 14:10:16 +09:00
53298933e4 Update @types/mongodb requirement from 3.1.14 to 3.1.18
Updates the requirements on [@types/mongodb](https://github.com/DefinitelyTyped/DefinitelyTyped) to permit the latest version.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-01-09 20:16:29 +00:00
e7cfae3ccb Update @types/showdown requirement from 1.9.0 to 1.9.1
Updates the requirements on [@types/showdown](https://github.com/DefinitelyTyped/DefinitelyTyped) to permit the latest version.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-01-08 20:29:07 +00:00
ebb03113ab Update ts-loader requirement from 5.3.1 to 5.3.3
Updates the requirements on [ts-loader](https://github.com/TypeStrong/ts-loader) to permit the latest version.
- [Release notes](https://github.com/TypeStrong/ts-loader/releases)
- [Changelog](https://github.com/TypeStrong/ts-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TypeStrong/ts-loader/commits/v5.3.3)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-01-08 20:19:39 +00:00
b3a0fe823e Update eslint requirement from 5.11.1 to 5.12.0
Updates the requirements on [eslint](https://github.com/eslint/eslint) to permit the latest version.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/commits/v5.12.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-01-08 10:15:52 +00:00
27 changed files with 162 additions and 74 deletions

View File

@ -1,6 +1,20 @@
ChangeLog ChangeLog
========= =========
10.77.0
----------
* ローカルタイムライン無効オプションをグローバルタイムライン無効オプションと分離
* モデレータはLTL無効時でもUIからLTLを消さない
* インスタンス情報ページに各種タイムラインの有効/無効を表示
10.76.0
----------
* disableLocalTimeline機能を強化
* インスタンス情報ページの強化
* ハッシュタグ判定の強化
* SVGサムネイルを表示するように
* CWの引き継ぎ機能を無効化
10.75.0 10.75.0
---------- ----------
* ダイレクトを非公開のように使えるように * ダイレクトを非公開のように使えるように

View File

@ -7,7 +7,7 @@
[![Dependencies](https://img.shields.io/david/syuilo/misskey.svg?style=for-the-badge)](https://david-dm.org/syuilo/misskey) [![Dependencies](https://img.shields.io/david/syuilo/misskey.svg?style=for-the-badge)](https://david-dm.org/syuilo/misskey)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=for-the-badge)](http://makeapullrequest.com) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=for-the-badge)](http://makeapullrequest.com)
**Sophisticated microblogging platform, evolving forever.** **A forever evolving, sophisticated microblogging platform.**
<p align="justify"> <p align="justify">
<a href="https://misskey.xyz">Misskey</a> is a decentralized microblogging platform born on Earth. <a href="https://misskey.xyz">Misskey</a> is a decentralized microblogging platform born on Earth.
@ -27,7 +27,7 @@ Why don't you take a short break from the hustle and bustle of the city, and div
<h3 align="left">Posting</h3> <h3 align="left">Posting</h3>
<p align="justify"> <p align="justify">
Just post your idea, hot topics and anything you want to share. You may decorate your words, attach your favorite pictures or movies, and create a poll - those are all supported in Misskey! Post your ideas, discussion topics, fun moments, or anything else you want to share! Misskey supports text, emoji, pictures, videos, and polls!
</p> </p>
--- ---
@ -36,7 +36,7 @@ Just post your idea, hot topics and anything you want to share. You may decorate
<h3 align="right">Reactions</h3> <h3 align="right">Reactions</h3>
<p align="justify"> <p align="justify">
The simplest way to tell your emotions to the posts. You can choose the best reaction from various reactions. Reactions on Misskey has much more expressive than other social media which only allows pushing “likes”. Reactions are the simplest way to respond to others' posts. Simply pick a reaction emote from the list! Reactions on Misskey are much more expressive than other social media services which only allow “liking”.
</p> </p>
--- ---
@ -45,7 +45,7 @@ The simplest way to tell your emotions to the posts. You can choose the best rea
<h3 align="left">Interface</h3> <h3 align="left">Interface</h3>
<p align="justify"> <p align="justify">
Highly customizable UI for your taste. We understand no UI fits for everyone. Make your graceful home by editing, adjusting layouts of timeline, and placing widgets. Customize the UI to your own tastes! No UI will work for everyone, so Misskey is completely customizable. Make Misskey *yours* by editing the style, adjusting timeline layouts, and placing widgets.
</p> </p>
--- ---
@ -54,20 +54,20 @@ Highly customizable UI for your taste. We understand no UI fits for everyone. Ma
<h3 align="right">Misskey Drive</h3> <h3 align="right">Misskey Drive</h3>
<p align="justify"> <p align="justify">
Organized uploaded files. Wanna post a picture you have already uploaded? Wish to create a folder for your files? Misskey Drive is the best solution for you. Organize and store your files! Want to post a picture you have already uploaded? Wish you could organize your files into folders? Misskey Drive is a solution!
</p> </p>
--- ---
and more! Now it's time to experience the world with your own eyes at [misskey.xyz](https://misskey.xyz) or [other instances](https://joinmisskey.github.io/). ...and more! Experience Misskey with your own eyes at [misskey.xyz](https://misskey.xyz) or join one of the [other instances](https://joinmisskey.github.io/) that are available.
:package: Create your own instance :package: Create Your Own Instance
---------------------------------------------------------------- ----------------------------------------------------------------
Please see [Setup and installation guide](./docs/setup.en.md). Please see the [Setup and Installation Guide](./docs/setup.en.md).
:wrench: Contribution :wrench: Contribution
---------------------------------------------------------------- ----------------------------------------------------------------
Please see [Contribution guide](./CONTRIBUTING.md). Please see the [Contribution Guide](./CONTRIBUTING.md).
:heart: Backers & Sponsors :heart: Backers & Sponsors
---------------------------------------------------------------- ----------------------------------------------------------------
@ -123,7 +123,7 @@ Please see [Contribution guide](./CONTRIBUTING.md).
---------------------------------------------------------------- ----------------------------------------------------------------
> Copyright (c) 2014-2019 syuilo > Copyright (c) 2014-2019 syuilo
Misskey is an open-source software licensed under the [GNU AGPLv3](LICENSE). Misskey is open-source software licensed under the [GNU AGPLv3](LICENSE).
[![][agpl-3.0-badge]][AGPL-3.0] [![][agpl-3.0-badge]][AGPL-3.0]

View File

@ -11,14 +11,14 @@ Ce guide explique comment installer et configurer Misskey avec Docker.
*1.* Télécharger Misskey *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. 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` Permet de se déplacer dans le dossier du dépôt. 2. `cd misskey` Naviguez dans le dossier du dépôt.
3. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` Checkout sur le tag de la [dernière version](https://github.com/syuilo/misskey/releases/latest). 3. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` Checkout sur le tag de la [dernière version](https://github.com/syuilo/misskey/releases/latest).
*2.* Configuration de Misskey *2.* Configuration de Misskey
---------------------------------------------------------------- ----------------------------------------------------------------
1. `cp .config/example.yml .config/default.yml` Copie le fichier `.config/example.yml` et le renommer en `default.yml`. 1. `cp .config/example.yml .config/default.yml` Copiez le fichier `.config/example.yml` et renommez-le `default.yml`.
2. `cp .config/mongo_initdb_example.js .config/mongo_initdb.js` Copie le fichier `.config/mongo_initdb_example.js` et le renomme en `mongo_initdb.js`. 2. `cp .config/mongo_initdb_example.js .config/mongo_initdb.js` Copie le fichier `.config/mongo_initdb_example.js` et le renomme en `mongo_initdb.js`.
3. Editer `default.yml` et `mongo_initdb.js`. 3. Editez `default.yml` et `mongo_initdb.js`.
*3.* Configurer Docker *3.* Configurer Docker
---------------------------------------------------------------- ----------------------------------------------------------------

View File

@ -10,8 +10,8 @@ Ce guide décrit les étapes à suivre afin d'installer et de configurer une ins
*1.* Création de l'utilisateur Misskey *1.* Création de l'utilisateur Misskey
---------------------------------------------------------------- ----------------------------------------------------------------
Lancer misskey en tant qu'utilisateur est une mauvaise idée, nous avons besoin de créer un utilisateur dédié. Executer misskey en tant que super-utilisateur étant une mauvaise idée, nous allons créer un utilisateur dédié.
Sur Debian, à titre d'exemple : Sous Debian, par exemple :
``` ```
adduser --disabled-password --disabled-login misskey adduser --disabled-password --disabled-login misskey
@ -32,10 +32,10 @@ Installez les paquets suivants :
*3.* Paramètrage de MongoDB *3.* Paramètrage de MongoDB
---------------------------------------------------------------- ----------------------------------------------------------------
En mode root : En root :
1. `mongo` Accédez au shell de mango 1. `mongo` Ouvrez le shell mongo
2. `use misskey` Utilisez la base de données misskey 2. `use misskey` Utilisez la base de données misskey
3. `db.users.save( {dummy:"dummy"} )` Write dummy data to initialize the db. 3. `db.users.save( {dummy:"dummy"} )` Écrivez une donnée factice pour initialiser la base de données.
4. `db.createUser( { user: "misskey", pwd: "<password>", roles: [ { role: "readWrite", db: "misskey" } ] } )` Créez l'utilisateur misskey. 4. `db.createUser( { user: "misskey", pwd: "<password>", roles: [ { role: "readWrite", db: "misskey" } ] } )` Créez l'utilisateur misskey.
5. `exit` Vous avez terminé ! 5. `exit` Vous avez terminé !
@ -44,12 +44,12 @@ En mode root :
1. `su - misskey` Basculez vers l'utilisateur misskey. 1. `su - misskey` Basculez vers l'utilisateur misskey.
2. `git clone -b master git://github.com/syuilo/misskey.git` Clonez la branche master du dépôt misskey. 2. `git clone -b master git://github.com/syuilo/misskey.git` Clonez la branche master du dépôt misskey.
3. `cd misskey` Accédez au dossier misskey. 3. `cd misskey` Accédez au dossier misskey.
4. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` Télécharge la [version la plus récente](https://github.com/syuilo/misskey/releases/latest) 4. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` Checkout sur le tag de la [version la plus récente](https://github.com/syuilo/misskey/releases/latest)
5. `npm install` Installez les dépendances de misskey. 5. `npm install` Installez les dépendances de misskey.
*5.* Création du fichier de configuration *5.* Création du fichier de configuration
---------------------------------------------------------------- ----------------------------------------------------------------
1. `cp .config/example.yml .config/default.yml` Copiez le fichier `.config/example.yml` et renommez-le `default.yml`. 1. `cp .config/example.yml .config/default.yml` Copiez le fichier `.config/example.yml` et renommez-le`default.yml`.
2. Editez le fichier `default.yml` 2. Editez le fichier `default.yml`
*6.* Construction de Misskey *6.* Construction de Misskey
@ -59,7 +59,7 @@ Construisez Misskey comme ceci :
`npm run build` `npm run build`
Si vous êtes sous Debian, vous serez amené à installer les paquets `build-essential`, `python`. Si vous êtes sous Debian, vous serez amené à installer les paquets `build-essential` et `python`.
Si vous rencontrez des erreurs concernant certains modules, utilisez node-gyp: Si vous rencontrez des erreurs concernant certains modules, utilisez node-gyp:
@ -77,7 +77,7 @@ Lancez tout simplement `npm start`. Bonne chance et amusez-vous bien !
### Démarrage avec systemd ### Démarrage avec systemd
1. Créez une 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 : 2. Editez-le puis copiez et coller ceci dans le fichier :
``` ```

View File

@ -1163,6 +1163,7 @@ admin/views/instance.vue:
max-note-text-length: "投稿の最大文字数" max-note-text-length: "投稿の最大文字数"
disable-registration: "ユーザー登録の受付を停止する" disable-registration: "ユーザー登録の受付を停止する"
disable-local-timeline: "ローカルタイムラインを無効にする" disable-local-timeline: "ローカルタイムラインを無効にする"
disable-global-timeline: "グローバルタイムラインを無効にする"
invite: "招待" invite: "招待"
save: "保存" save: "保存"
saved: "保存しました" saved: "保存しました"

View File

@ -1,8 +1,8 @@
{ {
"name": "misskey", "name": "misskey",
"author": "syuilo <i@syuilo.com>", "author": "syuilo <i@syuilo.com>",
"version": "10.75.0", "version": "10.77.0",
"clientVersion": "2.0.13368", "clientVersion": "2.0.13397",
"codename": "nighthike", "codename": "nighthike",
"main": "./built/index.js", "main": "./built/index.js",
"private": true, "private": true,
@ -43,6 +43,7 @@
"@types/gulp-uglify": "3.0.6", "@types/gulp-uglify": "3.0.6",
"@types/gulp-util": "3.0.34", "@types/gulp-util": "3.0.34",
"@types/is-root": "1.0.0", "@types/is-root": "1.0.0",
"@types/is-svg": "3.0.0",
"@types/is-url": "1.2.28", "@types/is-url": "1.2.28",
"@types/js-yaml": "3.11.4", "@types/js-yaml": "3.11.4",
"@types/katex": "0.5.0", "@types/katex": "0.5.0",
@ -60,7 +61,7 @@
"@types/minio": "7.0.1", "@types/minio": "7.0.1",
"@types/mkdirp": "0.5.2", "@types/mkdirp": "0.5.2",
"@types/mocha": "5.2.5", "@types/mocha": "5.2.5",
"@types/mongodb": "3.1.14", "@types/mongodb": "3.1.18",
"@types/ms": "0.7.30", "@types/ms": "0.7.30",
"@types/node": "10.12.18", "@types/node": "10.12.18",
"@types/nodemailer": "4.6.5", "@types/nodemailer": "4.6.5",
@ -76,7 +77,7 @@
"@types/rimraf": "2.0.2", "@types/rimraf": "2.0.2",
"@types/seedrandom": "2.4.27", "@types/seedrandom": "2.4.27",
"@types/sharp": "0.21.0", "@types/sharp": "0.21.0",
"@types/showdown": "1.9.0", "@types/showdown": "1.9.1",
"@types/speakeasy": "2.0.3", "@types/speakeasy": "2.0.3",
"@types/systeminformation": "3.23.1", "@types/systeminformation": "3.23.1",
"@types/tinycolor2": "1.4.1", "@types/tinycolor2": "1.4.1",
@ -96,12 +97,12 @@
"bootstrap-vue": "2.0.0-rc.11", "bootstrap-vue": "2.0.0-rc.11",
"cafy": "12.0.0", "cafy": "12.0.0",
"chai": "4.2.0", "chai": "4.2.0",
"chai-http": "4.2.0", "chalk": "2.4.2",
"chalk": "2.4.1", "chai-http": "4.2.1",
"commander": "2.19.0", "commander": "2.19.0",
"crc-32": "1.2.0", "crc-32": "1.2.0",
"css-loader": "1.0.1", "css-loader": "1.0.1",
"cssnano": "4.1.7", "cssnano": "4.1.8",
"dateformat": "3.0.3", "dateformat": "3.0.3",
"debug": "4.1.0", "debug": "4.1.0",
"deep-equal": "1.0.1", "deep-equal": "1.0.1",
@ -111,7 +112,7 @@
"elasticsearch": "15.2.0", "elasticsearch": "15.2.0",
"emojilib": "2.4.0", "emojilib": "2.4.0",
"escape-regexp": "0.0.1", "escape-regexp": "0.0.1",
"eslint": "5.11.1", "eslint": "5.12.0",
"eslint-plugin-vue": "5.0.0", "eslint-plugin-vue": "5.0.0",
"eventemitter3": "3.1.0", "eventemitter3": "3.1.0",
"feed": "2.0.2", "feed": "2.0.2",
@ -136,6 +137,7 @@
"http-signature": "1.2.0", "http-signature": "1.2.0",
"insert-text-at-cursor": "0.1.1", "insert-text-at-cursor": "0.1.1",
"is-root": "2.0.0", "is-root": "2.0.0",
"is-svg": "3.0.0",
"is-url": "1.2.4", "is-url": "1.2.4",
"js-yaml": "3.12.0", "js-yaml": "3.12.0",
"jsdom": "13.1.0", "jsdom": "13.1.0",
@ -157,7 +159,7 @@
"langmap": "0.0.16", "langmap": "0.0.16",
"loader-utils": "1.2.3", "loader-utils": "1.2.3",
"lookup-dns-cache": "2.1.0", "lookup-dns-cache": "2.1.0",
"minio": "7.0.2", "minio": "7.0.3",
"mkdirp": "0.5.1", "mkdirp": "0.5.1",
"mocha": "5.2.0", "mocha": "5.2.0",
"moji": "0.5.1", "moji": "0.5.1",
@ -210,7 +212,7 @@
"textarea-caret": "3.1.0", "textarea-caret": "3.1.0",
"tinycolor2": "1.4.1", "tinycolor2": "1.4.1",
"tmp": "0.0.33", "tmp": "0.0.33",
"ts-loader": "5.3.1", "ts-loader": "5.3.3",
"ts-node": "7.0.1", "ts-node": "7.0.1",
"tslint": "5.12.0", "tslint": "5.12.0",
"tslint-sonarts": "1.8.0", "tslint-sonarts": "1.8.0",
@ -224,7 +226,7 @@
"vue-color": "2.7.0", "vue-color": "2.7.0",
"vue-content-loading": "1.5.3", "vue-content-loading": "1.5.3",
"vue-cropperjs": "3.0.0", "vue-cropperjs": "3.0.0",
"vue-i18n": "8.6.0", "vue-i18n": "8.7.0",
"vue-js-modal": "1.3.28", "vue-js-modal": "1.3.28",
"vue-loader": "15.4.2", "vue-loader": "15.4.2",
"vue-marquee-text-component": "1.1.1", "vue-marquee-text-component": "1.1.1",
@ -240,7 +242,7 @@
"web-push": "3.3.3", "web-push": "3.3.3",
"webfinger.js": "2.7.0", "webfinger.js": "2.7.0",
"webpack": "4.28.3", "webpack": "4.28.3",
"webpack-cli": "3.1.2", "webpack-cli": "3.2.1",
"websocket": "1.0.28", "websocket": "1.0.28",
"ws": "6.1.2", "ws": "6.1.2",
"xev": "2.0.1" "xev": "2.0.1"

View File

@ -22,6 +22,7 @@
<section> <section>
<ui-switch v-model="disableRegistration">{{ $t('disable-registration') }}</ui-switch> <ui-switch v-model="disableRegistration">{{ $t('disable-registration') }}</ui-switch>
<ui-switch v-model="disableLocalTimeline">{{ $t('disable-local-timeline') }}</ui-switch> <ui-switch v-model="disableLocalTimeline">{{ $t('disable-local-timeline') }}</ui-switch>
<ui-switch v-model="disableGlobalTimeline">{{ $t('disable-global-timeline') }}</ui-switch>
</section> </section>
<section class="fit-bottom"> <section class="fit-bottom">
<header><fa icon="cloud"/> {{ $t('drive-config') }}</header> <header><fa icon="cloud"/> {{ $t('drive-config') }}</header>
@ -150,6 +151,7 @@ export default Vue.extend({
maintainerEmail: null, maintainerEmail: null,
disableRegistration: false, disableRegistration: false,
disableLocalTimeline: false, disableLocalTimeline: false,
disableGlobalTimeline: false,
mascotImageUrl: null, mascotImageUrl: null,
bannerUrl: null, bannerUrl: null,
errorImageUrl: null, errorImageUrl: null,
@ -198,6 +200,7 @@ export default Vue.extend({
this.maintainerEmail = meta.maintainer.email; this.maintainerEmail = meta.maintainer.email;
this.disableRegistration = meta.disableRegistration; this.disableRegistration = meta.disableRegistration;
this.disableLocalTimeline = meta.disableLocalTimeline; this.disableLocalTimeline = meta.disableLocalTimeline;
this.disableGlobalTimeline = meta.disableGlobalTimeline;
this.mascotImageUrl = meta.mascotImageUrl; this.mascotImageUrl = meta.mascotImageUrl;
this.bannerUrl = meta.bannerUrl; this.bannerUrl = meta.bannerUrl;
this.errorImageUrl = meta.errorImageUrl; this.errorImageUrl = meta.errorImageUrl;
@ -256,6 +259,7 @@ export default Vue.extend({
maintainerEmail: this.maintainerEmail, maintainerEmail: this.maintainerEmail,
disableRegistration: this.disableRegistration, disableRegistration: this.disableRegistration,
disableLocalTimeline: this.disableLocalTimeline, disableLocalTimeline: this.disableLocalTimeline,
disableGlobalTimeline: this.disableGlobalTimeline,
mascotImageUrl: this.mascotImageUrl, mascotImageUrl: this.mascotImageUrl,
bannerUrl: this.bannerUrl, bannerUrl: this.bannerUrl,
errorImageUrl: this.errorImageUrl, errorImageUrl: this.errorImageUrl,

View File

@ -222,12 +222,6 @@ export default Vue.extend({
}); });
} }
// keep cw when reply
if (this.reply && this.reply.cw != null) {
this.useCw = true;
this.cw = this.reply.cw;
}
this.$nextTick(() => { this.$nextTick(() => {
// 書きかけの投稿を復元 // 書きかけの投稿を復元
if (!this.instant && !this.mention) { if (!this.instant && !this.mention) {

View File

@ -4,7 +4,7 @@
<span :data-active="src == 'home'" @click="src = 'home'"><fa icon="home"/> {{ $t('home') }}</span> <span :data-active="src == 'home'" @click="src = 'home'"><fa icon="home"/> {{ $t('home') }}</span>
<span :data-active="src == 'local'" @click="src = 'local'" v-if="enableLocalTimeline"><fa :icon="['far', 'comments']"/> {{ $t('local') }}</span> <span :data-active="src == 'local'" @click="src = 'local'" v-if="enableLocalTimeline"><fa :icon="['far', 'comments']"/> {{ $t('local') }}</span>
<span :data-active="src == 'hybrid'" @click="src = 'hybrid'" v-if="enableLocalTimeline"><fa icon="share-alt"/> {{ $t('hybrid') }}</span> <span :data-active="src == 'hybrid'" @click="src = 'hybrid'" v-if="enableLocalTimeline"><fa icon="share-alt"/> {{ $t('hybrid') }}</span>
<span :data-active="src == 'global'" @click="src = 'global'"><fa icon="globe"/> {{ $t('global') }}</span> <span :data-active="src == 'global'" @click="src = 'global'" v-if="enableGlobalTimeline"><fa icon="globe"/> {{ $t('global') }}</span>
<span :data-active="src == 'tag'" @click="src = 'tag'" v-if="tagTl"><fa icon="hashtag"/> {{ tagTl.title }}</span> <span :data-active="src == 'tag'" @click="src = 'tag'" v-if="tagTl"><fa icon="hashtag"/> {{ tagTl.title }}</span>
<span :data-active="src == 'list'" @click="src = 'list'" v-if="list"><fa icon="list"/> {{ list.title }}</span> <span :data-active="src == 'list'" @click="src = 'list'" v-if="list"><fa icon="list"/> {{ list.title }}</span>
<div class="buttons"> <div class="buttons">
@ -43,7 +43,8 @@ export default Vue.extend({
src: 'home', src: 'home',
list: null, list: null,
tagTl: null, tagTl: null,
enableLocalTimeline: false enableLocalTimeline: false,
enableGlobalTimeline: false,
}; };
}, },
@ -65,7 +66,8 @@ export default Vue.extend({
created() { created() {
this.$root.getMeta().then(meta => { this.$root.getMeta().then(meta => {
this.enableLocalTimeline = !meta.disableLocalTimeline; this.enableLocalTimeline = !meta.disableLocalTimeline || this.$store.state.i.isModerator || this.$store.state.i.isAdmin;
this.enableGlobalTimeline = !meta.disableGlobalTimeline || this.$store.state.i.isModerator || this.$store.state.i.isAdmin;
}); });
if (this.$store.state.device.tl) { if (this.$store.state.device.tl) {

View File

@ -211,12 +211,6 @@ export default Vue.extend({
}); });
} }
// keep cw when reply
if (this.reply && this.reply.cw != null) {
this.useCw = true;
this.cw = this.reply.cw;
}
this.focus(); this.focus();
this.$nextTick(() => { this.$nextTick(() => {

View File

@ -31,7 +31,7 @@
<span :data-active="src == 'home'" @click="src = 'home'"><fa icon="home"/> {{ $t('home') }}</span> <span :data-active="src == 'home'" @click="src = 'home'"><fa icon="home"/> {{ $t('home') }}</span>
<span :data-active="src == 'local'" @click="src = 'local'" v-if="enableLocalTimeline"><fa :icon="['far', 'comments']"/> {{ $t('local') }}</span> <span :data-active="src == 'local'" @click="src = 'local'" v-if="enableLocalTimeline"><fa :icon="['far', 'comments']"/> {{ $t('local') }}</span>
<span :data-active="src == 'hybrid'" @click="src = 'hybrid'" v-if="enableLocalTimeline"><fa icon="share-alt"/> {{ $t('hybrid') }}</span> <span :data-active="src == 'hybrid'" @click="src = 'hybrid'" v-if="enableLocalTimeline"><fa icon="share-alt"/> {{ $t('hybrid') }}</span>
<span :data-active="src == 'global'" @click="src = 'global'"><fa icon="globe"/> {{ $t('global') }}</span> <span :data-active="src == 'global'" @click="src = 'global'" v-if="enableGlobalTimeline"><fa icon="globe"/> {{ $t('global') }}</span>
<div class="hr"></div> <div class="hr"></div>
<span :data-active="src == 'mentions'" @click="src = 'mentions'"><fa icon="at"/> {{ $t('mentions') }}<i class="badge" v-if="$store.state.i.hasUnreadMentions"><fa icon="circle"/></i></span> <span :data-active="src == 'mentions'" @click="src = 'mentions'"><fa icon="at"/> {{ $t('mentions') }}<i class="badge" v-if="$store.state.i.hasUnreadMentions"><fa icon="circle"/></i></span>
<span :data-active="src == 'messages'" @click="src = 'messages'"><fa :icon="['far', 'envelope']"/> {{ $t('messages') }}<i class="badge" v-if="$store.state.i.hasUnreadSpecifiedNotes"><fa icon="circle"/></i></span> <span :data-active="src == 'messages'" @click="src = 'messages'"><fa :icon="['far', 'envelope']"/> {{ $t('messages') }}<i class="badge" v-if="$store.state.i.hasUnreadSpecifiedNotes"><fa icon="circle"/></i></span>
@ -79,7 +79,8 @@ export default Vue.extend({
lists: null, lists: null,
tagTl: null, tagTl: null,
showNav: false, showNav: false,
enableLocalTimeline: false enableLocalTimeline: false,
enableGlobalTimeline: false,
}; };
}, },
@ -112,7 +113,8 @@ export default Vue.extend({
created() { created() {
this.$root.getMeta().then(meta => { this.$root.getMeta().then(meta => {
this.enableLocalTimeline = !meta.disableLocalTimeline; this.enableLocalTimeline = !meta.disableLocalTimeline || this.$store.state.i.isModerator || this.$store.state.i.isAdmin;
this.enableGlobalTimeline = !meta.disableGlobalTimeline || this.$store.state.i.isModerator || this.$store.state.i.isAdmin;
}); });
if (this.$store.state.device.tl) { if (this.$store.state.device.tl) {

View File

@ -205,7 +205,7 @@ const mfm = P.createLanguage({
hashtag: r => hashtag: r =>
P((input, i) => { P((input, i) => {
const text = input.substr(i); const text = input.substr(i);
const match = text.match(/^#([^\s\.,!\?#]+)/i); const match = text.match(/^#([^\s\.,!\?#:]+)/i);
if (!match) return P.makeFailure(i, 'not a hashtag'); if (!match) return P.makeFailure(i, 'not a hashtag');
let hashtag = match[1]; let hashtag = match[1];
hashtag = removeOrphanedBrackets(hashtag); hashtag = removeOrphanedBrackets(hashtag);

View File

@ -184,6 +184,7 @@ export type IMeta = {
disableRegistration?: boolean; disableRegistration?: boolean;
disableLocalTimeline?: boolean; disableLocalTimeline?: boolean;
disableGlobalTimeline?: boolean;
hidedTags?: string[]; hidedTags?: string[];
mascotImageUrl?: string; mascotImageUrl?: string;
bannerUrl?: string; bannerUrl?: string;

View File

@ -32,6 +32,13 @@ export const meta = {
} }
}, },
disableGlobalTimeline: {
validator: $.bool.optional.nullable,
desc: {
'ja-JP': 'グローバルタイムラインを無効にするか否か'
}
},
hidedTags: { hidedTags: {
validator: $.arr($.str).optional.nullable, validator: $.arr($.str).optional.nullable,
desc: { desc: {
@ -331,6 +338,10 @@ export default define(meta, (ps) => new Promise(async (res, rej) => {
set.disableLocalTimeline = ps.disableLocalTimeline; set.disableLocalTimeline = ps.disableLocalTimeline;
} }
if (typeof ps.disableGlobalTimeline === 'boolean') {
set.disableGlobalTimeline = ps.disableGlobalTimeline;
}
if (Array.isArray(ps.hidedTags)) { if (Array.isArray(ps.hidedTags)) {
set.hidedTags = ps.hidedTags; set.hidedTags = ps.hidedTags;
} }

View File

@ -59,6 +59,7 @@ export default define(meta, (ps, me) => new Promise(async (res, rej) => {
broadcasts: instance.broadcasts || [], broadcasts: instance.broadcasts || [],
disableRegistration: instance.disableRegistration, disableRegistration: instance.disableRegistration,
disableLocalTimeline: instance.disableLocalTimeline, disableLocalTimeline: instance.disableLocalTimeline,
disableGlobalTimeline: instance.disableGlobalTimeline,
driveCapacityPerLocalUserMb: instance.localDriveCapacityMb, driveCapacityPerLocalUserMb: instance.localDriveCapacityMb,
driveCapacityPerRemoteUserMb: instance.remoteDriveCapacityMb, driveCapacityPerRemoteUserMb: instance.remoteDriveCapacityMb,
cacheRemoteFiles: instance.cacheRemoteFiles, cacheRemoteFiles: instance.cacheRemoteFiles,
@ -81,6 +82,7 @@ export default define(meta, (ps, me) => new Promise(async (res, rej) => {
response.features = { response.features = {
registration: !instance.disableRegistration, registration: !instance.disableRegistration,
localTimeLine: !instance.disableLocalTimeline, localTimeLine: !instance.disableLocalTimeline,
globalTimeLine: !instance.disableGlobalTimeline,
elasticsearch: config.elasticsearch ? true : false, elasticsearch: config.elasticsearch ? true : false,
recaptcha: instance.enableRecaptcha, recaptcha: instance.enableRecaptcha,
objectStorage: config.drive && config.drive.storage === 'minio', objectStorage: config.drive && config.drive.storage === 'minio',

View File

@ -4,6 +4,7 @@ import Mute from '../../../../models/mute';
import { packMany } from '../../../../models/note'; import { packMany } from '../../../../models/note';
import define from '../../define'; import define from '../../define';
import { countIf } from '../../../../prelude/array'; import { countIf } from '../../../../prelude/array';
import fetchMeta from '../../../../misc/fetch-meta';
export const meta = { export const meta = {
desc: { desc: {
@ -51,6 +52,13 @@ export const meta = {
}; };
export default define(meta, (ps, user) => new Promise(async (res, rej) => { export default define(meta, (ps, user) => new Promise(async (res, rej) => {
const meta = await fetchMeta();
if (meta.disableGlobalTimeline) {
if (user == null || (!user.isAdmin && !user.isModerator)) {
return rej('global timeline disabled');
}
}
// Check if only one of sinceId, untilId, sinceDate, untilDate specified // Check if only one of sinceId, untilId, sinceDate, untilDate specified
if (countIf(x => x != null, [ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate]) > 1) { if (countIf(x => x != null, [ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate]) > 1) {
return rej('only one of sinceId, untilId, sinceDate, untilDate can be specified'); return rej('only one of sinceId, untilId, sinceDate, untilDate can be specified');

View File

@ -5,6 +5,7 @@ import { getFriends } from '../../common/get-friends';
import { packMany } from '../../../../models/note'; import { packMany } from '../../../../models/note';
import define from '../../define'; import define from '../../define';
import { countIf } from '../../../../prelude/array'; import { countIf } from '../../../../prelude/array';
import fetchMeta from '../../../../misc/fetch-meta';
export const meta = { export const meta = {
desc: { desc: {
@ -91,6 +92,11 @@ export const meta = {
}; };
export default define(meta, (ps, user) => new Promise(async (res, rej) => { export default define(meta, (ps, user) => new Promise(async (res, rej) => {
const meta = await fetchMeta();
if (meta.disableLocalTimeline && !user.isAdmin && !user.isModerator) {
return rej('local timeline disabled');
}
// Check if only one of sinceId, untilId, sinceDate, untilDate specified // Check if only one of sinceId, untilId, sinceDate, untilDate specified
if (countIf(x => x != null, [ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate]) > 1) { if (countIf(x => x != null, [ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate]) > 1) {
return rej('only one of sinceId, untilId, sinceDate, untilDate can be specified'); return rej('only one of sinceId, untilId, sinceDate, untilDate can be specified');

View File

@ -4,6 +4,7 @@ import Mute from '../../../../models/mute';
import { packMany } from '../../../../models/note'; import { packMany } from '../../../../models/note';
import define from '../../define'; import define from '../../define';
import { countIf } from '../../../../prelude/array'; import { countIf } from '../../../../prelude/array';
import fetchMeta from '../../../../misc/fetch-meta';
export const meta = { export const meta = {
desc: { desc: {
@ -66,6 +67,13 @@ export const meta = {
}; };
export default define(meta, (ps, user) => new Promise(async (res, rej) => { export default define(meta, (ps, user) => new Promise(async (res, rej) => {
const meta = await fetchMeta();
if (meta.disableLocalTimeline) {
if (user == null || (!user.isAdmin && !user.isModerator)) {
return rej('local timeline disabled');
}
}
// Check if only one of sinceId, untilId, sinceDate, untilDate specified // Check if only one of sinceId, untilId, sinceDate, untilDate specified
if (countIf(x => x != null, [ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate]) > 1) { if (countIf(x => x != null, [ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate]) > 1) {
return rej('only one of sinceId, untilId, sinceDate, untilDate can be specified'); return rej('only one of sinceId, untilId, sinceDate, untilDate can be specified');

View File

@ -3,6 +3,7 @@ import Mute from '../../../../models/mute';
import { pack } from '../../../../models/note'; import { pack } from '../../../../models/note';
import shouldMuteThisNote from '../../../../misc/should-mute-this-note'; import shouldMuteThisNote from '../../../../misc/should-mute-this-note';
import Channel from '../channel'; import Channel from '../channel';
import fetchMeta from '../../../../misc/fetch-meta';
export default class extends Channel { export default class extends Channel {
public readonly chName = 'globalTimeline'; public readonly chName = 'globalTimeline';
@ -13,6 +14,11 @@ export default class extends Channel {
@autobind @autobind
public async init(params: any) { public async init(params: any) {
const meta = await fetchMeta();
if (meta.disableGlobalTimeline) {
if (this.user == null || (!this.user.isAdmin && !this.user.isModerator)) return;
}
// Subscribe events // Subscribe events
this.subscriber.on('globalTimeline', this.onNote); this.subscriber.on('globalTimeline', this.onNote);

View File

@ -3,6 +3,7 @@ import Mute from '../../../../models/mute';
import { pack } from '../../../../models/note'; import { pack } from '../../../../models/note';
import shouldMuteThisNote from '../../../../misc/should-mute-this-note'; import shouldMuteThisNote from '../../../../misc/should-mute-this-note';
import Channel from '../channel'; import Channel from '../channel';
import fetchMeta from '../../../../misc/fetch-meta';
export default class extends Channel { export default class extends Channel {
public readonly chName = 'hybridTimeline'; public readonly chName = 'hybridTimeline';
@ -13,6 +14,9 @@ export default class extends Channel {
@autobind @autobind
public async init(params: any) { public async init(params: any) {
const meta = await fetchMeta();
if (meta.disableLocalTimeline && !this.user.isAdmin && !this.user.isModerator) return;
// Subscribe events // Subscribe events
this.subscriber.on('hybridTimeline', this.onNewNote); this.subscriber.on('hybridTimeline', this.onNewNote);
this.subscriber.on(`hybridTimeline:${this.user._id}`, this.onNewNote); this.subscriber.on(`hybridTimeline:${this.user._id}`, this.onNewNote);

View File

@ -3,6 +3,7 @@ import Mute from '../../../../models/mute';
import { pack } from '../../../../models/note'; import { pack } from '../../../../models/note';
import shouldMuteThisNote from '../../../../misc/should-mute-this-note'; import shouldMuteThisNote from '../../../../misc/should-mute-this-note';
import Channel from '../channel'; import Channel from '../channel';
import fetchMeta from '../../../../misc/fetch-meta';
export default class extends Channel { export default class extends Channel {
public readonly chName = 'localTimeline'; public readonly chName = 'localTimeline';
@ -13,6 +14,11 @@ export default class extends Channel {
@autobind @autobind
public async init(params: any) { public async init(params: any) {
const meta = await fetchMeta();
if (meta.disableLocalTimeline) {
if (this.user == null || (!this.user.isAdmin && !this.user.isModerator)) return;
}
// Subscribe events // Subscribe events
this.subscriber.on('localTimeline', this.onNote); this.subscriber.on('localTimeline', this.onNote);

View File

@ -65,6 +65,9 @@ html
tr tr
th Instance th Instance
td= meta.name td= meta.name
tr
th Description
td= meta.description
tr tr
th Maintainer th Maintainer
td td
@ -82,12 +85,24 @@ html
tr tr
th CPU th CPU
td= cpu.model td= cpu.model
tr
th Original users
td= meta.stats.originalUsersCount
tr
th Original notes
td= meta.stats.originalNotesCount
tr tr
th Registration th Registration
td= !meta.disableRegistration ? 'yes' : 'no' td= !meta.disableRegistration ? 'yes' : 'no'
tr tr
th reCAPTCHA enabled th reCAPTCHA enabled
td= meta.enableRecaptcha ? 'yes' : 'no' td= meta.enableRecaptcha ? 'enabled' : 'disabled'
tr
th LTL(STL) enabled
td= !meta.disableLocalTimeline ? 'enabled' : 'disabled'
tr
th GTL enabled
td= !meta.disableGlobalTimeline ? 'enabled' : 'disabled'
tr tr
th Cache remote files th Cache remote files
td= meta.cacheRemoteFiles ? 'yes' : 'no' td= meta.cacheRemoteFiles ? 'yes' : 'no'

View File

@ -4,10 +4,11 @@ import * as fs from 'fs';
import * as mongodb from 'mongodb'; import * as mongodb from 'mongodb';
import * as crypto from 'crypto'; import * as crypto from 'crypto';
import * as debug from 'debug'; import * as debug from 'debug';
import fileType = require('file-type');
import * as Minio from 'minio'; import * as Minio from 'minio';
import * as uuid from 'uuid'; import * as uuid from 'uuid';
import * as sharp from 'sharp'; import * as sharp from 'sharp';
import * as fileType from 'file-type';
import * as isSvg from 'is-svg';
import DriveFile, { IMetadata, getDriveFileBucket, IDriveFile } from '../../models/drive-file'; import DriveFile, { IMetadata, getDriveFileBucket, IDriveFile } from '../../models/drive-file';
import DriveFolder from '../../models/drive-folder'; import DriveFolder from '../../models/drive-folder';
@ -320,6 +321,8 @@ export default async function(
const type = fileType(buffer); const type = fileType(buffer);
if (type) { if (type) {
res([type.mime, type.ext]); res([type.mime, type.ext]);
} else if (isSvg(buffer)) {
res(['image/svg+xml', 'svg'])
} else { } else {
// 種類が同定できなかったら application/octet-stream にする // 種類が同定できなかったら application/octet-stream にする
res(['application/octet-stream', null]); res(['application/octet-stream', null]);

View File

@ -1,31 +1,17 @@
import * as mongo from 'mongodb'; import * as mongo from 'mongodb';
import redis from './db/redis'; import redis from './db/redis';
import Xev from 'xev'; import Xev from 'xev';
import { IMeta } from './models/meta';
import fetchMeta from './misc/fetch-meta';
type ID = string | mongo.ObjectID; type ID = string | mongo.ObjectID;
class Publisher { class Publisher {
private ev: Xev; private ev: Xev;
private meta: IMeta;
constructor() { constructor() {
// Redisがインストールされてないときはプロセス間通信を使う // Redisがインストールされてないときはプロセス間通信を使う
if (redis == null) { if (redis == null) {
this.ev = new Xev(); this.ev = new Xev();
} }
setInterval(async () => {
this.meta = await fetchMeta();
}, 5000);
}
public fetchMeta = async () => {
if (this.meta != null) return this.meta;
this.meta = await fetchMeta();
return this.meta;
} }
private publish = (channel: string, type: string, value?: any): void => { private publish = (channel: string, type: string, value?: any): void => {
@ -83,14 +69,10 @@ class Publisher {
} }
public publishLocalTimelineStream = async (note: any): Promise<void> => { public publishLocalTimelineStream = async (note: any): Promise<void> => {
const meta = await this.fetchMeta();
if (meta.disableLocalTimeline) return;
this.publish('localTimeline', null, note); this.publish('localTimeline', null, note);
} }
public publishHybridTimelineStream = async (userId: ID, note: any): Promise<void> => { public publishHybridTimelineStream = async (userId: ID, note: any): Promise<void> => {
const meta = await this.fetchMeta();
if (meta.disableLocalTimeline) return;
this.publish(userId ? `hybridTimeline:${userId}` : 'hybridTimeline', null, note); this.publish(userId ? `hybridTimeline:${userId}` : 'hybridTimeline', null, note);
} }

View File

@ -808,6 +808,20 @@ describe('API', () => {
expect(res).have.status(400); expect(res).have.status(400);
})); }));
it('SVGファイルを作成できる', async(async () => {
const izumi = await signup({ username: 'izumi' });
const res = await assert.request(server)
.post('/drive/files/create')
.field('i', izumi.token)
.attach('file', fs.readFileSync(__dirname + '/resources/image.svg'), 'image.svg');
expect(res).have.status(200);
expect(res.body).be.a('object');
expect(res.body).have.property('name').eql('image.svg');
expect(res.body).have.property('type').eql('image/svg+xml');
}));
}); });
describe('drive/files/update', () => { describe('drive/files/update', () => {

View File

@ -357,6 +357,14 @@ describe('MFM', () => {
]); ]);
}); });
it('ignore colon', () => {
const tokens = analyze('#Foo:');
assert.deepStrictEqual(tokens, [
leaf('hashtag', { hashtag: 'Foo' }),
text(':'),
]);
});
it('allow including number', () => { it('allow including number', () => {
const tokens = analyze('#foo123'); const tokens = analyze('#foo123');
assert.deepStrictEqual(tokens, [ assert.deepStrictEqual(tokens, [

1
test/resources/image.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><path fill="#FF40A4" d="M128 80c-16 4-20 24-20 48v16c0 8-8 16-20.3 8 4.3 20 24.3 28 40.3 24s20-24 20-48v-16c0-8 8-16 20.3-8C164 84 144 76 128 80"/><path fill="#FFBF40" d="M192 80c-16 4-20 24-20 48v16c0 8-8 16-20.3 8 4.3 20 24.3 28 40.3 24s20-24 20-48v-16c0-8 8-16 20.3-8C228 84 208 76 192 80"/><path fill="#408EFF" d="M64 80c-16 4-20 24-20 48v16c0 8-8 16-20.3 8C28 172 48 180 64 176s20-24 20-48v-16c0-8 8-16 20.3-8C100 84 80 76 64 80"/></svg>

After

Width:  |  Height:  |  Size: 505 B