diff --git a/.config/docker_example.env b/.config/docker_example.env new file mode 100644 index 000000000..411d93659 --- /dev/null +++ b/.config/docker_example.env @@ -0,0 +1,5 @@ +# db settings +POSTGRES_PASSWORD="example-misskey-pass" +POSTGRES_USER="example-misskey-user" +POSTGRES_DB="misskey" + diff --git a/.config/example.yml b/.config/example.yml index 70c096baa..48b1a0fd1 100644 --- a/.config/example.yml +++ b/.config/example.yml @@ -1,8 +1,16 @@ +#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Misskey configuration +#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +# ┌─────┐ +#───┘ URL └───────────────────────────────────────────────────── + # Final accessible URL seen by a user. url: https://example.tld/ +# ┌───────────────────────┐ +#───┘ Port and TLS settings └─────────────────────────────────── -### Port and TLS settings ###################################### # # Misskey supports two deployment options for public. # @@ -30,28 +38,51 @@ url: https://example.tld/ # You need to set Certificate in 'https' section. # To use option 1, uncomment below line. -# port: 3000 # A port that your Misskey server should listen. +#port: 3000 # A port that your Misskey server should listen. # To use option 2, uncomment below lines. -# port: 443 -# -# https: -# # path for certification -# key: /etc/letsencrypt/live/example.tld/privkey.pem -# cert: /etc/letsencrypt/live/example.tld/fullchain.pem +#port: 443 -################################################################ +#https: +# # path for certification +# key: /etc/letsencrypt/live/example.tld/privkey.pem +# cert: /etc/letsencrypt/live/example.tld/fullchain.pem +# ┌──────────────────────────┐ +#───┘ PostgreSQL configuration └──────────────────────────────── -mongodb: +db: host: localhost - port: 27017 + port: 5432 + + # Database name db: misskey + + # Auth user: example-misskey-user pass: example-misskey-pass +# ┌─────────────────────┐ +#───┘ Redis configuration └───────────────────────────────────── + +redis: + host: localhost + port: 6379 + #pass: example-pass + +# ┌─────────────────────────────┐ +#───┘ Elasticsearch configuration └───────────────────────────── + +#elasticsearch: +# host: localhost +# port: 9200 +# pass: null + +# ┌────────────────────────────────────┐ +#───┘ File storage (Drive) configuration └────────────────────── + drive: - storage: 'db' + storage: 'fs' # OR @@ -88,26 +119,28 @@ drive: # accessKey: XXX # secretKey: YYY +# ┌───────────────┐ +#───┘ ID generation └─────────────────────────────────────────── + +# You can select the ID generation method. +# You don't usually need to change this setting, but you can +# change it according to your preferences. + +# Available methods: +# aid ... Short, Millisecond accuracy +# meid ... Similar to ObjectID, Millisecond accuracy +# ulid ... Millisecond accuracy +# objectid ... This is left for backward compatibility + +id: 'aid' + +# ┌─────────────────────┐ +#───┘ Other configuration └───────────────────────────────────── + # If enabled: # The first account created is automatically marked as Admin. autoAdmin: true -# -# Below settings are optional -# - -# Redis -#redis: -# host: localhost -# port: 6379 -# pass: example-pass - -# Elasticsearch -#elasticsearch: -# host: localhost -# port: 9200 -# pass: null - # Whether disable HSTS #disableHsts: true diff --git a/.config/mongo_initdb_example.js b/.config/mongo_initdb_example.js deleted file mode 100644 index b7e7321f3..000000000 --- a/.config/mongo_initdb_example.js +++ /dev/null @@ -1,13 +0,0 @@ -var user = { - user: 'example-misskey-user', - pwd: 'example-misskey-pass', - roles: [ - { - role: 'readWrite', - db: 'misskey' - } - ] -}; - -db.createUser(user); - diff --git a/.dockerignore b/.dockerignore old mode 100755 new mode 100644 index a25d4e571..324c4bce5 --- a/.dockerignore +++ b/.dockerignore @@ -5,8 +5,8 @@ .vscode Dockerfile build/ +db/ docker-compose.yml -node_modules/ -mongo/ -redis/ elasticsearch/ +node_modules/ +redis/ diff --git a/.gitignore b/.gitignore index 6dd78fc97..650d4f612 100644 --- a/.gitignore +++ b/.gitignore @@ -8,14 +8,14 @@ built /data /.cache-loader +/db +/elasticsearch npm-debug.log *.pem run.bat api-docs.json *.log /redis -/mongo -/elasticsearch *.code-workspace yarn.lock .DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md index fc621a66c..e0aa4aad9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,32 @@ 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.0.0 (daybreak) +----------------- +* **データベースがMongoDBからPostgreSQLに変更されました** +* **Redisが必須に** +* アカウントを完全に削除できるように +* 投稿フォームで添付ファイルの閲覧注意を確認/設定できるように +* ミュート/ブロック時にそのユーザーの投稿のウォッチをすべて解除するように +* フォロー申請数が実際より1すくなくなる問題を修正 +* リストからアカウント削除したユーザーを削除できない問題を修正 +* リストTLでフォローしていないユーザーの非公開投稿が流れる問題を修正 +* リストTLでダイレクト投稿が流れない問題を修正 +* ミュートしているユーザーの投稿がタイムラインに流れてくることがある問題を修正 + +### APIの破壊的変更 +* v10時点で deprecated だったパラメータなどを削除 +* ユーザーリストの title が name に +* リバーシの対局の`settings`プロパティがなくなり、その中にあったプロパティがすべて上の階層に + * 例えば`game.settings.map`は`game.map`になる + +### 既知の問題 +* アプリが作成できない + * 依存ライブラリの問題と思わるため、対応が難しい + +### Migration +coming soon... + 10.100.0 ---------- * ユーザーリストでフォローボタンを表示するように diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c1ad1f804..6825225e0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -75,3 +75,95 @@ src ... Source code test ... Test code ``` + +## Notes +### placeholder +SQLをクエリビルダで組み立てる際、使用するプレースホルダは重複してはならない +例えば +``` ts +query.andWhere(new Brackets(qb => { + for (const type of ps.fileType) { + qb.orWhere(`:type = ANY(note.attachedFileTypes)`, { type: type }); + } +})); +``` +と書くと、ループ中で`type`というプレースホルダが複数回使われてしまいおかしくなる +だから次のようにする必要がある +```ts +query.andWhere(new Brackets(qb => { + for (const type of ps.fileType) { + const i = ps.fileType.indexOf(type); + qb.orWhere(`:type${i} = ANY(note.attachedFileTypes)`, { [`type${i}`]: type }); + } +})); +``` + +### `null` in SQL +SQLを発行する際、パラメータが`null`になる可能性のある場合はSQL文を出し分けなければならない +例えば +``` ts +query.where('file.folderId = :folderId', { folderId: ps.folderId }); +``` +という処理で、`ps.folderId`が`null`だと結果的に`file.folderId = null`のようなクエリが発行されてしまい、これは正しいSQLではないので期待した結果が得られない +だから次のようにする必要がある +``` ts +if (ps.folderId) { + query.where('file.folderId = :folderId', { folderId: ps.folderId }); +} else { + query.where('file.folderId IS NULL'); +} +``` + +### `[]` in SQL +SQLを発行する際、`IN`のパラメータが`[]`(空の配列)になる可能性のある場合はSQL文を出し分けなければならない +例えば +``` ts +const users = await Users.find({ + id: In(userIds) +}); +``` +という処理で、`userIds`が`[]`だと結果的に`user.id IN ()`のようなクエリが発行されてしまい、これは正しいSQLではないので期待した結果が得られない +だから次のようにする必要がある +``` ts +const users = userIds.length > 0 ? await Users.find({ + id: In(userIds) +}) : []; +``` + +### 配列のインデックス in SQL +SQLでは配列のインデックスは**1始まり**。 +`[a, b, c]`の `a`にアクセスしたいなら`[0]`ではなく`[1]`と書く + +### `undefined`にご用心 +MongoDBの時とは違い、findOneでレコードを取得する時に対象レコードが存在しない場合 **`undefined`** が返ってくるので注意。 +MongoDBは`null`で返してきてたので、その感覚で`if (x === null)`とか書くとバグる。代わりに`if (x == null)`と書いてください + +### 簡素な`undefined`チェック +データベースからレコードを取得するときに、プログラムの流れ的に(ほぼ)絶対`undefined`にはならない場合でも、`undefined`チェックしないとTypeScriptに怒られます。 +でもいちいち複数行を費やして、発生するはずのない`undefined`をチェックするのも面倒なので、`ensure`というユーティリティ関数を用意しています。 +例えば、 +``` ts +const user = await Users.findOne(userId); +// この時点で user の型は User | undefined +if (user == null) { + throw 'missing user'; +} +// この時点で user の型は User +``` +という処理を`ensure`を使うと +``` ts +const user = await Users.findOne(userId).then(ensure); +// この時点で user の型は User +``` +という風に書けます。 +もちろん`ensure`内部でエラーを握りつぶすようなことはしておらず、万が一`undefined`だった場合はPromiseがRejectされ後続の処理は実行されません。 +``` ts +const user = await Users.findOne(userId).then(ensure); +// 万が一 Users.findOne の結果が undefined だったら、ensure でエラーが発生するので +// この行に到達することは無い +// なので、.then(ensure) は +// if (user == null) { +// throw 'missing user'; +// } +// の糖衣構文のような扱いです +``` diff --git a/Dockerfile b/Dockerfile index ad04fb33d..ec7d8a6a2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,8 +23,9 @@ RUN apk add --no-cache \ zlib-dev RUN npm i -g yarn -COPY . ./ +COPY package.json ./ RUN yarn install +COPY . ./ RUN yarn build FROM base AS runner diff --git a/README.md b/README.md index 15b195fc8..6a6ef1deb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ - + [![Misskey](/assets/title.png)](https://misskey.xyz/) ================================================================ @@ -101,30 +101,33 @@ Please see the [Contribution Guide](./CONTRIBUTING.md). ---------------------------------------------------------------- - - + + - - + + + +
Hiroshi SekiweepHiroshi Sekiweep naga_rusMelilotosaponne_moniMelilotosapon 見当かなみ
Hiroshi Seki weep naga_rusne_moni Melilot osapon 見当かなみ
- - + + - + - + - + + @@ -134,18 +137,19 @@ Please see the [Contribution Guide](./CONTRIBUTING.md). +
gutfuckllcmydarkstargutfuckllcmydarkstar Peter G. itiradinemunemu sikyosyouninYUKIMOCHIYUKIMOCHI SampottakimuraSatsuki Yanagitakimura
gutfuckllc mydarkstarsikyosyounin YUKIMOCHI SampotSatsuki Yanagi takimura
- - - - - - - - - + + + + + + + + + @@ -157,8 +161,11 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
DamilloraAtsuko TominaganatalieHiratakeHekovicdansupGargronNokotaro TakedaTakashi ShibuyaDamilloraAtsuko TominaganatalieHiratakeHekovicdansupGargronNokotaro TakedaTakashi Shibuya
Damillora Atsuko TominagaNokotaro Takeda Takashi Shibuya
+ + +
-**Last updated:** Sat, 06 Apr 2019 03:35:05 UTC +**Last updated:** Sun, 14 Apr 2019 08:13:12 UTC :four_leaf_clover: Copyright diff --git a/cli/mark-admin.js b/cli/mark-admin.js deleted file mode 100644 index e10035fde..000000000 --- a/cli/mark-admin.js +++ /dev/null @@ -1,23 +0,0 @@ -const mongo = require('mongodb'); -const User = require('../built/models/user').default; - -const args = process.argv.slice(2); - -const user = args[0]; - -const q = user.startsWith('@') ? { - username: user.split('@')[1], - host: user.split('@')[2] || null -} : { _id: new mongo.ObjectID(user) }; - -console.log(`Mark as admin ${user}...`); - -User.update(q, { - $set: { - isAdmin: true - } -}).then(() => { - console.log(`Done ${user}`); -}, e => { - console.error(e); -}); diff --git a/cli/migration/2.0.0.js b/cli/migration/2.0.0.js deleted file mode 100644 index f7298972e..000000000 --- a/cli/migration/2.0.0.js +++ /dev/null @@ -1,57 +0,0 @@ -// for Node.js interpret - -const chalk = require('chalk'); -const sequential = require('promise-sequential'); - -const { default: User } = require('../../built/models/user'); -const { default: DriveFile } = require('../../built/models/drive-file'); - -async function main() { - const promiseGens = []; - - const count = await DriveFile.count({}); - - let prev; - - for (let i = 0; i < count; i++) { - promiseGens.push(() => { - const promise = new Promise(async (res, rej) => { - const file = await DriveFile.findOne(prev ? { - _id: { $gt: prev._id } - } : {}, { - sort: { - _id: 1 - } - }); - - prev = file; - - const user = await User.findOne({ _id: file.metadata.userId }); - - DriveFile.update({ - _id: file._id - }, { - $set: { - 'metadata._user': { - host: user.host - } - } - }).then(() => { - res([i, file]); - }).catch(rej); - }); - - promise.then(([i, file]) => { - console.log(chalk`{gray ${i}} {green done: {bold ${file._id}} ${file.filename}}`); - }); - - return promise; - }); - } - - return await sequential(promiseGens); -} - -main().then(() => { - console.log('ALL DONE'); -}).catch(console.error); diff --git a/cli/migration/2.4.0.js b/cli/migration/2.4.0.js deleted file mode 100644 index aa37849aa..000000000 --- a/cli/migration/2.4.0.js +++ /dev/null @@ -1,71 +0,0 @@ -// for Node.js interpret - -const chalk = require('chalk'); -const sequential = require('promise-sequential'); - -const { default: User } = require('../../built/models/user'); -const { default: DriveFile } = require('../../built/models/drive-file'); - -async function main() { - const promiseGens = []; - - const count = await User.count({}); - - let prev; - - for (let i = 0; i < count; i++) { - promiseGens.push(() => { - const promise = new Promise(async (res, rej) => { - const user = await User.findOne(prev ? { - _id: { $gt: prev._id } - } : {}, { - sort: { - _id: 1 - } - }); - - prev = user; - - const set = {}; - - if (user.avatarId != null) { - const file = await DriveFile.findOne({ _id: user.avatarId }); - - if (file && file.metadata.properties.avgColor) { - set.avatarColor = file.metadata.properties.avgColor; - } - } - - if (user.bannerId != null) { - const file = await DriveFile.findOne({ _id: user.bannerId }); - - if (file && file.metadata.properties.avgColor) { - set.bannerColor = file.metadata.properties.avgColor; - } - } - - if (Object.keys(set).length === 0) return res([i, user]); - - User.update({ - _id: user._id - }, { - $set: set - }).then(() => { - res([i, user]); - }).catch(rej); - }); - - promise.then(([i, user]) => { - console.log(chalk`{gray ${i}} {green done: {bold ${user._id}} @${user.username}}`); - }); - - return promise; - }); - } - - return await sequential(promiseGens); -} - -main().then(() => { - console.log('ALL DONE'); -}).catch(console.error); diff --git a/cli/migration/5.0.0.js b/cli/migration/5.0.0.js deleted file mode 100644 index bef103fe4..000000000 --- a/cli/migration/5.0.0.js +++ /dev/null @@ -1,9 +0,0 @@ -const { default: DriveFile } = require('../../built/models/drive-file'); - -DriveFile.update({}, { - $rename: { - 'metadata.isMetaOnly': 'metadata.withoutChunks' - } -}, { - multi: true -}); diff --git a/cli/migration/7.0.0.js b/cli/migration/7.0.0.js deleted file mode 100644 index fa5e363db..000000000 --- a/cli/migration/7.0.0.js +++ /dev/null @@ -1,134 +0,0 @@ -const { default: Stats } = require('../../built/models/stats'); -const { default: User } = require('../../built/models/user'); -const { default: Note } = require('../../built/models/note'); -const { default: DriveFile } = require('../../built/models/drive-file'); - -const now = new Date(); -const y = now.getFullYear(); -const m = now.getMonth(); -const d = now.getDate(); -const today = new Date(y, m, d); - -async function main() { - const localUsersCount = await User.count({ - host: null - }); - - const remoteUsersCount = await User.count({ - host: { $ne: null } - }); - - const localNotesCount = await Note.count({ - '_user.host': null - }); - - const remoteNotesCount = await Note.count({ - '_user.host': { $ne: null } - }); - - const localDriveFilesCount = await DriveFile.count({ - 'metadata._user.host': null - }); - - const remoteDriveFilesCount = await DriveFile.count({ - 'metadata._user.host': { $ne: null } - }); - - const localDriveFilesSize = await DriveFile - .aggregate([{ - $match: { - 'metadata._user.host': null, - 'metadata.deletedAt': { $exists: false } - } - }, { - $project: { - length: true - } - }, { - $group: { - _id: null, - usage: { $sum: '$length' } - } - }]) - .then(aggregates => { - if (aggregates.length > 0) { - return aggregates[0].usage; - } - return 0; - }); - - const remoteDriveFilesSize = await DriveFile - .aggregate([{ - $match: { - 'metadata._user.host': { $ne: null }, - 'metadata.deletedAt': { $exists: false } - } - }, { - $project: { - length: true - } - }, { - $group: { - _id: null, - usage: { $sum: '$length' } - } - }]) - .then(aggregates => { - if (aggregates.length > 0) { - return aggregates[0].usage; - } - return 0; - }); - - await Stats.insert({ - date: today, - users: { - local: { - total: localUsersCount, - diff: 0 - }, - remote: { - total: remoteUsersCount, - diff: 0 - } - }, - notes: { - local: { - total: localNotesCount, - diff: 0, - diffs: { - normal: 0, - reply: 0, - renote: 0 - } - }, - remote: { - total: remoteNotesCount, - diff: 0, - diffs: { - normal: 0, - reply: 0, - renote: 0 - } - } - }, - drive: { - local: { - totalCount: localDriveFilesCount, - totalSize: localDriveFilesSize, - diffCount: 0, - diffSize: 0 - }, - remote: { - totalCount: remoteDriveFilesCount, - totalSize: remoteDriveFilesSize, - diffCount: 0, - diffSize: 0 - } - } - }); - - console.log('done'); -} - -main(); diff --git a/cli/migration/8.0.0.js b/cli/migration/8.0.0.js deleted file mode 100644 index fd6cb2452..000000000 --- a/cli/migration/8.0.0.js +++ /dev/null @@ -1,144 +0,0 @@ -const { default: Stats } = require('../../built/models/stats'); -const { default: User } = require('../../built/models/user'); -const { default: Note } = require('../../built/models/note'); -const { default: DriveFile } = require('../../built/models/drive-file'); - -const now = new Date(); -const y = now.getFullYear(); -const m = now.getMonth(); -const d = now.getDate(); -const h = now.getHours(); -const date = new Date(y, m, d, h); - -async function main() { - await Stats.update({}, { - $set: { - span: 'day' - } - }, { - multi: true - }); - - const localUsersCount = await User.count({ - host: null - }); - - const remoteUsersCount = await User.count({ - host: { $ne: null } - }); - - const localNotesCount = await Note.count({ - '_user.host': null - }); - - const remoteNotesCount = await Note.count({ - '_user.host': { $ne: null } - }); - - const localDriveFilesCount = await DriveFile.count({ - 'metadata._user.host': null - }); - - const remoteDriveFilesCount = await DriveFile.count({ - 'metadata._user.host': { $ne: null } - }); - - const localDriveFilesSize = await DriveFile - .aggregate([{ - $match: { - 'metadata._user.host': null, - 'metadata.deletedAt': { $exists: false } - } - }, { - $project: { - length: true - } - }, { - $group: { - _id: null, - usage: { $sum: '$length' } - } - }]) - .then(aggregates => { - if (aggregates.length > 0) { - return aggregates[0].usage; - } - return 0; - }); - - const remoteDriveFilesSize = await DriveFile - .aggregate([{ - $match: { - 'metadata._user.host': { $ne: null }, - 'metadata.deletedAt': { $exists: false } - } - }, { - $project: { - length: true - } - }, { - $group: { - _id: null, - usage: { $sum: '$length' } - } - }]) - .then(aggregates => { - if (aggregates.length > 0) { - return aggregates[0].usage; - } - return 0; - }); - - await Stats.insert({ - date: date, - span: 'hour', - users: { - local: { - total: localUsersCount, - diff: 0 - }, - remote: { - total: remoteUsersCount, - diff: 0 - } - }, - notes: { - local: { - total: localNotesCount, - diff: 0, - diffs: { - normal: 0, - reply: 0, - renote: 0 - } - }, - remote: { - total: remoteNotesCount, - diff: 0, - diffs: { - normal: 0, - reply: 0, - renote: 0 - } - } - }, - drive: { - local: { - totalCount: localDriveFilesCount, - totalSize: localDriveFilesSize, - diffCount: 0, - diffSize: 0 - }, - remote: { - totalCount: remoteDriveFilesCount, - totalSize: remoteDriveFilesSize, - diffCount: 0, - diffSize: 0 - } - } - }); - - console.log('done'); -} - -main(); diff --git a/docker-compose.yml b/docker-compose.yml index 7ff8f6a26..12c7f514c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,8 +5,8 @@ services: build: . restart: always links: - - mongo -# - redis + - db + - redis # - es ports: - "127.0.0.1:3000:3000" @@ -14,26 +14,23 @@ services: - internal_network - external_network -# redis: -# restart: always -# image: redis:4.0-alpine -# networks: -# - internal_network -### Uncomment to enable Redis persistance -## volumes: -## - ./redis:/data - - mongo: + redis: restart: always - image: mongo:4.1 + image: redis:4.0-alpine networks: - internal_network - environment: - MONGO_INITDB_DATABASE: "misskey" volumes: - - ./.config/mongo_initdb.js:/docker-entrypoint-initdb.d/mongo_initdb.js:ro -### Uncomment to enable MongoDB persistance -# - ./mongo:/data + - ./redis:/data + + db: + restart: always + image: postgres:11.2-alpine + networks: + - internal_network + env_file: + - .config/docker.env + volumes: + - ./db:/var/lib/postgresql/data # es: # restart: always @@ -42,9 +39,8 @@ services: # - "ES_JAVA_OPTS=-Xms512m -Xmx512m" # networks: # - internal_network -#### Uncomment to enable ES persistence -## volumes: -## - ./elasticsearch:/usr/share/elasticsearch/data +# volumes: +# - ./elasticsearch:/usr/share/elasticsearch/data networks: internal_network: diff --git a/docs/backup.fr.md b/docs/backup.fr.md deleted file mode 100644 index 19e99068c..000000000 --- a/docs/backup.fr.md +++ /dev/null @@ -1,22 +0,0 @@ -Comment faire une sauvegarde de votre Misskey ? -========================== - -Assurez-vous d'avoir installé **mongodb-tools**. - ---- - -Dans votre terminal : -``` shell -$ mongodump --archive=db-backup -u -p -``` - -Pour plus de détails, merci de consulter [la documentation de mongodump](https://docs.mongodb.com/manual/reference/program/mongodump/). - -Restauration -------- - -``` shell -$ mongorestore --archive=db-backup -``` - -Pour plus de détails, merci de consulter [la documentation de mongorestore](https://docs.mongodb.com/manual/reference/program/mongorestore/). diff --git a/docs/backup.md b/docs/backup.md deleted file mode 100644 index a69af0255..000000000 --- a/docs/backup.md +++ /dev/null @@ -1,22 +0,0 @@ -How to backup your Misskey -========================== - -Make sure **mongodb-tools** installed. - ---- - -In your shell: -``` shell -$ mongodump --archive=db-backup -u -p -``` - -For details, please see [mongodump docs](https://docs.mongodb.com/manual/reference/program/mongodump/). - -Restore -------- - -``` shell -$ mongorestore --archive=db-backup -``` - -For details, please see [mongorestore docs](https://docs.mongodb.com/manual/reference/program/mongorestore/). diff --git a/docs/docker.en.md b/docs/docker.en.md index f0fcdb66d..1b607f9ea 100644 --- a/docs/docker.en.md +++ b/docs/docker.en.md @@ -11,13 +11,41 @@ This guide describes how to install and setup Misskey with Docker. ---------------------------------------------------------------- 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 -v 'rc[0-9]*$' | sort -V | tail -n 1)` Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest) tag. +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. *2.* Configure Misskey ---------------------------------------------------------------- -1. `cp .config/example.yml .config/default.yml` Copy the `.config/example.yml` and rename it to `default.yml`. -2. `cp .config/mongo_initdb_example.js .config/mongo_initdb.js` Copy the `.config/mongo_initdb_example.js` and rename it to `mongo_initdb.js`. -3. Edit `default.yml` and `mongo_initdb.js`. + +Create configuration files with following: + +```bash +cd .config +cp example.yml default.yml +cp docker_example.env docker.env +``` + +### `default.yml` + +Edit this file the same as non-Docker environment. +However hostname of Postgresql, Redis and Elasticsearch are not `localhost`, they are set in `docker-compose.yml`. +The following is default hostname: + +| Service | Hostname | +|---------------|----------| +| Postgresql | `db` | +| Redis | `redis` | +| Elasticsearch | `es` | + +### `docker.env` + +Configure Postgresql in this file. +The minimum required settings are: + +| name | Description | +|---------------------|---------------| +| `POSTGRES_PASSWORD` | Password | +| `POSTGRES_USER` | Username | +| `POSTGRES_DB` | Database name | *3.* Configure Docker ---------------------------------------------------------------- @@ -39,7 +67,7 @@ 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 -v 'rc[0-9]*$' | sort -V | tail -n 1)` +3. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` 4. `git stash pop` 5. `docker-compose build` 6. Check [ChangeLog](../CHANGELOG.md) for migration information diff --git a/docs/docker.fr.md b/docs/docker.fr.md index 8f7e9f429..e89a8f1b1 100644 --- a/docs/docker.fr.md +++ b/docs/docker.fr.md @@ -12,7 +12,7 @@ Ce guide explique comment installer et configurer Misskey avec Docker. ---------------------------------------------------------------- 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 -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 -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). *2.* Configuration de Misskey ---------------------------------------------------------------- @@ -40,7 +40,7 @@ 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 -v 'rc[0-9]*$' | sort -V | tail -n 1)` +3. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` 4. `git stash pop` 5. `docker-compose build` 6. Consultez le [ChangeLog](../CHANGELOG.md) pour avoir les éventuelles informations de migration diff --git a/docs/docker.ja.md b/docs/docker.ja.md index 0baf28572..ecc75fef2 100644 --- a/docs/docker.ja.md +++ b/docs/docker.ja.md @@ -11,13 +11,41 @@ Dockerを使った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 -v 'rc[0-9]*$' | sort -V | tail -n 1)` [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認 +3. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認 -*2.* 設定ファイルを作成する +*2.* 設定ファイルの作成と編集 ---------------------------------------------------------------- -1. `cp .config/example.yml .config/default.yml` `.config/example.yml`をコピーし名前を`default.yml`にする -2. `cp .config/mongo_initdb_example.js .config/mongo_initdb.js` `.config/mongo_initdb_example.js`をコピーし名前を`mongo_initdb.js`にする -3. `default.yml`と`mongo_initdb.js`を編集する + +下記コマンドで設定ファイルを作成してください。 + +```bash +cd .config +cp example.yml default.yml +cp docker_example.env docker.env +``` + +### `default.yml`の編集 + +非Docker環境と同じ様に編集してください。 +ただし、Postgresql、RedisとElasticsearchのホストは`localhost`ではなく、`docker-compose.yml`で設定されたサービス名になっています。 +標準設定では次の通りです。 + +| サービス | ホスト名 | +|---------------|---------| +| Postgresql |`db` | +| Redis |`redis` | +| Elasticsearch |`es` | + +### `docker.env`の編集 + +このファイルはPostgresqlの設定を記述します。 +最低限記述する必要がある設定は次の通りです。 + +| 設定 | 内容 | +|---------------------|--------------| +| `POSTGRES_PASSWORD` | パスワード | +| `POSTGRES_USER` | ユーザー名 | +| `POSTGRES_DB` | データベース名 | *3.* Dockerの設定 ---------------------------------------------------------------- @@ -39,7 +67,7 @@ Dockerを使ったMisskey構築方法 ### Misskeyを最新バージョンにアップデートする方法: 1. `git fetch` 2. `git stash` -3. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` +3. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` 4. `git stash pop` 5. `docker-compose build` 6. [ChangeLog](../CHANGELOG.md)でマイグレーション情報を確認する diff --git a/docs/setup.en.md b/docs/setup.en.md index 112508144..45e3e2c68 100644 --- a/docs/setup.en.md +++ b/docs/setup.en.md @@ -22,37 +22,28 @@ adduser --disabled-password --disabled-login misskey Please install and setup these softwares: #### Dependencies :package: -* **[Node.js](https://nodejs.org/en/)** >= 10.0.0 -* **[MongoDB](https://www.mongodb.com/)** >= 3.6 +* **[Node.js](https://nodejs.org/en/)** >= 11.7.0 +* **[PostgreSQL](https://www.postgresql.org/)** >= 10 +* **[Redis](https://redis.io/)** ##### Optional -* [Redis](https://redis.io/) - * Redis is optional, but we strongly recommended to install it * [Elasticsearch](https://www.elastic.co/) - required to enable the search feature * [FFmpeg](https://www.ffmpeg.org/) -*3.* Setup MongoDB ----------------------------------------------------------------- -As root: -1. `mongo` Go to the mongo shell -2. `use misskey` Use the misskey database -3. `db.createUser( { user: "misskey", pwd: "", roles: [ { role: "readWrite", db: "misskey" } ] } )` Create the misskey user. -4. `exit` You're done! - -*4.* Install Misskey +*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 -v 'rc[0-9]*$' | sort -V | tail -n 1)` Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest) +4. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest) 5. `npm install` Install misskey dependencies. -*5.* Configure Misskey +*4.* Configure Misskey ---------------------------------------------------------------- 1. `cp .config/example.yml .config/default.yml` Copy the `.config/example.yml` and rename it to `default.yml`. 2. Edit `default.yml` -*6.* Build Misskey +*5.* Build Misskey ---------------------------------------------------------------- Build misskey with the following: @@ -68,6 +59,12 @@ If you're still encountering errors about some modules, use node-gyp: 3. `node-gyp build` 4. `NODE_ENV=production npm run build` +*6.* Init DB +---------------------------------------------------------------- +``` shell +npm run init +``` + *7.* That is it. ---------------------------------------------------------------- Well done! Now, you have an environment that run to Misskey. @@ -107,7 +104,7 @@ 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 -v 'rc[0-9]*$' | sort -V | tail -n 1)` +2. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` 3. `npm install` 4. `NODE_ENV=production npm run build` 5. Check [ChangeLog](../CHANGELOG.md) for migration information diff --git a/docs/setup.fr.md b/docs/setup.fr.md index 959ec3392..e6d36aeff 100644 --- a/docs/setup.fr.md +++ b/docs/setup.fr.md @@ -22,37 +22,28 @@ adduser --disabled-password --disabled-login misskey Installez les paquets suivants : #### Dépendences :package: -* **[Node.js](https://nodejs.org/en/)** >= 10.0.0 -* **[MongoDB](https://www.mongodb.com/)** >= 3.6 +* **[Node.js](https://nodejs.org/en/)** >= 11.7.0 +* **[PostgreSQL](https://www.postgresql.org/)** >= 10 +* **[Redis](https://redis.io/)** ##### Optionnels -* [Redis](https://redis.io/) - * Redis est optionnel mais nous vous recommandons vivement de l'installer * [Elasticsearch](https://www.elastic.co/) - requis pour pouvoir activer la fonctionnalité de recherche * [FFmpeg](https://www.ffmpeg.org/) -*3.* Paramètrage de MongoDB ----------------------------------------------------------------- -En root : -1. `mongo` Ouvrez le shell mongo -2. `use misskey` Utilisez la base de données misskey -3. `db.createUser( { user: "misskey", pwd: "", roles: [ { role: "readWrite", db: "misskey" } ] } )` Créez l'utilisateur misskey. -4. `exit` Vous avez terminé ! - -*4.* Installation de Misskey +*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 -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) +4. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` Checkout sur le tag de la [version la plus récente](https://github.com/syuilo/misskey/releases/latest) 5. `npm install` Installez les dépendances de misskey. -*5.* Création du fichier de configuration +*4.* Création du fichier de configuration ---------------------------------------------------------------- 1. `cp .config/example.yml .config/default.yml` Copiez le fichier `.config/example.yml` et renommez-le`default.yml`. 2. Editez le fichier `default.yml` -*6.* Construction de Misskey +*5.* Construction de Misskey ---------------------------------------------------------------- Construisez Misskey comme ceci : @@ -68,7 +59,7 @@ Si vous rencontrez des erreurs concernant certains modules, utilisez node-gyp: 3. `node-gyp build` 4. `NODE_ENV=production npm run build` -*7.* C'est tout. +*6.* C'est tout. ---------------------------------------------------------------- Excellent ! Maintenant, vous avez un environnement prêt pour lancer Misskey @@ -107,7 +98,7 @@ Vous pouvez vérifier si le service a démarré en utilisant la commande `system ### Méthode de mise à jour vers la plus récente version de Misskey 1. `git fetch` -2. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` +2. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` 3. `npm install` 4. `NODE_ENV=production npm run build` 5. Consultez [ChangeLog](../CHANGELOG.md) pour les information de migration. diff --git a/docs/setup.ja.md b/docs/setup.ja.md index 8a21e104d..1b1730b69 100644 --- a/docs/setup.ja.md +++ b/docs/setup.ja.md @@ -22,44 +22,29 @@ adduser --disabled-password --disabled-login misskey これらのソフトウェアをインストール・設定してください: #### 依存関係 :package: -* **[Node.js](https://nodejs.org/en/)** (10.0.0以上) -* **[MongoDB](https://www.mongodb.com/)** (3.6以上) +* **[Node.js](https://nodejs.org/en/)** (11.7.0以上) +* **[PostgreSQL](https://www.postgresql.org/)** (10以上) +* **[Redis](https://redis.io/)** ##### オプション -* [Redis](https://redis.io/) - * Redisはオプションですが、インストールすることを強く推奨します。 - * インストールしなくていいのは、あなたのインスタンスが自分専用のときだけとお考えください。 - * 具体的には、Redisをインストールしないと、次の事が出来なくなります: - * Misskeyプロセスを複数起動しての負荷分散 - * レートリミット - * ジョブキュー - * Twitter連携 * [Elasticsearch](https://www.elastic.co/) * 検索機能を有効にするためにはインストールが必要です。 * [FFmpeg](https://www.ffmpeg.org/) -*3.* MongoDBの設定 ----------------------------------------------------------------- -ルートで: -1. `mongo` mongoシェルを起動 -2. `use misskey` misskeyデータベースを使用 -3. `db.createUser( { user: "misskey", pwd: "", roles: [ { role: "readWrite", db: "misskey" } ] } )` misskeyユーザーを作成 -4. `exit` mongoシェルを終了 - -*4.* 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 -v 'rc[0-9]*$' | sort -V | tail -n 1)` [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認 +4. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認 5. `npm install` Misskeyの依存パッケージをインストール -*5.* 設定ファイルを作成する +*4.* 設定ファイルを作成する ---------------------------------------------------------------- 1. `cp .config/example.yml .config/default.yml` `.config/example.yml`をコピーし名前を`default.yml`にする。 2. `default.yml` を編集する。 -*6.* Misskeyのビルド +*5.* Misskeyのビルド ---------------------------------------------------------------- 次のコマンドでMisskeyをビルドしてください: @@ -74,6 +59,12 @@ Debianをお使いであれば、`build-essential`パッケージをインスト 3. `node-gyp build` 4. `NODE_ENV=production npm run build` +*6.* データベースを初期化 +---------------------------------------------------------------- +``` shell +npm run init +``` + *7.* 以上です! ---------------------------------------------------------------- お疲れ様でした。これでMisskeyを動かす準備は整いました。 @@ -113,7 +104,7 @@ CentOSで1024以下のポートを使用してMisskeyを使用する場合は`Ex ### Misskeyを最新バージョンにアップデートする方法: 1. `git fetch` -2. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` +2. `git checkout $(git tag -l | grep -Ev -- '-(rc|alpha)\.[0-9]+$' | sort -V | tail -n 1)` 3. `npm install` 4. `NODE_ENV=production npm run build` 5. [ChangeLog](../CHANGELOG.md)でマイグレーション情報を確認する diff --git a/gulpfile.ts b/gulpfile.ts index b2956c240..2242843db 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -120,7 +120,7 @@ gulp.task('copy:client', () => ]) .pipe(isProduction ? (imagemin as any)() : gutil.noop()) .pipe(rename(path => { - path.dirname = path.dirname.replace('assets', '.'); + path.dirname = path.dirname!.replace('assets', '.'); })) .pipe(gulp.dest('./built/client/assets/')) ); diff --git a/index.js b/index.js index 5b7d1347a..bc7e8b2f3 100644 --- a/index.js +++ b/index.js @@ -1 +1 @@ -require('./built'); +require('./built').default(); diff --git a/locales/cs-CZ.yml b/locales/cs-CZ.yml index 34148c97d..eaba7edc7 100644 --- a/locales/cs-CZ.yml +++ b/locales/cs-CZ.yml @@ -20,7 +20,7 @@ common: outro: "Podívejte se na unikátní vlastnosti Misskey vlastníma očima! Pokud si myslíte, že tato instance není pro vás, zkuste jiné instance, neboť Misskey je decentralizovaná sociální síť, takže můžete snadno najít své přátele. Hodně štěstí a zábavy!" adblock: detected: "Prosím vypněte svůj blokovač reklam" - warning: "Misskey nepoužívá reklamy, některé vlastnosti však mohou být nedostupné nebo mohou způsobovat chyby, pokud máte povolený blokovač reklam." + warning: "Některé vlastnosti mohou být nedostupné nebo mohou způsobovat chyby, pokud máte povolený blokovač reklam. Misskey nepoužívá reklamy." application-authorization: "Autorizované aplikace" close: "Zavřít" do-not-copy-paste: "Prosím nezadávejte ani nevkládejte sem kód. Váš účet může být kompromitován." @@ -227,6 +227,7 @@ common: cancel: "Zrušit" update-available-title: "Aktualizace k dispozici" update-available: "Je k dispozici nová verze Misskey ({newer},vaše verze je {current}). Pro aplikování nové verze znovunačtěte stránku." + my-token-regenerated: "Váš token byl regenerován, proto budete odhlášen/a." verified-user: "Ověřené účty" hide-password: "Skrýt heslo" show-password: "Zobrazit heslo" @@ -281,12 +282,6 @@ common: auth/views/form.vue: share-access: "Chcete dovolit aplikaci {name} přístup k vašemu účtu?" permission-ask: "Tato aplikace vyžaduje následující oprávnění:" - account-read: "Zobrazit informace účtu" - note-write: "Odeslat." - following-write: "Sledovat a přestat sledovat" - drive-read: "Přečíst váš Disk" - notification-read: "Sledovat oznámení." - notification-write: "Zpravovat notifikace." cancel: "Zrušit" accept: "Povolit přístup" auth/views/index.vue: @@ -302,6 +297,7 @@ common/views/pages/explore.vue: popular-tags: "Populární tagy" federated: "Z fedivesmíru" explore: "Prozkoumat {host}" + users-info: "Aktuálně je zde registrováno {users} uživatelů" common/views/components/url-preview.vue: enable-player: "Otevřít v přehrávači" disable-player: "Zavřít přehrávač" @@ -354,19 +350,23 @@ common/views/components/connect-failed.troubleshooter.vue: no-network-desc: "Ujistěte se že jste připojeni k Internetu." no-internet: "Nejste připojeni k internetu" no-internet-desc: "Jste připojen k síti, ale zdá se že stále chybí připojení k Internetu. Prosím zkontrolujte Vaše připojení k Internetu." + no-server: "Nelze se připojit k serveru Misskey" common/views/components/media-banner.vue: click-to-show: "Klikněte pro zobrazení" common/views/components/theme.vue: - light-theme: "Šablona pro použití ve světlém vzhledu" - dark-theme: "Šablona pro použití v tmavém vzhledu" + light-theme: "Motiv pro použití ve světlém vzhledu" + dark-theme: "Motiv pro použití v tmavém vzhledu" light-themes: "Světlý vzhled" dark-themes: "Tmavý vzhled" - install-a-theme: "Nainstalovat šablonu" - theme-code: "Kód šablony" + install-a-theme: "Nainstalovat motiv" + theme-code: "Kód motivu" install: "Nainstalovat" installed: "\"{}\" byl nainstalován" create-a-theme: "Vytvořit motiv" + save-created-theme: "Uložit motiv" base-theme: "Základní vzhled" + base-theme-light: "Světlý" + base-theme-dark: "Tmavý" find-more-theme: "Najít další vzhledy" theme-name: "Jméno vzhledu" preview-created-theme: "Náhled" @@ -435,6 +435,7 @@ common/views/components/user-menu.vue: unblock: "Odblokovat" push-to-list: "Přidat do seznamu" select-list: "Vyberte seznam" + report-abuse: "Nahlásit spam" report-abuse-reported: "Problém byl nahlášen administrátorovi. Děkujeme za Vaší kooperaci." silence: "Ztlumit" suspend: "Zmrazit" @@ -793,8 +794,6 @@ desktop/views/components/settings.tags.vue: title: "Tagy" add: "Přidat" save: "Uložit" -desktop/views/components/taskmanager.vue: - title: "Správce úloh" desktop/views/components/timeline.vue: home: "Domů" local: "Lokální" @@ -839,7 +838,7 @@ admin/views/index.vue: emoji: "Emoji" moderators: "Moderátoři" users: "Uživatelé" - federation: "Federovaná" + federation: "Z fedivesmíru" announcements: "Oznámení" hashtags: "Hashtagy" queue: "Fronta úloh" @@ -851,7 +850,7 @@ admin/views/dashboard.vue: drive: "Disk" instances: "Instance" this-instance: "Tato instance" - federated: "Federovaná" + federated: "Z fedivesmíru" admin/views/abuse.vue: details: "Popis" remove-report: "Odstranit" @@ -1006,7 +1005,7 @@ admin/views/federation.vue: status: "Status" latest-request-received-at: "Poslední požadavek přijat" block: "Blokován" - instances: "Federovaná" + instances: "Z fedivesmíru" states: all: "Všechny" blocked: "Blokován" @@ -1184,10 +1183,3 @@ deck/deck.user-column.vue: dev/views/new-app.vue: app-name-desc: "Jméno vaší aplikace" app-desc: "Stručný popis nebo představení vaší aplikace." - account-read: "Zobrazit informace účtu" - note-write: "Odeslat." - reaction-write: "Přidat nebo odebrat reakce." - following-write: "Sledovat a přestat sledovat" - drive-read: "Přečíst váš Disk" - notification-read: "Sledovat oznámení." - notification-write: "Zpravovat notifikace." diff --git a/locales/de-DE.yml b/locales/de-DE.yml index 68b0b587a..0e83327af 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -138,13 +138,6 @@ common: auth/views/form.vue: share-access: "Erlaubst Du {name} auf deinen Account zuzugreifen?" permission-ask: "Diese Applikation benötigt folgende Berechtigungen:" - account-read: "Accountinformationen anzeigen." - account-write: "Accountinformationen bearbeiten." - note-write: "Senden." - like-write: "Auf Beiträge reagieren." - following-write: "Folgen oder entfolgen." - notification-read: "Siehe deine Benachrichtigungen." - notification-write: "Benachrichtigungen verwalten." cancel: "Abbrechen" accept: "Zugriff erlauben." auth/views/index.vue: @@ -478,7 +471,6 @@ desktop/views/components/post-form.vue: posting: "Posting" attach-media-from-local: "Medien von deinem PC hinzufügen" attach-media-from-drive: "Medien von deinem Speicher hinzufügen" - attach-cancel: "Hinzufügen abbrechen" create-poll: "Eine Abstimmung erstellen" text-remain: "{} Zeichen verbleibend" visibility: "Sichtbarkeit" @@ -524,8 +516,6 @@ desktop/views/components/sub-note-content.vue: desktop/views/components/settings.tags.vue: add: "Hinzufügen" save: "Speichern" -desktop/views/components/taskmanager.vue: - title: "Taskmanager" desktop/views/components/timeline.vue: home: "Home" local: "Lokal" @@ -664,10 +654,3 @@ deck: rename: "Umbenennen" deck/deck.user-column.vue: activity: "Aktivität" -dev/views/new-app.vue: - account-read: "Accountinformationen anzeigen." - account-write: "Accountinformationen bearbeiten." - note-write: "Senden." - following-write: "Folgen oder entfolgen." - notification-read: "Siehe deine Benachrichtigungen." - notification-write: "Benachrichtigungen verwalten." diff --git a/locales/en-US.yml b/locales/en-US.yml index 2b11de112..85bc71399 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -69,6 +69,11 @@ common: following: "Following" followers: "Followers" favorites: "Favorites" + permissions: + 'read:account': "View account information" + 'write:account': "Update your account information" + 'read:drive': "Browse the Drive" + 'write:drive': "Work with the Drive" empty-timeline-info: follow-users-to-make-your-timeline: "Following users will show their posts in your timeline." explore: "Find users" @@ -282,15 +287,6 @@ common: auth/views/form.vue: share-access: "Would you allow {name} to access your account?" permission-ask: "This application requires the following permissions:" - account-read: "View account information." - account-write: "Modify account information." - note-write: "Post." - like-write: "Express yourself about this post." - following-write: "Follow and unfollow." - drive-read: "Read your drive." - drive-write: "Upload/delete files in your drive." - notification-read: "Read your notifications." - notification-write: "Manage your notifications." cancel: "Cancel" accept: "Allow access." auth/views/index.vue: @@ -877,7 +873,6 @@ desktop/views/components/post-form.vue: posting: "Posting" attach-media-from-local: "Attach media from your device" attach-media-from-drive: "Attach media from your Drive" - attach-cancel: "Cancel attachment" insert-a-kao: "v('ω')v" create-poll: "Create a poll" text-remain: "{} characters remaining" @@ -970,6 +965,10 @@ common/views/components/password-settings.vue: not-match: "The new passwords do not match" changed: "Password changed" failed: "Failed to change password" +common/views/components/post-form-attaches.vue: + attach-cancel: "Remove Attachment" + mark-as-sensitive: "Mark as 'sensitive'" + unmark-as-sensitive: "Unmark as 'sensitive'" desktop/views/components/sub-note-content.vue: private: "This post is private" deleted: "This post has been deleted" @@ -980,8 +979,6 @@ desktop/views/components/settings.tags.vue: query: "Query (optional)" add: "Add" save: "Save" -desktop/views/components/taskmanager.vue: - title: "Task Manager" desktop/views/components/timeline.vue: home: "Home" local: "Local" @@ -1115,11 +1112,6 @@ admin/views/instance.vue: save: "Save" saved: "Saved" user-recommendation-config: "Recommended users" - enable-external-user-recommendation: "Enable external user recommendations" - external-user-recommendation-engine: "Engine" - external-user-recommendation-engine-desc: "Example : https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}" - external-user-recommendation-timeout: "Timeout" - external-user-recommendation-timeout-desc: "Number of milliseconds (ex. 300,000)" email-config: "Email server settings" email-config-info: "Used to confirm email and password reset etc." enable-email: "Enable email delivery" @@ -1632,12 +1624,3 @@ dev/views/new-app.vue: authority: "Permissions" authority-desc: "Only the functions requested here can be accessed via the API." authority-warning: "You can change it even after creating the application, but if you give different permissions, all user keys associated at that time will be invalidated." - account-read: "View account information." - account-write: "Modify account information." - note-write: "Post." - reaction-write: "Add or remove reactions." - following-write: "Follow and unfollow." - drive-read: "Read the drive." - drive-write: "Upload/delete files in the drive." - notification-read: "Read your notifications." - notification-write: "Manage your notifications." diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 237a10f85..9ce261326 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -169,15 +169,6 @@ common: you: "Tú" auth/views/form.vue: permission-ask: "La aplicación requiere los siguientes permisos:" - account-read: "Viendo información de la cuenta:" - account-write: "Modificar información de la cuenta:" - note-write: "Publicación." - like-write: "Para reaccionar a las publicaciones." - following-write: "Seguir o dejar de seguir" - drive-read: "Leer tu unidad." - drive-write: "Cargar o borrar archivos de tu unidad." - notification-read: "Leer tus notificaciones." - notification-write: "Administrar tus notificaciones." cancel: "Cancelar" accept: "Garantizar acceso." auth/views/index.vue: @@ -631,7 +622,6 @@ desktop/views/components/post-form.vue: posting: "Publicando" attach-media-from-local: "Agregar medios de tu dispositivo" attach-media-from-drive: "Adjunta multimedia desde tu Disco" - attach-cancel: "Quitar el archivo adjunto" create-poll: "Crea una encuesta" text-remain: "quedan {} caracteres" recent-tags: "Reciente" @@ -697,6 +687,9 @@ common/views/components/mute-and-block.vue: mute: "Silenciar" block: "Bloquear" save: "Guardar" +common/views/components/post-form-attaches.vue: + mark-as-sensitive: "Marcar como 'sensible'" + unmark-as-sensitive: "Desmarcar como 'sensible'" desktop/views/components/sub-note-content.vue: private: "Esta publicación es privada" deleted: "Esta publicación ha sido removida" @@ -708,7 +701,6 @@ desktop/views/components/settings.tags.vue: desktop/views/components/timeline.vue: home: "Inicio" local: "Local" - hybrid: "Social" global: "Global" list: "Listas" hashtag: "Hashtags" @@ -768,7 +760,6 @@ admin/views/instance.vue: recaptcha-secret-key: "clave secreta reCAPTCHA" invite: "Invitar" save: "Guardar" - external-user-recommendation-timeout: "Tiempo de espera" email: "Correo electrónico" smtp-host: "Host SMTP" smtp-port: "Puerto SMTP" @@ -898,7 +889,6 @@ mobile/views/pages/user-lists.vue: mobile/views/pages/home.vue: home: "Inicio" local: "Local" - hybrid: "Social" global: "Global" mobile/views/pages/widgets.vue: dashboard: "Panel de control" @@ -921,7 +911,6 @@ mobile/views/pages/user/home.photos.vue: deck: home: "Inicio" local: "Local" - hybrid: "Social" hashtag: "Etiquetas" global: "Global" notifications: "Notificaciones" @@ -929,12 +918,3 @@ deck: rename: "Renombrar" deck/deck.user-column.vue: activity: "Actividad" -dev/views/new-app.vue: - account-read: "Viendo información de la cuenta:" - account-write: "Modificar información de la cuenta:" - note-write: "Publicación." - following-write: "Seguir o dejar de seguir" - drive-read: "Leer tu unidad." - drive-write: "Cargar o borrar archivos de tu unidad." - notification-read: "Leer tus notificaciones." - notification-write: "Administrar tus notificaciones." diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index d53c522bc..ab7588b68 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -67,6 +67,11 @@ common: following: "Suit" followers: "Abonné·e·s" favorites: "Mettre cette note en favoris" + permissions: + 'read:account': "Afficher les informations du compte" + 'write:account': "Mettre à jour les informations de votre compte" + 'read:drive': "Parcourir le Drive" + 'write:drive': "Écrire sur le Drive" empty-timeline-info: follow-users-to-make-your-timeline: "Les utilisateurs suivants afficheront leurs publications sur votre fil." explore: "Trouver des utilisateurs" @@ -121,6 +126,7 @@ common: notification: "Notifications" apps: "Applications" tags: "Hashtags" + mute-and-block: "Silencer / Bloquer" blocking: "En cours blocage" security: "Sécurité" signin: "Historique des connexions" @@ -134,6 +140,16 @@ common: remember-note-visibility: "Se souvenir du mode de visibilité de la publication" web-search-engine: "Moteur de recherche Web" web-search-engine-desc: "Exemple : https://www.google.com/?#q={{query}}" + keep-cw: "Maintenir l'avertissement de contenu" + i-like-sushi: "Je préfère les sushis plutôt que le pudding" + show-reversi-board-labels: "Afficher les étiquettes des lignes et colonnes dans Reversi" + use-avatar-reversi-stones: "Utiliser l’avatar comme pion dans Reversi" + disable-animated-mfm: "Désactiver les textes animés dans les publications" + disable-showing-animated-images: "Désactiver l'animation des images" + suggest-recent-hashtags: "Afficher les hashtags populaires dans le champs de saisie" + always-show-nsfw: "Toujours afficher les contenus sensibles" + always-mark-nsfw: "Toujours marquer les notes ayant des médias comme sensibles" + show-full-acct: "Afficher l’adresse complète de l’utilisateur" show-via: "Afficher via" reduce-motion: "Réduire les animations dans l’interface utilisateur" this-setting-is-this-device-only: "Uniquement sur cet appareil" @@ -143,25 +159,69 @@ common: line-width-normal: "Normale" line-width-thick: "Épaisse" font-size: "Taille du texte" + font-size-x-small: "Très petit" + font-size-small: "Petite" font-size-medium: "Normale" + font-size-large: "Grande" font-size-x-large: "Large" + deck-column-align: "Alignement des colonnes du Deck" deck-column-align-center: "Centrer" deck-column-align-left: "À gauche" deck-column-align-flexible: "Flexible" deck-column-width: "Largeur des colonnes du Deck" + deck-column-width-narrow: "Étroite" + deck-column-width-narrower: "Légèrement étroite" deck-column-width-normal: "Normale" + deck-column-width-wider: "Légèrement large" + deck-column-width-wide: "Large" + use-shadow: "Utiliser les ombres dans l'interface utilisateur" + rounded-corners: "Coins arrondis de l'interface utilisateur" + circle-icons: "Utiliser des icônes circulaires" + contrasted-acct: "Ajouter du contraste au nom de l’utilisateur" + wallpaper: "Image du fond d'écran" + choose-wallpaper: "Sélectionner un fond d'écran" + delete-wallpaper: "Supprimer le fond d'écran" + post-form-on-timeline: "Afficher le champs de saisie en haut du fil" + show-clock-on-header: "Afficher l'horloge sur le coté supérieur droit" timeline: "Fil d’actualité" + show-my-renotes: "Afficher mes republications dans le fil" + remain-deleted-note: "Continuer à afficher les notes supprimées" + sound: "Son" + enable-sounds: "Activer les sons" + enable-sounds-desc: "Jouer un son lorsque vous recevez un message/publication. Ce paramètre est sauvegardé dans le navigateur." + volume: "Volume" + test: "Test" + update: "Mise à jour de Misskey" + version: "Version actuelle :" + latest-version: "Dernière version :" + update-checking: "Recherche de mises à jour" + do-update: "Rechercher des mises à jour" + update-settings: "Paramètres avancés" + no-updates: "Aucune mise à jour disponible" + no-updates-desc: "Votre Misskey est à jour." + update-available: "Nouvelle version disponible !" + update-available-desc: "Les mises à jour seront appliquées une fois la page est rechargée." + advanced-settings: "Paramètres avancés" + debug-mode: "Activer le mode débogage" + debug-mode-desc: "Ce paramètre est stocké dans le navigateur." + navbar-position: "Position de la barre de navigation" navbar-position-top: "en haut" navbar-position-left: "À gauche" navbar-position-right: "à droite" + i-am-under-limited-internet: "J'ai un accès Internet limité" + post-style: "Style d'affichage des notes" post-style-standard: "Standard" post-style-smart: "Intelligent" notification-position: "Afficher les notifications" notification-position-bottom: "en bas" notification-position-top: "en haut" + disable-via-mobile: "Enlever la mention publié via 'mobile'" + load-raw-images: "Afficher les photos jointes dans leur qualité originale" + load-remote-media: "Afficher les médias depuis le serveur distant" search: "Recherche" delete: "Supprimer" loading: "Chargement en cours …" + ok: "Confirmer" cancel: "Quitter" update-available-title: "Mise à jour disponible" update-available: "Une nouvelle version de Misskey est disponible ({newer}, version actuelle: {current}). Veuillez recharger la page pour appliquer la mise à jour." @@ -176,7 +236,7 @@ common: view-on-remote: " Consulter le profil complet" renoted-by: "Renoté par {user}" no-notes: "Sans aucune note" - turn-on-darkmode: "Basculer vers le mode nuit" + turn-on-darkmode: "Mode nuit" turn-off-darkmode: "Mode jour" error: title: "Une erreur est survenue" @@ -220,15 +280,6 @@ common: auth/views/form.vue: share-access: "Désirez-vous autoriser {name} à avoir accès à votre compte ?" permission-ask: "Cette application nécessite les autorisations suivantes :" - account-read: "Afficher les informations du compte." - account-write: "Modifications des informations du compte." - note-write: "Publier." - like-write: "Réagir aux publications." - following-write: "Suivre des comptes et se désabonner." - drive-read: "Lire votre Drive" - drive-write: "Téléverser/supprimer des fichiers dans votre Drive." - notification-read: "Lire vos notifications." - notification-write: "Gérer vos notifications." cancel: "Annuler" accept: "Autoriser l’accès" auth/views/index.vue: @@ -250,6 +301,8 @@ common/views/pages/explore.vue: federated: "Du Fédiverse" explore: "Explorer {host}" users-info: "Actuellement, {users} utilisateurs se sont inscrit ici" +common/views/components/url-preview.vue: + disable-player: "Fermer le lecteur" common/views/components/user-list.vue: no-users: "Il n'y a aucun utilisateur" common/views/components/games/reversi/reversi.vue: @@ -424,19 +477,32 @@ common/views/components/user-menu.vue: common/views/components/poll.vue: vote-to: "Voter pour '{}'" vote-count: "{} votes" + total-votes: "{} Total des votes" vote: "Vote" show-result: "Montrer les résultats" voted: "Voté" + closed: "Terminé" + remaining-days: "{d} jours, {h} heures restantes" + remaining-hours: "{h} heures et {m} minutes restantes" + remaining-minutes: "{m} minutes et {s} secondes restantes" + remaining-seconds: "{s} secondes restantes" common/views/components/poll-editor.vue: no-only-one-choice: "Vous devez saisir au moins deux choix." choice-n: "Choix {}" remove: "Supprimer ce choix" add: "+ Ajouter un choix" destroy: "Annuler ce sondage" + expiration: "Valide jusqu'à" + infinite: "Illimité" + at: "Choisir une date et une durée" + no-more: "Vous ne pouvez pas en ajouter davantage" + deadline-date: "Date d’échéance" + deadline-time: "Durée" interval: "Durée" unit: "Unité" second: "secondes" minute: "Minutes" + hour: "Heures" day: "D" common/views/components/reaction-picker.vue: choose-reaction: "Choisissez votre réaction" @@ -568,6 +634,7 @@ common/views/components/profile-editor.vue: email-not-verified: "Adresse de courriel n’est pas confirmée. Veuillez vérifier votre boite de réception." export: "Exporter" import: "Importer" + export-and-import: "Exportation et importation" export-targets: all-notes: "Toutes les notes publiées" following-list: "Liste des abonnements" @@ -793,7 +860,6 @@ desktop/views/components/post-form.vue: posting: "Publication …" attach-media-from-local: "Joindre un média depuis votre appareil" attach-media-from-drive: "Joindre un média depuis votre Drive" - attach-cancel: "Annuler le fichier attaché" insert-a-kao: "v('ω')v" create-poll: "Créer un sondage" text-remain: "{} caractères restants" @@ -886,6 +952,9 @@ common/views/components/password-settings.vue: not-match: "Les nouveaux mots de passe ne sont pas identiques" changed: "Mot de passe modifié avec succès" failed: "Échec lors de la modification du mot de passe" +common/views/components/post-form-attaches.vue: + mark-as-sensitive: "Marquer comme sensible" + unmark-as-sensitive: "Ne pas marquer comme sensible" desktop/views/components/sub-note-content.vue: private: "cette publication est privée" deleted: "cette publication a été supprimée" @@ -896,8 +965,6 @@ desktop/views/components/settings.tags.vue: query: "Requête (optionnelle)" add: "Ajouter" save: "Enregistrer" -desktop/views/components/taskmanager.vue: - title: "Gestionnaire de tâches" desktop/views/components/timeline.vue: home: "Accueil" local: "Local" @@ -958,6 +1025,7 @@ admin/views/index.vue: hashtags: "Hashtags" abuse: "Abus" queue: "File d’attente" + logs: "Journaux" back-to-misskey: "Retour vers Misskey" admin/views/dashboard.vue: dashboard: "Tableau de bord" @@ -1026,11 +1094,6 @@ admin/views/instance.vue: save: "Sauvegarder" saved: "Enregistré" user-recommendation-config: "Utilisateurs" - enable-external-user-recommendation: "Activer la recommandation des utilisateurs distants" - external-user-recommendation-engine: "Moteur" - external-user-recommendation-engine-desc: "Exemple : https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}" - external-user-recommendation-timeout: "Délai d’expiration" - external-user-recommendation-timeout-desc: "En millisecondes (par exemple : 300000)" email-config: "Paramètres du serveur de messagerie" email-config-info: "Utilisé pour confirmer votre adresse de courrier électronique et la réinitialisation de votre mot de passe." enable-email: "Activation de la distribution du courrier" @@ -1199,6 +1262,7 @@ admin/views/federation.vue: marked-as-closed: "Marquées comme fermées" lookup: "Recherche" instances: "Fédérées" + instance-not-registered: "L’instance n’a pas encore été découverte" sort: "Trier par" sorts: caughtAtAsc: "Date d’inscription (Ascendant)" @@ -1206,6 +1270,7 @@ admin/views/federation.vue: lastCommunicatedAtAsc: "La date et l'heure des interactions plus anciennes" lastCommunicatedAtDesc: "La date et l'heure des nouvelles interactions" notesDesc: "Description des notes" + usersAsc: "Peu d'abonnés" followingAsc: "Les moins suivies" followingDesc: "Ayant le plus d'abonné·e·s" followersAsc: "Ayant le moins d'abonné·e·s" @@ -1530,12 +1595,3 @@ dev/views/new-app.vue: authority: "Autorisations " authority-desc: "Sont accessibles via l’API, uniquement les fonctionnalités demandées ici." authority-warning: "Vous pouvez le changer même après avoir créé l'application, mais si vous attribuez une nouvelle permission, toutes les clés utilisateur associées seront dès lors invalides." - account-read: "Afficher les informations du compte" - account-write: "Modifications des informations du compte" - note-write: "Publications." - reaction-write: "Ajout et suppression de réactions." - following-write: "S’abonner et se désabonner." - drive-read: "Lecture du Drive." - drive-write: "Téléversement/suppression des fichiers de votre Lecteur." - notification-read: "Lire vos notifications." - notification-write: "Gestion de vos notifications." diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index d4457b659..cc6fe2b08 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -73,6 +73,12 @@ common: followers: "フォロワー" favorites: "お気に入り" + permissions: + 'read:account': "アカウントの情報を見る" + 'write:account': "アカウントの情報を変更する" + 'read:drive': "ドライブを見る" + 'write:drive': "ドライブを操作する" + empty-timeline-info: follow-users-to-make-your-timeline: "ユーザーをフォローすると投稿がタイムラインに表示されます。" explore: "ユーザーを探索する" @@ -299,15 +305,6 @@ common: auth/views/form.vue: share-access: "{name}があなたのアカウントにアクセスすることを許可しますか?" permission-ask: "このアプリは次の権限を要求しています:" - account-read: "アカウントの情報を見る。" - account-write: "アカウントの情報を操作する。" - note-write: "投稿する。" - like-write: "いいねしたりいいね解除する。" - following-write: "フォローしたりフォロー解除する。" - drive-read: "ドライブを見る。" - drive-write: "ドライブを操作する。" - notification-read: "通知を見る。" - notification-write: "通知を操作する。" cancel: "キャンセル" accept: "アクセスを許可" @@ -967,7 +964,6 @@ desktop/views/components/post-form.vue: posting: "投稿中" attach-media-from-local: "PCからメディアを添付" attach-media-from-drive: "ドライブからメディアを添付" - attach-cancel: "添付取り消し" insert-a-kao: "v('ω')v" create-poll: "アンケートを作成" text-remain: "残り{}文字" @@ -1073,6 +1069,11 @@ common/views/components/password-settings.vue: changed: "パスワードを変更しました" failed: "パスワード変更に失敗しました" +common/views/components/post-form-attaches.vue: + attach-cancel: "添付取り消し" + mark-as-sensitive: "閲覧注意に設定" + unmark-as-sensitive: "閲覧注意を解除" + desktop/views/components/sub-note-content.vue: private: "この投稿は非公開です" deleted: "この投稿は削除されました" @@ -1085,9 +1086,6 @@ desktop/views/components/settings.tags.vue: add: "追加" save: "保存" -desktop/views/components/taskmanager.vue: - title: "タスクマネージャ" - desktop/views/components/timeline.vue: home: "ホーム" local: "ローカル" @@ -1238,11 +1236,6 @@ admin/views/instance.vue: save: "保存" saved: "保存しました" user-recommendation-config: "おすすめユーザー" - enable-external-user-recommendation: "外部ユーザーレコメンデーションを有効にする" - external-user-recommendation-engine: "エンジン" - external-user-recommendation-engine-desc: "例: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}" - external-user-recommendation-timeout: "タイムアウト" - external-user-recommendation-timeout-desc: "ミリ秒単位 (例: 300000)" email-config: "メールサーバーの設定" email-config-info: "メールアドレス確認やパスワードリセットの際に使われます。" enable-email: "メール配信を有効にする" @@ -1823,12 +1816,3 @@ dev/views/new-app.vue: authority: "権限" authority-desc: "ここで要求した機能だけがAPIからアクセスできます。" authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。" - account-read: "アカウントの情報を見る。" - account-write: "アカウントの情報を操作する。" - note-write: "投稿する。" - reaction-write: "リアクションしたりリアクションをキャンセルする。" - following-write: "フォローしたりフォロー解除する。" - drive-read: "ドライブを見る。" - drive-write: "ドライブを操作する。" - notification-read: "通知を見る。" - notification-write: "通知を操作する。" diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index 3e0c3d028..9f8e581ef 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -166,15 +166,6 @@ common: auth/views/form.vue: share-access: "あんたのアカウントに{name}がアクセスしようとしてるで?ええか?" permission-ask: "このアプリは次の権限を要求してんで:" - account-read: "アカウントの情報を見させてもらうで。" - account-write: "アカウントの情報を操作させてもらうで。" - note-write: "投稿させてもらうで。" - like-write: "いいねしたりいいね解除させてもらうで。" - following-write: "フォローしたりフォロー解除させてもらうで。" - drive-read: "ドライブを見させてもらうで。" - drive-write: "ドライブを操作させてもらうで。" - notification-read: "通知を見させてもらうで。" - notification-write: "通知を操作させてもらうで。" cancel: "やめとくわ" accept: "アクセスを許可や!" auth/views/index.vue: @@ -688,7 +679,6 @@ desktop/views/components/post-form.vue: posting: "投稿中" attach-media-from-local: "PCからメディア持ってくる" attach-media-from-drive: "ドライブからメディア持ってくる" - attach-cancel: "くっつけるのやめよか" create-poll: "アンケートを作成" text-remain: "残り{}文字" recent-tags: "最近のタグ" @@ -779,6 +769,9 @@ common/views/components/password-settings.vue: enter-new-password-again: "もっぺん入れてや" not-match: "パスワードがおうとらん" changed: "パスワード変えたわ" +common/views/components/post-form-attaches.vue: + mark-as-sensitive: "見たらあかん感じにしとく" + unmark-as-sensitive: "やっぱ見せたるわ" desktop/views/components/sub-note-content.vue: private: "この投稿は見せられへんわ" deleted: "この投稿なんか無くなってもうたわ" @@ -787,12 +780,9 @@ desktop/views/components/sub-note-content.vue: desktop/views/components/settings.tags.vue: add: "増やす" save: "保存" -desktop/views/components/taskmanager.vue: - title: "タスクマネージャ" desktop/views/components/timeline.vue: home: "ホーム" local: "ローカル" - hybrid: "ソーシャル" global: "グローバル" mentions: "あんた宛て" messages: "ダイレクト投稿" @@ -908,11 +898,6 @@ admin/views/instance.vue: save: "保存" saved: "保存したで!" user-recommendation-config: "このユーザーええで" - enable-external-user-recommendation: "外部ユーザーレコメンデーションを使えるようにする" - external-user-recommendation-engine: "エンジン" - external-user-recommendation-engine-desc: "例: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}" - external-user-recommendation-timeout: "タイムアウト" - external-user-recommendation-timeout-desc: "ミリ秒単位 (例: 300000)" email-config: "メールサーバーの設定" email-config-info: "メールアドレス確認やパスワードリセットの際に使うで。" enable-email: "メール配信を有効にする" @@ -1174,7 +1159,6 @@ mobile/views/pages/following.vue: mobile/views/pages/home.vue: home: "ホーム" local: "ローカル" - hybrid: "ソーシャル" global: "グローバル" mentions: "あんた宛て" messages: "ダイレクト投稿" @@ -1229,7 +1213,6 @@ deck: widgets: "ウィジェット" home: "ホーム" local: "ローカル" - hybrid: "ソーシャル" hashtag: "ハッシュタグ" global: "グローバル" mentions: "あんた宛て" @@ -1298,12 +1281,3 @@ dev/views/new-app.vue: authority: "権限" authority-desc: "ここにチェックした機能しかAPIからアクセスできひんから気ぃつけてな" authority-warning: "アプリ作った後でも変えれるけど、新しいやつ追加したらそん時関連付いてるユーザーキーは全部ほかされるで。" - account-read: "アカウントの情報見せて" - account-write: "アカウントの情報いじらせて" - note-write: "投稿させて" - reaction-write: "リアクションしたりそれをキャンセルさせて" - following-write: "フォローとかフォロー解除させて" - drive-read: "ドライブ見せて" - drive-write: "ドライブいじらせて" - notification-read: "通知見せて" - notification-write: "通知いじらせて" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index d74658608..83e971adf 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -69,6 +69,11 @@ common: following: "팔로우 중" followers: "팔로워" favorites: "즐겨찾기" + permissions: + 'read:account': "계정 정보 보기" + 'write:account': "계정 정보 변경" + 'read:drive': "드라이브 보기" + 'write:drive': "드라이브 수정" empty-timeline-info: follow-users-to-make-your-timeline: "사용자를 팔로우하면 글이 타임라인에 표시됩니다." explore: "사용자 탐색" @@ -282,15 +287,6 @@ common: auth/views/form.vue: share-access: "{name}가 당신의 계정에 엑세스하도록 허용하시겠습니까?" permission-ask: "이 앱은 다음의 권한을 요청합니다:" - account-read: "계정 정보 보기." - account-write: "계정 정보의 수정." - note-write: "게시하기." - like-write: "좋아요 하거나 좋아요 해제하기." - following-write: "팔로우하거나 팔로우를 취소하기." - drive-read: "드라이브 보기." - drive-write: "드라이브의 수정." - notification-read: "알림 읽기." - notification-write: "알림 수정하기." cancel: "취소" accept: "접근 권한 허용" auth/views/index.vue: @@ -877,7 +873,6 @@ desktop/views/components/post-form.vue: posting: "게시중" attach-media-from-local: "PC에서 미디어 첨부" attach-media-from-drive: "드라이브에서 미디어 첨부" - attach-cancel: "첨부 취소" insert-a-kao: "v('ω')v" create-poll: "투표 만들기" text-remain: "{}문자 남음" @@ -970,6 +965,9 @@ common/views/components/password-settings.vue: not-match: "새 비밀번호가 일치하지 않습니다" changed: "비밀번호를 변경하였습니다" failed: "비밀번호 변경을 실패하였습니다." +common/views/components/post-form-attaches.vue: + mark-as-sensitive: "열람주의로 설정" + unmark-as-sensitive: "열람주의 해제" desktop/views/components/sub-note-content.vue: private: "이 글은 비공개입니다" deleted: "이 글은 삭제되었습니다" @@ -980,8 +978,6 @@ desktop/views/components/settings.tags.vue: query: "쿼리 (생략 가능)" add: "추가" save: "저장" -desktop/views/components/taskmanager.vue: - title: "작업 관리자" desktop/views/components/timeline.vue: home: "홈" local: "로컬" @@ -1115,11 +1111,6 @@ admin/views/instance.vue: save: "저장" saved: "저장하였습니다" user-recommendation-config: "추천 사용자" - enable-external-user-recommendation: "외부 사용자 추천 활성화" - external-user-recommendation-engine: "엔진" - external-user-recommendation-engine-desc: "예: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}" - external-user-recommendation-timeout: "타임 아웃" - external-user-recommendation-timeout-desc: "밀리초 (예: 300000)" email-config: "메일 서버 설정" email-config-info: "메일 주소 확인 혹은 비밀번호 재설정에 사용 됩니다." enable-email: "메일 발신 활성화" @@ -1632,12 +1623,3 @@ dev/views/new-app.vue: authority: "권한" authority-desc: "이곳에서 요청한 권한에 한정하여 API로 액세스할 수 있습니다." authority-warning: "앱을 생성한 뒤에도 변경할 수 있지만, 새로운 권한을 설정하는 경우 그 시점부터 예전에 발급받았던 유저 키는 모두 무효화됩니다." - account-read: "계정 정보 보기." - account-write: "계정 정보 편집." - note-write: "글 쓰기." - reaction-write: "리액션을 하거나 리액션을 취소할 수 있음." - following-write: "팔로우하거나 팔로우 해제하기." - drive-read: "드라이브 보기." - drive-write: "드라이브를 조작." - notification-read: "알림 보기." - notification-write: "알림 조작." diff --git a/locales/nl-NL.yml b/locales/nl-NL.yml index ee798cd8d..772d41f93 100644 --- a/locales/nl-NL.yml +++ b/locales/nl-NL.yml @@ -334,7 +334,6 @@ desktop/views/components/post-form.vue: posting: "Bezig met plaatsen" attach-media-from-local: "Media bijvoegen van je computer" attach-media-from-drive: "Media bijvoegen uit je Drive" - attach-cancel: "Bijlage annuleren" create-poll: "Peiling creëren" text-remain: "{} resterende tekens" desktop/views/components/post-form-window.vue: @@ -384,8 +383,6 @@ desktop/views/components/sub-note-content.vue: poll: "Peilingen" desktop/views/components/settings.tags.vue: add: "Toevoegen" -desktop/views/components/taskmanager.vue: - title: "Taakbeheer" desktop/views/components/timeline.vue: home: "Startpagina" local: "Lokaal" diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml index 16199f6cc..61d7a10e1 100644 --- a/locales/pl-PL.yml +++ b/locales/pl-PL.yml @@ -23,6 +23,7 @@ common: enter-password: "Wprowadź Hasło" 2fa: "Uwierzytelnienie dwuetapowe" customize-home: "Dostosuj stronę główną" + featured-notes: "Wyróżnienia" dark-mode: "Tryb ciemny" signin: "Zaloguj się" signup: "Rejestracja" @@ -61,6 +62,8 @@ common: following: "Śledzisz" followers: "Śledzący" favorites: "Moje ulubione" + permissions: + 'read:drive': "Wyświetl dysk" empty-timeline-info: explore: "Poznaj" weekday-short: @@ -201,15 +204,6 @@ common: you: "Ty" auth/views/form.vue: permission-ask: "Ta aplikacja wymaga następujących uprawnień:" - account-read: "Wyświetlanie informacji o koncie:" - account-write: "Modyfikowanie informacji o koncie:" - note-write: "Publikacja." - like-write: "Reagowanie na wpisy." - following-write: "Śledzenie i cofanie śledzenia." - drive-read: "Odczytywanie Twojego dysku." - drive-write: "Wysyłanie i usuwanie plików na Twoim dysku." - notification-read: "Odczytywanie Twoich powiadomień." - notification-write: "Zarządzanie Twoimi powiadomieniami." cancel: "Anuluj" accept: "Przyznaj dostęp." auth/views/index.vue: @@ -715,7 +709,6 @@ desktop/views/components/post-form.vue: posting: "Wysyłanie" attach-media-from-local: "Załącz zawartość multimedialną z komputera" attach-media-from-drive: "Załącz zawartość multimedialną z dysku" - attach-cancel: "Usuń załącznik" insert-a-kao: "v('ω')v" create-poll: "Utwórz ankietę" text-remain: "pozostałe znaki: {}" @@ -795,6 +788,9 @@ common/views/components/password-settings.vue: enter-current-password: "Wprowadź obecne hasło" enter-new-password: "Wprowadź nowe hasło" enter-new-password-again: "Wprowadź ponownie nowe hasło" +common/views/components/post-form-attaches.vue: + mark-as-sensitive: "Oznacz jako zawartość wrażliwą" + unmark-as-sensitive: "Cofnij oznaczenie jako zawartość wrażliwą" desktop/views/components/sub-note-content.vue: private: "ten wpis jest prywatny" deleted: "ten wpis został usunięty" @@ -805,12 +801,9 @@ desktop/views/components/settings.tags.vue: query: "Zapytanie (opcjonalne)" add: "Dodaj" save: "Zapisz" -desktop/views/components/taskmanager.vue: - title: "Menedżer zadań" desktop/views/components/timeline.vue: home: "Strona główna" local: "Lokalne" - hybrid: "Społeczność" global: "Globalne" mentions: "Wspomnienia" messages: "Bezpośrednie wpisy" @@ -882,8 +875,6 @@ admin/views/instance.vue: save: "Zapisz" saved: "Zapisano" user-recommendation-config: "Polecani użytkownicy" - external-user-recommendation-engine: "Silnik" - external-user-recommendation-engine-desc: "Np: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}" email: "Adres e-mail" admin/views/charts.vue: notes: "Wpisy" @@ -1119,7 +1110,6 @@ mobile/views/pages/signup.vue: mobile/views/pages/home.vue: home: "Strona główna" local: "Lokalne" - hybrid: "Społeczność" global: "Globalne" mentions: "Wspomnienia" messages: "Bezpośrednie wpisy" @@ -1169,7 +1159,6 @@ deck: widgets: "Widżety" home: "Strona główna" local: "Lokalne" - hybrid: "Społeczność" hashtag: "Hashtag" global: "Globalne" mentions: "Wspomnienia" @@ -1224,11 +1213,3 @@ dev/views/apps.vue: dev/views/new-app.vue: app-name: "Nazwa Aplikacji" authority: "Uprawnienia" - account-read: "Wyświetlanie informacji o koncie:" - account-write: "Modyfikowanie informacji o koncie:" - note-write: "Publikacja." - following-write: "Śledzenie i cofanie śledzenia." - drive-read: "Odczytywanie Twojego dysku." - drive-write: "Wysyłanie i usuwanie plików na Twoim dysku." - notification-read: "Odczytywanie Twoich powiadomień." - notification-write: "Zarządzanie Twoimi powiadomieniami." diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml index 83db77ad9..7732f1c94 100644 --- a/locales/pt-PT.yml +++ b/locales/pt-PT.yml @@ -119,9 +119,6 @@ common: you: "Você" auth/views/form.vue: permission-ask: "Este aplicativo precisa das seguintes permissões:" - account-read: "Ver informações da conta." - account-write: "Modificar informações da conta." - note-write: "Publicar" cancel: "Cancelar" accept: "Permitir acesso" auth/views/index.vue: @@ -292,7 +289,3 @@ docs: description: "Descrição" dev/views/index.vue: manage-apps: "Gerenciar aplicativos" -dev/views/new-app.vue: - account-read: "Ver informações da conta." - account-write: "Modificar informações da conta." - note-write: "Publicar" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index bd25cbf6f..195c6d5ef 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -69,6 +69,11 @@ common: following: "正在关注" followers: "关注者" favorites: "最爱" + permissions: + 'read:account': "查看账户信息" + 'write:account': "更改我的帐户信息" + 'read:drive': "查看网盘" + 'write:drive': "管理网盘文件" empty-timeline-info: follow-users-to-make-your-timeline: "关注其他用户时,帖子将显示在时间线中。" explore: "查找用户" @@ -282,15 +287,6 @@ common: auth/views/form.vue: share-access: "您要允许{name}来访问您的账户吗?" permission-ask: "这个应用程序需要以下权限:" - account-read: "查看账户信息" - account-write: "修改账户信息" - note-write: "投稿。" - like-write: "点赞或取消赞。" - following-write: "关注或取消关注。" - drive-read: "查看您的网盘" - drive-write: "管理网盘文件。" - notification-read: "查看通知。" - notification-write: "管理通知。" cancel: "取消" accept: "允许访问。" auth/views/index.vue: @@ -877,7 +873,6 @@ desktop/views/components/post-form.vue: posting: "发送中" attach-media-from-local: "从设备中添加媒体文件" attach-media-from-drive: "从网盘中添加媒体文件" - attach-cancel: "删除附件" insert-a-kao: "v('ω')v" create-poll: "创建一个投票" text-remain: "还剩{}字" @@ -970,6 +965,9 @@ common/views/components/password-settings.vue: not-match: "新密码不匹配" changed: "密码已更改" failed: "更改密码失败" +common/views/components/post-form-attaches.vue: + mark-as-sensitive: "标记为“敏感”" + unmark-as-sensitive: "取消标记为“敏感”" desktop/views/components/sub-note-content.vue: private: "这个帖子是私密的" deleted: "帖子已删除" @@ -980,8 +978,6 @@ desktop/views/components/settings.tags.vue: query: "查询 (可选)" add: "添加" save: "保存" -desktop/views/components/taskmanager.vue: - title: "任务管理器" desktop/views/components/timeline.vue: home: "首页" local: "本地" @@ -1115,11 +1111,6 @@ admin/views/instance.vue: save: "保存" saved: "保存完毕" user-recommendation-config: "推荐用户" - enable-external-user-recommendation: "启用外部用户推荐" - external-user-recommendation-engine: "引擎" - external-user-recommendation-engine-desc: "例如: https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}" - external-user-recommendation-timeout: "超时" - external-user-recommendation-timeout-desc: "单位为毫秒 (例如:300000)" email-config: "电子邮件服务器设置" email-config-info: "用于确认电子邮件和密码重置等。" enable-email: "启用电子邮件送递" @@ -1503,7 +1494,7 @@ mobile/views/pages/following.vue: mobile/views/pages/home.vue: home: "首页" local: "Local" - hybrid: "Social" + hybrid: "社交" global: "Global" mentions: "Mentions" messages: "直接发布" @@ -1559,7 +1550,7 @@ deck: widgets: "小部件" home: "首页" local: "Local" - hybrid: "Social" + hybrid: "社交" hashtag: "标签" global: "Global" mentions: "Mentions" @@ -1632,12 +1623,3 @@ dev/views/new-app.vue: authority: "权限" authority-desc: "只能通过API访问此处请求的功能。" authority-warning: "您可以在创建应用程序后对其进行更改,但如果您授予不同的权限,则当时关联的所有用户密钥都将失效。" - account-read: "查看账户信息" - account-write: "修改账户信息" - note-write: "投稿。" - reaction-write: "添加或删除回应。" - following-write: "关注和不关注" - drive-read: "查看网盘" - drive-write: "管理网盘文件。" - notification-read: "阅读您的通知" - notification-write: "管理通知" diff --git a/package.json b/package.json index 79ac69e8c..5ec8c524d 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "misskey", "author": "syuilo ", - "version": "10.100.0", - "codename": "nighthike", + "version": "11.0.0", + "codename": "daybreak", "repository": { "type": "git", "url": "https://github.com/syuilo/misskey.git" @@ -11,7 +11,8 @@ "private": true, "scripts": { "start": "node ./index.js", - "debug": "DEBUG=misskey:* node ./index.js", + "init": "node ./built/init.js", + "migrate": "node ./built/migrate.js", "build": "webpack && gulp build", "webpack": "webpack", "watch": "webpack --watch", @@ -32,14 +33,13 @@ "@prezzemolo/rap": "0.1.2", "@prezzemolo/zip": "0.0.3", "@types/bcryptjs": "2.4.2", - "@types/bull": "3.5.8", - "@types/chai-http": "3.0.5", + "@types/bull": "3.5.11", "@types/dateformat": "3.0.0", "@types/deep-equal": "1.0.1", "@types/double-ended-queue": "2.1.0", - "@types/elasticsearch": "5.0.30", - "@types/file-type": "10.6.0", - "@types/gulp": "4.0.5", + "@types/elasticsearch": "5.0.32", + "@types/file-type": "10.9.1", + "@types/gulp": "4.0.6", "@types/gulp-mocha": "0.0.32", "@types/gulp-rename": "0.0.33", "@types/gulp-replace": "0.0.31", @@ -47,66 +47,66 @@ "@types/gulp-util": "3.0.34", "@types/is-root": "1.0.0", "@types/is-url": "1.2.28", - "@types/js-yaml": "3.12.0", + "@types/js-yaml": "3.12.1", "@types/jsdom": "12.2.3", "@types/katex": "0.10.1", "@types/koa": "2.0.48", "@types/koa-bodyparser": "5.0.2", - "@types/koa-compress": "2.0.8", + "@types/koa-compress": "2.0.9", "@types/koa-cors": "0.0.0", "@types/koa-favicon": "2.0.19", "@types/koa-logger": "3.1.1", "@types/koa-mount": "3.0.1", "@types/koa-multer": "1.0.0", "@types/koa-router": "7.0.40", - "@types/koa-send": "4.1.1", + "@types/koa-send": "4.1.2", "@types/koa-views": "2.0.3", "@types/koa__cors": "2.2.3", + "@types/lolex": "3.1.1", "@types/minio": "7.0.1", - "@types/mkdirp": "0.5.2", - "@types/mocha": "5.2.5", - "@types/mongodb": "3.1.20", - "@types/node": "11.10.4", - "@types/nodemailer": "4.6.6", + "@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", "@types/oauth": "0.9.1", "@types/parse5": "5.0.0", "@types/parsimmon": "1.10.0", "@types/portscanner": "2.1.0", "@types/pug": "2.0.4", - "@types/qrcode": "1.3.0", + "@types/qrcode": "1.3.2", "@types/ratelimiter": "2.1.28", - "@types/redis": "2.8.10", + "@types/redis": "2.8.12", "@types/rename": "1.0.1", "@types/request": "2.48.1", "@types/request-promise-native": "1.0.15", "@types/request-stats": "3.0.0", "@types/rimraf": "2.0.2", - "@types/seedrandom": "2.4.27", - "@types/sharp": "0.21.2", + "@types/sharp": "0.22.1", "@types/showdown": "1.9.2", "@types/speakeasy": "2.0.4", "@types/systeminformation": "3.23.1", "@types/tinycolor2": "1.4.1", - "@types/tmp": "0.0.33", + "@types/tmp": "0.1.0", "@types/uuid": "3.4.4", "@types/web-push": "3.3.0", - "@types/webpack": "4.4.24", + "@types/webpack": "4.4.27", "@types/webpack-stream": "3.2.10", "@types/websocket": "0.0.40", "@types/ws": "6.0.1", "animejs": "3.0.1", - "apexcharts": "3.6.2", + "apexcharts": "3.6.7", "autobind-decorator": "2.4.0", "autosize": "4.0.2", "autwh": "0.1.0", "bcryptjs": "2.4.3", "bootstrap-vue": "2.0.0-rc.13", "bull": "3.7.0", - "cafy": "15.1.0", + "cafy": "15.1.1", "chai": "4.2.0", - "chai-http": "4.2.1", "chalk": "2.4.2", + "cli-highlight": "2.1.0", "commander": "2.20.0", "content-disposition": "0.5.3", "crc-32": "1.2.0", @@ -114,17 +114,15 @@ "cssnano": "4.1.10", "dateformat": "3.0.3", "deep-equal": "1.0.1", - "deepcopy": "0.6.3", "diskusage": "1.0.0", "double-ended-queue": "2.1.0-0", "elasticsearch": "15.4.1", "emojilib": "2.4.0", - "escape-regexp": "0.0.1", - "eslint": "5.15.1", + "eslint": "5.16.0", "eslint-plugin-vue": "5.2.2", "eventemitter3": "3.1.0", "feed": "2.0.4", - "file-type": "10.10.0", + "file-type": "10.11.0", "fuckadblock": "3.2.1", "gulp": "4.0.0", "gulp-cssnano": "2.1.3", @@ -135,19 +133,19 @@ "gulp-sourcemaps": "2.6.5", "gulp-stylus": "2.7.0", "gulp-tslint": "8.1.4", - "gulp-typescript": "5.0.0", + "gulp-typescript": "5.0.1", "gulp-uglify": "3.0.2", "gulp-util": "3.0.8", "hard-source-webpack-plugin": "0.13.1", - "html-minifier": "3.5.21", + "html-minifier": "4.0.0", "http-signature": "1.2.0", - "insert-text-at-cursor": "0.1.2", + "insert-text-at-cursor": "0.2.0", "is-root": "2.0.0", - "is-svg": "4.0.0", - "js-yaml": "3.13.0", + "is-svg": "4.1.0", + "js-yaml": "3.13.1", "jsdom": "14.0.0", "json5": "2.1.0", - "json5-loader": "1.0.1", + "json5-loader": "2.0.0", "katex": "0.10.1", "koa": "2.7.0", "koa-bodyparser": "4.2.1", @@ -163,23 +161,25 @@ "koa-views": "6.2.0", "langmap": "0.0.16", "loader-utils": "1.2.3", + "lolex": "3.1.0", "lookup-dns-cache": "2.1.0", "minio": "7.0.5", - "mkdirp": "0.5.1", - "mocha": "5.2.0", + "mocha": "6.1.3", "moji": "0.5.1", "moment": "2.24.0", - "mongodb": "3.2.2", + "mongodb": "3.2.3", "monk": "6.0.6", "ms": "2.1.1", "nan": "2.12.1", "nested-property": "0.0.7", - "nodemailer": "5.1.1", + "node-fetch": "2.3.0", + "nodemailer": "6.1.0", "nprogress": "0.2.0", "object-assign-deep": "0.4.0", "os-utils": "0.0.14", "parse5": "5.1.0", "parsimmon": "1.12.0", + "pg": "7.9.0", "portscanner": "2.2.0", "postcss-loader": "3.0.0", "prismjs": "1.16.0", @@ -195,14 +195,15 @@ "recaptcha-promise": "0.1.3", "reconnecting-websocket": "4.1.10", "redis": "2.8.0", + "reflect-metadata": "0.1.13", "rename": "1.0.4", "request": "2.88.0", "request-promise-native": "1.0.7", "request-stats": "3.0.0", + "require-all": "3.0.0", "rimraf": "2.6.3", "rndstr": "1.0.0", "s-age": "1.1.2", - "seedrandom": "2.4.4", "sharp": "0.22.0", "showdown": "1.9.0", "showdown-highlightjs-extension": "0.1.2", @@ -212,19 +213,21 @@ "stylus": "0.54.5", "stylus-loader": "3.0.2", "summaly": "2.2.0", - "systeminformation": "4.0.16", + "systeminformation": "4.1.4", "syuilo-password-strength": "0.0.1", "terser-webpack-plugin": "1.2.3", "textarea-caret": "3.1.0", "tinycolor2": "1.4.1", - "tmp": "0.0.33", + "tmp": "0.1.0", "ts-loader": "5.3.3", - "ts-node": "8.0.3", - "tslint": "5.13.1", + "ts-node": "7.0.1", + "tslint": "5.15.0", "tslint-sonarts": "1.9.0", + "typeorm": "0.2.16-rc.1", "typescript": "3.3.3333", "typescript-eslint-parser": "22.0.0", "uglify-es": "3.3.9", + "ulid": "2.3.0", "url-loader": "1.1.2", "uuid": "3.3.2", "v-animate-css": "0.0.3", @@ -232,7 +235,7 @@ "video-thumbnail-generator": "1.1.3", "vue": "2.6.10", "vue-color": "2.7.0", - "vue-content-loading": "1.5.3", + "vue-content-loading": "1.6.0", "vue-cropperjs": "3.0.0", "vue-i18n": "8.10.0", "vue-js-modal": "1.3.28", @@ -240,7 +243,7 @@ "vue-loader": "15.7.0", "vue-marquee-text-component": "1.1.1", "vue-prism-component": "1.1.1", - "vue-router": "3.0.2", + "vue-router": "3.0.4", "vue-sequential-entrance": "1.1.3", "vue-style-loader": "4.1.2", "vue-svg-inline-loader": "1.2.15", @@ -250,9 +253,8 @@ "vuex": "3.1.0", "vuex-persistedstate": "2.5.4", "web-push": "3.3.3", - "webfinger.js": "2.7.0", - "webpack": "4.28.4", - "webpack-cli": "3.2.3", + "webpack": "4.30.0", + "webpack-cli": "3.3.0", "websocket": "1.0.28", "ws": "6.2.1", "xev": "2.0.1" diff --git a/src/@types/deepcopy.d.ts b/src/@types/deepcopy.d.ts deleted file mode 100644 index f276b7e67..000000000 --- a/src/@types/deepcopy.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -declare module 'deepcopy' { - type DeepcopyCustomizerValueType = 'Object'; - - type DeepcopyCustomizer = ( - value: T, - valueType: DeepcopyCustomizerValueType) => T; - - interface IDeepcopyOptions { - customizer: DeepcopyCustomizer; - } - - function deepcopy( - value: T, - options?: IDeepcopyOptions | DeepcopyCustomizer): T; - - namespace deepcopy {} // Hack - - export = deepcopy; -} diff --git a/src/@types/escape-regexp.d.ts b/src/@types/escape-regexp.d.ts deleted file mode 100644 index d68e6048a..000000000 --- a/src/@types/escape-regexp.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -declare module 'escape-regexp' { - function escapeRegExp(str: string): string; - - namespace escapeRegExp {} // Hack - - export = escapeRegExp; -} diff --git a/src/@types/webfinger.js.d.ts b/src/@types/webfinger.js.d.ts deleted file mode 100644 index 3556c4577..000000000 --- a/src/@types/webfinger.js.d.ts +++ /dev/null @@ -1,65 +0,0 @@ -declare module 'webfinger.js' { - interface IWebFingerConstructorConfig { - tls_only?: boolean; - webfist_fallback?: boolean; - uri_fallback?: boolean; - request_timeout?: number; - } - - type JRDProperties = { [type: string]: string }; - - interface IJRDLink { - rel: string; - type?: string; - href?: string; - template?: string; - titles?: { [lang: string]: string }; - properties?: JRDProperties; - } - - interface IJRD { - subject?: string; - expires?: Date; - aliases?: string[]; - properties?: JRDProperties; - links?: IJRDLink[]; - } - - interface IIDXLinks { - 'avatar': IJRDLink[]; - 'remotestorage': IJRDLink[]; - 'blog': IJRDLink[]; - 'vcard': IJRDLink[]; - 'updates': IJRDLink[]; - 'share': IJRDLink[]; - 'profile': IJRDLink[]; - 'webfist': IJRDLink[]; - 'camlistore': IJRDLink[]; - [type: string]: IJRDLink[]; - } - - interface IIDXProperties { - 'name': string; - [type: string]: string; - } - - interface IIDX { - links: IIDXLinks; - properties: IIDXProperties; - } - - interface ILookupCallbackResult { - object: IJRD; - json: string; - idx: IIDX; - } - - type LookupCallback = (err: Error | string, result?: ILookupCallbackResult) => void; - - export class WebFinger { - constructor(config?: IWebFingerConstructorConfig); - - public lookup(address: string, cb: LookupCallback): NodeJS.Timeout; - public lookupLink(address: string, rel: string, cb: IJRDLink): void; - } -} diff --git a/src/argv.ts b/src/argv.ts index b5540441c..562852d17 100644 --- a/src/argv.ts +++ b/src/argv.ts @@ -15,5 +15,8 @@ program .parse(process.argv); if (process.env.MK_ONLY_QUEUE) program.onlyQueue = true; +if (process.env.NODE_ENV === 'test') program.disableClustering = true; +if (process.env.NODE_ENV === 'test') program.quiet = true; +if (process.env.NODE_ENV === 'test') program.noDaemons = true; export { program }; diff --git a/src/boot/index.ts b/src/boot/index.ts new file mode 100644 index 000000000..2c86d8ed8 --- /dev/null +++ b/src/boot/index.ts @@ -0,0 +1,77 @@ +import * as cluster from 'cluster'; +import chalk from 'chalk'; +import Xev from 'xev'; + +import Logger from '../services/logger'; +import { program } from '../argv'; + +// for typeorm +import 'reflect-metadata'; +import { masterMain } from './master'; +import { workerMain } from './worker'; + +const logger = new Logger('core', 'cyan'); +const clusterLogger = logger.createSubLogger('cluster', 'orange', false); +const ev = new Xev(); + +/** + * Init process + */ +export default async function() { + process.title = `Misskey (${cluster.isMaster ? 'master' : 'worker'})`; + + if (cluster.isMaster || program.disableClustering) { + await masterMain(); + + if (cluster.isMaster) { + ev.mount(); + } + } + + if (cluster.isWorker || program.disableClustering) { + await workerMain(); + } + + // ユニットテスト時にMisskeyが子プロセスで起動された時のため + // それ以外のときは process.send は使えないので弾く + if (process.send) { + process.send('ok'); + } +} + +//#region Events + +// Listen new workers +cluster.on('fork', worker => { + clusterLogger.debug(`Process forked: [${worker.id}]`); +}); + +// Listen online workers +cluster.on('online', worker => { + clusterLogger.debug(`Process is now online: [${worker.id}]`); +}); + +// Listen for dying workers +cluster.on('exit', worker => { + // Replace the dead worker, + // we're not sentimental + clusterLogger.error(chalk.red(`[${worker.id}] died :(`)); + cluster.fork(); +}); + +// Display detail of unhandled promise rejection +if (!program.quiet) { + process.on('unhandledRejection', console.dir); +} + +// Display detail of uncaught exception +process.on('uncaughtException', err => { + logger.error(err); +}); + +// Dying away... +process.on('exit', code => { + logger.info(`The process is going to exit with code ${code}`); +}); + +//#endregion diff --git a/src/boot/master.ts b/src/boot/master.ts new file mode 100644 index 000000000..4d360c726 --- /dev/null +++ b/src/boot/master.ts @@ -0,0 +1,176 @@ +import * as os from 'os'; +import * as cluster from 'cluster'; +import chalk from 'chalk'; +import * as portscanner from 'portscanner'; +import * as isRoot from 'is-root'; + +import Logger from '../services/logger'; +import loadConfig from '../config/load'; +import { Config } from '../config/types'; +import { lessThan } from '../prelude/array'; +import * as pkg from '../../package.json'; +import { program } from '../argv'; +import { showMachineInfo } from '../misc/show-machine-info'; +import { initDb } from '../db/postgre'; + +const logger = new Logger('core', 'cyan'); +const bootLogger = logger.createSubLogger('boot', 'magenta', false); + +function greet() { + if (!program.quiet) { + //#region Misskey logo + const v = `v${pkg.version}`; + console.log(' _____ _ _ '); + console.log(' | |_|___ ___| |_ ___ _ _ '); + console.log(' | | | | |_ -|_ -| \'_| -_| | |'); + console.log(' |_|_|_|_|___|___|_,_|___|_ |'); + console.log(' ' + chalk.gray(v) + (' |___|\n'.substr(v.length))); + //#endregion + + console.log(' Misskey is maintained by @syuilo, @AyaMorisawa, @mei23, and @acid-chicken.'); + console.log(chalk.keyword('orange')(' If you like Misskey, please donate to support development. https://www.patreon.com/syuilo')); + + console.log(''); + console.log(chalk`< ${os.hostname()} {gray (PID: ${process.pid.toString()})} >`); + } + + bootLogger.info('Welcome to Misskey!'); + bootLogger.info(`Misskey v${pkg.version}`, null, true); +} + +/** + * Init master process + */ +export async function masterMain() { + greet(); + + let config!: Config; + + try { + // initialize app + config = await init(); + + if (config.port == null) { + bootLogger.error('The port is not configured. Please configure port.', null, true); + process.exit(1); + } + + if (process.platform === 'linux' && isWellKnownPort(config.port) && !isRoot()) { + bootLogger.error('You need root privileges to listen on well-known port on Linux', null, true); + process.exit(1); + } + + if (!await isPortAvailable(config.port)) { + bootLogger.error(`Port ${config.port} is already in use`, null, true); + process.exit(1); + } + } catch (e) { + bootLogger.error('Fatal error occurred during initialization', null, true); + process.exit(1); + } + + bootLogger.succ('Misskey initialized'); + + if (!program.disableClustering) { + await spawnWorkers(config.clusterLimit); + } + + if (!program.noDaemons) { + require('../daemons/server-stats').default(); + require('../daemons/notes-stats').default(); + require('../daemons/queue-stats').default(); + } + + bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`, null, true); +} + +const runningNodejsVersion = process.version.slice(1).split('.').map(x => parseInt(x, 10)); +const requiredNodejsVersion = [11, 7, 0]; +const satisfyNodejsVersion = !lessThan(runningNodejsVersion, requiredNodejsVersion); + +function isWellKnownPort(port: number): boolean { + return port < 1024; +} + +async function isPortAvailable(port: number): Promise { + return await portscanner.checkPortStatus(port, '127.0.0.1') === 'closed'; +} + +function showEnvironment(): void { + const env = process.env.NODE_ENV; + const logger = bootLogger.createSubLogger('env'); + logger.info(typeof env == 'undefined' ? 'NODE_ENV is not set' : `NODE_ENV: ${env}`); + + if (env !== 'production') { + logger.warn('The environment is not in production mode.'); + logger.warn('DO NOT USE FOR PRODUCTION PURPOSE!', null, true); + } + + logger.info(`You ${isRoot() ? '' : 'do not '}have root privileges`); +} + +/** + * Init app + */ +async function init(): Promise { + showEnvironment(); + + const nodejsLogger = bootLogger.createSubLogger('nodejs'); + + nodejsLogger.info(`Version ${runningNodejsVersion.join('.')}`); + + if (!satisfyNodejsVersion) { + nodejsLogger.error(`Node.js version is less than ${requiredNodejsVersion.join('.')}. Please upgrade it.`, null, true); + process.exit(1); + } + + await showMachineInfo(bootLogger); + + const configLogger = bootLogger.createSubLogger('config'); + let config; + + try { + config = loadConfig(); + } catch (exception) { + if (typeof exception === 'string') { + configLogger.error(exception); + process.exit(1); + } + if (exception.code === 'ENOENT') { + configLogger.error('Configuration file not found', null, true); + process.exit(1); + } + throw exception; + } + + configLogger.succ('Loaded'); + + // Try to connect to DB + try { + bootLogger.info('Connecting database...'); + await initDb(); + } catch (e) { + bootLogger.error('Cannot connect to database', null, true); + bootLogger.error(e); + process.exit(1); + } + + return config; +} + +async function spawnWorkers(limit: number = Infinity) { + const workers = Math.min(limit, os.cpus().length); + bootLogger.info(`Starting ${workers} worker${workers === 1 ? '' : 's'}...`); + await Promise.all([...Array(workers)].map(spawnWorker)); + bootLogger.succ('All workers started'); +} + +function spawnWorker(): Promise { + return new Promise(res => { + const worker = cluster.fork(); + worker.on('message', message => { + if (message !== 'ready') return; + res(); + }); + }); +} diff --git a/src/boot/worker.ts b/src/boot/worker.ts new file mode 100644 index 000000000..362fa3f26 --- /dev/null +++ b/src/boot/worker.ts @@ -0,0 +1,20 @@ +import * as cluster from 'cluster'; +import { initDb } from '../db/postgre'; + +/** + * Init worker process + */ +export async function workerMain() { + await initDb(); + + // start server + await require('../server').default(); + + // start job queue + require('../queue').default(); + + if (cluster.isWorker) { + // Send a 'ready' message to parent process + process.send!('ready'); + } +} diff --git a/src/client/app/admin/views/drive.vue b/src/client/app/admin/views/drive.vue index 7812aadaa..e4565b78f 100644 --- a/src/client/app/admin/views/drive.vue +++ b/src/client/app/admin/views/drive.vue @@ -38,7 +38,7 @@
-
+
@@ -48,7 +48,7 @@
{{ file.type }} - {{ file.datasize | bytes }} + {{ file.size | bytes }}
@@ -75,10 +75,15 @@ import Vue from 'vue'; import i18n from '../../i18n'; import { faCloud, faTerminal, faSearch } from '@fortawesome/free-solid-svg-icons'; import { faTrashAlt, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons'; +import XFileThumbnail from '../../common/views/components/drive-file-thumbnail.vue'; export default Vue.extend({ i18n: i18n('admin/views/drive.vue'), + components: { + XFileThumbnail + }, + data() { return { file: null, @@ -151,13 +156,6 @@ export default Vue.extend({ }); }, - thumbnail(file: any): any { - return { - 'background-color': file.properties.avgColor && file.properties.avgColor.length == 3 ? `rgb(${file.properties.avgColor.join(',')})` : 'transparent', - 'background-image': `url(${file.thumbnailUrl})` - }; - }, - async del(file: any) { const process = async () => { await this.$root.api('drive/files/delete', { fileId: file.id }); @@ -179,9 +177,9 @@ export default Vue.extend({ this.$root.api('drive/files/update', { fileId: file.id, isSensitive: !file.isSensitive + }).then(() => { + file.isSensitive = !file.isSensitive; }); - - file.isSensitive = !file.isSensitive; }, async show() { diff --git a/src/client/app/admin/views/hashtags.vue b/src/client/app/admin/views/hashtags.vue index b3190c29c..e1cc4b494 100644 --- a/src/client/app/admin/views/hashtags.vue +++ b/src/client/app/admin/views/hashtags.vue @@ -3,7 +3,7 @@
- + {{ $t('save') }}
@@ -18,18 +18,18 @@ export default Vue.extend({ i18n: i18n('admin/views/hashtags.vue'), data() { return { - hidedTags: '', + hiddenTags: '', }; }, created() { this.$root.getMeta().then(meta => { - this.hidedTags = meta.hidedTags.join('\n'); + this.hiddenTags = meta.hiddenTags.join('\n'); }); }, methods: { save() { this.$root.api('admin/update-meta', { - hidedTags: this.hidedTags.split('\n') + hiddenTags: this.hiddenTags.split('\n') }).then(() => { //this.$root.os.apis.dialog({ text: `Saved` }); }).catch(e => { diff --git a/src/client/app/admin/views/instance.vue b/src/client/app/admin/views/instance.vue index 2d2a07784..bc2a5fba8 100644 --- a/src/client/app/admin/views/instance.vue +++ b/src/client/app/admin/views/instance.vue @@ -77,12 +77,6 @@
summaly Proxy
URL -
-
{{ $t('user-recommendation-config') }}
- {{ $t('enable-external-user-recommendation') }} - {{ $t('external-user-recommendation-engine') }} - {{ $t('external-user-recommendation-timeout') }} -
{{ $t('save') }}
@@ -184,9 +178,6 @@ export default Vue.extend({ discordClientSecret: null, proxyAccount: null, inviteCode: null, - enableExternalUserRecommendation: false, - externalUserRecommendationEngine: null, - externalUserRecommendationTimeout: null, summalyProxy: null, enableEmail: false, email: null, @@ -205,8 +196,8 @@ export default Vue.extend({ created() { this.$root.getMeta().then(meta => { - this.maintainerName = meta.maintainer.name; - this.maintainerEmail = meta.maintainer.email; + this.maintainerName = meta.maintainerName; + this.maintainerEmail = meta.maintainerEmail; this.disableRegistration = meta.disableRegistration; this.disableLocalTimeline = meta.disableLocalTimeline; this.disableGlobalTimeline = meta.disableGlobalTimeline; @@ -236,9 +227,6 @@ export default Vue.extend({ this.enableDiscordIntegration = meta.enableDiscordIntegration; this.discordClientId = meta.discordClientId; this.discordClientSecret = meta.discordClientSecret; - this.enableExternalUserRecommendation = meta.enableExternalUserRecommendation; - this.externalUserRecommendationEngine = meta.externalUserRecommendationEngine; - this.externalUserRecommendationTimeout = meta.externalUserRecommendationTimeout; this.summalyProxy = meta.summalyProxy; this.enableEmail = meta.enableEmail; this.email = meta.email; @@ -299,9 +287,6 @@ export default Vue.extend({ enableDiscordIntegration: this.enableDiscordIntegration, discordClientId: this.discordClientId, discordClientSecret: this.discordClientSecret, - enableExternalUserRecommendation: this.enableExternalUserRecommendation, - externalUserRecommendationEngine: this.externalUserRecommendationEngine, - externalUserRecommendationTimeout: parseInt(this.externalUserRecommendationTimeout, 10), summalyProxy: this.summalyProxy, enableEmail: this.enableEmail, email: this.email, diff --git a/src/client/app/admin/views/logs.vue b/src/client/app/admin/views/logs.vue index 4a2d957ed..5c2cfdb39 100644 --- a/src/client/app/admin/views/logs.vue +++ b/src/client/app/admin/views/logs.vue @@ -19,7 +19,7 @@
- +
[{{ log.domain.join('.') }}] {{ log.message }} diff --git a/src/client/app/admin/views/users.vue b/src/client/app/admin/views/users.vue index ff485cec8..0f46b564a 100644 --- a/src/client/app/admin/views/users.vue +++ b/src/client/app/admin/views/users.vue @@ -165,7 +165,7 @@ export default Vue.extend({ /** 処理対象ユーザーの情報を更新する */ async refreshUser() { - this.$root.api('admin/show-user', { userId: this.user._id }).then(info => { + this.$root.api('admin/show-user', { userId: this.user.id }).then(info => { this.user = info; }); }, @@ -173,7 +173,7 @@ export default Vue.extend({ async resetPassword() { if (!await this.getConfirmed(this.$t('reset-password-confirm'))) return; - this.$root.api('admin/reset-password', { userId: this.user._id }).then(res => { + this.$root.api('admin/reset-password', { userId: this.user.id }).then(res => { this.$root.dialog({ type: 'success', text: this.$t('password-updated', { password: res.password }) @@ -187,7 +187,7 @@ export default Vue.extend({ this.verifying = true; const process = async () => { - await this.$root.api('admin/verify-user', { userId: this.user._id }); + await this.$root.api('admin/verify-user', { userId: this.user.id }); this.$root.dialog({ type: 'success', text: this.$t('verified') @@ -212,7 +212,7 @@ export default Vue.extend({ this.unverifying = true; const process = async () => { - await this.$root.api('admin/unverify-user', { userId: this.user._id }); + await this.$root.api('admin/unverify-user', { userId: this.user.id }); this.$root.dialog({ type: 'success', text: this.$t('unverified') @@ -233,7 +233,7 @@ export default Vue.extend({ async silenceUser() { const process = async () => { - await this.$root.api('admin/silence-user', { userId: this.user._id }); + await this.$root.api('admin/silence-user', { userId: this.user.id }); this.$root.dialog({ type: 'success', splash: true @@ -252,7 +252,7 @@ export default Vue.extend({ async unsilenceUser() { const process = async () => { - await this.$root.api('admin/unsilence-user', { userId: this.user._id }); + await this.$root.api('admin/unsilence-user', { userId: this.user.id }); this.$root.dialog({ type: 'success', splash: true @@ -275,7 +275,7 @@ export default Vue.extend({ this.suspending = true; const process = async () => { - await this.$root.api('admin/suspend-user', { userId: this.user._id }); + await this.$root.api('admin/suspend-user', { userId: this.user.id }); this.$root.dialog({ type: 'success', text: this.$t('suspended') @@ -300,7 +300,7 @@ export default Vue.extend({ this.unsuspending = true; const process = async () => { - await this.$root.api('admin/unsuspend-user', { userId: this.user._id }); + await this.$root.api('admin/unsuspend-user', { userId: this.user.id }); this.$root.dialog({ type: 'success', text: this.$t('unsuspended') @@ -320,7 +320,7 @@ export default Vue.extend({ }, async updateRemoteUser() { - this.$root.api('admin/update-remote-user', { userId: this.user._id }).then(res => { + this.$root.api('admin/update-remote-user', { userId: this.user.id }).then(res => { this.$root.dialog({ type: 'success', text: this.$t('remote-user-updated') diff --git a/src/client/app/auth/views/form.vue b/src/client/app/auth/views/form.vue index 105af375b..b640a4056 100644 --- a/src/client/app/auth/views/form.vue +++ b/src/client/app/auth/views/form.vue @@ -14,15 +14,7 @@

{{ $t('permission-ask') }}

diff --git a/src/client/app/common/define-widget.ts b/src/client/app/common/define-widget.ts index 1efdbb188..632ddf2ed 100644 --- a/src/client/app/common/define-widget.ts +++ b/src/client/app/common/define-widget.ts @@ -45,15 +45,9 @@ export default function (data: { this.$watch('props', () => { this.mergeProps(); }); - - this.bakeProps(); }, methods: { - bakeProps() { - this.bakedOldProps = JSON.stringify(this.props); - }, - mergeProps() { if (data.props) { const defaultProps = data.props(); @@ -65,17 +59,10 @@ export default function (data: { }, save() { - if (this.bakedOldProps == JSON.stringify(this.props)) return; - - this.bakeProps(); - if (this.platform == 'deck') { this.$store.commit('device/updateDeckColumn', this.column); } else { - this.$root.api('i/update_widget', { - id: this.id, - data: this.props - }); + this.$store.commit('device/updateWidget', this.widget); } } } diff --git a/src/client/app/common/scripts/note-mixin.ts b/src/client/app/common/scripts/note-mixin.ts index 5707d1bb4..67bbe8c0a 100644 --- a/src/client/app/common/scripts/note-mixin.ts +++ b/src/client/app/common/scripts/note-mixin.ts @@ -70,8 +70,8 @@ export default (opts: Opts = {}) => ({ }, reactionsCount(): number { - return this.appearNote.reactionCounts - ? sum(Object.values(this.appearNote.reactionCounts)) + return this.appearNote.reactions + ? sum(Object.values(this.appearNote.reactions)) : 0; }, diff --git a/src/client/app/common/scripts/note-subscriber.ts b/src/client/app/common/scripts/note-subscriber.ts index c2b4dd6df..02d810ded 100644 --- a/src/client/app/common/scripts/note-subscriber.ts +++ b/src/client/app/common/scripts/note-subscriber.ts @@ -87,16 +87,16 @@ export default prop => ({ case 'reacted': { const reaction = body.reaction; - if (this.$_ns_target.reactionCounts == null) { - Vue.set(this.$_ns_target, 'reactionCounts', {}); + if (this.$_ns_target.reactions == null) { + Vue.set(this.$_ns_target, 'reactions', {}); } - if (this.$_ns_target.reactionCounts[reaction] == null) { - Vue.set(this.$_ns_target.reactionCounts, reaction, 0); + if (this.$_ns_target.reactions[reaction] == null) { + Vue.set(this.$_ns_target.reactions, reaction, 0); } // Increment the count - this.$_ns_target.reactionCounts[reaction]++; + this.$_ns_target.reactions[reaction]++; if (body.userId == this.$store.state.i.id) { Vue.set(this.$_ns_target, 'myReaction', reaction); @@ -107,16 +107,16 @@ export default prop => ({ case 'unreacted': { const reaction = body.reaction; - if (this.$_ns_target.reactionCounts == null) { + if (this.$_ns_target.reactions == null) { return; } - if (this.$_ns_target.reactionCounts[reaction] == null) { + if (this.$_ns_target.reactions[reaction] == null) { return; } // Decrement the count - if (this.$_ns_target.reactionCounts[reaction] > 0) this.$_ns_target.reactionCounts[reaction]--; + if (this.$_ns_target.reactions[reaction] > 0) this.$_ns_target.reactions[reaction]--; if (body.userId == this.$store.state.i.id) { Vue.set(this.$_ns_target, 'myReaction', null); @@ -125,9 +125,11 @@ export default prop => ({ } case 'pollVoted': { - if (body.userId == this.$store.state.i.id) return; const choice = body.choice; - this.$_ns_target.poll.choices.find(c => c.id === choice).votes++; + this.$_ns_target.poll.choices[choice].votes++; + if (body.userId == this.$store.state.i.id) { + Vue.set(this.$_ns_target.poll.choices[choice], 'isVoted', true); + } break; } diff --git a/src/client/app/common/views/components/avatar.vue b/src/client/app/common/views/components/avatar.vue index dce594e70..04f3ed9f7 100644 --- a/src/client/app/common/views/components/avatar.vue +++ b/src/client/app/common/views/components/avatar.vue @@ -55,11 +55,7 @@ export default Vue.extend({ }, icon(): any { return { - backgroundColor: this.lightmode - ? `rgb(${this.user.avatarColor.slice(0, 3).join(',')})` - : this.user.avatarColor && this.user.avatarColor.length == 3 - ? `rgb(${this.user.avatarColor.join(',')})` - : null, + backgroundColor: this.user.avatarColor, backgroundImage: this.lightmode ? null : `url(${this.url})`, borderRadius: this.$store.state.settings.circleIcons ? '100%' : null }; @@ -67,7 +63,7 @@ export default Vue.extend({ }, mounted() { if (this.user.avatarColor) { - this.$el.style.color = `rgb(${this.user.avatarColor.slice(0, 3).join(',')})`; + this.$el.style.color = this.user.avatarColor; } }, methods: { diff --git a/src/client/app/common/views/components/drive-file-thumbnail.vue b/src/client/app/common/views/components/drive-file-thumbnail.vue index faa727f3b..1a3ef3719 100644 --- a/src/client/app/common/views/components/drive-file-thumbnail.vue +++ b/src/client/app/common/views/components/drive-file-thumbnail.vue @@ -105,15 +105,11 @@ export default Vue.extend({ }, isThumbnailAvailable(): boolean { return this.file.thumbnailUrl - ? this.file.thumbnailUrl.endsWith('?thumbnail') - ? (this.is === 'image' || this.is === 'video') - : true + ? (this.is === 'image' || this.is === 'video') : false; }, background(): string { - return this.file.properties.avgColor && this.file.properties.avgColor.length == 3 - ? `rgb(${this.file.properties.avgColor.join(',')})` - : 'transparent'; + return this.file.properties.avgColor || 'transparent'; } }, mounted() { @@ -122,10 +118,10 @@ export default Vue.extend({ }, methods: { onThumbnailLoaded() { - if (this.file.properties.avgColor && this.file.properties.avgColor.length == 3) { + if (this.file.properties.avgColor) { anime({ targets: this.$refs.thumbnail, - backgroundColor: `rgba(${this.file.properties.avgColor.join(',')}, 0)`, + backgroundColor: this.file.properties.avgColor.replace('255)', '0)'), duration: 100, easing: 'linear' }); diff --git a/src/client/app/common/views/components/games/reversi/reversi.game.vue b/src/client/app/common/views/components/games/reversi/reversi.game.vue index c6fc36db3..bd0401f78 100644 --- a/src/client/app/common/views/components/games/reversi/reversi.game.vue +++ b/src/client/app/common/views/components/games/reversi/reversi.game.vue @@ -24,11 +24,11 @@
- {{ String.fromCharCode(64 + i) }} + {{ String.fromCharCode(64 + i) }}
-
{{ i }}
+
{{ i }}
-
{{ i }}
+
{{ i }}
- {{ String.fromCharCode(64 + i) }} + {{ String.fromCharCode(64 + i) }}
@@ -71,9 +71,9 @@
-

{{ $t('is-llotheo') }}

-

{{ $t('looped-map') }}

-

{{ $t('can-put-everywhere') }}

+

{{ $t('is-llotheo') }}

+

{{ $t('looped-map') }}

+

{{ $t('can-put-everywhere') }}

@@ -160,8 +160,8 @@ export default Vue.extend({ cellsStyle(): any { return { - 'grid-template-rows': `repeat(${this.game.settings.map.length}, 1fr)`, - 'grid-template-columns': `repeat(${this.game.settings.map[0].length}, 1fr)` + 'grid-template-rows': `repeat(${this.game.map.length}, 1fr)`, + 'grid-template-columns': `repeat(${this.game.map[0].length}, 1fr)` }; } }, @@ -169,10 +169,10 @@ export default Vue.extend({ watch: { logPos(v) { if (!this.game.isEnded) return; - this.o = new Reversi(this.game.settings.map, { - isLlotheo: this.game.settings.isLlotheo, - canPutEverywhere: this.game.settings.canPutEverywhere, - loopedBoard: this.game.settings.loopedBoard + this.o = new Reversi(this.game.map, { + isLlotheo: this.game.isLlotheo, + canPutEverywhere: this.game.canPutEverywhere, + loopedBoard: this.game.loopedBoard }); for (const log of this.logs.slice(0, v)) { this.o.put(log.color, log.pos); @@ -184,10 +184,10 @@ export default Vue.extend({ created() { this.game = this.initGame; - this.o = new Reversi(this.game.settings.map, { - isLlotheo: this.game.settings.isLlotheo, - canPutEverywhere: this.game.settings.canPutEverywhere, - loopedBoard: this.game.settings.loopedBoard + this.o = new Reversi(this.game.map, { + isLlotheo: this.game.isLlotheo, + canPutEverywhere: this.game.canPutEverywhere, + loopedBoard: this.game.loopedBoard }); for (const log of this.game.logs) { @@ -286,10 +286,10 @@ export default Vue.extend({ onRescue(game) { this.game = game; - this.o = new Reversi(this.game.settings.map, { - isLlotheo: this.game.settings.isLlotheo, - canPutEverywhere: this.game.settings.canPutEverywhere, - loopedBoard: this.game.settings.loopedBoard + this.o = new Reversi(this.game.map, { + isLlotheo: this.game.isLlotheo, + canPutEverywhere: this.game.canPutEverywhere, + loopedBoard: this.game.loopedBoard }); for (const log of this.game.logs) { diff --git a/src/client/app/common/views/components/games/reversi/reversi.room.vue b/src/client/app/common/views/components/games/reversi/reversi.room.vue index d5d148790..9ee1a78b8 100644 --- a/src/client/app/common/views/components/games/reversi/reversi.room.vue +++ b/src/client/app/common/views/components/games/reversi/reversi.room.vue @@ -17,9 +17,9 @@
-
-
-
+
+
@@ -35,9 +35,9 @@
- {{ $t('random') }} - {{ this.$t('black-is').split('{}')[0] }}{{ this.$t('black-is').split('{}')[1] }} - {{ this.$t('black-is').split('{}')[0] }}{{ this.$t('black-is').split('{}')[1] }} + {{ $t('random') }} + {{ this.$t('black-is').split('{}')[0] }}{{ this.$t('black-is').split('{}')[1] }} + {{ this.$t('black-is').split('{}')[0] }}{{ this.$t('black-is').split('{}')[1] }}
@@ -47,9 +47,9 @@
- {{ $t('is-llotheo') }} - {{ $t('looped-map') }} - {{ $t('can-put-everywhere') }} + {{ $t('is-llotheo') }} + {{ $t('looped-map') }} + {{ $t('can-put-everywhere') }}
@@ -159,8 +159,8 @@ export default Vue.extend({ this.connection.on('initForm', this.onInitForm); this.connection.on('message', this.onMessage); - if (this.game.user1Id != this.$store.state.i.id && this.game.settings.form1) this.form = this.game.settings.form1; - if (this.game.user2Id != this.$store.state.i.id && this.game.settings.form2) this.form = this.game.settings.form2; + if (this.game.user1Id != this.$store.state.i.id && this.game.form1) this.form = this.game.form1; + if (this.game.user2Id != this.$store.state.i.id && this.game.form2) this.form = this.game.form2; }, beforeDestroy() { @@ -189,18 +189,19 @@ export default Vue.extend({ this.$forceUpdate(); }, - updateSettings() { + updateSettings(key: string) { this.connection.send('updateSettings', { - settings: this.game.settings + key: key, + value: this.game[key] }); }, - onUpdateSettings(settings) { - this.game.settings = settings; - if (this.game.settings.map == null) { + onUpdateSettings({ key, value }) { + this.game[key] = value; + if (this.game.map == null) { this.mapName = null; } else { - const found = Object.values(maps).find(x => x.data.join('') == this.game.settings.map.join('')); + const found = Object.values(maps).find(x => x.data.join('') == this.game.map.join('')); this.mapName = found ? found.name : '-Custom-'; } }, @@ -224,27 +225,27 @@ export default Vue.extend({ onMapChange() { if (this.mapName == null) { - this.game.settings.map = null; + this.game.map = null; } else { - this.game.settings.map = Object.values(maps).find(x => x.name == this.mapName).data; + this.game.map = Object.values(maps).find(x => x.name == this.mapName).data; } this.$forceUpdate(); this.updateSettings(); }, onPixelClick(pos, pixel) { - const x = pos % this.game.settings.map[0].length; - const y = Math.floor(pos / this.game.settings.map[0].length); + const x = pos % this.game.map[0].length; + const y = Math.floor(pos / this.game.map[0].length); const newPixel = pixel == ' ' ? '-' : pixel == '-' ? 'b' : pixel == 'b' ? 'w' : ' '; - const line = this.game.settings.map[y].split(''); + const line = this.game.map[y].split(''); line[x] = newPixel; - this.$set(this.game.settings.map, y, line.join('')); + this.$set(this.game.map, y, line.join('')); this.$forceUpdate(); - this.updateSettings(); + this.updateSettings('map'); } } }); diff --git a/src/client/app/common/views/components/games/reversi/reversi.vue b/src/client/app/common/views/components/games/reversi/reversi.vue index b6803cd7f..d33471a04 100644 --- a/src/client/app/common/views/components/games/reversi/reversi.vue +++ b/src/client/app/common/views/components/games/reversi/reversi.vue @@ -106,7 +106,7 @@ export default Vue.extend({ async nav(game, actualNav = true) { if (this.selfNav) { // 受け取ったゲーム情報が省略されたものなら完全な情報を取得する - if (game != null && (game.settings == null || game.settings.map == null)) { + if (game != null && game.map == null) { game = await this.$root.api('games/reversi/games/show', { gameId: game.id }); diff --git a/src/client/app/common/views/components/instance.vue b/src/client/app/common/views/components/instance.vue index 7b8d4f8e0..497e4976f 100644 --- a/src/client/app/common/views/components/instance.vue +++ b/src/client/app/common/views/components/instance.vue @@ -2,7 +2,7 @@
-

{{ meta.name }}

+

{{ meta.name || 'Misskey' }}

{{ $t('start') }}
diff --git a/src/client/app/common/views/components/media-image.vue b/src/client/app/common/views/components/media-image.vue index 3947ef552..255990751 100644 --- a/src/client/app/common/views/components/media-image.vue +++ b/src/client/app/common/views/components/media-image.vue @@ -52,7 +52,7 @@ export default Vue.extend({ } return { - 'background-color': this.image.properties.avgColor && this.image.properties.avgColor.length == 3 ? `rgb(${this.image.properties.avgColor.join(',')})` : 'transparent', + 'background-color': this.image.properties.avgColor || 'transparent', 'background-image': url }; } diff --git a/src/client/app/common/views/components/mention.vue b/src/client/app/common/views/components/mention.vue index 11dddbd52..e1f67282b 100644 --- a/src/client/app/common/views/components/mention.vue +++ b/src/client/app/common/views/components/mention.vue @@ -33,7 +33,7 @@ export default Vue.extend({ }, computed: { canonical(): string { - return `@${this.username}@${toUnicode(this.host)}`; + 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(); diff --git a/src/client/app/common/views/components/messaging-room.message.vue b/src/client/app/common/views/components/messaging-room.message.vue index ce76c402f..256ea760b 100644 --- a/src/client/app/common/views/components/messaging-room.message.vue +++ b/src/client/app/common/views/components/messaging-room.message.vue @@ -11,7 +11,7 @@ diff --git a/src/client/app/common/views/components/poll.vue b/src/client/app/common/views/components/poll.vue index ba14ba3a4..dc3aaa34f 100644 --- a/src/client/app/common/views/components/poll.vue +++ b/src/client/app/common/views/components/poll.vue @@ -1,7 +1,7 @@
- {{ $t('@.load-more') }} + {{ $t('@.load-more') }}
@@ -48,7 +48,7 @@ export default Vue.extend({ Progress.done(); }); }, - more() { + fetchMore() { this.moreFetching = true; this.$root.api('i/favorites', { limit: 11, diff --git a/src/client/app/desktop/views/home/home.vue b/src/client/app/desktop/views/home/home.vue index fb7af5a9a..d0b2fc10b 100644 --- a/src/client/app/desktop/views/home/home.vue +++ b/src/client/app/desktop/views/home/home.vue @@ -101,7 +101,7 @@ export default Vue.extend({ computed: { home(): any[] { if (this.$store.getters.isSignedIn) { - return this.$store.state.settings.home || []; + return this.$store.state.device.home || []; } else { return [{ name: 'instance', @@ -182,12 +182,8 @@ export default Vue.extend({ } //#endregion - if (this.$store.state.settings.home == null) { - this.$root.api('i/update_home', { - home: _defaultDesktopHomeWidgets - }).then(() => { - this.$store.commit('settings/setHome', _defaultDesktopHomeWidgets); - }); + if (this.$store.state.device.home == null) { + this.$store.commit('device/setHome', _defaultDesktopHomeWidgets); } } }, @@ -226,7 +222,7 @@ export default Vue.extend({ }, addWidget() { - this.$store.dispatch('settings/addHomeWidget', { + this.$store.commit('device/addHomeWidget', { name: this.widgetAdderSelected, id: uuid(), place: 'left', @@ -237,12 +233,9 @@ export default Vue.extend({ saveHome() { const left = this.widgets.left; const right = this.widgets.right; - this.$store.commit('settings/setHome', left.concat(right)); + this.$store.commit('device/setHome', left.concat(right)); for (const w of left) w.place = 'left'; for (const w of right) w.place = 'right'; - this.$root.api('i/update_home', { - home: this.home - }); }, done() { diff --git a/src/client/app/desktop/views/home/search.vue b/src/client/app/desktop/views/home/search.vue index 1632e730d..84153d18c 100644 --- a/src/client/app/desktop/views/home/search.vue +++ b/src/client/app/desktop/views/home/search.vue @@ -35,7 +35,7 @@ export default Vue.extend({ } else { return { notes: notes, - cursor: null + more: false }; } }) diff --git a/src/client/app/desktop/views/home/tag.vue b/src/client/app/desktop/views/home/tag.vue index 4f9bc66e7..92f5a4752 100644 --- a/src/client/app/desktop/views/home/tag.vue +++ b/src/client/app/desktop/views/home/tag.vue @@ -21,7 +21,7 @@ export default Vue.extend({ i18n: i18n('desktop/views/pages/tag.vue'), data() { return { - makePromise: cursor => this.$root.api('notes/search_by_tag', { + makePromise: cursor => this.$root.api('notes/search-by-tag', { limit: limit + 1, offset: cursor ? cursor : undefined, tag: this.$route.params.tag @@ -35,7 +35,7 @@ export default Vue.extend({ } else { return { notes: notes, - cursor: null + more: false }; } }) diff --git a/src/client/app/desktop/views/home/timeline.core.vue b/src/client/app/desktop/views/home/timeline.core.vue index e306ac873..12806365d 100644 --- a/src/client/app/desktop/views/home/timeline.core.vue +++ b/src/client/app/desktop/views/home/timeline.core.vue @@ -58,7 +58,7 @@ export default Vue.extend({ }; if (this.src == 'tag') { - this.endpoint = 'notes/search_by_tag'; + this.endpoint = 'notes/search-by-tag'; this.query = { query: this.tagTl.query }; @@ -113,12 +113,12 @@ export default Vue.extend({ notes.pop(); return { notes: notes, - cursor: notes[notes.length - 1].id + more: true }; } else { return { notes: notes, - cursor: null + more: false }; } }); diff --git a/src/client/app/desktop/views/home/timeline.vue b/src/client/app/desktop/views/home/timeline.vue index 0b8ced479..f257f1fa9 100644 --- a/src/client/app/desktop/views/home/timeline.vue +++ b/src/client/app/desktop/views/home/timeline.vue @@ -9,7 +9,7 @@ {{ $t('hybrid') }} {{ $t('global') }} {{ tagTl.title }} - {{ list.title }} + {{ list.name }}
@@ -143,7 +143,7 @@ export default Vue.extend({ menu = menu.concat(lists.map(list => ({ icon: 'list', - text: list.title, + text: list.name, action: () => { this.list = list; this.src = 'list'; diff --git a/src/client/app/desktop/views/home/user/index.vue b/src/client/app/desktop/views/home/user/index.vue index 17a34a30c..338cd1c59 100644 --- a/src/client/app/desktop/views/home/user/index.vue +++ b/src/client/app/desktop/views/home/user/index.vue @@ -4,7 +4,7 @@ {{ $t('@.user-suspended') }}
- {{ $t('@.is-remote-user') }}{{ $t('@.view-on-remote') }} + {{ $t('@.is-remote-user') }}{{ $t('@.view-on-remote') }}
diff --git a/src/client/app/desktop/views/home/user/user.header.vue b/src/client/app/desktop/views/home/user/user.header.vue index 85dcd3dda..e21757ccf 100644 --- a/src/client/app/desktop/views/home/user/user.header.vue +++ b/src/client/app/desktop/views/home/user/user.header.vue @@ -36,8 +36,8 @@
- {{ user.profile.location }} - {{ user.profile.birthday.replace('-', $t('year')).replace('-', $t('month')) + $t('day') }} ({{ $t('years-old', { age }) }}) + {{ user.location }} + {{ user.birthday.replace('-', $t('year')).replace('-', $t('month')) + $t('day') }} ({{ $t('years-old', { age }) }})
{{ user.notesCount | number }}{{ $t('posts') }} @@ -65,13 +65,13 @@ export default Vue.extend({ style(): any { if (this.user.bannerUrl == null) return {}; return { - backgroundColor: this.user.bannerColor && this.user.bannerColor.length == 3 ? `rgb(${ this.user.bannerColor.join(',') })` : null, + backgroundColor: this.user.bannerColor, backgroundImage: `url(${ this.user.bannerUrl })` }; }, age(): number { - return age(this.user.profile.birthday); + return age(this.user.birthday); } }, mounted() { diff --git a/src/client/app/desktop/views/home/user/user.timeline.vue b/src/client/app/desktop/views/home/user/user.timeline.vue index 4bdf4b6cd..eafac4c7f 100644 --- a/src/client/app/desktop/views/home/user/user.timeline.vue +++ b/src/client/app/desktop/views/home/user/user.timeline.vue @@ -42,12 +42,12 @@ export default Vue.extend({ notes.pop(); return { notes: notes, - cursor: new Date(notes[notes.length - 1].createdAt).getTime() + more: true }; } else { return { notes: notes, - cursor: null + more: false }; } }) diff --git a/src/client/app/desktop/views/pages/welcome.vue b/src/client/app/desktop/views/pages/welcome.vue index ddffeae40..5a5cd9c8e 100644 --- a/src/client/app/desktop/views/pages/welcome.vue +++ b/src/client/app/desktop/views/pages/welcome.vue @@ -13,8 +13,8 @@
-

{{ name }}

-

+

{{ name }}

+

Misskey

{{ host }} - @@ -87,7 +87,7 @@

Version: {{ meta.version }}

-

Maintainer: {{ meta.maintainer.name }}

+

Maintainer: {{ meta.maintainerName }}

@@ -162,7 +162,7 @@ export default Vue.extend({ banner: null, copyright, host: toUnicode(host), - name: 'Misskey', + name: null, description: '', announcements: [], photos: [] diff --git a/src/client/app/dev/views/new-app.vue b/src/client/app/dev/views/new-app.vue index d8c128904..00f2ed60d 100644 --- a/src/client/app/dev/views/new-app.vue +++ b/src/client/app/dev/views/new-app.vue @@ -15,15 +15,21 @@ {{ $t('authority-warning') }} - {{ $t('account-read') }} - {{ $t('account-write') }} - {{ $t('note-write') }} - {{ $t('reaction-write') }} - {{ $t('following-write') }} - {{ $t('drive-read') }} - {{ $t('drive-write') }} - {{ $t('notification-read') }} - {{ $t('notification-write') }} + {{ $t('read:account') }} + {{ $t('write:account') }} + {{ $t('write:notes') }} + {{ $t('read:reactions') }} + {{ $t('write:reactions') }} + {{ $t('read:following') }} + {{ $t('write:following') }} + {{ $t('read:mutes') }} + {{ $t('write:mutes') }} + {{ $t('read:blocks') }} + {{ $t('write:blocks') }} + {{ $t('read:drive') }} + {{ $t('write:drive') }} + {{ $t('read:notifications') }} + {{ $t('write:notifications') }} diff --git a/src/client/app/mios.ts b/src/client/app/mios.ts index 9e191bf43..a3525ed31 100644 --- a/src/client/app/mios.ts +++ b/src/client/app/mios.ts @@ -28,7 +28,7 @@ export default class MiOS extends EventEmitter { }; public get instanceName() { - return this.meta ? this.meta.data.name : 'Misskey'; + return this.meta ? (this.meta.data.name || 'Misskey') : 'Misskey'; } private isMetaFetching = false; @@ -278,21 +278,6 @@ export default class MiOS extends EventEmitter { }); }); - main.on('homeUpdated', x => { - this.store.commit('settings/setHome', x); - }); - - main.on('mobileHomeUpdated', x => { - this.store.commit('settings/setMobileHome', x); - }); - - main.on('widgetUpdated', x => { - this.store.commit('settings/updateWidget', { - id: x.id, - data: x.data - }); - }); - // トークンが再生成されたとき // このままではMisskeyが利用できないので強制的にサインアウトさせる main.on('myTokenRegenerated', () => { diff --git a/src/client/app/mobile/views/components/drive.file-detail.vue b/src/client/app/mobile/views/components/drive.file-detail.vue index 92f5c1fd1..98124354e 100644 --- a/src/client/app/mobile/views/components/drive.file-detail.vue +++ b/src/client/app/mobile/views/components/drive.file-detail.vue @@ -22,7 +22,7 @@
{{ file.type }} - {{ file.datasize | bytes }} + {{ file.size | bytes }} - @@ -53,7 +53,7 @@ export default Vue.extend({ Progress.done(); }); }, - more() { + fetchMore() { this.moreFetching = true; this.$root.api('i/favorites', { limit: 11, diff --git a/src/client/app/mobile/views/pages/home.timeline.vue b/src/client/app/mobile/views/pages/home.timeline.vue index 4f9f5119a..809158dd2 100644 --- a/src/client/app/mobile/views/pages/home.timeline.vue +++ b/src/client/app/mobile/views/pages/home.timeline.vue @@ -59,7 +59,7 @@ export default Vue.extend({ }; if (this.src == 'tag') { - this.endpoint = 'notes/search_by_tag'; + this.endpoint = 'notes/search-by-tag'; this.query = { query: this.tagTl.query }; @@ -114,12 +114,12 @@ export default Vue.extend({ notes.pop(); return { notes: notes, - cursor: notes[notes.length - 1].id + more: true }; } else { return { notes: notes, - cursor: null + more: false }; } }); diff --git a/src/client/app/mobile/views/pages/home.vue b/src/client/app/mobile/views/pages/home.vue index 59fae2340..cf15670f3 100644 --- a/src/client/app/mobile/views/pages/home.vue +++ b/src/client/app/mobile/views/pages/home.vue @@ -9,7 +9,7 @@ {{ $t('global') }} {{ $t('mentions') }} {{ $t('messages') }} - {{ list.title }} + {{ list.name }} {{ tagTl.title }} diff --git a/src/client/app/mobile/views/pages/search.vue b/src/client/app/mobile/views/pages/search.vue index 9e4be8204..f4b251280 100644 --- a/src/client/app/mobile/views/pages/search.vue +++ b/src/client/app/mobile/views/pages/search.vue @@ -21,19 +21,19 @@ export default Vue.extend({ return { makePromise: cursor => this.$root.api('notes/search', { limit: limit + 1, - offset: cursor ? cursor : undefined, + untilId: cursor ? cursor : undefined, query: this.q }).then(notes => { if (notes.length == limit + 1) { notes.pop(); return { notes: notes, - cursor: cursor ? cursor + limit : limit + more: true }; } else { return { notes: notes, - cursor: null + more: false }; } }) diff --git a/src/client/app/mobile/views/pages/tag.vue b/src/client/app/mobile/views/pages/tag.vue index 318e63a47..f41cf1f18 100644 --- a/src/client/app/mobile/views/pages/tag.vue +++ b/src/client/app/mobile/views/pages/tag.vue @@ -19,21 +19,21 @@ export default Vue.extend({ i18n: i18n('mobile/views/pages/tag.vue'), data() { return { - makePromise: cursor => this.$root.api('notes/search_by_tag', { + makePromise: cursor => this.$root.api('notes/search-by-tag', { limit: limit + 1, - offset: cursor ? cursor : undefined, + untilId: cursor ? cursor : undefined, tag: this.$route.params.tag }).then(notes => { if (notes.length == limit + 1) { notes.pop(); return { notes: notes, - cursor: cursor ? cursor + limit : limit + more: true }; } else { return { notes: notes, - cursor: null + more: false }; } }) diff --git a/src/client/app/mobile/views/pages/user-list.vue b/src/client/app/mobile/views/pages/user-list.vue index 874bae5d1..68fd0358c 100644 --- a/src/client/app/mobile/views/pages/user-list.vue +++ b/src/client/app/mobile/views/pages/user-list.vue @@ -1,6 +1,6 @@

{{ $t('@.user-suspended') }}

-

{{ $t('@.is-remote-user') }}{{ $t('@.view-on-remote') }}

+

{{ $t('@.is-remote-user') }}{{ $t('@.view-on-remote') }}

@@ -36,11 +36,11 @@
-

- {{ user.profile.location }} +

+ {{ user.location }}

-

- {{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ $t('years-old', { age }) }}) +

+ {{ user.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ $t('years-old', { age }) }})

@@ -104,7 +104,7 @@ export default Vue.extend({ }, computed: { age(): number { - return age(this.user.profile.birthday); + return age(this.user.birthday); }, avator(): string { return this.$store.state.device.disableShowingAnimatedImages @@ -114,7 +114,7 @@ export default Vue.extend({ style(): any { if (this.user.bannerUrl == null) return {}; return { - backgroundColor: this.user.bannerColor && this.user.bannerColor.length == 3 ? `rgb(${ this.user.bannerColor.join(',') })` : null, + backgroundColor: this.user.bannerColor, backgroundImage: `url(${ this.user.bannerUrl })` }; } diff --git a/src/client/app/mobile/views/pages/welcome.vue b/src/client/app/mobile/views/pages/welcome.vue index 1a2b0b6c1..dd71a918d 100644 --- a/src/client/app/mobile/views/pages/welcome.vue +++ b/src/client/app/mobile/views/pages/welcome.vue @@ -3,10 +3,10 @@
- + Misskey

{{ host }}

-

{{ name }}

+

{{ name || 'Misskey' }}

@@ -62,7 +62,7 @@

Version: {{ meta.version }}

-

Maintainer: {{ meta.maintainer.name }}

+

Maintainer: {{ meta.maintainerName }}