From cf33e483f7e6f40e8cbbbc0118a7df70bdaf651f Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 29 Mar 2018 20:32:18 +0900 Subject: 整理した MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/client/app/common/scripts/check-for-update.ts | 33 +++++ .../app/common/scripts/compose-notification.ts | 67 ++++++++++ src/client/app/common/scripts/contains.ts | 8 ++ src/client/app/common/scripts/copy-to-clipboard.ts | 13 ++ src/client/app/common/scripts/date-stringify.ts | 13 ++ src/client/app/common/scripts/fuck-ad-block.ts | 21 ++++ src/client/app/common/scripts/gcd.ts | 2 + src/client/app/common/scripts/get-kao.ts | 5 + src/client/app/common/scripts/get-median.ts | 11 ++ src/client/app/common/scripts/loading.ts | 21 ++++ .../app/common/scripts/parse-search-query.ts | 53 ++++++++ src/client/app/common/scripts/streaming/channel.ts | 13 ++ src/client/app/common/scripts/streaming/drive.ts | 34 +++++ src/client/app/common/scripts/streaming/home.ts | 57 +++++++++ .../common/scripts/streaming/messaging-index.ts | 34 +++++ .../app/common/scripts/streaming/messaging.ts | 20 +++ .../app/common/scripts/streaming/othello-game.ts | 11 ++ src/client/app/common/scripts/streaming/othello.ts | 31 +++++ .../app/common/scripts/streaming/requests.ts | 30 +++++ src/client/app/common/scripts/streaming/server.ts | 30 +++++ .../app/common/scripts/streaming/stream-manager.ts | 108 ++++++++++++++++ src/client/app/common/scripts/streaming/stream.ts | 137 +++++++++++++++++++++ 22 files changed, 752 insertions(+) create mode 100644 src/client/app/common/scripts/check-for-update.ts create mode 100644 src/client/app/common/scripts/compose-notification.ts create mode 100644 src/client/app/common/scripts/contains.ts create mode 100644 src/client/app/common/scripts/copy-to-clipboard.ts create mode 100644 src/client/app/common/scripts/date-stringify.ts create mode 100644 src/client/app/common/scripts/fuck-ad-block.ts create mode 100644 src/client/app/common/scripts/gcd.ts create mode 100644 src/client/app/common/scripts/get-kao.ts create mode 100644 src/client/app/common/scripts/get-median.ts create mode 100644 src/client/app/common/scripts/loading.ts create mode 100644 src/client/app/common/scripts/parse-search-query.ts create mode 100644 src/client/app/common/scripts/streaming/channel.ts create mode 100644 src/client/app/common/scripts/streaming/drive.ts create mode 100644 src/client/app/common/scripts/streaming/home.ts create mode 100644 src/client/app/common/scripts/streaming/messaging-index.ts create mode 100644 src/client/app/common/scripts/streaming/messaging.ts create mode 100644 src/client/app/common/scripts/streaming/othello-game.ts create mode 100644 src/client/app/common/scripts/streaming/othello.ts create mode 100644 src/client/app/common/scripts/streaming/requests.ts create mode 100644 src/client/app/common/scripts/streaming/server.ts create mode 100644 src/client/app/common/scripts/streaming/stream-manager.ts create mode 100644 src/client/app/common/scripts/streaming/stream.ts (limited to 'src/client/app/common/scripts') diff --git a/src/client/app/common/scripts/check-for-update.ts b/src/client/app/common/scripts/check-for-update.ts new file mode 100644 index 0000000000..81c1eb9812 --- /dev/null +++ b/src/client/app/common/scripts/check-for-update.ts @@ -0,0 +1,33 @@ +import MiOS from '../mios'; +import { version as current } from '../../config'; + +export default async function(mios: MiOS, force = false, silent = false) { + const meta = await mios.getMeta(force); + const newer = meta.version; + + if (newer != current) { + localStorage.setItem('should-refresh', 'true'); + localStorage.setItem('v', newer); + + // Clear cache (serive worker) + try { + if (navigator.serviceWorker.controller) { + navigator.serviceWorker.controller.postMessage('clear'); + } + + navigator.serviceWorker.getRegistrations().then(registrations => { + registrations.forEach(registration => registration.unregister()); + }); + } catch (e) { + console.error(e); + } + + if (!silent) { + alert('%i18n:common.update-available%'.replace('{newer}', newer).replace('{current}', current)); + } + + return newer; + } else { + return null; + } +} diff --git a/src/client/app/common/scripts/compose-notification.ts b/src/client/app/common/scripts/compose-notification.ts new file mode 100644 index 0000000000..273579cbc6 --- /dev/null +++ b/src/client/app/common/scripts/compose-notification.ts @@ -0,0 +1,67 @@ +import getPostSummary from '../../../../common/get-post-summary'; +import getReactionEmoji from '../../../../common/get-reaction-emoji'; + +type Notification = { + title: string; + body: string; + icon: string; + onclick?: any; +}; + +// TODO: i18n + +export default function(type, data): Notification { + switch (type) { + case 'drive_file_created': + return { + title: 'ファイルがアップロードされました', + body: data.name, + icon: data.url + '?thumbnail&size=64' + }; + + case 'mention': + return { + title: `${data.user.name}さんから:`, + body: getPostSummary(data), + icon: data.user.avatarUrl + '?thumbnail&size=64' + }; + + case 'reply': + return { + title: `${data.user.name}さんから返信:`, + body: getPostSummary(data), + icon: data.user.avatarUrl + '?thumbnail&size=64' + }; + + case 'quote': + return { + title: `${data.user.name}さんが引用:`, + body: getPostSummary(data), + icon: data.user.avatarUrl + '?thumbnail&size=64' + }; + + case 'reaction': + return { + title: `${data.user.name}: ${getReactionEmoji(data.reaction)}:`, + body: getPostSummary(data.post), + icon: data.user.avatarUrl + '?thumbnail&size=64' + }; + + case 'unread_messaging_message': + return { + title: `${data.user.name}さんからメッセージ:`, + body: data.text, // TODO: getMessagingMessageSummary(data), + icon: data.user.avatarUrl + '?thumbnail&size=64' + }; + + case 'othello_invited': + return { + title: '対局への招待があります', + body: `${data.parent.name}さんから`, + icon: data.parent.avatarUrl + '?thumbnail&size=64' + }; + + default: + return null; + } +} diff --git a/src/client/app/common/scripts/contains.ts b/src/client/app/common/scripts/contains.ts new file mode 100644 index 0000000000..a5071b3f25 --- /dev/null +++ b/src/client/app/common/scripts/contains.ts @@ -0,0 +1,8 @@ +export default (parent, child) => { + let node = child.parentNode; + while (node) { + if (node == parent) return true; + node = node.parentNode; + } + return false; +}; diff --git a/src/client/app/common/scripts/copy-to-clipboard.ts b/src/client/app/common/scripts/copy-to-clipboard.ts new file mode 100644 index 0000000000..3d2741f8d7 --- /dev/null +++ b/src/client/app/common/scripts/copy-to-clipboard.ts @@ -0,0 +1,13 @@ +/** + * Clipboardに値をコピー(TODO: 文字列以外も対応) + */ +export default val => { + const form = document.createElement('textarea'); + form.textContent = val; + document.body.appendChild(form); + form.select(); + const result = document.execCommand('copy'); + document.body.removeChild(form); + + return result; +}; diff --git a/src/client/app/common/scripts/date-stringify.ts b/src/client/app/common/scripts/date-stringify.ts new file mode 100644 index 0000000000..e51de8833d --- /dev/null +++ b/src/client/app/common/scripts/date-stringify.ts @@ -0,0 +1,13 @@ +export default date => { + if (typeof date == 'string') date = new Date(date); + return ( + date.getFullYear() + '年' + + (date.getMonth() + 1) + '月' + + date.getDate() + '日' + + ' ' + + date.getHours() + '時' + + date.getMinutes() + '分' + + ' ' + + `(${['日', '月', '火', '水', '木', '金', '土'][date.getDay()]})` + ); +}; diff --git a/src/client/app/common/scripts/fuck-ad-block.ts b/src/client/app/common/scripts/fuck-ad-block.ts new file mode 100644 index 0000000000..9bcf7deeff --- /dev/null +++ b/src/client/app/common/scripts/fuck-ad-block.ts @@ -0,0 +1,21 @@ +require('fuckadblock'); + +declare const fuckAdBlock: any; + +export default (os) => { + function adBlockDetected() { + os.apis.dialog({ + title: '%fa:exclamation-triangle%広告ブロッカーを無効にしてください', + text: 'Misskeyは広告を掲載していませんが、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。', + actins: [{ + text: 'OK' + }] + }); + } + + if (fuckAdBlock === undefined) { + adBlockDetected(); + } else { + fuckAdBlock.onDetected(adBlockDetected); + } +}; diff --git a/src/client/app/common/scripts/gcd.ts b/src/client/app/common/scripts/gcd.ts new file mode 100644 index 0000000000..9a19f9da66 --- /dev/null +++ b/src/client/app/common/scripts/gcd.ts @@ -0,0 +1,2 @@ +const gcd = (a, b) => !b ? a : gcd(b, a % b); +export default gcd; diff --git a/src/client/app/common/scripts/get-kao.ts b/src/client/app/common/scripts/get-kao.ts new file mode 100644 index 0000000000..2168c5be88 --- /dev/null +++ b/src/client/app/common/scripts/get-kao.ts @@ -0,0 +1,5 @@ +export default () => [ + '(=^・・^=)', + 'v(‘ω’)v', + '🐡( \'-\' 🐡 )フグパンチ!!!!' +][Math.floor(Math.random() * 3)]; diff --git a/src/client/app/common/scripts/get-median.ts b/src/client/app/common/scripts/get-median.ts new file mode 100644 index 0000000000..91a415d5b2 --- /dev/null +++ b/src/client/app/common/scripts/get-median.ts @@ -0,0 +1,11 @@ +/** + * 中央値を求めます + * @param samples サンプル + */ +export default function(samples) { + if (!samples.length) return 0; + const numbers = samples.slice(0).sort((a, b) => a - b); + const middle = Math.floor(numbers.length / 2); + const isEven = numbers.length % 2 === 0; + return isEven ? (numbers[middle] + numbers[middle - 1]) / 2 : numbers[middle]; +} diff --git a/src/client/app/common/scripts/loading.ts b/src/client/app/common/scripts/loading.ts new file mode 100644 index 0000000000..c48e626648 --- /dev/null +++ b/src/client/app/common/scripts/loading.ts @@ -0,0 +1,21 @@ +const NProgress = require('nprogress'); +NProgress.configure({ + trickleSpeed: 500, + showSpinner: false +}); + +const root = document.getElementsByTagName('html')[0]; + +export default { + start: () => { + root.classList.add('progress'); + NProgress.start(); + }, + done: () => { + root.classList.remove('progress'); + NProgress.done(); + }, + set: val => { + NProgress.set(val); + } +}; diff --git a/src/client/app/common/scripts/parse-search-query.ts b/src/client/app/common/scripts/parse-search-query.ts new file mode 100644 index 0000000000..4f09d2b93f --- /dev/null +++ b/src/client/app/common/scripts/parse-search-query.ts @@ -0,0 +1,53 @@ +export default function(qs: string) { + const q = { + text: '' + }; + + qs.split(' ').forEach(x => { + if (/^([a-z_]+?):(.+?)$/.test(x)) { + const [key, value] = x.split(':'); + switch (key) { + case 'user': + q['includeUserUsernames'] = value.split(','); + break; + case 'exclude_user': + q['excludeUserUsernames'] = value.split(','); + break; + case 'follow': + q['following'] = value == 'null' ? null : value == 'true'; + break; + case 'reply': + q['reply'] = value == 'null' ? null : value == 'true'; + break; + case 'repost': + q['repost'] = value == 'null' ? null : value == 'true'; + break; + case 'media': + q['media'] = value == 'null' ? null : value == 'true'; + break; + case 'poll': + q['poll'] = value == 'null' ? null : value == 'true'; + break; + case 'until': + case 'since': + // YYYY-MM-DD + if (/^[0-9]+\-[0-9]+\-[0-9]+$/) { + const [yyyy, mm, dd] = value.split('-'); + q[`${key}_date`] = (new Date(parseInt(yyyy, 10), parseInt(mm, 10) - 1, parseInt(dd, 10))).getTime(); + } + break; + default: + q[key] = value; + break; + } + } else { + q.text += x + ' '; + } + }); + + if (q.text) { + q.text = q.text.trim(); + } + + return q; +} diff --git a/src/client/app/common/scripts/streaming/channel.ts b/src/client/app/common/scripts/streaming/channel.ts new file mode 100644 index 0000000000..cab5f4edb4 --- /dev/null +++ b/src/client/app/common/scripts/streaming/channel.ts @@ -0,0 +1,13 @@ +import Stream from './stream'; +import MiOS from '../../mios'; + +/** + * Channel stream connection + */ +export default class Connection extends Stream { + constructor(os: MiOS, channelId) { + super(os, 'channel', { + channel: channelId + }); + } +} diff --git a/src/client/app/common/scripts/streaming/drive.ts b/src/client/app/common/scripts/streaming/drive.ts new file mode 100644 index 0000000000..f11573685e --- /dev/null +++ b/src/client/app/common/scripts/streaming/drive.ts @@ -0,0 +1,34 @@ +import Stream from './stream'; +import StreamManager from './stream-manager'; +import MiOS from '../../mios'; + +/** + * Drive stream connection + */ +export class DriveStream extends Stream { + constructor(os: MiOS, me) { + super(os, 'drive', { + i: me.account.token + }); + } +} + +export class DriveStreamManager extends StreamManager { + private me; + private os: MiOS; + + constructor(os: MiOS, me) { + super(); + + this.me = me; + this.os = os; + } + + public getConnection() { + if (this.connection == null) { + this.connection = new DriveStream(this.os, this.me); + } + + return this.connection; + } +} diff --git a/src/client/app/common/scripts/streaming/home.ts b/src/client/app/common/scripts/streaming/home.ts new file mode 100644 index 0000000000..c198619400 --- /dev/null +++ b/src/client/app/common/scripts/streaming/home.ts @@ -0,0 +1,57 @@ +import * as merge from 'object-assign-deep'; + +import Stream from './stream'; +import StreamManager from './stream-manager'; +import MiOS from '../../mios'; + +/** + * Home stream connection + */ +export class HomeStream extends Stream { + constructor(os: MiOS, me) { + super(os, '', { + i: me.account.token + }); + + // 最終利用日時を更新するため定期的にaliveメッセージを送信 + setInterval(() => { + this.send({ type: 'alive' }); + me.account.lastUsedAt = new Date(); + }, 1000 * 60); + + // 自分の情報が更新されたとき + this.on('i_updated', i => { + if (os.debug) { + console.log('I updated:', i); + } + merge(me, i); + }); + + // トークンが再生成されたとき + // このままではAPIが利用できないので強制的にサインアウトさせる + this.on('my_token_regenerated', () => { + alert('%i18n:common.my-token-regenerated%'); + os.signout(); + }); + } +} + +export class HomeStreamManager extends StreamManager { + private me; + private os: MiOS; + + constructor(os: MiOS, me) { + super(); + + this.me = me; + this.os = os; + } + + public getConnection() { + if (this.connection == null) { + this.connection = new HomeStream(this.os, this.me); + } + + return this.connection; + } +} diff --git a/src/client/app/common/scripts/streaming/messaging-index.ts b/src/client/app/common/scripts/streaming/messaging-index.ts new file mode 100644 index 0000000000..24f0ce0c9f --- /dev/null +++ b/src/client/app/common/scripts/streaming/messaging-index.ts @@ -0,0 +1,34 @@ +import Stream from './stream'; +import StreamManager from './stream-manager'; +import MiOS from '../../mios'; + +/** + * Messaging index stream connection + */ +export class MessagingIndexStream extends Stream { + constructor(os: MiOS, me) { + super(os, 'messaging-index', { + i: me.account.token + }); + } +} + +export class MessagingIndexStreamManager extends StreamManager { + private me; + private os: MiOS; + + constructor(os: MiOS, me) { + super(); + + this.me = me; + this.os = os; + } + + public getConnection() { + if (this.connection == null) { + this.connection = new MessagingIndexStream(this.os, this.me); + } + + return this.connection; + } +} diff --git a/src/client/app/common/scripts/streaming/messaging.ts b/src/client/app/common/scripts/streaming/messaging.ts new file mode 100644 index 0000000000..4c593deb31 --- /dev/null +++ b/src/client/app/common/scripts/streaming/messaging.ts @@ -0,0 +1,20 @@ +import Stream from './stream'; +import MiOS from '../../mios'; + +/** + * Messaging stream connection + */ +export class MessagingStream extends Stream { + constructor(os: MiOS, me, otherparty) { + super(os, 'messaging', { + i: me.account.token, + otherparty + }); + + (this as any).on('_connected_', () => { + this.send({ + i: me.account.token + }); + }); + } +} diff --git a/src/client/app/common/scripts/streaming/othello-game.ts b/src/client/app/common/scripts/streaming/othello-game.ts new file mode 100644 index 0000000000..f34ef35147 --- /dev/null +++ b/src/client/app/common/scripts/streaming/othello-game.ts @@ -0,0 +1,11 @@ +import Stream from './stream'; +import MiOS from '../../mios'; + +export class OthelloGameStream extends Stream { + constructor(os: MiOS, me, game) { + super(os, 'othello-game', { + i: me ? me.account.token : null, + game: game.id + }); + } +} diff --git a/src/client/app/common/scripts/streaming/othello.ts b/src/client/app/common/scripts/streaming/othello.ts new file mode 100644 index 0000000000..8c6f4b9c3c --- /dev/null +++ b/src/client/app/common/scripts/streaming/othello.ts @@ -0,0 +1,31 @@ +import StreamManager from './stream-manager'; +import Stream from './stream'; +import MiOS from '../../mios'; + +export class OthelloStream extends Stream { + constructor(os: MiOS, me) { + super(os, 'othello', { + i: me.account.token + }); + } +} + +export class OthelloStreamManager extends StreamManager { + private me; + private os: MiOS; + + constructor(os: MiOS, me) { + super(); + + this.me = me; + this.os = os; + } + + public getConnection() { + if (this.connection == null) { + this.connection = new OthelloStream(this.os, this.me); + } + + return this.connection; + } +} diff --git a/src/client/app/common/scripts/streaming/requests.ts b/src/client/app/common/scripts/streaming/requests.ts new file mode 100644 index 0000000000..5bec30143f --- /dev/null +++ b/src/client/app/common/scripts/streaming/requests.ts @@ -0,0 +1,30 @@ +import Stream from './stream'; +import StreamManager from './stream-manager'; +import MiOS from '../../mios'; + +/** + * Requests stream connection + */ +export class RequestsStream extends Stream { + constructor(os: MiOS) { + super(os, 'requests'); + } +} + +export class RequestsStreamManager extends StreamManager { + private os: MiOS; + + constructor(os: MiOS) { + super(); + + this.os = os; + } + + public getConnection() { + if (this.connection == null) { + this.connection = new RequestsStream(this.os); + } + + return this.connection; + } +} diff --git a/src/client/app/common/scripts/streaming/server.ts b/src/client/app/common/scripts/streaming/server.ts new file mode 100644 index 0000000000..3d35ef4d9d --- /dev/null +++ b/src/client/app/common/scripts/streaming/server.ts @@ -0,0 +1,30 @@ +import Stream from './stream'; +import StreamManager from './stream-manager'; +import MiOS from '../../mios'; + +/** + * Server stream connection + */ +export class ServerStream extends Stream { + constructor(os: MiOS) { + super(os, 'server'); + } +} + +export class ServerStreamManager extends StreamManager { + private os: MiOS; + + constructor(os: MiOS) { + super(); + + this.os = os; + } + + public getConnection() { + if (this.connection == null) { + this.connection = new ServerStream(this.os); + } + + return this.connection; + } +} diff --git a/src/client/app/common/scripts/streaming/stream-manager.ts b/src/client/app/common/scripts/streaming/stream-manager.ts new file mode 100644 index 0000000000..568b8b0372 --- /dev/null +++ b/src/client/app/common/scripts/streaming/stream-manager.ts @@ -0,0 +1,108 @@ +import { EventEmitter } from 'eventemitter3'; +import * as uuid from 'uuid'; +import Connection from './stream'; + +/** + * ストリーム接続を管理するクラス + * 複数の場所から同じストリームを利用する際、接続をまとめたりする + */ +export default abstract class StreamManager extends EventEmitter { + private _connection: T = null; + + private disposeTimerId: any; + + /** + * コネクションを必要としているユーザー + */ + private users = []; + + protected set connection(connection: T) { + this._connection = connection; + + if (this._connection == null) { + this.emit('disconnected'); + } else { + this.emit('connected', this._connection); + + this._connection.on('_connected_', () => { + this.emit('_connected_'); + }); + + this._connection.on('_disconnected_', () => { + this.emit('_disconnected_'); + }); + + this._connection.user = 'Managed'; + } + } + + protected get connection() { + return this._connection; + } + + /** + * コネクションを持っているか否か + */ + public get hasConnection() { + return this._connection != null; + } + + public get state(): string { + if (!this.hasConnection) return 'no-connection'; + return this._connection.state; + } + + /** + * コネクションを要求します + */ + public abstract getConnection(): T; + + /** + * 現在接続しているコネクションを取得します + */ + public borrow() { + return this._connection; + } + + /** + * コネクションを要求するためのユーザーIDを発行します + */ + public use() { + // タイマー解除 + if (this.disposeTimerId) { + clearTimeout(this.disposeTimerId); + this.disposeTimerId = null; + } + + // ユーザーID生成 + const userId = uuid(); + + this.users.push(userId); + + this._connection.user = `Managed (${ this.users.length })`; + + return userId; + } + + /** + * コネクションを利用し終わってもう必要ないことを通知します + * @param userId use で発行したユーザーID + */ + public dispose(userId) { + this.users = this.users.filter(id => id != userId); + + this._connection.user = `Managed (${ this.users.length })`; + + // 誰もコネクションの利用者がいなくなったら + if (this.users.length == 0) { + // また直ぐに再利用される可能性があるので、一定時間待ち、 + // 新たな利用者が現れなければコネクションを切断する + this.disposeTimerId = setTimeout(() => { + this.disposeTimerId = null; + + this.connection.close(); + this.connection = null; + }, 3000); + } + } +} diff --git a/src/client/app/common/scripts/streaming/stream.ts b/src/client/app/common/scripts/streaming/stream.ts new file mode 100644 index 0000000000..3912186ad3 --- /dev/null +++ b/src/client/app/common/scripts/streaming/stream.ts @@ -0,0 +1,137 @@ +import { EventEmitter } from 'eventemitter3'; +import * as uuid from 'uuid'; +import * as ReconnectingWebsocket from 'reconnecting-websocket'; +import { wsUrl } from '../../../config'; +import MiOS from '../../mios'; + +/** + * Misskey stream connection + */ +export default class Connection extends EventEmitter { + public state: string; + private buffer: any[]; + public socket: ReconnectingWebsocket; + public name: string; + public connectedAt: Date; + public user: string = null; + public in: number = 0; + public out: number = 0; + public inout: Array<{ + type: 'in' | 'out', + at: Date, + data: string + }> = []; + public id: string; + public isSuspended = false; + private os: MiOS; + + constructor(os: MiOS, endpoint, params?) { + super(); + + //#region BIND + this.onOpen = this.onOpen.bind(this); + this.onClose = this.onClose.bind(this); + this.onMessage = this.onMessage.bind(this); + this.send = this.send.bind(this); + this.close = this.close.bind(this); + //#endregion + + this.id = uuid(); + this.os = os; + this.name = endpoint; + this.state = 'initializing'; + this.buffer = []; + + const query = params + ? Object.keys(params) + .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])) + .join('&') + : null; + + this.socket = new ReconnectingWebsocket(`${wsUrl}/${endpoint}${query ? '?' + query : ''}`); + this.socket.addEventListener('open', this.onOpen); + this.socket.addEventListener('close', this.onClose); + this.socket.addEventListener('message', this.onMessage); + + // Register this connection for debugging + this.os.registerStreamConnection(this); + } + + /** + * Callback of when open connection + */ + private onOpen() { + this.state = 'connected'; + this.emit('_connected_'); + + this.connectedAt = new Date(); + + // バッファーを処理 + const _buffer = [].concat(this.buffer); // Shallow copy + this.buffer = []; // Clear buffer + _buffer.forEach(data => { + this.send(data); // Resend each buffered messages + + if (this.os.debug) { + this.out++; + this.inout.push({ type: 'out', at: new Date(), data }); + } + }); + } + + /** + * Callback of when close connection + */ + private onClose() { + this.state = 'reconnecting'; + this.emit('_disconnected_'); + } + + /** + * Callback of when received a message from connection + */ + private onMessage(message) { + if (this.isSuspended) return; + + if (this.os.debug) { + this.in++; + this.inout.push({ type: 'in', at: new Date(), data: message.data }); + } + + try { + const msg = JSON.parse(message.data); + if (msg.type) this.emit(msg.type, msg.body); + } catch (e) { + // noop + } + } + + /** + * Send a message to connection + */ + public send(data) { + if (this.isSuspended) return; + + // まだ接続が確立されていなかったらバッファリングして次に接続した時に送信する + if (this.state != 'connected') { + this.buffer.push(data); + return; + } + + if (this.os.debug) { + this.out++; + this.inout.push({ type: 'out', at: new Date(), data }); + } + + this.socket.send(JSON.stringify(data)); + } + + /** + * Close this connection + */ + public close() { + this.os.unregisterStreamConnection(this); + this.socket.removeEventListener('open', this.onOpen); + this.socket.removeEventListener('message', this.onMessage); + } +} -- cgit v1.2.3-freya From cd2542e0fd8578f6e41114ffebbda1f16f7d04ce Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 2 Apr 2018 04:15:27 +0900 Subject: Refactor --- src/client/app/ch/tags/channel.tag | 2 +- .../app/common/scripts/compose-notification.ts | 4 +- .../app/common/views/components/autocomplete.vue | 2 +- .../views/components/messaging-room.message.vue | 2 +- .../app/common/views/components/messaging.vue | 2 +- .../app/common/views/components/othello.game.vue | 2 +- .../app/common/views/components/othello.room.vue | 2 +- .../app/common/views/components/post-html.ts | 2 +- .../common/views/components/welcome-timeline.vue | 2 +- .../app/desktop/views/components/friends-maker.vue | 2 +- .../views/components/messaging-room-window.vue | 2 +- .../app/desktop/views/components/notifications.vue | 4 +- .../desktop/views/components/post-detail.sub.vue | 2 +- .../app/desktop/views/components/post-detail.vue | 2 +- .../app/desktop/views/components/post-preview.vue | 2 +- .../desktop/views/components/posts.post.sub.vue | 2 +- .../app/desktop/views/components/posts.post.vue | 2 +- .../app/desktop/views/components/settings.mute.vue | 2 +- .../app/desktop/views/components/user-preview.vue | 4 +- .../desktop/views/components/users-list.item.vue | 2 +- src/client/app/desktop/views/pages/home.vue | 2 +- .../app/desktop/views/pages/messaging-room.vue | 2 +- .../views/pages/user/user.followers-you-know.vue | 2 +- .../app/desktop/views/pages/user/user.friends.vue | 2 +- .../app/desktop/views/pages/user/user.header.vue | 2 +- src/client/app/desktop/views/pages/user/user.vue | 2 +- src/client/app/desktop/views/pages/welcome.vue | 2 +- .../desktop/views/widgets/channel.channel.post.vue | 2 +- src/client/app/desktop/views/widgets/polls.vue | 2 +- src/client/app/desktop/views/widgets/trends.vue | 2 +- src/client/app/desktop/views/widgets/users.vue | 2 +- src/client/app/mobile/api/post.ts | 2 +- .../views/components/notification-preview.vue | 2 +- .../app/mobile/views/components/notification.vue | 4 +- .../app/mobile/views/components/post-card.vue | 4 +- .../mobile/views/components/post-detail.sub.vue | 2 +- .../app/mobile/views/components/post-detail.vue | 2 +- .../app/mobile/views/components/post-preview.vue | 2 +- .../app/mobile/views/components/post.sub.vue | 2 +- src/client/app/mobile/views/components/post.vue | 2 +- .../app/mobile/views/components/user-card.vue | 2 +- .../app/mobile/views/components/user-preview.vue | 2 +- src/client/app/mobile/views/pages/followers.vue | 2 +- src/client/app/mobile/views/pages/following.vue | 2 +- src/client/app/mobile/views/pages/home.vue | 2 +- .../app/mobile/views/pages/messaging-room.vue | 2 +- src/client/app/mobile/views/pages/messaging.vue | 2 +- src/client/app/mobile/views/pages/user.vue | 4 +- .../views/pages/user/home.followers-you-know.vue | 2 +- .../app/mobile/views/pages/user/home.photos.vue | 2 +- src/common/drive/add-file.ts | 2 +- src/common/drive/upload-from-url.ts | 46 ++ src/common/drive/upload_from_url.ts | 46 -- src/common/get-notification-summary.ts | 27 - src/common/get-post-summary.ts | 45 - src/common/get-reaction-emoji.ts | 14 - src/common/othello/ai/back.ts | 376 --------- src/common/othello/ai/front.ts | 233 ------ src/common/othello/ai/index.ts | 1 - src/common/othello/core.ts | 340 -------- src/common/othello/maps.ts | 911 --------------------- src/common/remote/activitypub/act/create.ts | 9 - src/common/remote/activitypub/act/index.ts | 22 - src/common/remote/activitypub/create.ts | 87 -- src/common/remote/activitypub/renderer/context.ts | 5 - src/common/remote/activitypub/renderer/document.ts | 7 - src/common/remote/activitypub/renderer/follow.ts | 8 - src/common/remote/activitypub/renderer/hashtag.ts | 7 - src/common/remote/activitypub/renderer/image.ts | 6 - src/common/remote/activitypub/renderer/key.ts | 10 - src/common/remote/activitypub/renderer/note.ts | 44 - .../activitypub/renderer/ordered-collection.ts | 6 - src/common/remote/activitypub/renderer/person.ts | 20 - src/common/remote/activitypub/resolve-person.ts | 109 --- src/common/remote/activitypub/resolver.ts | 97 --- src/common/remote/activitypub/type.ts | 3 - src/common/remote/resolve-user.ts | 26 - src/common/remote/webfinger.ts | 25 - src/common/text/parse/elements/mention.ts | 2 +- src/common/user/get-acct.ts | 3 - src/common/user/get-summary.ts | 18 - src/common/user/parse-acct.ts | 4 - src/misc/get-notification-summary.ts | 27 + src/misc/get-post-summary.ts | 45 + src/misc/get-reaction-emoji.ts | 14 + src/misc/othello/ai/back.ts | 376 +++++++++ src/misc/othello/ai/front.ts | 233 ++++++ src/misc/othello/ai/index.ts | 1 + src/misc/othello/core.ts | 340 ++++++++ src/misc/othello/maps.ts | 911 +++++++++++++++++++++ src/misc/user/get-acct.ts | 3 + src/misc/user/get-summary.ts | 18 + src/misc/user/parse-acct.ts | 4 + src/processor/http/follow.ts | 4 +- src/processor/http/perform-activitypub.ts | 2 +- src/remote/activitypub/act/create.ts | 9 + src/remote/activitypub/act/index.ts | 22 + src/remote/activitypub/create.ts | 87 ++ src/remote/activitypub/renderer/context.ts | 5 + src/remote/activitypub/renderer/document.ts | 7 + src/remote/activitypub/renderer/follow.ts | 8 + src/remote/activitypub/renderer/hashtag.ts | 7 + src/remote/activitypub/renderer/image.ts | 6 + src/remote/activitypub/renderer/key.ts | 10 + src/remote/activitypub/renderer/note.ts | 44 + .../activitypub/renderer/ordered-collection.ts | 6 + src/remote/activitypub/renderer/person.ts | 20 + src/remote/activitypub/resolve-person.ts | 109 +++ src/remote/activitypub/resolver.ts | 97 +++ src/remote/activitypub/type.ts | 3 + src/remote/resolve-user.ts | 26 + src/remote/webfinger.ts | 25 + src/server/activitypub/inbox.ts | 2 +- src/server/activitypub/outbox.ts | 6 +- src/server/activitypub/post.ts | 6 +- src/server/activitypub/publickey.ts | 4 +- src/server/activitypub/user.ts | 4 +- src/server/activitypub/with-user.ts | 2 +- src/server/api/bot/core.ts | 8 +- src/server/api/bot/interfaces/line.ts | 6 +- .../api/endpoints/drive/files/upload_from_url.ts | 2 +- src/server/api/endpoints/othello/games/show.ts | 2 +- src/server/api/endpoints/othello/match.ts | 2 +- src/server/api/endpoints/posts/create.ts | 4 +- src/server/api/endpoints/users/show.ts | 2 +- src/server/api/limitter.ts | 2 +- src/server/api/stream/othello-game.ts | 4 +- src/server/webfinger.ts | 2 +- 128 files changed, 2599 insertions(+), 2599 deletions(-) create mode 100644 src/common/drive/upload-from-url.ts delete mode 100644 src/common/drive/upload_from_url.ts delete mode 100644 src/common/get-notification-summary.ts delete mode 100644 src/common/get-post-summary.ts delete mode 100644 src/common/get-reaction-emoji.ts delete mode 100644 src/common/othello/ai/back.ts delete mode 100644 src/common/othello/ai/front.ts delete mode 100644 src/common/othello/ai/index.ts delete mode 100644 src/common/othello/core.ts delete mode 100644 src/common/othello/maps.ts delete mode 100644 src/common/remote/activitypub/act/create.ts delete mode 100644 src/common/remote/activitypub/act/index.ts delete mode 100644 src/common/remote/activitypub/create.ts delete mode 100644 src/common/remote/activitypub/renderer/context.ts delete mode 100644 src/common/remote/activitypub/renderer/document.ts delete mode 100644 src/common/remote/activitypub/renderer/follow.ts delete mode 100644 src/common/remote/activitypub/renderer/hashtag.ts delete mode 100644 src/common/remote/activitypub/renderer/image.ts delete mode 100644 src/common/remote/activitypub/renderer/key.ts delete mode 100644 src/common/remote/activitypub/renderer/note.ts delete mode 100644 src/common/remote/activitypub/renderer/ordered-collection.ts delete mode 100644 src/common/remote/activitypub/renderer/person.ts delete mode 100644 src/common/remote/activitypub/resolve-person.ts delete mode 100644 src/common/remote/activitypub/resolver.ts delete mode 100644 src/common/remote/activitypub/type.ts delete mode 100644 src/common/remote/resolve-user.ts delete mode 100644 src/common/remote/webfinger.ts delete mode 100644 src/common/user/get-acct.ts delete mode 100644 src/common/user/get-summary.ts delete mode 100644 src/common/user/parse-acct.ts create mode 100644 src/misc/get-notification-summary.ts create mode 100644 src/misc/get-post-summary.ts create mode 100644 src/misc/get-reaction-emoji.ts create mode 100644 src/misc/othello/ai/back.ts create mode 100644 src/misc/othello/ai/front.ts create mode 100644 src/misc/othello/ai/index.ts create mode 100644 src/misc/othello/core.ts create mode 100644 src/misc/othello/maps.ts create mode 100644 src/misc/user/get-acct.ts create mode 100644 src/misc/user/get-summary.ts create mode 100644 src/misc/user/parse-acct.ts create mode 100644 src/remote/activitypub/act/create.ts create mode 100644 src/remote/activitypub/act/index.ts create mode 100644 src/remote/activitypub/create.ts create mode 100644 src/remote/activitypub/renderer/context.ts create mode 100644 src/remote/activitypub/renderer/document.ts create mode 100644 src/remote/activitypub/renderer/follow.ts create mode 100644 src/remote/activitypub/renderer/hashtag.ts create mode 100644 src/remote/activitypub/renderer/image.ts create mode 100644 src/remote/activitypub/renderer/key.ts create mode 100644 src/remote/activitypub/renderer/note.ts create mode 100644 src/remote/activitypub/renderer/ordered-collection.ts create mode 100644 src/remote/activitypub/renderer/person.ts create mode 100644 src/remote/activitypub/resolve-person.ts create mode 100644 src/remote/activitypub/resolver.ts create mode 100644 src/remote/activitypub/type.ts create mode 100644 src/remote/resolve-user.ts create mode 100644 src/remote/webfinger.ts (limited to 'src/client/app/common/scripts') diff --git a/src/client/app/ch/tags/channel.tag b/src/client/app/ch/tags/channel.tag index 2abfb106a5..70e494aedd 100644 --- a/src/client/app/ch/tags/channel.tag +++ b/src/client/app/ch/tags/channel.tag @@ -229,7 +229,7 @@ diff --git a/src/client/app/common/scripts/compose-notification.ts b/src/client/app/common/scripts/compose-notification.ts index ebc15952f6..e99d502960 100644 --- a/src/client/app/common/scripts/compose-notification.ts +++ b/src/client/app/common/scripts/compose-notification.ts @@ -1,5 +1,6 @@ import getPostSummary from '../../../../renderers/get-post-summary'; import getReactionEmoji from '../../../../renderers/get-reaction-emoji'; +import getUserName from '../../../../renderers/get-user-name'; type Notification = { title: string; @@ -21,35 +22,35 @@ export default function(type, data): Notification { case 'mention': return { - title: `${data.user.name}さんから:`, + title: `${getUserName(data.user)}さんから:`, body: getPostSummary(data), icon: data.user.avatarUrl + '?thumbnail&size=64' }; case 'reply': return { - title: `${data.user.name}さんから返信:`, + title: `${getUserName(data.user)}さんから返信:`, body: getPostSummary(data), icon: data.user.avatarUrl + '?thumbnail&size=64' }; case 'quote': return { - title: `${data.user.name}さんが引用:`, + title: `${getUserName(data.user)}さんが引用:`, body: getPostSummary(data), icon: data.user.avatarUrl + '?thumbnail&size=64' }; case 'reaction': return { - title: `${data.user.name}: ${getReactionEmoji(data.reaction)}:`, + title: `${getUserName(data.user)}: ${getReactionEmoji(data.reaction)}:`, body: getPostSummary(data.post), icon: data.user.avatarUrl + '?thumbnail&size=64' }; case 'unread_messaging_message': return { - title: `${data.user.name}さんからメッセージ:`, + title: `${getUserName(data.user)}さんからメッセージ:`, body: data.text, // TODO: getMessagingMessageSummary(data), icon: data.user.avatarUrl + '?thumbnail&size=64' }; @@ -57,7 +58,7 @@ export default function(type, data): Notification { case 'othello_invited': return { title: '対局への招待があります', - body: `${data.parent.name}さんから`, + body: `${getUserName(data.parent)}さんから`, icon: data.parent.avatarUrl + '?thumbnail&size=64' }; diff --git a/src/client/app/common/views/components/autocomplete.vue b/src/client/app/common/views/components/autocomplete.vue index 38eaf86508..8837fde6be 100644 --- a/src/client/app/common/views/components/autocomplete.vue +++ b/src/client/app/common/views/components/autocomplete.vue @@ -3,7 +3,7 @@
  1. - {{ user.name }} + {{ getUserName(user) }} @{{ getAcct(user) }}
@@ -22,6 +22,7 @@ import Vue from 'vue'; import * as emojilib from 'emojilib'; import contains from '../../../common/scripts/contains'; import getAcct from '../../../../../acct/render'; +import getUserName from '../../../../../renderers/get-user-name'; const lib = Object.entries(emojilib.lib).filter((x: any) => { return x[1].category != 'flags'; @@ -107,6 +108,7 @@ export default Vue.extend({ }, methods: { getAcct, + getUserName, exec() { this.select = -1; if (this.$refs.suggests) { diff --git a/src/client/app/common/views/components/messaging.vue b/src/client/app/common/views/components/messaging.vue index 4ab3e46e89..9b1449daa5 100644 --- a/src/client/app/common/views/components/messaging.vue +++ b/src/client/app/common/views/components/messaging.vue @@ -14,7 +14,7 @@ tabindex="-1" > - {{ user.name }} + {{ getUserName(user) }} @{{ getAcct(user) }} @@ -33,7 +33,7 @@
- {{ isMe(message) ? message.recipient.name : message.user.name }} + {{ getUserName(isMe(message) ? message.recipient : message.user) }} @{{ getAcct(isMe(message) ? message.recipient : message.user) }}
@@ -52,6 +52,7 @@ diff --git a/src/client/app/desktop/views/components/following-window.vue b/src/client/app/desktop/views/components/following-window.vue index 612847b386..cbd8ec5f94 100644 --- a/src/client/app/desktop/views/components/following-window.vue +++ b/src/client/app/desktop/views/components/following-window.vue @@ -1,7 +1,7 @@ @@ -36,7 +36,7 @@ export default define({ post() { this.posting = true; - (this as any).api('posts/create', { + (this as any).api('notes/create', { text: this.text }).then(data => { this.clear(); diff --git a/src/client/app/desktop/views/widgets/trends.vue b/src/client/app/desktop/views/widgets/trends.vue index 27c1860b32..c2c7636bb3 100644 --- a/src/client/app/desktop/views/widgets/trends.vue +++ b/src/client/app/desktop/views/widgets/trends.vue @@ -5,8 +5,8 @@

%fa:spinner .pulse .fw%%i18n:common.loading%

-
-

{{ post.text }}

+
+

{{ note.text }}

@{{ acct }}

%i18n:desktop.tags.mk-trends-home-widget.nothing%

@@ -25,12 +25,12 @@ export default define({ }).extend({ computed: { acct() { - return getAcct(this.post.user); + return getAcct(this.note.user); }, }, data() { return { - post: null, + note: null, fetching: true, offset: 0 }; @@ -44,23 +44,23 @@ export default define({ }, fetch() { this.fetching = true; - this.post = null; + this.note = null; - (this as any).api('posts/trend', { + (this as any).api('notes/trend', { limit: 1, offset: this.offset, - repost: false, + renote: false, reply: false, media: false, poll: false - }).then(posts => { - const post = posts ? posts[0] : null; - if (post == null) { + }).then(notes => { + const note = notes ? notes[0] : null; + if (note == null) { this.offset = 0; } else { this.offset++; } - this.post = post; + this.note = note; this.fetching = false; }); } @@ -103,7 +103,7 @@ export default define({ &:active color #999 - > .post + > .note padding 16px font-size 12px font-style oblique diff --git a/src/client/app/dev/views/new-app.vue b/src/client/app/dev/views/new-app.vue index e407ca00d7..c9d5971395 100644 --- a/src/client/app/dev/views/new-app.vue +++ b/src/client/app/dev/views/new-app.vue @@ -27,7 +27,7 @@ アカウントの情報を見る。 アカウントの情報を操作する。 - 投稿する。 + 投稿する。 リアクションしたりリアクションをキャンセルする。 フォローしたりフォロー解除する。 ドライブを見る。 diff --git a/src/client/app/mobile/api/post.ts b/src/client/app/mobile/api/post.ts index 98309ba8de..72919c6505 100644 --- a/src/client/app/mobile/api/post.ts +++ b/src/client/app/mobile/api/post.ts @@ -1,24 +1,24 @@ import PostForm from '../views/components/post-form.vue'; -//import RepostForm from '../views/components/repost-form.vue'; -import getPostSummary from '../../../../renderers/get-post-summary'; +//import RenoteForm from '../views/components/renote-form.vue'; +import getNoteSummary from '../../../../renderers/get-note-summary'; export default (os) => (opts) => { const o = opts || {}; - if (o.repost) { - /*const vm = new RepostForm({ + if (o.renote) { + /*const vm = new RenoteForm({ propsData: { - repost: o.repost + renote: o.renote } }).$mount(); vm.$once('cancel', recover); - vm.$once('post', recover); + vm.$once('note', recover); document.body.appendChild(vm.$el);*/ - const text = window.prompt(`「${getPostSummary(o.repost)}」をRepost`); + const text = window.prompt(`「${getNoteSummary(o.renote)}」をRenote`); if (text == null) return; - os.api('posts/create', { - repostId: o.repost.id, + os.api('notes/create', { + renoteId: o.renote.id, text: text == '' ? undefined : text }); } else { @@ -36,7 +36,7 @@ export default (os) => (opts) => { } }).$mount(); vm.$once('cancel', recover); - vm.$once('post', recover); + vm.$once('note', recover); document.body.appendChild(vm.$el); (vm as any).focus(); } diff --git a/src/client/app/mobile/script.ts b/src/client/app/mobile/script.ts index 4776fccddb..6265d0d45f 100644 --- a/src/client/app/mobile/script.ts +++ b/src/client/app/mobile/script.ts @@ -25,7 +25,7 @@ import MkDrive from './views/pages/drive.vue'; import MkNotifications from './views/pages/notifications.vue'; import MkMessaging from './views/pages/messaging.vue'; import MkMessagingRoom from './views/pages/messaging-room.vue'; -import MkPost from './views/pages/post.vue'; +import MkNote from './views/pages/note.vue'; import MkSearch from './views/pages/search.vue'; import MkFollowers from './views/pages/followers.vue'; import MkFollowing from './views/pages/following.vue'; @@ -68,7 +68,7 @@ init((launch) => { { path: '/@:user', component: MkUser }, { path: '/@:user/followers', component: MkFollowers }, { path: '/@:user/following', component: MkFollowing }, - { path: '/@:user/:post', component: MkPost } + { path: '/@:user/:note', component: MkNote } ] }); diff --git a/src/client/app/mobile/views/components/activity.vue b/src/client/app/mobile/views/components/activity.vue index 2e44017e77..dcd319cb69 100644 --- a/src/client/app/mobile/views/components/activity.vue +++ b/src/client/app/mobile/views/components/activity.vue @@ -2,14 +2,14 @@
- - @@ -32,12 +32,12 @@ export default Vue.extend({ userId: this.user.id, limit: 30 }).then(data => { - data.forEach(d => d.total = d.posts + d.replies + d.reposts); + data.forEach(d => d.total = d.notes + d.replies + d.renotes); this.peak = Math.max.apply(null, data.map(d => d.total)); data.forEach(d => { - d.postsH = d.posts / this.peak; + d.notesH = d.notes / this.peak; d.repliesH = d.replies / this.peak; - d.repostsH = d.reposts / this.peak; + d.renotesH = d.renotes / this.peak; }); data.reverse(); this.data = data; diff --git a/src/client/app/mobile/views/components/index.ts b/src/client/app/mobile/views/components/index.ts index fb8f65f47d..9346700304 100644 --- a/src/client/app/mobile/views/components/index.ts +++ b/src/client/app/mobile/views/components/index.ts @@ -2,16 +2,16 @@ import Vue from 'vue'; import ui from './ui.vue'; import timeline from './timeline.vue'; -import post from './post.vue'; -import posts from './posts.vue'; +import note from './note.vue'; +import notes from './notes.vue'; import mediaImage from './media-image.vue'; import mediaVideo from './media-video.vue'; import drive from './drive.vue'; -import postPreview from './post-preview.vue'; -import subPostContent from './sub-post-content.vue'; -import postCard from './post-card.vue'; +import notePreview from './note-preview.vue'; +import subNoteContent from './sub-note-content.vue'; +import noteCard from './note-card.vue'; import userCard from './user-card.vue'; -import postDetail from './post-detail.vue'; +import noteDetail from './note-detail.vue'; import followButton from './follow-button.vue'; import friendsMaker from './friends-maker.vue'; import notification from './notification.vue'; @@ -25,16 +25,16 @@ import widgetContainer from './widget-container.vue'; Vue.component('mk-ui', ui); Vue.component('mk-timeline', timeline); -Vue.component('mk-post', post); -Vue.component('mk-posts', posts); +Vue.component('mk-note', note); +Vue.component('mk-notes', notes); Vue.component('mk-media-image', mediaImage); Vue.component('mk-media-video', mediaVideo); Vue.component('mk-drive', drive); -Vue.component('mk-post-preview', postPreview); -Vue.component('mk-sub-post-content', subPostContent); -Vue.component('mk-post-card', postCard); +Vue.component('mk-note-preview', notePreview); +Vue.component('mk-sub-note-content', subNoteContent); +Vue.component('mk-note-card', noteCard); Vue.component('mk-user-card', userCard); -Vue.component('mk-post-detail', postDetail); +Vue.component('mk-note-detail', noteDetail); Vue.component('mk-follow-button', followButton); Vue.component('mk-friends-maker', friendsMaker); Vue.component('mk-notification', notification); diff --git a/src/client/app/mobile/views/components/note-card.vue b/src/client/app/mobile/views/components/note-card.vue new file mode 100644 index 0000000000..9ad0d3e294 --- /dev/null +++ b/src/client/app/mobile/views/components/note-card.vue @@ -0,0 +1,93 @@ + + + + + diff --git a/src/client/app/mobile/views/components/note-detail.sub.vue b/src/client/app/mobile/views/components/note-detail.sub.vue new file mode 100644 index 0000000000..38aea4ba20 --- /dev/null +++ b/src/client/app/mobile/views/components/note-detail.sub.vue @@ -0,0 +1,113 @@ + + + + + + diff --git a/src/client/app/mobile/views/components/note-detail.vue b/src/client/app/mobile/views/components/note-detail.vue new file mode 100644 index 0000000000..e1682e58ed --- /dev/null +++ b/src/client/app/mobile/views/components/note-detail.vue @@ -0,0 +1,462 @@ + + + + + + + diff --git a/src/client/app/mobile/views/components/note-preview.vue b/src/client/app/mobile/views/components/note-preview.vue new file mode 100644 index 0000000000..8c8d8645bb --- /dev/null +++ b/src/client/app/mobile/views/components/note-preview.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/src/client/app/mobile/views/components/note.sub.vue b/src/client/app/mobile/views/components/note.sub.vue new file mode 100644 index 0000000000..a37d0dea08 --- /dev/null +++ b/src/client/app/mobile/views/components/note.sub.vue @@ -0,0 +1,119 @@ + + + + + + diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue new file mode 100644 index 0000000000..4b33c6f071 --- /dev/null +++ b/src/client/app/mobile/views/components/note.vue @@ -0,0 +1,540 @@ + + + + + + + diff --git a/src/client/app/mobile/views/components/notes.vue b/src/client/app/mobile/views/components/notes.vue new file mode 100644 index 0000000000..573026d53e --- /dev/null +++ b/src/client/app/mobile/views/components/notes.vue @@ -0,0 +1,111 @@ + + + + + diff --git a/src/client/app/mobile/views/components/notification-preview.vue b/src/client/app/mobile/views/components/notification-preview.vue index 0492c5d86c..79ca3321e4 100644 --- a/src/client/app/mobile/views/components/notification-preview.vue +++ b/src/client/app/mobile/views/components/notification-preview.vue @@ -4,23 +4,23 @@ avatar

{{ name }}

-

%fa:quote-left%{{ getPostSummary(notification.post) }}%fa:quote-right%

+

%fa:quote-left%{{ getNoteSummary(notification.note) }}%fa:quote-right%

- @@ -51,7 +51,7 @@ avatar

%fa:chart-pie%{{ name }}

-

%fa:quote-left%{{ getPostSummary(notification.post) }}%fa:quote-right%

+

%fa:quote-left%{{ getNoteSummary(notification.note) }}%fa:quote-right%

@@ -59,7 +59,7 @@ - - diff --git a/src/client/app/mobile/views/components/post-detail.sub.vue b/src/client/app/mobile/views/components/post-detail.sub.vue deleted file mode 100644 index 98d6a14cac..0000000000 --- a/src/client/app/mobile/views/components/post-detail.sub.vue +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - diff --git a/src/client/app/mobile/views/components/post-detail.vue b/src/client/app/mobile/views/components/post-detail.vue index 0226ce081a..e1682e58ed 100644 --- a/src/client/app/mobile/views/components/post-detail.vue +++ b/src/client/app/mobile/views/components/post-detail.vue @@ -1,5 +1,5 @@
- +
- +
-
+

- avatar + avatar %fa:retweet% {{ name }} - がRepost + がRenote

@@ -38,33 +38,33 @@
- +
{{ tag }}
- + %fa:map-marker-alt% 位置情報
-
- +
+
- - - -
- +
@@ -84,9 +84,9 @@ import getAcct from '../../../../../acct/render'; import getUserName from '../../../../../renderers/get-user-name'; import parse from '../../../../../text/parse'; -import MkPostMenu from '../../../common/views/components/post-menu.vue'; +import MkNoteMenu from '../../../common/views/components/note-menu.vue'; import MkReactionPicker from '../../../common/views/components/reaction-picker.vue'; -import XSub from './post-detail.sub.vue'; +import XSub from './note-detail.sub.vue'; export default Vue.extend({ components: { @@ -94,7 +94,7 @@ export default Vue.extend({ }, props: { - post: { + note: { type: Object, required: true }, @@ -113,10 +113,10 @@ export default Vue.extend({ computed: { acct(): string { - return getAcct(this.post.user); + return getAcct(this.note.user); }, name(): string { - return getUserName(this.post.user); + return getUserName(this.note.user); }, pAcct(): string { return getAcct(this.p.user); @@ -124,14 +124,14 @@ export default Vue.extend({ pName(): string { return getUserName(this.p.user); }, - isRepost(): boolean { - return (this.post.repost && - this.post.text == null && - this.post.mediaIds == null && - this.post.poll == null); + isRenote(): boolean { + return (this.note.renote && + this.note.text == null && + this.note.mediaIds == null && + this.note.poll == null); }, p(): any { - return this.isRepost ? this.post.repost : this.post; + return this.isRenote ? this.note.renote : this.note; }, reactionsCount(): number { return this.p.reactionCounts @@ -155,8 +155,8 @@ export default Vue.extend({ mounted() { // Get replies if (!this.compact) { - (this as any).api('posts/replies', { - postId: this.p.id, + (this as any).api('notes/replies', { + noteId: this.p.id, limit: 8 }).then(replies => { this.replies = replies; @@ -187,8 +187,8 @@ export default Vue.extend({ this.contextFetching = true; // Fetch context - (this as any).api('posts/context', { - postId: this.p.replyId + (this as any).api('notes/context', { + noteId: this.p.replyId }).then(context => { this.contextFetching = false; this.context = context.reverse(); @@ -199,22 +199,22 @@ export default Vue.extend({ reply: this.p }); }, - repost() { + renote() { (this as any).apis.post({ - repost: this.p + renote: this.p }); }, react() { (this as any).os.new(MkReactionPicker, { source: this.$refs.reactButton, - post: this.p, + note: this.p, compact: true }); }, menu() { - (this as any).os.new(MkPostMenu, { + (this as any).os.new(MkNoteMenu, { source: this.$refs.menuButton, - post: this.p, + note: this.p, compact: true }); } @@ -225,7 +225,7 @@ export default Vue.extend({ diff --git a/src/client/app/mobile/views/components/post.sub.vue b/src/client/app/mobile/views/components/post.sub.vue deleted file mode 100644 index 909d5cb597..0000000000 --- a/src/client/app/mobile/views/components/post.sub.vue +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - diff --git a/src/client/app/mobile/views/components/post.vue b/src/client/app/mobile/views/components/post.vue index eee1e80fd3..4b33c6f071 100644 --- a/src/client/app/mobile/views/components/post.vue +++ b/src/client/app/mobile/views/components/post.vue @@ -1,19 +1,19 @@ @@ -25,7 +25,7 @@ export default Vue.extend({ return { fetching: true, existMore: false, - posts: [], + notes: [], offset: 0 }; }, @@ -48,30 +48,30 @@ export default Vue.extend({ this.fetching = true; Progress.start(); - (this as any).api('posts/search', Object.assign({ + (this as any).api('notes/search', Object.assign({ limit: limit + 1 - }, parse(this.q))).then(posts => { - if (posts.length == limit + 1) { - posts.pop(); + }, parse(this.q))).then(notes => { + if (notes.length == limit + 1) { + notes.pop(); this.existMore = true; } - this.posts = posts; + this.notes = notes; this.fetching = false; Progress.done(); }); }, more() { this.offset += limit; - (this as any).api('posts/search', Object.assign({ + (this as any).api('notes/search', Object.assign({ limit: limit + 1, offset: this.offset - }, parse(this.q))).then(posts => { - if (posts.length == limit + 1) { - posts.pop(); + }, parse(this.q))).then(notes => { + if (notes.length == limit + 1) { + notes.pop(); } else { this.existMore = false; } - this.posts = this.posts.concat(posts); + this.notes = this.notes.concat(notes); }); } } @@ -79,7 +79,7 @@ export default Vue.extend({ diff --git a/src/client/app/mobile/views/pages/user/home.photos.vue b/src/client/app/mobile/views/pages/user/home.photos.vue index ecf5082072..1c59260812 100644 --- a/src/client/app/mobile/views/pages/user/home.photos.vue +++ b/src/client/app/mobile/views/pages/user/home.photos.vue @@ -5,7 +5,7 @@

%i18n:mobile.tags.mk-user-overview-photos.no-photos%

@@ -28,15 +28,15 @@ export default Vue.extend({ getAcct }, mounted() { - (this as any).api('users/posts', { + (this as any).api('users/notes', { userId: this.user.id, withMedia: true, limit: 6 - }).then(posts => { - posts.forEach(post => { - post.media.forEach(media => { + }).then(notes => { + notes.forEach(note => { + note.media.forEach(media => { if (this.images.length < 9) this.images.push({ - post, + note, media }); }); diff --git a/src/client/app/mobile/views/pages/user/home.posts.vue b/src/client/app/mobile/views/pages/user/home.posts.vue deleted file mode 100644 index 654f7f63e0..0000000000 --- a/src/client/app/mobile/views/pages/user/home.posts.vue +++ /dev/null @@ -1,57 +0,0 @@ - - - - - diff --git a/src/client/app/mobile/views/pages/user/home.vue b/src/client/app/mobile/views/pages/user/home.vue index 1afcd1f5ba..2554084969 100644 --- a/src/client/app/mobile/views/pages/user/home.vue +++ b/src/client/app/mobile/views/pages/user/home.vue @@ -1,10 +1,10 @@ diff --git a/src/client/app/mobile/views/pages/welcome.vue b/src/client/app/mobile/views/pages/welcome.vue index 17cdf93065..27baf8bee4 100644 --- a/src/client/app/mobile/views/pages/welcome.vue +++ b/src/client/app/mobile/views/pages/welcome.vue @@ -8,7 +8,7 @@
- +
@@ -70,7 +70,7 @@ export default Vue.extend({ (this as any).api('signin', { username: this.username, password: this.password, - token: this.user && this.user.account.twoFactorEnabled ? this.token : undefined + token: this.user && this.user.twoFactorEnabled ? this.token : undefined }).then(() => { location.reload(); }).catch(() => { diff --git a/src/models/user.ts b/src/models/user.ts index f86aefe9a4..906bcb533b 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -11,7 +11,7 @@ import config from '../config'; const User = db.get('users'); User.createIndex('username'); -User.createIndex('account.token'); +User.createIndex('token'); export default User; @@ -40,45 +40,41 @@ type IUserBase = { export interface ILocalUser extends IUserBase { host: null; - account: { - keypair: string; - email: string; - links: string[]; - password: string; - token: string; - twitter: { - accessToken: string; - accessTokenSecret: string; - userId: string; - screenName: string; - }; - line: { - userId: string; - }; - profile: { - location: string; - birthday: string; // 'YYYY-MM-DD' - tags: string[]; - }; - lastUsedAt: Date; - isBot: boolean; - isPro: boolean; - twoFactorSecret: string; - twoFactorEnabled: boolean; - twoFactorTempSecret: string; - clientSettings: any; - settings: any; + keypair: string; + email: string; + links: string[]; + password: string; + token: string; + twitter: { + accessToken: string; + accessTokenSecret: string; + userId: string; + screenName: string; }; + line: { + userId: string; + }; + profile: { + location: string; + birthday: string; // 'YYYY-MM-DD' + tags: string[]; + }; + lastUsedAt: Date; + isBot: boolean; + isPro: boolean; + twoFactorSecret: string; + twoFactorEnabled: boolean; + twoFactorTempSecret: string; + clientSettings: any; + settings: any; } export interface IRemoteUser extends IUserBase { - account: { - inbox: string; - uri: string; - publicKey: { - id: string; - publicKeyPem: string; - }; + inbox: string; + uri: string; + publicKey: { + id: string; + publicKeyPem: string; }; } @@ -150,11 +146,11 @@ export const pack = ( const fields = opts.detail ? { } : { - 'account.settings': false, - 'account.clientSettings': false, - 'account.profile': false, - 'account.keywords': false, - 'account.domains': false + settings: false, + clientSettings: false, + profile: false, + keywords: false, + domains: false }; // Populate the user if 'user' is ID @@ -188,29 +184,29 @@ export const pack = ( // Remove needless properties delete _user.latestNote; - if (!_user.host) { + if (_user.host == null) { // Remove private properties - delete _user.account.keypair; - delete _user.account.password; - delete _user.account.token; - delete _user.account.twoFactorTempSecret; - delete _user.account.twoFactorSecret; + delete _user.keypair; + delete _user.password; + delete _user.token; + delete _user.twoFactorTempSecret; + delete _user.twoFactorSecret; delete _user.usernameLower; - if (_user.account.twitter) { - delete _user.account.twitter.accessToken; - delete _user.account.twitter.accessTokenSecret; + if (_user.twitter) { + delete _user.twitter.accessToken; + delete _user.twitter.accessTokenSecret; } - delete _user.account.line; + delete _user.line; // Visible via only the official client if (!opts.includeSecrets) { - delete _user.account.email; - delete _user.account.settings; - delete _user.account.clientSettings; + delete _user.email; + delete _user.settings; + delete _user.clientSettings; } if (!opts.detail) { - delete _user.account.twoFactorEnabled; + delete _user.twoFactorEnabled; } } diff --git a/src/queue/processors/http/process-inbox.ts b/src/queue/processors/http/process-inbox.ts index eb4b62d37f..6608907a7a 100644 --- a/src/queue/processors/http/process-inbox.ts +++ b/src/queue/processors/http/process-inbox.ts @@ -36,7 +36,7 @@ export default async (job: kue.Job, done): Promise => { } else { user = await User.findOne({ host: { $ne: null }, - 'account.publicKey.id': signature.keyId + 'publicKey.id': signature.keyId }) as IRemoteUser; // アクティビティを送信してきたユーザーがまだMisskeyサーバーに登録されていなかったら登録する @@ -50,7 +50,7 @@ export default async (job: kue.Job, done): Promise => { return; } - if (!verifySignature(signature, user.account.publicKey.publicKeyPem)) { + if (!verifySignature(signature, user.publicKey.publicKeyPem)) { console.warn('signature verification failed'); done(); return; diff --git a/src/remote/activitypub/act/create/image.ts b/src/remote/activitypub/act/create/image.ts index 30a75e7377..c87423c5fd 100644 --- a/src/remote/activitypub/act/create/image.ts +++ b/src/remote/activitypub/act/create/image.ts @@ -7,7 +7,7 @@ import { IDriveFile } from '../../../../models/drive-file'; const log = debug('misskey:activitypub'); export default async function(actor: IRemoteUser, image): Promise { - if ('attributedTo' in image && actor.account.uri !== image.attributedTo) { + if ('attributedTo' in image && actor.uri !== image.attributedTo) { log(`invalid image: ${JSON.stringify(image, null, 2)}`); throw new Error('invalid image'); } diff --git a/src/remote/activitypub/act/create/index.ts b/src/remote/activitypub/act/create/index.ts index dd0b112141..7cb9b08449 100644 --- a/src/remote/activitypub/act/create/index.ts +++ b/src/remote/activitypub/act/create/index.ts @@ -9,7 +9,7 @@ import { ICreate } from '../../type'; const log = debug('misskey:activitypub'); export default async (actor: IRemoteUser, activity: ICreate): Promise => { - if ('actor' in activity && actor.account.uri !== activity.actor) { + if ('actor' in activity && actor.uri !== activity.actor) { throw new Error('invalid actor'); } diff --git a/src/remote/activitypub/act/delete/index.ts b/src/remote/activitypub/act/delete/index.ts index 6c6faa1ae5..10b47dc4ca 100644 --- a/src/remote/activitypub/act/delete/index.ts +++ b/src/remote/activitypub/act/delete/index.ts @@ -7,7 +7,7 @@ import { IRemoteUser } from '../../../../models/user'; * 削除アクティビティを捌きます */ export default async (actor: IRemoteUser, activity): Promise => { - if ('actor' in activity && actor.account.uri !== activity.actor) { + if ('actor' in activity && actor.uri !== activity.actor) { throw new Error('invalid actor'); } diff --git a/src/remote/activitypub/act/undo/index.ts b/src/remote/activitypub/act/undo/index.ts index 3ede9fcfb8..71f547aeb9 100644 --- a/src/remote/activitypub/act/undo/index.ts +++ b/src/remote/activitypub/act/undo/index.ts @@ -8,7 +8,7 @@ import Resolver from '../../resolver'; const log = debug('misskey:activitypub'); export default async (actor: IRemoteUser, activity: IUndo): Promise => { - if ('actor' in activity && actor.account.uri !== activity.actor) { + if ('actor' in activity && actor.uri !== activity.actor) { throw new Error('invalid actor'); } diff --git a/src/remote/activitypub/renderer/follow.ts b/src/remote/activitypub/renderer/follow.ts index 6d1ded9a95..0a1ae1a4b2 100644 --- a/src/remote/activitypub/renderer/follow.ts +++ b/src/remote/activitypub/renderer/follow.ts @@ -4,5 +4,5 @@ import { IRemoteUser } from '../../../models/user'; export default ({ username }, followee: IRemoteUser) => ({ type: 'Follow', actor: `${config.url}/@${username}`, - object: followee.account.uri + object: followee.uri }); diff --git a/src/remote/activitypub/renderer/key.ts b/src/remote/activitypub/renderer/key.ts index 85be7b1367..76e2f13bcc 100644 --- a/src/remote/activitypub/renderer/key.ts +++ b/src/remote/activitypub/renderer/key.ts @@ -6,5 +6,5 @@ export default (user: ILocalUser) => ({ id: `${config.url}/@${user.username}/publickey`, type: 'Key', owner: `${config.url}/@${user.username}`, - publicKeyPem: extractPublic(user.account.keypair) + publicKeyPem: extractPublic(user.keypair) }); diff --git a/src/remote/request.ts b/src/remote/request.ts index a375aebfbb..a0c69cf4ef 100644 --- a/src/remote/request.ts +++ b/src/remote/request.ts @@ -4,10 +4,11 @@ import { URL } from 'url'; import * as debug from 'debug'; import config from '../config'; +import { ILocalUser } from '../models/user'; const log = debug('misskey:activitypub:deliver'); -export default ({ account, username }, url, object) => new Promise((resolve, reject) => { +export default (user: ILocalUser, url, object) => new Promise((resolve, reject) => { log(`--> ${url}`); const { protocol, hostname, port, pathname, search } = new URL(url); @@ -35,8 +36,8 @@ export default ({ account, username }, url, object) => new Promise((resolve, rej sign(req, { authorizationHeaderName: 'Signature', - key: account.keypair, - keyId: `acct:${username}@${config.host}` + key: user.keypair, + keyId: `acct:${user.username}@${config.host}` }); req.end(JSON.stringify(object)); diff --git a/src/renderers/get-user-summary.ts b/src/renderers/get-user-summary.ts index 52309954d3..1bd9a7fb47 100644 --- a/src/renderers/get-user-summary.ts +++ b/src/renderers/get-user-summary.ts @@ -11,8 +11,7 @@ export default function(user: IUser): string { `${user.notesCount}投稿、${user.followingCount}フォロー、${user.followersCount}フォロワー\n`; if (isLocalUser(user)) { - const account = user.account; - string += `場所: ${account.profile.location}、誕生日: ${account.profile.birthday}\n`; + string += `場所: ${user.profile.location}、誕生日: ${user.profile.birthday}\n`; } return string + `「${user.description}」`; diff --git a/src/server/api/authenticate.ts b/src/server/api/authenticate.ts index 8566744831..adbeeb3b34 100644 --- a/src/server/api/authenticate.ts +++ b/src/server/api/authenticate.ts @@ -34,7 +34,7 @@ export default (req: express.Request) => new Promise(async (resolv if (isNativeToken(token)) { const user: IUser = await User - .findOne({ 'account.token': token }); + .findOne({ 'token': token }); if (user === null) { return reject('user not found'); diff --git a/src/server/api/bot/core.ts b/src/server/api/bot/core.ts index 1cf0522349..d41af48057 100644 --- a/src/server/api/bot/core.ts +++ b/src/server/api/bot/core.ts @@ -226,7 +226,7 @@ class SigninContext extends Context { } } else { // Compare password - const same = await bcrypt.compare(query, this.temporaryUser.account.password); + const same = await bcrypt.compare(query, this.temporaryUser.password); if (same) { this.bot.signin(this.temporaryUser); diff --git a/src/server/api/bot/interfaces/line.ts b/src/server/api/bot/interfaces/line.ts index b6b0c257e9..be3bfe33d3 100644 --- a/src/server/api/bot/interfaces/line.ts +++ b/src/server/api/bot/interfaces/line.ts @@ -112,11 +112,11 @@ class LineBot extends BotCore { data: `showtl|${user.id}` }); - if (user.account.twitter) { + if (user.twitter) { actions.push({ type: 'uri', label: 'Twitterアカウントを見る', - uri: `https://twitter.com/${user.account.twitter.screenName}` + uri: `https://twitter.com/${user.twitter.screenName}` }); } @@ -174,7 +174,7 @@ module.exports = async (app: express.Application) => { if (session == null) { const user = await User.findOne({ host: null, - 'account.line': { + 'line': { userId: sourceId } }); @@ -184,7 +184,7 @@ module.exports = async (app: express.Application) => { bot.on('signin', user => { User.update(user._id, { $set: { - 'account.line': { + 'line': { userId: sourceId } } @@ -194,7 +194,7 @@ module.exports = async (app: express.Application) => { bot.on('signout', user => { User.update(user._id, { $set: { - 'account.line': { + 'line': { userId: null } } diff --git a/src/server/api/common/signin.ts b/src/server/api/common/signin.ts index f9688790c4..8bb327694d 100644 --- a/src/server/api/common/signin.ts +++ b/src/server/api/common/signin.ts @@ -2,7 +2,7 @@ import config from '../../../config'; export default function(res, user, redirect: boolean) { const expires = 1000 * 60 * 60 * 24 * 365; // One Year - res.cookie('i', user.account.token, { + res.cookie('i', user.token, { path: '/', domain: `.${config.hostname}`, secure: config.url.substr(0, 5) === 'https', diff --git a/src/server/api/endpoints/following/create.ts b/src/server/api/endpoints/following/create.ts index 0ccac8d83d..d3cc549ca7 100644 --- a/src/server/api/endpoints/following/create.ts +++ b/src/server/api/endpoints/following/create.ts @@ -31,7 +31,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }, { fields: { data: false, - 'account.profile': false + 'profile': false } }); diff --git a/src/server/api/endpoints/following/delete.ts b/src/server/api/endpoints/following/delete.ts index 0684b87504..0d0a6c7132 100644 --- a/src/server/api/endpoints/following/delete.ts +++ b/src/server/api/endpoints/following/delete.ts @@ -31,7 +31,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }, { fields: { data: false, - 'account.profile': false + 'profile': false } }); diff --git a/src/server/api/endpoints/i.ts b/src/server/api/endpoints/i.ts index 44de71d162..0be30500c4 100644 --- a/src/server/api/endpoints/i.ts +++ b/src/server/api/endpoints/i.ts @@ -5,12 +5,6 @@ import User, { pack } from '../../../models/user'; /** * Show myself - * - * @param {any} params - * @param {any} user - * @param {any} app - * @param {Boolean} isSecure - * @return {Promise} */ module.exports = (params, user, _, isSecure) => new Promise(async (res, rej) => { // Serialize @@ -22,7 +16,7 @@ module.exports = (params, user, _, isSecure) => new Promise(async (res, rej) => // Update lastUsedAt User.update({ _id: user._id }, { $set: { - 'account.lastUsedAt': new Date() + lastUsedAt: new Date() } }); }); diff --git a/src/server/api/endpoints/i/2fa/done.ts b/src/server/api/endpoints/i/2fa/done.ts index 0b2e32c13f..3e824feffd 100644 --- a/src/server/api/endpoints/i/2fa/done.ts +++ b/src/server/api/endpoints/i/2fa/done.ts @@ -28,8 +28,8 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { await User.update(user._id, { $set: { - 'account.twoFactorSecret': user.twoFactorTempSecret, - 'account.twoFactorEnabled': true + 'twoFactorSecret': user.twoFactorTempSecret, + 'twoFactorEnabled': true } }); diff --git a/src/server/api/endpoints/i/2fa/register.ts b/src/server/api/endpoints/i/2fa/register.ts index dc7fb959bb..bed64a2545 100644 --- a/src/server/api/endpoints/i/2fa/register.ts +++ b/src/server/api/endpoints/i/2fa/register.ts @@ -14,7 +14,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { if (passwordErr) return rej('invalid password param'); // Compare password - const same = await bcrypt.compare(password, user.account.password); + const same = await bcrypt.compare(password, user.password); if (!same) { return rej('incorrect password'); diff --git a/src/server/api/endpoints/i/2fa/unregister.ts b/src/server/api/endpoints/i/2fa/unregister.ts index ff2a435fee..f9d7a25f53 100644 --- a/src/server/api/endpoints/i/2fa/unregister.ts +++ b/src/server/api/endpoints/i/2fa/unregister.ts @@ -11,7 +11,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { if (passwordErr) return rej('invalid password param'); // Compare password - const same = await bcrypt.compare(password, user.account.password); + const same = await bcrypt.compare(password, user.password); if (!same) { return rej('incorrect password'); @@ -19,8 +19,8 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { await User.update(user._id, { $set: { - 'account.twoFactorSecret': null, - 'account.twoFactorEnabled': false + 'twoFactorSecret': null, + 'twoFactorEnabled': false } }); diff --git a/src/server/api/endpoints/i/change_password.ts b/src/server/api/endpoints/i/change_password.ts index a38b56a216..57415083f1 100644 --- a/src/server/api/endpoints/i/change_password.ts +++ b/src/server/api/endpoints/i/change_password.ts @@ -22,7 +22,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { if (newPasswordErr) return rej('invalid newPassword param'); // Compare password - const same = await bcrypt.compare(currentPassword, user.account.password); + const same = await bcrypt.compare(currentPassword, user.password); if (!same) { return rej('incorrect password'); @@ -34,7 +34,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { await User.update(user._id, { $set: { - 'account.password': hash + 'password': hash } }); diff --git a/src/server/api/endpoints/i/regenerate_token.ts b/src/server/api/endpoints/i/regenerate_token.ts index 9aa6725f8c..f9e92c1797 100644 --- a/src/server/api/endpoints/i/regenerate_token.ts +++ b/src/server/api/endpoints/i/regenerate_token.ts @@ -20,7 +20,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { if (passwordErr) return rej('invalid password param'); // Compare password - const same = await bcrypt.compare(password, user.account.password); + const same = await bcrypt.compare(password, user.password); if (!same) { return rej('incorrect password'); @@ -31,7 +31,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { await User.update(user._id, { $set: { - 'account.token': secret + 'token': secret } }); diff --git a/src/server/api/endpoints/i/update.ts b/src/server/api/endpoints/i/update.ts index 279b062f52..a8caa0ebc4 100644 --- a/src/server/api/endpoints/i/update.ts +++ b/src/server/api/endpoints/i/update.ts @@ -29,12 +29,12 @@ module.exports = async (params, user, _, isSecure) => new Promise(async (res, re // Get 'location' parameter const [location, locationErr] = $(params.location).optional.nullable.string().pipe(isValidLocation).$; if (locationErr) return rej('invalid location param'); - if (location !== undefined) user.account.profile.location = location; + if (location !== undefined) user.profile.location = location; // Get 'birthday' parameter const [birthday, birthdayErr] = $(params.birthday).optional.nullable.string().pipe(isValidBirthday).$; if (birthdayErr) return rej('invalid birthday param'); - if (birthday !== undefined) user.account.profile.birthday = birthday; + if (birthday !== undefined) user.profile.birthday = birthday; // Get 'avatarId' parameter const [avatarId, avatarIdErr] = $(params.avatarId).optional.id().$; @@ -49,12 +49,12 @@ module.exports = async (params, user, _, isSecure) => new Promise(async (res, re // Get 'isBot' parameter const [isBot, isBotErr] = $(params.isBot).optional.boolean().$; if (isBotErr) return rej('invalid isBot param'); - if (isBot != null) user.account.isBot = isBot; + if (isBot != null) user.isBot = isBot; // Get 'autoWatch' parameter const [autoWatch, autoWatchErr] = $(params.autoWatch).optional.boolean().$; if (autoWatchErr) return rej('invalid autoWatch param'); - if (autoWatch != null) user.account.settings.autoWatch = autoWatch; + if (autoWatch != null) user.settings.autoWatch = autoWatch; await User.update(user._id, { $set: { @@ -62,9 +62,9 @@ module.exports = async (params, user, _, isSecure) => new Promise(async (res, re description: user.description, avatarId: user.avatarId, bannerId: user.bannerId, - 'account.profile': user.account.profile, - 'account.isBot': user.account.isBot, - 'account.settings': user.account.settings + 'profile': user.profile, + 'isBot': user.isBot, + 'settings': user.settings } }); diff --git a/src/server/api/endpoints/i/update_client_setting.ts b/src/server/api/endpoints/i/update_client_setting.ts index 10741aceba..b0d5db5ec2 100644 --- a/src/server/api/endpoints/i/update_client_setting.ts +++ b/src/server/api/endpoints/i/update_client_setting.ts @@ -22,14 +22,14 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { if (valueErr) return rej('invalid value param'); const x = {}; - x[`account.clientSettings.${name}`] = value; + x[`clientSettings.${name}`] = value; await User.update(user._id, { $set: x }); // Serialize - user.account.clientSettings[name] = value; + user.clientSettings[name] = value; const iObj = await pack(user, user, { detail: true, includeSecrets: true diff --git a/src/server/api/endpoints/i/update_home.ts b/src/server/api/endpoints/i/update_home.ts index 91be0714d7..ce7661ede0 100644 --- a/src/server/api/endpoints/i/update_home.ts +++ b/src/server/api/endpoints/i/update_home.ts @@ -26,7 +26,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { if (home) { await User.update(user._id, { $set: { - 'account.clientSettings.home': home + 'clientSettings.home': home } }); @@ -38,7 +38,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { } else { if (id == null && data == null) return rej('you need to set id and data params if home param unset'); - const _home = user.account.clientSettings.home; + const _home = user.clientSettings.home; const widget = _home.find(w => w.id == id); if (widget == null) return rej('widget not found'); @@ -47,7 +47,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { await User.update(user._id, { $set: { - 'account.clientSettings.home': _home + 'clientSettings.home': _home } }); diff --git a/src/server/api/endpoints/i/update_mobile_home.ts b/src/server/api/endpoints/i/update_mobile_home.ts index 1efda120d5..b710e2f330 100644 --- a/src/server/api/endpoints/i/update_mobile_home.ts +++ b/src/server/api/endpoints/i/update_mobile_home.ts @@ -25,7 +25,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { if (home) { await User.update(user._id, { $set: { - 'account.clientSettings.mobileHome': home + 'clientSettings.mobileHome': home } }); @@ -37,7 +37,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { } else { if (id == null && data == null) return rej('you need to set id and data params if home param unset'); - const _home = user.account.clientSettings.mobileHome || []; + const _home = user.clientSettings.mobileHome || []; const widget = _home.find(w => w.id == id); if (widget == null) return rej('widget not found'); @@ -46,7 +46,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { await User.update(user._id, { $set: { - 'account.clientSettings.mobileHome': _home + 'clientSettings.mobileHome': _home } }); diff --git a/src/server/api/endpoints/mute/create.ts b/src/server/api/endpoints/mute/create.ts index a7fa5f7b4b..19894d07af 100644 --- a/src/server/api/endpoints/mute/create.ts +++ b/src/server/api/endpoints/mute/create.ts @@ -30,7 +30,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }, { fields: { data: false, - 'account.profile': false + 'profile': false } }); diff --git a/src/server/api/endpoints/mute/delete.ts b/src/server/api/endpoints/mute/delete.ts index 687f010336..10096352ba 100644 --- a/src/server/api/endpoints/mute/delete.ts +++ b/src/server/api/endpoints/mute/delete.ts @@ -30,7 +30,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }, { fields: { data: false, - 'account.profile': false + 'profile': false } }); diff --git a/src/server/api/endpoints/notes/polls/vote.ts b/src/server/api/endpoints/notes/polls/vote.ts index 0e27f87ee2..fd4412ad35 100644 --- a/src/server/api/endpoints/notes/polls/vote.ts +++ b/src/server/api/endpoints/notes/polls/vote.ts @@ -100,7 +100,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }); // この投稿をWatchする - if (user.account.settings.autoWatch !== false) { + if (user.settings.autoWatch !== false) { watch(user._id, note); } }); diff --git a/src/server/api/endpoints/users/recommendation.ts b/src/server/api/endpoints/users/recommendation.ts index 60483936fb..2de22da13e 100644 --- a/src/server/api/endpoints/users/recommendation.ts +++ b/src/server/api/endpoints/users/recommendation.ts @@ -32,7 +32,7 @@ module.exports = (params, me) => new Promise(async (res, rej) => { }, $or: [ { - 'account.lastUsedAt': { + 'lastUsedAt': { $gte: new Date(Date.now() - ms('7days')) } }, { diff --git a/src/server/api/private/signin.ts b/src/server/api/private/signin.ts index e0bd67d1ca..d7c4832c95 100644 --- a/src/server/api/private/signin.ts +++ b/src/server/api/private/signin.ts @@ -37,7 +37,7 @@ export default async (req: express.Request, res: express.Response) => { }, { fields: { data: false, - 'account.profile': false + 'profile': false } }) as ILocalUser; @@ -48,15 +48,13 @@ export default async (req: express.Request, res: express.Response) => { return; } - const account = user.account; - // Compare password - const same = await bcrypt.compare(password, account.password); + const same = await bcrypt.compare(password, password); if (same) { - if (account.twoFactorEnabled) { + if (user.twoFactorEnabled) { const verified = (speakeasy as any).totp.verify({ - secret: account.twoFactorSecret, + secret: user.twoFactorSecret, encoding: 'base32', token: token }); diff --git a/src/server/api/private/signup.ts b/src/server/api/private/signup.ts index 5818ba25cd..f441e1b754 100644 --- a/src/server/api/private/signup.ts +++ b/src/server/api/private/signup.ts @@ -119,44 +119,29 @@ export default async (req: express.Request, res: express.Response) => { usernameLower: username.toLowerCase(), host: null, hostLower: null, - account: { - keypair: generateKeypair(), - token: secret, - email: null, - links: null, - password: hash, - profile: { - bio: null, - birthday: null, - blood: null, - gender: null, - handedness: null, - height: null, - location: null, - weight: null - }, - settings: { - autoWatch: true - }, - clientSettings: { - home: homeData - } + keypair: generateKeypair(), + token: secret, + email: null, + links: null, + password: hash, + profile: { + bio: null, + birthday: null, + blood: null, + gender: null, + handedness: null, + height: null, + location: null, + weight: null + }, + settings: { + autoWatch: true + }, + clientSettings: { + home: homeData } }); // Response res.send(await pack(account)); - - // Create search index - if (config.elasticsearch.enable) { - const es = require('../../db/elasticsearch'); - es.index({ - index: 'misskey', - type: 'user', - id: account._id.toString(), - body: { - username: username - } - }); - } }; diff --git a/src/server/api/service/twitter.ts b/src/server/api/service/twitter.ts index 77b932b13b..da48e30a8a 100644 --- a/src/server/api/service/twitter.ts +++ b/src/server/api/service/twitter.ts @@ -40,10 +40,10 @@ module.exports = (app: express.Application) => { const user = await User.findOneAndUpdate({ host: null, - 'account.token': userToken + 'token': userToken }, { $set: { - 'account.twitter': null + 'twitter': null } }); @@ -128,7 +128,7 @@ module.exports = (app: express.Application) => { const user = await User.findOne({ host: null, - 'account.twitter.userId': result.userId + 'twitter.userId': result.userId }); if (user == null) { @@ -151,10 +151,10 @@ module.exports = (app: express.Application) => { const user = await User.findOneAndUpdate({ host: null, - 'account.token': userToken + 'token': userToken }, { $set: { - 'account.twitter': { + 'twitter': { accessToken: result.accessToken, accessTokenSecret: result.accessTokenSecret, userId: result.userId, diff --git a/src/server/api/stream/home.ts b/src/server/api/stream/home.ts index 313558851b..359ef74aff 100644 --- a/src/server/api/stream/home.ts +++ b/src/server/api/stream/home.ts @@ -74,7 +74,7 @@ export default async function(request: websocket.request, connection: websocket. // Update lastUsedAt User.update({ _id: user._id }, { $set: { - 'account.lastUsedAt': new Date() + 'lastUsedAt': new Date() } }); break; diff --git a/src/server/api/streaming.ts b/src/server/api/streaming.ts index edcf505d24..26946b524e 100644 --- a/src/server/api/streaming.ts +++ b/src/server/api/streaming.ts @@ -97,7 +97,7 @@ function authenticate(token: string): Promise { const user: IUser = await User .findOne({ host: null, - 'account.token': token + 'token': token }); resolve(user); diff --git a/src/services/following/create.ts b/src/services/following/create.ts index d919f4487f..31e3be19ed 100644 --- a/src/services/following/create.ts +++ b/src/services/following/create.ts @@ -60,13 +60,13 @@ export default async function(follower: IUser, followee: IUser, activity?) { const content = renderFollow(follower, followee); content['@context'] = context; - deliver(follower, content, followee.account.inbox).save(); + deliver(follower, content, followee.inbox).save(); } if (isRemoteUser(follower) && isLocalUser(followee)) { const content = renderAccept(activity); content['@context'] = context; - deliver(followee, content, follower.account.inbox).save(); + deliver(followee, content, follower.inbox).save(); } } diff --git a/src/services/following/delete.ts b/src/services/following/delete.ts index 364a4803b9..d79bf64f53 100644 --- a/src/services/following/delete.ts +++ b/src/services/following/delete.ts @@ -59,6 +59,6 @@ export default async function(follower: IUser, followee: IUser, activity?) { const content = renderUndo(renderFollow(follower, followee)); content['@context'] = context; - deliver(follower, content, followee.account.inbox).save(); + deliver(follower, content, followee.inbox).save(); } } diff --git a/src/services/note/create.ts b/src/services/note/create.ts index 8eee8f44af..551d618569 100644 --- a/src/services/note/create.ts +++ b/src/services/note/create.ts @@ -78,7 +78,7 @@ export default async (user: IUser, data: { host: user.host, hostLower: user.hostLower, account: isLocalUser(user) ? {} : { - inbox: user.account.inbox + inbox: user.inbox } } }; @@ -133,7 +133,7 @@ export default async (user: IUser, data: { // 投稿がリプライかつ投稿者がローカルユーザーかつリプライ先の投稿の投稿者がリモートユーザーなら配送 if (data.reply && isLocalUser(user) && isRemoteUser(data.reply._user)) { - deliver(user, content, data.reply._user.account.inbox).save(); + deliver(user, content, data.reply._user.inbox).save(); } Promise.all(followers.map(follower => { @@ -145,7 +145,7 @@ export default async (user: IUser, data: { } else { // フォロワーがリモートユーザーかつ投稿者がローカルユーザーなら投稿を配信 if (isLocalUser(user)) { - deliver(user, content, follower.account.inbox).save(); + deliver(user, content, follower.inbox).save(); } } })); @@ -242,7 +242,7 @@ export default async (user: IUser, data: { }); // この投稿をWatchする - if (isLocalUser(user) && user.account.settings.autoWatch !== false) { + if (isLocalUser(user) && user.settings.autoWatch !== false) { watch(user._id, data.reply); } @@ -277,7 +277,7 @@ export default async (user: IUser, data: { }); // この投稿をWatchする - if (isLocalUser(user) && user.account.settings.autoWatch !== false) { + if (isLocalUser(user) && user.settings.autoWatch !== false) { watch(user._id, data.renote); } diff --git a/src/services/note/reaction/create.ts b/src/services/note/reaction/create.ts index d0ce65ee54..ea51b205d0 100644 --- a/src/services/note/reaction/create.ts +++ b/src/services/note/reaction/create.ts @@ -78,7 +78,7 @@ export default async (user: IUser, note: INote, reaction: string) => new Promise }); // ユーザーがローカルユーザーかつ自動ウォッチ設定がオンならばこの投稿をWatchする - if (isLocalUser(user) && user.account.settings.autoWatch !== false) { + if (isLocalUser(user) && user.settings.autoWatch !== false) { watch(user._id, note); } @@ -88,7 +88,7 @@ export default async (user: IUser, note: INote, reaction: string) => new Promise // リアクターがローカルユーザーかつリアクション対象がリモートユーザーの投稿なら配送 if (isLocalUser(user) && isRemoteUser(note._user)) { - deliver(user, content, note._user.account.inbox).save(); + deliver(user, content, note._user.inbox).save(); } //#endregion }); diff --git a/test/api.ts b/test/api.ts index 953c5aea0d..87bbb8ee16 100644 --- a/test/api.ts +++ b/test/api.ts @@ -32,7 +32,7 @@ const async = fn => (done) => { const request = (endpoint, params, me?) => new Promise((ok, ng) => { const auth = me ? { - i: me.account.token + i: me.token } : {}; _chai.request(server) @@ -157,10 +157,10 @@ describe('API', () => { res.should.have.status(200); res.body.should.be.a('object'); res.body.should.have.property('name').eql(myName); - res.body.should.have.nested.property('account.profile').a('object'); - res.body.should.have.nested.property('account.profile.location').eql(myLocation); - res.body.should.have.nested.property('account.profile.birthday').eql(myBirthday); - res.body.should.have.nested.property('account.profile.gender').eql('female'); + res.body.should.have.nested.property('profile').a('object'); + res.body.should.have.nested.property('profile.location').eql(myLocation); + res.body.should.have.nested.property('profile.birthday').eql(myBirthday); + res.body.should.have.nested.property('profile.gender').eql('female'); })); it('名前を空白にできない', async(async () => { @@ -180,8 +180,8 @@ describe('API', () => { }, me); res.should.have.status(200); res.body.should.be.a('object'); - res.body.should.have.nested.property('account.profile').a('object'); - res.body.should.have.nested.property('account.profile.birthday').eql(null); + res.body.should.have.nested.property('profile').a('object'); + res.body.should.have.nested.property('profile.birthday').eql(null); })); it('不正な誕生日の形式で怒られる', async(async () => { @@ -736,7 +736,7 @@ describe('API', () => { const me = await insertSakurako(); const res = await _chai.request(server) .post('/drive/files/create') - .field('i', me.account.token) + .field('i', me.token) .attach('file', fs.readFileSync(__dirname + '/resources/Lenna.png'), 'Lenna.png'); res.should.have.status(200); res.body.should.be.a('object'); diff --git a/tools/migration/nighthike/12.js b/tools/migration/nighthike/12.js new file mode 100644 index 0000000000..f4b61e2ee8 --- /dev/null +++ b/tools/migration/nighthike/12.js @@ -0,0 +1,58 @@ +// for Node.js interpret + +const { default: User } = require('../../../built/models/user'); +const { generate } = require('../../../built/crypto_key'); +const { default: zip } = require('@prezzemolo/zip') + +const migrate = async (user) => { + const result = await User.update(user._id, { + $unset: { + account: '' + }, + $set: { + host: null, + hostLower: null, + email: user.account.email, + links: user.account.links, + password: user.account.password, + token: user.account.token, + twitter: user.account.twitter, + line: user.account.line, + profile: user.account.profile, + lastUsedAt: user.account.lastUsedAt, + isBot: user.account.isBot, + isPro: user.account.isPro, + twoFactorSecret: user.account.twoFactorSecret, + twoFactorEnabled: user.account.twoFactorEnabled, + clientSettings: user.account.clientSettings, + settings: user.account.settings, + keypair: user.account.keypair + } + }); + return result.ok === 1; +} + +async function main() { + const count = await User.count({}); + + const dop = Number.parseInt(process.argv[2]) || 5 + const idop = ((count - (count % dop)) / dop) + 1 + + return zip( + 1, + async (time) => { + console.log(`${time} / ${idop}`) + const doc = await User.find({}, { + limit: dop, skip: time * dop + }) + return Promise.all(doc.map(migrate)) + }, + idop + ).then(a => { + const rv = [] + a.forEach(e => rv.push(...e)) + return rv + }) +} + +main().then(console.dir).catch(console.error) -- cgit v1.2.3-freya