Compare commits

...

39 Commits
7.1.0 ... 7.2.0

Author SHA1 Message Date
82059d4fd9 7.2.0 2018-08-22 05:24:16 +09:00
07ddeae2f1 Clean up 2018-08-22 04:53:02 +09:00
f2279758b2 Merge pull request #2366 from acid-chicken/patch-autogen
[AUTOMATED] Update README.md
2018-08-22 03:30:12 +09:00
1ed189a518 Merge pull request #2386 from acid-chicken/patch-3
Update boot.js
2018-08-22 02:25:41 +09:00
137741d307 Update index.js 2018-08-22 01:52:13 +09:00
d702f6e090 Rename ja-ks.yml to ja-KS.yml 2018-08-22 01:51:42 +09:00
f33701233c Update boot.js 2018-08-22 01:50:13 +09:00
70003269e5 Update boot.js 2018-08-22 01:48:08 +09:00
61896d2386 Merge branch 'master' of https://github.com/syuilo/misskey 2018-08-22 01:46:13 +09:00
52d640c5a7 Fix 2018-08-22 01:46:10 +09:00
c65f5761e1 Merge pull request #2385 from mei23/mei-0821-aptype
ActivityPub で Content-Type を正しく扱う
2018-08-22 01:23:43 +09:00
3016ac4805 Fix bug 2018-08-22 01:02:56 +09:00
28a47cd331 Fix 2018-08-22 00:59:07 +09:00
6ecb88b0d1 #2338 2018-08-22 00:52:00 +09:00
8df1278c8e Merge branch 'master' of https://github.com/syuilo/misskey 2018-08-22 00:44:26 +09:00
52bec430d4 use ja-JP 2018-08-22 00:44:07 +09:00
da4cec8767 Merge pull request #2362 from syuilo/greenkeeper/vue-loader-15.4.0
Update vue-loader to the latest version 🚀
2018-08-22 00:11:24 +09:00
ad0087d7dd Merge pull request #2382 from syuilo/greenkeeper/webpack-4.17.0
Update webpack to the latest version 🚀
2018-08-22 00:11:12 +09:00
9630860035 Merge pull request #2383 from syuilo/greenkeeper/sharp-0.20.7
fix(package): update sharp to version 0.20.7
2018-08-22 00:11:01 +09:00
75e4c8d74d Better reponse 2018-08-21 23:56:15 +09:00
1a5ee81e7e fix(package): update sharp to version 0.20.7
Closes #2368
2018-08-21 11:18:21 +00:00
3476be16ab Merge pull request #2381 from mei23/mei-0821-apnote
ActivityPub Note/Outbox の公開範囲の修正
2018-08-21 20:07:33 +09:00
c42f61a0f4 fix(package): update webpack to version 4.17.0 2018-08-21 08:48:10 +00:00
b42a9e1c4e Set ActivityPub Content-Type 2018-08-21 13:48:03 +09:00
4495525705 Respect visibility in ActivityPub Note/Outbox 2018-08-21 13:22:30 +09:00
a603602f32 Clean up 2018-08-21 05:42:31 +09:00
fd947407af Revert "Fix bug?"
This reverts commit 2c9bacfcea.
2018-08-21 01:23:39 +09:00
30444e5f1a #2359 など 2018-08-21 01:03:58 +09:00
f0d818de24 Fix bug 2018-08-21 00:12:45 +09:00
3fb98e808f 7.1.2 2018-08-20 23:49:27 +09:00
2c9bacfcea Fix bug? 2018-08-20 23:49:00 +09:00
ae0284b1b1 Update README.md [AUTOGEN] 2018-08-20 19:03:01 +09:00
ec5aa10167 fix(package): update vue-loader to version 15.4.0 2018-08-20 00:44:56 +00:00
a542765cf8 Merge pull request #2352 from acid-chicken/patch-2
Update README.md
2018-08-20 07:45:35 +09:00
fd3f8d43db Merge pull request #2356 from acid-chicken/patch-3
Fix z-index
2018-08-20 07:44:57 +09:00
4f4496078a Update user.vue 2018-08-20 02:05:57 +09:00
8f4f5b4ce0 7.1.1 2018-08-20 01:42:56 +09:00
bdc6718ae5 Fix bug 2018-08-20 01:41:53 +09:00
09d1f1c20d Update README.md 2018-08-19 23:14:22 +09:00
26 changed files with 326 additions and 101 deletions

View File

