diff options
| author | gutfuckllc <40531868+gutfuckllc@users.noreply.github.com> | 2018-08-06 15:45:52 -0400 |
|---|---|---|
| committer | gutfuckllc <40531868+gutfuckllc@users.noreply.github.com> | 2018-08-06 15:45:52 -0400 |
| commit | a256393b81f2fda62641961ce515a85c8b9f51c3 (patch) | |
| tree | 9a205811a11b675b853aca3e463152a0d816ff69 /src | |
| parent | Translated mute. (diff) | |
| parent | 5.19.0 (diff) | |
| download | misskey-a256393b81f2fda62641961ce515a85c8b9f51c3.tar.gz misskey-a256393b81f2fda62641961ce515a85c8b9f51c3.tar.bz2 misskey-a256393b81f2fda62641961ce515a85c8b9f51c3.zip | |
Merge remote-tracking branch 'upstream/master' into devel
Diffstat (limited to 'src')
| -rw-r--r-- | src/client/app/common/scripts/date-stringify.ts | 13 | ||||
| -rw-r--r-- | src/client/app/common/views/components/autocomplete.vue | 2 | ||||
| -rw-r--r-- | src/client/app/common/views/components/signin.vue | 2 | ||||
| -rw-r--r-- | src/client/app/desktop/api/update-avatar.ts | 16 | ||||
| -rw-r--r-- | src/client/app/desktop/api/update-banner.ts | 16 | ||||
| -rw-r--r-- | src/client/app/desktop/views/components/note-detail.vue | 3 | ||||
| -rw-r--r-- | src/client/app/desktop/views/components/note-preview.vue | 3 | ||||
| -rw-r--r-- | src/client/app/desktop/views/components/notes.note.sub.vue | 3 | ||||
| -rw-r--r-- | src/client/app/desktop/views/components/notes.note.vue | 3 | ||||
| -rw-r--r-- | src/client/app/desktop/views/components/user-lists-window.vue | 2 | ||||
| -rw-r--r-- | src/client/app/desktop/views/pages/user/user.profile.vue | 4 | ||||
| -rw-r--r-- | src/client/app/desktop/views/widgets/post-form.vue | 2 | ||||
| -rw-r--r-- | src/index.ts | 2 | ||||
| -rw-r--r-- | src/queue/processors/http/deliver.ts | 5 | ||||
| -rw-r--r-- | src/server/api/endpoints/users/search.ts | 161 | ||||
| -rw-r--r-- | src/server/api/endpoints/users/search_by_username.ts | 70 |
16 files changed, 175 insertions, 132 deletions
diff --git a/src/client/app/common/scripts/date-stringify.ts b/src/client/app/common/scripts/date-stringify.ts deleted file mode 100644 index 2b8e525567..0000000000 --- a/src/client/app/common/scripts/date-stringify.ts +++ /dev/null @@ -1,13 +0,0 @@ -export default date => { - if (typeof date == 'string') date = new Date(date); - return ( - date.getFullYear() + '%i18n:common.date.full-year%' + - (date.getMonth() + 1) + '%i18n:common.date.month%' + - date.getDate() + '%i18n:common.date.day%' + - ' ' + - date.getHours() + '%i18n:common.date.hours%' + - date.getMinutes() + '%i18n:common.date.minutes%' + - ' ' + - `(${['日', '月', '火', '水', '木', '金', '土'][date.getDay()]})` - ); -}; diff --git a/src/client/app/common/views/components/autocomplete.vue b/src/client/app/common/views/components/autocomplete.vue index cd6066877c..b274eaa0a0 100644 --- a/src/client/app/common/views/components/autocomplete.vue +++ b/src/client/app/common/views/components/autocomplete.vue @@ -132,7 +132,7 @@ export default Vue.extend({ this.users = users; this.fetching = false; } else { - (this as any).api('users/search_by_username', { + (this as any).api('users/search', { query: this.q, limit: 30 }).then(users => { diff --git a/src/client/app/common/views/components/signin.vue b/src/client/app/common/views/components/signin.vue index 58241cef09..deaeeca6a7 100644 --- a/src/client/app/common/views/components/signin.vue +++ b/src/client/app/common/views/components/signin.vue @@ -12,7 +12,7 @@ </ui-input> <ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" required/> <ui-button type="submit" :disabled="signing">{{ signing ? '%i18n:@signing-in%' : '%i18n:@signin%' }}</ui-button> - <p style="margin: 8px 0;">または<a :href="`${apiUrl}/signin/twitter`">Twitterでログイン</a></p> + <p style="margin: 8px 0;">%i18n:@or%<a :href="`${apiUrl}/signin/twitter`">%i18n:@signin-with-twitter%</a></p> </form> </template> diff --git a/src/client/app/desktop/api/update-avatar.ts b/src/client/app/desktop/api/update-avatar.ts index 887367a24e..83820f92bd 100644 --- a/src/client/app/desktop/api/update-avatar.ts +++ b/src/client/app/desktop/api/update-avatar.ts @@ -8,7 +8,7 @@ export default (os: OS) => (cb, file = null) => { const w = os.new(CropWindow, { image: file, - title: 'アバターとして表示する部分を選択', + title: '%i18n:desktop.avatar-crop-title%', aspectRatio: 1 / 1 }); @@ -18,11 +18,11 @@ export default (os: OS) => (cb, file = null) => { data.append('file', blob, file.name + '.cropped.png'); os.api('drive/folders/find', { - name: 'アイコン' + name: '%i18n:desktop.avatar%' }).then(iconFolder => { if (iconFolder.length === 0) { os.api('drive/folders/create', { - name: 'アイコン' + name: '%i18n:desktop.avatar%' }).then(iconFolder => { upload(data, iconFolder); }); @@ -41,7 +41,7 @@ export default (os: OS) => (cb, file = null) => { const upload = (data, folder) => { const dialog = os.new(ProgressDialog, { - title: '新しいアバターをアップロードしています' + title: '%i18n:desktop.uploading-avatar%' }); document.body.appendChild(dialog.$el); @@ -76,10 +76,10 @@ export default (os: OS) => (cb, file = null) => { }); os.apis.dialog({ - title: '%fa:info-circle%アバターを更新しました', - text: '新しいアバターが反映されるまで時間がかかる場合があります。', + title: '%fa:info-circle% %i18n:desktop.avatar-updated%', + text: null, actions: [{ - text: 'わかった' + text: '%i18n:common.got-it%' }] }); @@ -92,7 +92,7 @@ export default (os: OS) => (cb, file = null) => { } else { os.apis.chooseDriveFile({ multiple: false, - title: '%fa:image%アバターにする画像を選択' + title: '%fa:image% %i18n:desktop.choose-avatar%' }).then(file => { fileSelected(file); }); diff --git a/src/client/app/desktop/api/update-banner.ts b/src/client/app/desktop/api/update-banner.ts index 4e6dd4e2c7..33c4e306a2 100644 --- a/src/client/app/desktop/api/update-banner.ts +++ b/src/client/app/desktop/api/update-banner.ts @@ -8,7 +8,7 @@ export default (os: OS) => { const cropImage = file => new Promise((resolve, reject) => { const w = os.new(CropWindow, { image: file, - title: 'バナーとして表示する部分を選択', + title: '%i18n:desktop.banner-crop-title%', aspectRatio: 16 / 9 }); @@ -18,11 +18,11 @@ export default (os: OS) => { data.append('file', blob, file.name + '.cropped.png'); os.api('drive/folders/find', { - name: 'バナー' + name: '%i18n:desktop.banner%' }).then(bannerFolder => { if (bannerFolder.length === 0) { os.api('drive/folders/create', { - name: 'バナー' + name: '%i18n:desktop.banner%' }).then(iconFolder => { resolve(upload(data, iconFolder)); }); @@ -43,7 +43,7 @@ export default (os: OS) => { const upload = (data, folder) => new Promise((resolve, reject) => { const dialog = os.new(ProgressDialog, { - title: '新しいバナーをアップロードしています' + title: '%i18n:desktop.uploading-banner%' }); document.body.appendChild(dialog.$el); @@ -79,10 +79,10 @@ export default (os: OS) => { }); os.apis.dialog({ - title: '%fa:info-circle%バナーを更新しました', - text: '新しいバナーが反映されるまで時間がかかる場合があります。', + title: '%fa:info-circle% %i18n:desktop.banner-updated%', + text: null, actions: [{ - text: 'わかった' + text: '%i18n:common.got-it%' }] }); @@ -95,7 +95,7 @@ export default (os: OS) => { ? Promise.resolve(file) : os.apis.chooseDriveFile({ multiple: false, - title: '%fa:image%バナーにする画像を選択' + title: '%fa:image% %i18n:desktop.choose-banner%' }); return selectedFile diff --git a/src/client/app/desktop/views/components/note-detail.vue b/src/client/app/desktop/views/components/note-detail.vue index 36a5889220..b6980fae72 100644 --- a/src/client/app/desktop/views/components/note-detail.vue +++ b/src/client/app/desktop/views/components/note-detail.vue @@ -79,7 +79,6 @@ <script lang="ts"> import Vue from 'vue'; -import dateStringify from '../../../common/scripts/date-stringify'; import parse from '../../../../../mfm/parse'; import MkPostFormWindow from './post-form-window.vue'; @@ -129,7 +128,7 @@ export default Vue.extend({ : 0; }, title(): string { - return dateStringify(this.p.createdAt); + return new Date(this.p.createdAt).toLocaleString(); }, urls(): string[] { if (this.p.text) { diff --git a/src/client/app/desktop/views/components/note-preview.vue b/src/client/app/desktop/views/components/note-preview.vue index 2a49557247..c723db98c0 100644 --- a/src/client/app/desktop/views/components/note-preview.vue +++ b/src/client/app/desktop/views/components/note-preview.vue @@ -12,7 +12,6 @@ <script lang="ts"> import Vue from 'vue'; -import dateStringify from '../../../common/scripts/date-stringify'; export default Vue.extend({ props: { @@ -28,7 +27,7 @@ export default Vue.extend({ }, computed: { title(): string { - return dateStringify(this.note.createdAt); + return new Date(this.note.createdAt).toLocaleString(); } } }); diff --git a/src/client/app/desktop/views/components/notes.note.sub.vue b/src/client/app/desktop/views/components/notes.note.sub.vue index a8186fb7e4..fc851e83e9 100644 --- a/src/client/app/desktop/views/components/notes.note.sub.vue +++ b/src/client/app/desktop/views/components/notes.note.sub.vue @@ -12,13 +12,12 @@ <script lang="ts"> import Vue from 'vue'; -import dateStringify from '../../../common/scripts/date-stringify'; export default Vue.extend({ props: ['note'], computed: { title(): string { - return dateStringify(this.note.createdAt); + return new Date(this.note.createdAt).toLocaleString(); } } }); diff --git a/src/client/app/desktop/views/components/notes.note.vue b/src/client/app/desktop/views/components/notes.note.vue index 3aa52f75f0..fbbd524070 100644 --- a/src/client/app/desktop/views/components/notes.note.vue +++ b/src/client/app/desktop/views/components/notes.note.vue @@ -71,7 +71,6 @@ <script lang="ts"> import Vue from 'vue'; -import dateStringify from '../../../common/scripts/date-stringify'; import parse from '../../../../../mfm/parse'; import MkPostFormWindow from './post-form-window.vue'; @@ -128,7 +127,7 @@ export default Vue.extend({ }, title(): string { - return dateStringify(this.p.createdAt); + return new Date(this.p.createdAt).toLocaleString(); }, urls(): string[] { diff --git a/src/client/app/desktop/views/components/user-lists-window.vue b/src/client/app/desktop/views/components/user-lists-window.vue index 47648c287d..72ae9cf4e4 100644 --- a/src/client/app/desktop/views/components/user-lists-window.vue +++ b/src/client/app/desktop/views/components/user-lists-window.vue @@ -27,7 +27,7 @@ export default Vue.extend({ methods: { add() { (this as any).apis.input({ - title: 'リスト名', + title: '%i18n:@list-name%', }).then(async title => { const list = await (this as any).api('users/lists/create', { title diff --git a/src/client/app/desktop/views/pages/user/user.profile.vue b/src/client/app/desktop/views/pages/user/user.profile.vue index 35993f19a5..efd5be4672 100644 --- a/src/client/app/desktop/views/pages/user/user.profile.vue +++ b/src/client/app/desktop/views/pages/user/user.profile.vue @@ -13,7 +13,7 @@ <span v-if="user.isMuted">%fa:eye% %i18n:@unmute%</span> <span v-if="!user.isMuted">%fa:eye-slash% %i18n:@mute%</span> </button> - <button class="mute ui" @click="list">%fa:list% %i18n:@add-to-list%</button> + <button class="mute ui" @click="list">%fa:list% %i18n:@push-to-a-list%</button> </div> </div> </template> @@ -76,7 +76,7 @@ export default Vue.extend({ }); (this as any).apis.dialog({ title: 'Done!', - text: `${this.user.name}を${list.title}に追加しました。` + text: '%i18n:@list-pushed%'.replace('{user}', this.user.name).replace('{list}', list.title) }); }); } diff --git a/src/client/app/desktop/views/widgets/post-form.vue b/src/client/app/desktop/views/widgets/post-form.vue index 618d19efc4..19a2790d95 100644 --- a/src/client/app/desktop/views/widgets/post-form.vue +++ b/src/client/app/desktop/views/widgets/post-form.vue @@ -55,7 +55,7 @@ export default define({ }).then(data => { this.clear(); }).catch(err => { - alert('失敗した'); + alert('Something happened'); }).then(() => { this.posting = false; }); diff --git a/src/index.ts b/src/index.ts index 18eff8176c..0dda8b05b7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,6 +4,8 @@ Error.stackTraceLimit = Infinity; +require('events').EventEmitter.defaultMaxListeners = 128; + import * as os from 'os'; import * as cluster from 'cluster'; import * as debug from 'debug'; diff --git a/src/queue/processors/http/deliver.ts b/src/queue/processors/http/deliver.ts index e06866da4e..75e46559dd 100644 --- a/src/queue/processors/http/deliver.ts +++ b/src/queue/processors/http/deliver.ts @@ -7,6 +7,11 @@ export default async (job: bq.Job, done: any): Promise<void> => { await request(job.data.user, job.data.to, job.data.content); done(); } catch (res) { + if (!res.hasOwnProperty('statusCode')) { + console.warn(`deliver failed (unknown): ${res}`); + return done(); + } + if (res.statusCode == null) return done(); if (res.statusCode >= 400 && res.statusCode < 500) { // HTTPステータスコード4xxはクライアントエラーであり、それはつまり diff --git a/src/server/api/endpoints/users/search.ts b/src/server/api/endpoints/users/search.ts index d443d35b47..eda3f95728 100644 --- a/src/server/api/endpoints/users/search.ts +++ b/src/server/api/endpoints/users/search.ts @@ -1,33 +1,156 @@ import $ from 'cafy'; -import User, { pack, ILocalUser } from '../../../../models/user'; const escapeRegexp = require('escape-regexp'); +import User, { pack, ILocalUser, validateUsername, IUser } from '../../../../models/user'; +import getParams from '../../get-params'; + +export const meta = { + desc: { + ja: 'ユーザーを検索します。' + }, + + requireCredential: false, + + params: { + query: $.str.note({ + desc: { + ja: 'クエリ' + } + }), + + offset: $.num.optional.min(0).note({ + default: 0, + desc: { + ja: 'オフセット' + } + }), + + limit: $.num.optional.range(1, 100).note({ + default: 10, + desc: { + ja: '取得する数' + } + }), + + localOnly: $.bool.optional.note({ + default: false, + desc: { + ja: 'ローカルユーザーのみ検索対象にするか否か' + } + }), + }, +}; /** * Search a user */ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => { - // Get 'query' parameter - const [query, queryError] = $.str.pipe(x => x != '').get(params.query); - if (queryError) return rej('invalid query param'); + const [ps, psErr] = getParams(meta, params); + if (psErr) return rej(psErr); + + const isUsername = validateUsername(ps.query.replace('@', '')); + + let users: IUser[] = []; + + if (isUsername) { + users = await User + .find({ + host: null, + usernameLower: new RegExp('^' + escapeRegexp(ps.query.replace('@', '').toLowerCase())) + }, { + limit: ps.limit, + skip: ps.offset + }); + + if (users.length < ps.limit && !ps.localOnly) { + const otherUsers = await User + .find({ + host: { $ne: null }, + usernameLower: new RegExp('^' + escapeRegexp(ps.query.replace('@', '').toLowerCase())) + }, { + limit: ps.limit - users.length + }); + + users = users.concat(otherUsers); + } - // Get 'max' parameter - const [max = 10, maxErr] = $.num.optional.range(1, 30).get(params.max); - if (maxErr) return rej('invalid max param'); + if (users.length < ps.limit) { + const otherUsers = await User + .find({ + _id: { $nin: users.map(u => u._id) }, + host: null, + usernameLower: new RegExp(escapeRegexp(ps.query.replace('@', '').toLowerCase())) + }, { + limit: ps.limit - users.length + }); - const escapedQuery = escapeRegexp(query); + users = users.concat(otherUsers); + } - // Search users - const users = await User - .find({ - host: null, - $or: [{ - usernameLower: new RegExp(escapedQuery.replace('@', '').toLowerCase()) + if (users.length < ps.limit && !ps.localOnly) { + const otherUsers = await User + .find({ + _id: { $nin: users.map(u => u._id) }, + host: { $ne: null }, + usernameLower: new RegExp(escapeRegexp(ps.query.replace('@', '').toLowerCase())) + }, { + limit: ps.limit - users.length + }); + + users = users.concat(otherUsers); + } + } + + if (users.length < ps.limit) { + const otherUsers = await User + .find({ + _id: { $nin: users.map(u => u._id) }, + host: null, + name: new RegExp('^' + escapeRegexp(ps.query.toLowerCase())) + }, { + limit: ps.limit - users.length + }); + + users = users.concat(otherUsers); + } + + if (users.length < ps.limit && !ps.localOnly) { + const otherUsers = await User + .find({ + _id: { $nin: users.map(u => u._id) }, + host: { $ne: null }, + name: new RegExp('^' + escapeRegexp(ps.query.toLowerCase())) + }, { + limit: ps.limit - users.length + }); + + users = users.concat(otherUsers); + } + + if (users.length < ps.limit) { + const otherUsers = await User + .find({ + _id: { $nin: users.map(u => u._id) }, + host: null, + name: new RegExp(escapeRegexp(ps.query.toLowerCase())) + }, { + limit: ps.limit - users.length + }); + + users = users.concat(otherUsers); + } + + if (users.length < ps.limit && !ps.localOnly) { + const otherUsers = await User + .find({ + _id: { $nin: users.map(u => u._id) }, + host: { $ne: null }, + name: new RegExp(escapeRegexp(ps.query.toLowerCase())) }, { - name: new RegExp(escapedQuery) - }] - }, { - limit: max - }); + limit: ps.limit - users.length + }); + + users = users.concat(otherUsers); + } // Serialize res(await Promise.all(users.map(user => pack(user, me, { detail: true })))); diff --git a/src/server/api/endpoints/users/search_by_username.ts b/src/server/api/endpoints/users/search_by_username.ts deleted file mode 100644 index bfab378389..0000000000 --- a/src/server/api/endpoints/users/search_by_username.ts +++ /dev/null @@ -1,70 +0,0 @@ -import $ from 'cafy'; -import User, { pack, ILocalUser } from '../../../../models/user'; -const escapeRegexp = require('escape-regexp'); - -/** - * Search a user by username - */ -export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => { - // Get 'query' parameter - const [query, queryError] = $.str.get(params.query); - if (queryError) return rej('invalid query param'); - - // Get 'offset' parameter - const [offset = 0, offsetErr] = $.num.optional.min(0).get(params.offset); - if (offsetErr) return rej('invalid offset param'); - - // Get 'limit' parameter - const [limit = 10, limitErr] = $.num.optional.range(1, 100).get(params.limit); - if (limitErr) return rej('invalid limit param'); - - let users = await User - .find({ - host: null, - usernameLower: new RegExp('^' + escapeRegexp(query.toLowerCase())) - }, { - limit: limit, - skip: offset - }); - - if (users.length < limit) { - const otherUsers = await User - .find({ - host: { $ne: null }, - usernameLower: new RegExp('^' + escapeRegexp(query.toLowerCase())) - }, { - limit: limit - users.length - }); - - users = users.concat(otherUsers); - } - - if (users.length < limit) { - const otherUsers = await User - .find({ - _id: { $nin: users.map(u => u._id) }, - host: null, - usernameLower: new RegExp(escapeRegexp(query.toLowerCase())) - }, { - limit: limit - users.length - }); - - users = users.concat(otherUsers); - } - - if (users.length < limit) { - const otherUsers = await User - .find({ - _id: { $nin: users.map(u => u._id) }, - host: { $ne: null }, - usernameLower: new RegExp(escapeRegexp(query.toLowerCase())) - }, { - limit: limit - users.length - }); - - users = users.concat(otherUsers); - } - - // Serialize - res(await Promise.all(users.map(user => pack(user, me, { detail: true })))); -}); |