@ -39,9 +39,15 @@ please see [Setup and installation guide](./docs/setup.en.md).
---------------------------------------------------------------- ----------------------------------------------------------------
**[PR](https://github.com/syuilo/misskey/pulls)s welcome!** **[PR](https://github.com/syuilo/misskey/pulls)s welcome!**
If you want to... ### i18n
* i18n ... please see [Translation guide](./docs/translate.en.md).
* l10n ... please visit https://crowdin.com/project/misskey Please see [Translation guide](./docs/translate.en.md).
### l10n
Misskey is using Crowdin for l10n.
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/misskey/localized.svg)](https://crowdin.com/project/misskey)
:heart: Backers & Sponsors :heart: Backers & Sponsors
---------------------------------------------------------------- ----------------------------------------------------------------
@ -53,8 +59,8 @@ If you want to...
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/3384329/8b713330cb27404ea6e9fac50ff96efe/1?token-time=2145916800&token-hash=0eu4-m1gTWA9PhptVZt6rdKcusqcD7RB87rJT23VVFI%3D" alt="べすれい"></td> <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/3384329/8b713330cb27404ea6e9fac50ff96efe/1?token-time=2145916800&token-hash=0eu4-m1gTWA9PhptVZt6rdKcusqcD7RB87rJT23VVFI%3D" alt="べすれい"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12021162/963128bb8d14476dbd8407943db8f31a/1?token-time=2145916800&token-hash=GgJ_NmUB6_nnRNLVGUWjV-WX91On7BOu59LKncYV9fE%3D" alt="gutfuckllc"></td> <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12021162/963128bb8d14476dbd8407943db8f31a/1?token-time=2145916800&token-hash=GgJ_NmUB6_nnRNLVGUWjV-WX91On7BOu59LKncYV9fE%3D" alt="gutfuckllc"></td>
<td><img src="https://c8.patreon.com/2/100/12718187" alt="Peter G."></td> <td><img src="https://c8.patreon.com/2/100/12718187" alt="Peter G."></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13039004/509d0c412eb14ae08d6a812a3054f7d6/1?token-time=2145916800&token-hash=zwSu01tOtn5xTUucDZHuPsCxF2HBEMVs9ROJKTlEV_o%3D" alt="nemu"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/2?token-time=2145916800&token-hash=zElv7ZcPL3viGsXbNG_KWiKrbV0vvw1gk0panx8DJoo%3D" alt="Naoki Kosaka"></td> <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/2?token-time=2145916800&token-hash=zElv7ZcPL3viGsXbNG_KWiKrbV0vvw1gk0panx8DJoo%3D" alt="Naoki Kosaka"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12931605/ead494101f364dffa90efe49e36fb494/1?token-time=2145916800&token-hash=NzSFPjIlodXyv41rwK61aZWVZWfI4surJaNj8vWKvqM%3D" alt="Reiju"></td>
</tr><tr> </tr><tr>
<td><a href="https://www.patreon.com/user?u=12378075">39ff</a></td> <td><a href="https://www.patreon.com/user?u=12378075">39ff</a></td>
<td><a href="https://www.patreon.com/user?u=12731202">negao</a></td> <td><a href="https://www.patreon.com/user?u=12731202">negao</a></td>
@ -62,22 +68,26 @@ If you want to...
<td><a href="https://www.patreon.com/user?u=3384329">べすれい</a></td> <td><a href="https://www.patreon.com/user?u=3384329">べすれい</a></td>
<td><a href="https://www.patreon.com/gutfuckllc">gutfuckllc</a></td> <td><a href="https://www.patreon.com/gutfuckllc">gutfuckllc</a></td>
<td><a href="https://www.patreon.com/user?u=12718187">Peter G.</a></td> <td><a href="https://www.patreon.com/user?u=12718187">Peter G.</a></td>
<td><a href="https://www.patreon.com/user?u=13039004">nemu</a></td>
<td><a href="https://www.patreon.com/user?u=5881381">Naoki Kosaka</a></td> <td><a href="https://www.patreon.com/user?u=5881381">Naoki Kosaka</a></td>
<td><a href="https://www.patreon.com/user?u=12931605">Reiju</a></td>
</tr></table> </tr></table>
<table><tr> <table><tr>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12931605/ead494101f364dffa90efe49e36fb494/1?token-time=2145916800&token-hash=NzSFPjIlodXyv41rwK61aZWVZWfI4surJaNj8vWKvqM%3D" alt="Reiju"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13034746/c711c7f58e204ecfbc2fd646bc8a4eee/1?token-time=2145916800&token-hash=UERBN4OyP7Nh5XwwdDg0N0IE5cD6_qUQMO81Z5Wizso%3D" alt="Hiratake"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb/1?token-time=2145916800&token-hash=S1zP0QyLU52Dqq6dtc9qNYyWfW86XrYHiR4NMbeOrnA%3D" alt="dansup"></td> <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb/1?token-time=2145916800&token-hash=S1zP0QyLU52Dqq6dtc9qNYyWfW86XrYHiR4NMbeOrnA%3D" alt="dansup"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/4950409/28e7d016209243759d9316be2e21381d/2?token-time=2145916800&token-hash=LuEaDkchH3GQWUcTOhBQ8xfKQYF0s5FjlZRd7Yduia8%3D" alt="mikan54951"></td> <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/4950409/28e7d016209243759d9316be2e21381d/2?token-time=2145916800&token-hash=LuEaDkchH3GQWUcTOhBQ8xfKQYF0s5FjlZRd7Yduia8%3D" alt="mikan54951"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12531784/93a45137841849329ba692da92ac7c60/1?token-time=2145916800&token-hash=tMosUojzUYJCH_3t--tvYA-SMCyrS__hzSndyaRSnbo%3D" alt="Takashi Shibuya"></td> <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12531784/93a45137841849329ba692da92ac7c60/1?token-time=2145916800&token-hash=tMosUojzUYJCH_3t--tvYA-SMCyrS__hzSndyaRSnbo%3D" alt="Takashi Shibuya"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12959468/c249e15aebec4424b5c0f427173671b6/1?token-time=2145916800&token-hash=lubpCEdxAkxPlpR2O6bvZ7BIh8Q4nGf-U_mE1qpjVAQ%3D" alt="fujishan"></td> <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12959468/c249e15aebec4424b5c0f427173671b6/1?token-time=2145916800&token-hash=lubpCEdxAkxPlpR2O6bvZ7BIh8Q4nGf-U_mE1qpjVAQ%3D" alt="fujishan"></td>
</tr><tr> </tr><tr>
<td><a href="https://www.patreon.com/user?u=12931605">Reiju</a></td>
<td><a href="https://www.patreon.com/hiratake">Hiratake</a></td>
<td><a href="https://www.patreon.com/dansup">dansup</a></td> <td><a href="https://www.patreon.com/dansup">dansup</a></td>
<td><a href="https://www.patreon.com/user?u=4950409">mikan54951</a></td> <td><a href="https://www.patreon.com/user?u=4950409">mikan54951</a></td>
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td> <td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
<td><a href="https://www.patreon.com/fujishan">fujishan</a></td> <td><a href="https://www.patreon.com/fujishan">fujishan</a></td>
</tr></table> </tr></table>
**Last updated:** Sat, 18 Aug 2018 02:02:58 UTC **Last updated:** Mon, 20 Aug 2018 10:02:31 UTC
<!-- PATREON_END --> <!-- PATREON_END -->
:four_leaf_clover: Copyright :four_leaf_clover: Copyright

View File

@ -11,12 +11,12 @@ If you find an untranslated part on Misskey:
- In fact, `foo` should be a word that is appropriate for the situation and is easy to understand in English. - In fact, `foo` should be a word that is appropriate for the situation and is easy to understand in English.
- For example, if the untranslated portion is the following "タイムライン" you must write: `%i18n:@timeline%`. - For example, if the untranslated portion is the following "タイムライン" you must write: `%i18n:@timeline%`.
3. Open the `locales/ja.yml`, check whether the <strong>file name (path)</strong> found in step 1 exists, if not, create it. 3. Open the `locales/ja-JP.yml`, check whether the <strong>file name (path)</strong> found in step 1 exists, if not, create it.
- Do not put the beginning of the path `src/client/app/` in the locale file. - Do not put the beginning of the path `src/client/app/` in the locale file.
- For example, in this case we want to modify untranslated parts of `src/client/app/mobile/views/pages/home.vue`, so the key is `mobile/views/pages/home.vue`. - For example, in this case we want to modify untranslated parts of `src/client/app/mobile/views/pages/home.vue`, so the key is `mobile/views/pages/home.vue`.
4. Add the text property using the `foo` keyword below the path that you found or created in step 2. Make sure to type your text in quotation marks. Text should always be inside of quotes. 4. Add the text property using the `foo` keyword below the path that you found or created in step 2. Make sure to type your text in quotation marks. Text should always be inside of quotes.
- For example, in this case we add timeline: `timeline: "タイムライン"` to `locales/ja.yml`. - For example, in this case we add timeline: `timeline: "タイムライン"` to `locales/ja-JP.yml`.
5. And done 5. And done

View File

@ -16,7 +16,7 @@ Si vous trouvez un segment non-traduit sur Misskey :
- Par exemple, dans ce cas de figure, nous voulons modifier le segment non-traduit de : `src/client/app/mobile/views/pages/home.vue`donc il faut juste écrire : `mobile/views/pages/home.vue` dans les fichiers linguistiques. - Par exemple, dans ce cas de figure, nous voulons modifier le segment non-traduit de : `src/client/app/mobile/views/pages/home.vue`donc il faut juste écrire : `mobile/views/pages/home.vue` dans les fichiers linguistiques.
4. Ajoutez la propriété du texte traduit grâce à la clef `foo`, en-dessous du chemin correspondant à votre modification que vous avez trouvé ou créé dans l'étape 2. À côté, veuillez indiquer entre "guillemets" la valeur de votre traduction. 4. Ajoutez la propriété du texte traduit grâce à la clef `foo`, en-dessous du chemin correspondant à votre modification que vous avez trouvé ou créé dans l'étape 2. À côté, veuillez indiquer entre "guillemets" la valeur de votre traduction.
- Par exemple, dans ce cas de figure, nous ajoutons la propriété et la traduction `timeline: "Timeline"` à `locales/fr.yml`, mais aussi la propriété et la version originale `timeline: "タイムライン"` à `locales/ja.yml`. - Par exemple, dans ce cas de figure, nous ajoutons la propriété et la traduction `timeline: "Timeline"` à `locales/fr.yml`, mais aussi la propriété et la version originale `timeline: "タイムライン"` à `locales/ja-JP.yml`.
5. Vous avez réussi à traduire une portion de misskey 5. Vous avez réussi à traduire une portion de misskey

View File

@ -11,12 +11,12 @@ Misskey内の未翻訳箇所を見つけたら
- `foo`は実際にはその場に適したわかりやすい(英語の)名前にしてください。 - `foo`は実際にはその場に適したわかりやすい(英語の)名前にしてください。
- 例えば未翻訳箇所が「タイムライン」というテキストだった場合、`%i18n:@timeline%`のようにします。 - 例えば未翻訳箇所が「タイムライン」というテキストだった場合、`%i18n:@timeline%`のようにします。
3. `locales/ja.yml`を開き、1.で見つけた<strong>ファイル名(パス)</strong>のキーが存在するか確認し、無ければ作成してください。 3. `locales/ja-JP.yml`を開き、1.で見つけた<strong>ファイル名(パス)</strong>のキーが存在するか確認し、無ければ作成してください。
- パスの`src/client/app/`は省略してください。 - パスの`src/client/app/`は省略してください。
- 例えば、今回の例では`src/client/app/mobile/views/pages/home.vue`の未翻訳箇所を修正したいので、キーは`mobile/views/pages/home.vue`になります。 - 例えば、今回の例では`src/client/app/mobile/views/pages/home.vue`の未翻訳箇所を修正したいので、キーは`mobile/views/pages/home.vue`になります。
4. そのキーの直下に2.で置換した`foo`の部分をキーとし、テキストを値とするプロパティを追加します。 4. そのキーの直下に2.で置換した`foo`の部分をキーとし、テキストを値とするプロパティを追加します。
- 例えば、今回の例で言うと`locales/ja.yml``timeline: "タイムライン"`を追加します。 - 例えば、今回の例で言うと`locales/ja-JP.yml``timeline: "タイムライン"`を追加します。
5. 完了です! 5. 完了です!

View File

@ -23,7 +23,6 @@ const uglifyes = require('uglify-es');
const locales = require('./locales'); const locales = require('./locales');
import { fa } from './src/misc/fa'; import { fa } from './src/misc/fa';
import config from './src/config';
const uglify = uglifyComposer(uglifyes, console); const uglify = uglifyComposer(uglifyes, console);
@ -118,7 +117,6 @@ gulp.task('build:client:script', () => {
const client = require('./built/client/meta.json'); const client = require('./built/client/meta.json');
return gulp.src(['./src/client/app/boot.js', './src/client/app/safe.js']) return gulp.src(['./src/client/app/boot.js', './src/client/app/safe.js'])
.pipe(replace('VERSION', JSON.stringify(client.version))) .pipe(replace('VERSION', JSON.stringify(client.version)))
.pipe(replace('API', JSON.stringify(config.api_url)))
.pipe(replace('ENV', JSON.stringify(env))) .pipe(replace('ENV', JSON.stringify(env)))
.pipe(replace('LANGS', JSON.stringify(Object.keys(locales)))) .pipe(replace('LANGS', JSON.stringify(Object.keys(locales))))
.pipe(isProduction ? uglify({ .pipe(isProduction ? uglify({

View File

@ -1,4 +1,4 @@
# **Please DO NOT edit these files** except `ja.yml`. # **Please DO NOT edit these files** except `ja-JP.yml`.
If you want to... If you want to...
* i18n ... please see [Translation guide](../docs/translate.en.md). * i18n ... please see [Translation guide](../docs/translate.en.md).

View File

@ -8,14 +8,14 @@ const yaml = require('js-yaml');
const loadLang = lang => yaml.safeLoad( const loadLang = lang => yaml.safeLoad(
fs.readFileSync(`${__dirname}/${lang}.yml`, 'utf-8')); fs.readFileSync(`${__dirname}/${lang}.yml`, 'utf-8'));
const native = loadLang('ja'); const native = loadLang('ja-JP');
const langs = { const langs = {
'de': loadLang('de'), 'de': loadLang('de'),
'en': loadLang('en'), 'en': loadLang('en'),
'fr': loadLang('fr'), 'fr': loadLang('fr'),
'ja': native, 'ja': native,
'ja-ks': loadLang('ja-ks'), 'ja-KS': loadLang('ja-KS'),
'pl': loadLang('pl'), 'pl': loadLang('pl'),
'es': loadLang('es') 'es': loadLang('es')
}; };

File diff suppressed because it is too large Load Diff

View File

@ -691,7 +691,6 @@ desktop/views/components/settings.vue:
password: "パスワード" password: "パスワード"
2fa: "二段階認証" 2fa: "二段階認証"
other: "その他" other: "その他"
license: "ライセンス"
behaviour: "動作" behaviour: "動作"
fetch-on-scroll: "スクロールで自動読み込み" fetch-on-scroll: "スクロールで自動読み込み"

View File

@ -1,8 +1,8 @@
{ {
"name": "misskey", "name": "misskey",
"author": "syuilo <i@syuilo.com>", "author": "syuilo <i@syuilo.com>",
"version": "7.1.0", "version": "7.2.0",
"clientVersion": "1.0.8685", "clientVersion": "1.0.8724",
"codename": "nighthike", "codename": "nighthike",
"main": "./built/index.js", "main": "./built/index.js",
"private": true, "private": true,
@ -181,7 +181,7 @@
"s-age": "1.1.2", "s-age": "1.1.2",
"sass-loader": "7.1.0", "sass-loader": "7.1.0",
"seedrandom": "2.4.4", "seedrandom": "2.4.4",
"sharp": "0.20.5", "sharp": "0.20.7",
"showdown": "1.8.6", "showdown": "1.8.6",
"showdown-highlightjs-extension": "0.1.2", "showdown-highlightjs-extension": "0.1.2",
"single-line-log": "1.1.2", "single-line-log": "1.1.2",
@ -208,7 +208,7 @@
"vue-cropperjs": "2.2.1", "vue-cropperjs": "2.2.1",
"vue-js-modal": "1.3.17", "vue-js-modal": "1.3.17",
"vue-json-tree-view": "2.1.4", "vue-json-tree-view": "2.1.4",
"vue-loader": "15.3.0", "vue-loader": "15.4.0",
"vue-router": "3.0.1", "vue-router": "3.0.1",
"vue-style-loader": "4.1.2", "vue-style-loader": "4.1.2",
"vue-template-compiler": "2.5.17", "vue-template-compiler": "2.5.17",
@ -217,7 +217,7 @@
"vuex-persistedstate": "2.5.4", "vuex-persistedstate": "2.5.4",
"web-push": "3.3.2", "web-push": "3.3.2",
"webfinger.js": "2.6.6", "webfinger.js": "2.6.6",
"webpack": "4.16.5", "webpack": "4.17.0",
"webpack-cli": "3.1.0", "webpack-cli": "3.1.0",
"websocket": "1.0.26", "websocket": "1.0.26",
"ws": "6.0.0", "ws": "6.0.0",

View File

@ -32,13 +32,15 @@
//#region Detect app name //#region Detect app name
let app = null; let app = null;
if (url.pathname == '/docs' || url.pathname.startsWith('/docs/')) app = 'docs'; if (`${url.pathname}/`.startsWith('/docs/')) app = 'docs';
if (url.pathname == '/dev' || url.pathname.startsWith('/dev/')) app = 'dev'; if (`${url.pathname}/`.startsWith('/dev/')) app = 'dev';
if (url.pathname == '/auth' || url.pathname.startsWith('/auth/')) app = 'auth'; if (`${url.pathname}/`.startsWith('/auth/')) app = 'auth';
//#endregion //#endregion
//#region Detect the user language //#region Detect the user language
let lang = navigator.language.split('-')[0]; let lang = navigator.language;
if (!LANGS.includes(lang)) lang = lang.split('-')[0];
// The default language is English // The default language is English
if (!LANGS.includes(lang)) lang = 'en'; if (!LANGS.includes(lang)) lang = 'en';
@ -104,7 +106,7 @@
// グローバルにタイマーIDを代入しておく // グローバルにタイマーIDを代入しておく
window.mkBootTimer = window.setTimeout(async () => { window.mkBootTimer = window.setTimeout(async () => {
// Fetch meta // Fetch meta
const res = await fetch(API + '/meta', { const res = await fetch('/api/meta', {
method: 'POST', method: 'POST',
cache: 'no-cache' cache: 'no-cache'
}); });

View File

@ -36,8 +36,7 @@ export default Vue.extend({
password: '', password: '',
token: '', token: '',
apiUrl, apiUrl,
host, host
twitterIntegration
}; };
}, },
methods: { methods: {

View File

@ -1,41 +1,43 @@
<template> <template>
<form class="mk-signup" @submit.prevent="onSubmit" :autocomplete="Math.random()"> <form class="mk-signup" @submit.prevent="onSubmit" :autocomplete="Math.random()">
<ui-input v-if="meta.disableRegistration" v-model="invitationCode" type="text" :autocomplete="Math.random()" spellcheck="false" required> <template v-if="meta">
<span>%i18n:@invitation-code%</span> <ui-input v-if="meta.disableRegistration" v-model="invitationCode" type="text" :autocomplete="Math.random()" spellcheck="false" required>
<span slot="prefix">%fa:id-card-alt%</span> <span>%i18n:@invitation-code%</span>
<p slot="text" v-html="'%i18n:@invitation-info%'.replace('{}', meta.maintainer.url)"></p> <span slot="prefix">%fa:id-card-alt%</span>
</ui-input> <p slot="text" v-html="'%i18n:@invitation-info%'.replace('{}', meta.maintainer.url)"></p>
<ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @input="onChangeUsername"> </ui-input>
<span>%i18n:@username%</span> <ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @input="onChangeUsername">
<span slot="prefix">@</span> <span>%i18n:@username%</span>
<span slot="suffix">@{{ host }}</span> <span slot="prefix">@</span>
<p slot="text" v-if="usernameState == 'wait'" style="color:#999">%fa:spinner .pulse .fw% %i18n:@checking%</p> <span slot="suffix">@{{ host }}</span>
<p slot="text" v-if="usernameState == 'ok'" style="color:#3CB7B5">%fa:check .fw% %i18n:@available%</p> <p slot="text" v-if="usernameState == 'wait'" style="color:#999">%fa:spinner .pulse .fw% %i18n:@checking%</p>
<p slot="text" v-if="usernameState == 'unavailable'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@unavailable%</p> <p slot="text" v-if="usernameState == 'ok'" style="color:#3CB7B5">%fa:check .fw% %i18n:@available%</p>
<p slot="text" v-if="usernameState == 'error'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@error%</p> <p slot="text" v-if="usernameState == 'unavailable'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@unavailable%</p>
<p slot="text" v-if="usernameState == 'invalid-format'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@invalid-format%</p> <p slot="text" v-if="usernameState == 'error'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@error%</p>
<p slot="text" v-if="usernameState == 'min-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-short%</p> <p slot="text" v-if="usernameState == 'invalid-format'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@invalid-format%</p>
<p slot="text" v-if="usernameState == 'max-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-long%</p> <p slot="text" v-if="usernameState == 'min-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-short%</p>
</ui-input> <p slot="text" v-if="usernameState == 'max-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-long%</p>
<ui-input v-model="password" type="password" :autocomplete="Math.random()" required @input="onChangePassword" :with-password-meter="true"> </ui-input>
<span>%i18n:@password%</span> <ui-input v-model="password" type="password" :autocomplete="Math.random()" required @input="onChangePassword" :with-password-meter="true">
<span slot="prefix">%fa:lock%</span> <span>%i18n:@password%</span>
<div slot="text"> <span slot="prefix">%fa:lock%</span>
<p slot="text" v-if="passwordStrength == 'low'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@weak-password%</p> <div slot="text">
<p slot="text" v-if="passwordStrength == 'medium'" style="color:#3CB7B5">%fa:check .fw% %i18n:@normal-password%</p> <p slot="text" v-if="passwordStrength == 'low'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@weak-password%</p>
<p slot="text" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw% %i18n:@strong-password%</p> <p slot="text" v-if="passwordStrength == 'medium'" style="color:#3CB7B5">%fa:check .fw% %i18n:@normal-password%</p>
</div> <p slot="text" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw% %i18n:@strong-password%</p>
</ui-input> </div>
<ui-input v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @input="onChangePasswordRetype"> </ui-input>
<span>%i18n:@password% (%i18n:@retype%)</span> <ui-input v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @input="onChangePasswordRetype">
<span slot="prefix">%fa:lock%</span> <span>%i18n:@password% (%i18n:@retype%)</span>
<div slot="text"> <span slot="prefix">%fa:lock%</span>
<p slot="text" v-if="passwordRetypeState == 'match'" style="color:#3CB7B5">%fa:check .fw% %i18n:@password-matched%</p> <div slot="text">
<p slot="text" v-if="passwordRetypeState == 'not-match'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@password-not-matched%</p> <p slot="text" v-if="passwordRetypeState == 'match'" style="color:#3CB7B5">%fa:check .fw% %i18n:@password-matched%</p>
</div> <p slot="text" v-if="passwordRetypeState == 'not-match'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@password-not-matched%</p>
</ui-input> </div>
<div v-if="meta && meta.recaptchaSitekey != null" class="g-recaptcha" :data-sitekey="meta.recaptchaSitekey" style="margin: 16px 0;"></div> </ui-input>
<ui-button type="submit">%i18n:@create%</ui-button> <div v-if="meta.recaptchaSitekey != null" class="g-recaptcha" :data-sitekey="meta.recaptchaSitekey" style="margin: 16px 0;"></div>
<ui-button type="submit">%i18n:@create%</ui-button>
</template>
</form> </form>
</template> </template>

View File

@ -4,7 +4,6 @@ declare const _THEME_COLOR_: string;
declare const _COPYRIGHT_: string; declare const _COPYRIGHT_: string;
declare const _VERSION_: string; declare const _VERSION_: string;
declare const _CODENAME_: string; declare const _CODENAME_: string;
declare const _LICENSE_: string;
const address = new URL(location.href); const address = new URL(location.href);
@ -19,4 +18,3 @@ export const themeColor = _THEME_COLOR_;
export const copyright = _COPYRIGHT_; export const copyright = _COPYRIGHT_;
export const version = _VERSION_; export const version = _VERSION_;
export const codename = _CODENAME_; export const codename = _CODENAME_;
export const license = _LICENSE_;

View File

@ -191,12 +191,6 @@
<button class="ui button block" @click="taskmngr">%i18n:@task-manager%</button> <button class="ui button block" @click="taskmngr">%i18n:@task-manager%</button>
</details> </details>
</section> </section>
<section class="other" v-show="page == 'other'">
<h1>%i18n:@license%</h1>
<div v-html="license"></div>
<a :href="licenseUrl" target="_blank">%i18n:@third-parties%</a>
</section>
</div> </div>
</div> </div>
</template> </template>
@ -211,7 +205,7 @@ import XApi from './settings.api.vue';
import XApps from './settings.apps.vue'; import XApps from './settings.apps.vue';
import XSignins from './settings.signins.vue'; import XSignins from './settings.signins.vue';
import XDrive from './settings.drive.vue'; import XDrive from './settings.drive.vue';
import { url, docsUrl, license, lang, langs, version } from '../../../config'; import { url, langs, version } from '../../../config';
import checkForUpdate from '../../../common/scripts/check-for-update'; import checkForUpdate from '../../../common/scripts/check-for-update';
import MkTaskManager from './taskmanager.vue'; import MkTaskManager from './taskmanager.vue';
@ -230,7 +224,6 @@ export default Vue.extend({
return { return {
page: 'profile', page: 'profile',
meta: null, meta: null,
license,
version, version,
langs, langs,
latestVersion: undefined, latestVersion: undefined,
@ -238,10 +231,6 @@ export default Vue.extend({
}; };
}, },
computed: { computed: {
licenseUrl(): string {
return `${docsUrl}/${lang}/license`;
},
apiViaStream: { apiViaStream: {
get() { return this.$store.state.device.apiViaStream; }, get() { return this.$store.state.device.apiViaStream; },
set(value) { this.$store.commit('device/set', { key: 'apiViaStream', value }); } set(value) { this.$store.commit('device/set', { key: 'apiViaStream', value }); }

View File

@ -247,7 +247,7 @@ root(isDark)
top 47px top 47px
box-shadow 0 4px 4px isDark ? rgba(#000, 0.3) : rgba(#000, 0.07) box-shadow 0 4px 4px isDark ? rgba(#000, 0.3) : rgba(#000, 0.07)
background-color $bg background-color $bg
z-index 1 z-index 2
> .nav-container > .nav-container
display flex display flex

View File

@ -118,6 +118,7 @@ export interface IRemoteUser extends IUserBase {
publicKeyPem: string; publicKeyPem: string;
}; };
updatedAt: Date; updatedAt: Date;
isAdmin: false;
} }
export type IUser = ILocalUser | IRemoteUser; export type IUser = ILocalUser | IRemoteUser;

View File

@ -41,10 +41,20 @@ function inbox(ctx: Router.IRouterContext) {
} }
function isActivityPubReq(ctx: Router.IRouterContext) { function isActivityPubReq(ctx: Router.IRouterContext) {
ctx.response.vary('Accept');
const accepted = ctx.accepts('html', 'application/activity+json', 'application/ld+json'); const accepted = ctx.accepts('html', 'application/activity+json', 'application/ld+json');
return ['application/activity+json', 'application/ld+json'].includes(accepted as string); return ['application/activity+json', 'application/ld+json'].includes(accepted as string);
} }
export function setResponseType(ctx: Router.IRouterContext) {
const accpet = ctx.accepts('application/activity+json', 'application/ld+json');
if (accpet === 'application/ld+json') {
ctx.response.type = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"; charset=utf-8';
} else {
ctx.response.type = 'application/activity+json; charset=utf-8';
}
}
// inbox // inbox
router.post('/inbox', json(), inbox); router.post('/inbox', json(), inbox);
router.post('/users/:user/inbox', json(), inbox); router.post('/users/:user/inbox', json(), inbox);
@ -54,7 +64,8 @@ router.get('/notes/:note', async (ctx, next) => {
if (!isActivityPubReq(ctx)) return await next(); if (!isActivityPubReq(ctx)) return await next();
const note = await Note.findOne({ const note = await Note.findOne({
_id: new mongo.ObjectID(ctx.params.note) _id: new mongo.ObjectID(ctx.params.note),
$or: [ { visibility: 'public' }, { visibility: 'home' } ]
}); });
if (note === null) { if (note === null) {
@ -62,7 +73,8 @@ router.get('/notes/:note', async (ctx, next) => {
return; return;
} }
ctx.body = pack(await renderNote(note)); ctx.body = pack(await renderNote(note, false));
setResponseType(ctx);
}); });
// outbox // outbox
@ -90,6 +102,7 @@ router.get('/users/:user/publickey', async ctx => {
if (isLocalUser(user)) { if (isLocalUser(user)) {
ctx.body = pack(renderKey(user)); ctx.body = pack(renderKey(user));
setResponseType(ctx);
} else { } else {
ctx.status = 400; ctx.status = 400;
} }
@ -103,6 +116,7 @@ async function userInfo(ctx: Router.IRouterContext, user: IUser) {
} }
ctx.body = pack(await renderPerson(user as ILocalUser)); ctx.body = pack(await renderPerson(user as ILocalUser));
setResponseType(ctx);
} }
router.get('/users/:user', async ctx => { router.get('/users/:user', async ctx => {

View File

@ -1,5 +1,5 @@
import * as mongo from 'mongodb'; import * as mongo from 'mongodb';
import * as Koa from 'koa'; import * as Router from 'koa-router';
import config from '../../config'; import config from '../../config';
import $ from 'cafy'; import ID from '../../misc/cafy-id'; import $ from 'cafy'; import ID from '../../misc/cafy-id';
import User from '../../models/user'; import User from '../../models/user';
@ -8,8 +8,9 @@ import pack from '../../remote/activitypub/renderer';
import renderOrderedCollection from '../../remote/activitypub/renderer/ordered-collection'; import renderOrderedCollection from '../../remote/activitypub/renderer/ordered-collection';
import renderOrderedCollectionPage from '../../remote/activitypub/renderer/ordered-collection-page'; import renderOrderedCollectionPage from '../../remote/activitypub/renderer/ordered-collection-page';
import renderFollowUser from '../../remote/activitypub/renderer/follow-user'; import renderFollowUser from '../../remote/activitypub/renderer/follow-user';
import { setResponseType } from '../activitypub';
export default async (ctx: Koa.Context) => { export default async (ctx: Router.IRouterContext) => {
const userId = new mongo.ObjectID(ctx.params.user); const userId = new mongo.ObjectID(ctx.params.user);
// Get 'cursor' parameter // Get 'cursor' parameter
@ -72,9 +73,11 @@ export default async (ctx: Koa.Context) => {
); );
ctx.body = pack(rendered); ctx.body = pack(rendered);
setResponseType(ctx);
} else { } else {
// index page // index page
const rendered = renderOrderedCollection(partOf, user.followersCount, `${partOf}?page=true`, null); const rendered = renderOrderedCollection(partOf, user.followersCount, `${partOf}?page=true`, null);
ctx.body = pack(rendered); ctx.body = pack(rendered);
setResponseType(ctx);
} }
}; };

View File

@ -1,5 +1,5 @@
import * as mongo from 'mongodb'; import * as mongo from 'mongodb';
import * as Koa from 'koa'; import * as Router from 'koa-router';
import config from '../../config'; import config from '../../config';
import $ from 'cafy'; import ID from '../../misc/cafy-id'; import $ from 'cafy'; import ID from '../../misc/cafy-id';
import User from '../../models/user'; import User from '../../models/user';
@ -8,8 +8,9 @@ import pack from '../../remote/activitypub/renderer';
import renderOrderedCollection from '../../remote/activitypub/renderer/ordered-collection'; import renderOrderedCollection from '../../remote/activitypub/renderer/ordered-collection';
import renderOrderedCollectionPage from '../../remote/activitypub/renderer/ordered-collection-page'; import renderOrderedCollectionPage from '../../remote/activitypub/renderer/ordered-collection-page';
import renderFollowUser from '../../remote/activitypub/renderer/follow-user'; import renderFollowUser from '../../remote/activitypub/renderer/follow-user';
import { setResponseType } from '../activitypub';
export default async (ctx: Koa.Context) => { export default async (ctx: Router.IRouterContext) => {
const userId = new mongo.ObjectID(ctx.params.user); const userId = new mongo.ObjectID(ctx.params.user);
// Get 'cursor' parameter // Get 'cursor' parameter
@ -72,9 +73,11 @@ export default async (ctx: Koa.Context) => {
); );
ctx.body = pack(rendered); ctx.body = pack(rendered);
setResponseType(ctx);
} else { } else {
// index page // index page
const rendered = renderOrderedCollection(partOf, user.followingCount, `${partOf}?page=true`, null); const rendered = renderOrderedCollection(partOf, user.followingCount, `${partOf}?page=true`, null);
ctx.body = pack(rendered); ctx.body = pack(rendered);
setResponseType(ctx);
} }
}; };

View File

@ -1,16 +1,17 @@
import * as mongo from 'mongodb'; import * as mongo from 'mongodb';
import * as Koa from 'koa'; import * as Router from 'koa-router';
import config from '../../config'; import config from '../../config';
import $ from 'cafy'; import ID from '../../misc/cafy-id'; import $ from 'cafy'; import ID from '../../misc/cafy-id';
import User from '../../models/user'; import User from '../../models/user';
import pack from '../../remote/activitypub/renderer'; import pack from '../../remote/activitypub/renderer';
import renderOrderedCollection from '../../remote/activitypub/renderer/ordered-collection'; import renderOrderedCollection from '../../remote/activitypub/renderer/ordered-collection';
import renderOrderedCollectionPage from '../../remote/activitypub/renderer/ordered-collection-page'; import renderOrderedCollectionPage from '../../remote/activitypub/renderer/ordered-collection-page';
import { setResponseType } from '../activitypub';
import Note from '../../models/note'; import Note from '../../models/note';
import renderNote from '../../remote/activitypub/renderer/note'; import renderNote from '../../remote/activitypub/renderer/note';
export default async (ctx: Koa.Context) => { export default async (ctx: Router.IRouterContext) => {
const userId = new mongo.ObjectID(ctx.params.user); const userId = new mongo.ObjectID(ctx.params.user);
// Get 'sinceId' parameter // Get 'sinceId' parameter
@ -83,7 +84,7 @@ export default async (ctx: Koa.Context) => {
if (sinceId) notes.reverse(); if (sinceId) notes.reverse();
const renderedNotes = await Promise.all(notes.map(note => renderNote(note))); const renderedNotes = await Promise.all(notes.map(note => renderNote(note, false)));
const rendered = renderOrderedCollectionPage( const rendered = renderOrderedCollectionPage(
`${partOf}?page=true${sinceId ? `&since_id=${sinceId}` : ''}${untilId ? `&until_id=${untilId}` : ''}`, `${partOf}?page=true${sinceId ? `&since_id=${sinceId}` : ''}${untilId ? `&until_id=${untilId}` : ''}`,
user.notesCount, renderedNotes, partOf, user.notesCount, renderedNotes, partOf,
@ -92,6 +93,7 @@ export default async (ctx: Koa.Context) => {
); );
ctx.body = pack(rendered); ctx.body = pack(rendered);
setResponseType(ctx);
} else { } else {
// index page // index page
const rendered = renderOrderedCollection(partOf, user.notesCount, const rendered = renderOrderedCollection(partOf, user.notesCount,
@ -99,5 +101,6 @@ export default async (ctx: Koa.Context) => {
`${partOf}?page=true&since_id=000000000000000000000000` `${partOf}?page=true&since_id=000000000000000000000000`
); );
ctx.body = pack(rendered); ctx.body = pack(rendered);
setResponseType(ctx);
} }
}; };

View File

@ -1,6 +1,6 @@
import { performance } from 'perf_hooks'; import { performance } from 'perf_hooks';
import limitter from './limitter'; import limitter from './limitter';
import { IUser, isLocalUser } from '../../models/user'; import { IUser } from '../../models/user';
import { IApp } from '../../models/app'; import { IApp } from '../../models/app';
import endpoints from './endpoints'; import endpoints from './endpoints';
@ -21,7 +21,7 @@ export default (endpoint: string, user: IUser, app: IApp, data: any, file?: any)
return rej('YOUR_ACCOUNT_HAS_BEEN_SUSPENDED'); return rej('YOUR_ACCOUNT_HAS_BEEN_SUSPENDED');
} }
if (ep.meta.requireAdmin && !(isLocalUser(user) && user.isAdmin)) { if (ep.meta.requireAdmin && !user.isAdmin) {
return rej('YOU_ARE_NOT_ADMIN'); return rej('YOU_ARE_NOT_ADMIN');
} }

View File

@ -34,6 +34,10 @@ export default (params: any) => new Promise(async (res, rej) => {
return rej('user not found'); return rej('user not found');
} }
if (user.isAdmin) {
return rej('cannot suspend admin');
}
await User.findOneAndUpdate({ await User.findOneAndUpdate({
_id: user._id _id: user._id
}, { }, {

View File

@ -63,7 +63,7 @@ export default async (ctx: Koa.Context) => {
if (verified) { if (verified) {
signin(ctx, user); signin(ctx, user);
} else { } else {
ctx.throw(400, { ctx.throw(403, {
error: 'invalid token' error: 'invalid token'
}); });
} }
@ -71,7 +71,7 @@ export default async (ctx: Koa.Context) => {
signin(ctx, user); signin(ctx, user);
} }
} else { } else {
ctx.throw(400, { ctx.throw(403, {
error: 'incorrect password' error: 'incorrect password'
}); });
} }

View File

@ -11,13 +11,13 @@ export default async function(
subscriber: Xev, subscriber: Xev,
user: IUser user: IUser
) { ) {
const mute = await Mute.find({ muterId: user._id });
const mutedUserIds = mute.map(m => m.muteeId.toString());
// Subscribe stream // Subscribe stream
subscriber.on('hybrid-timeline', onEvent); subscriber.on('hybrid-timeline', onEvent);
subscriber.on(`hybrid-timeline:${user._id}`, onEvent); subscriber.on(`hybrid-timeline:${user._id}`, onEvent);
const mute = await Mute.find({ muterId: user._id });
const mutedUserIds = mute.map(m => m.muteeId.toString());
async function onEvent(note: any) { async function onEvent(note: any) {
//#region 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する //#region 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
if (mutedUserIds.indexOf(note.userId) != -1) { if (mutedUserIds.indexOf(note.userId) != -1) {

View File

@ -16,7 +16,6 @@ import I18nReplacer from './src/misc/i18n';
import { pattern as i18nPattern, replacement as i18nReplacement } from './webpack/i18n'; import { pattern as i18nPattern, replacement as i18nReplacement } from './webpack/i18n';
import { pattern as faPattern, replacement as faReplacement } from './src/misc/fa'; import { pattern as faPattern, replacement as faReplacement } from './src/misc/fa';
const constants = require('./src/const.json'); const constants = require('./src/const.json');
import { licenseHtml } from './src/misc/license';
const locales = require('./locales'); const locales = require('./locales');
const meta = require('./package.json'); const meta = require('./package.json');
@ -74,8 +73,7 @@ const consts = {
_VERSION_: version, _VERSION_: version,
_CODENAME_: codename, _CODENAME_: codename,
_LANG_: '%lang%', _LANG_: '%lang%',
_LANGS_: Object.keys(locales).map(l => [l, locales[l].meta.lang]), _LANGS_: Object.keys(locales).map(l => [l, locales[l].meta.lang])
_LICENSE_: licenseHtml
}; };
const _consts: { [ key: string ]: any } = {}; const _consts: { [ key: string ]: any } = {};