Merge remote-tracking branch 'refs/remotes/origin/master' into #1288-2

This commit is contained in:
syuilo 2018-03-28 13:06:26 +09:00
commit e802198b27
18 changed files with 131 additions and 47 deletions

View File

@ -19,7 +19,7 @@ Key features
* Two-Factor Authentication support
* ServiceWorker support
* Web API for third-party applications
* No ads
* ActivityPub compatible
and more! You can touch with your own eyes at https://misskey.xyz/.

View File

@ -147,7 +147,7 @@ common:
available: "利用できます"
unavailable: "既に利用されています"
error: "通信エラー"
invalid-format: "a~z、A~Z、0~9、-(ハイフン)が使えます"
invalid-format: "a~z、A~Z、0~9、_が使えます"
too-short: "3文字以上でお願いします"
too-long: "20文字以内でお願いします"
password: "パスワード"

View File

@ -2,6 +2,7 @@
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "0.0.4224",
"codename": "nighthike",
"license": "MIT",
"description": "A miniblog-based SNS",
"bugs": "https://github.com/syuilo/misskey/issues",
@ -15,6 +16,7 @@
"swagger": "node ./swagger.js",
"build": "node --max_old_space_size=16384 ./node_modules/webpack/bin/webpack.js && gulp build",
"webpack": "node --max_old_space_size=16384 ./node_modules/webpack/bin/webpack.js",
"watch": "node --max_old_space_size=16384 ./node_modules/webpack/bin/webpack.js --watch",
"gulp": "gulp build",
"rebuild": "gulp rebuild",
"clean": "gulp clean",
@ -44,11 +46,11 @@
"@types/express": "4.11.1",
"@types/gm": "1.17.33",
"@types/gulp": "3.8.36",
"@types/gulp-htmlmin": "1.3.31",
"@types/gulp-mocha": "0.0.31",
"@types/gulp-htmlmin": "1.3.32",
"@types/gulp-mocha": "0.0.32",
"@types/gulp-rename": "0.0.33",
"@types/gulp-replace": "0.0.31",
"@types/gulp-uglify": "3.0.4",
"@types/gulp-uglify": "3.0.5",
"@types/gulp-util": "3.0.34",
"@types/inquirer": "0.0.38",
"@types/is-root": "1.0.0",
@ -56,13 +58,13 @@
"@types/js-yaml": "3.10.1",
"@types/license-checker": "15.0.0",
"@types/mkdirp": "0.5.2",
"@types/mocha": "2.2.48",
"@types/mongodb": "3.0.8",
"@types/mocha": "5.0.0",
"@types/mongodb": "3.0.9",
"@types/monk": "6.0.0",
"@types/morgan": "1.7.35",
"@types/ms": "0.7.30",
"@types/multer": "1.3.6",
"@types/node": "9.4.7",
"@types/node": "9.6.0",
"@types/proxy-addr": "2.0.0",
"@types/pug": "2.0.4",
"@types/qrcode": "0.8.1",
@ -76,13 +78,13 @@
"@types/speakeasy": "2.0.2",
"@types/tmp": "0.0.33",
"@types/uuid": "3.4.3",
"@types/webpack": "4.1.1",
"@types/webpack": "4.1.2",
"@types/webpack-stream": "3.2.10",
"@types/websocket": "0.0.38",
"@types/ws": "4.0.1",
"accesses": "2.5.0",
"animejs": "2.2.0",
"autosize": "4.0.0",
"autosize": "4.0.1",
"autwh": "0.0.1",
"bcryptjs": "2.4.3",
"body-parser": "1.18.2",
@ -114,7 +116,7 @@
"fuckadblock": "3.2.1",
"gm": "1.23.1",
"gulp": "3.9.1",
"gulp-cssnano": "2.1.2",
"gulp-cssnano": "2.1.3",
"gulp-htmlmin": "4.0.0",
"gulp-imagemin": "4.1.0",
"gulp-mocha": "5.0.0",
@ -130,25 +132,25 @@
"hard-source-webpack-plugin": "0.6.4",
"highlight.js": "9.12.0",
"html-minifier": "3.5.12",
"inquirer": "5.1.0",
"inquirer": "5.2.0",
"is-root": "2.0.0",
"is-url": "1.2.3",
"is-url": "1.2.4",
"js-yaml": "3.11.0",
"jsdom": "^11.6.2",
"jsdom": "11.6.2",
"license-checker": "18.0.0",
"loader-utils": "1.1.0",
"mecab-async": "0.1.2",
"mkdirp": "0.5.1",
"mocha": "5.0.4",
"mocha": "5.0.5",
"moji": "0.5.1",
"mongodb": "3.0.4",
"mongodb": "3.0.5",
"monk": "6.0.5",
"morgan": "1.9.0",
"ms": "2.1.1",
"multer": "1.3.0",
"nan": "^2.10.0",
"node-sass": "4.7.2",
"node-sass-json-importer": "3.1.5",
"nan": "2.10.0",
"node-sass": "4.8.3",
"node-sass-json-importer": "3.1.6",
"nprogress": "0.2.0",
"object-assign-deep": "0.3.1",
"on-build-webpack": "0.1.0",
@ -157,7 +159,7 @@
"prominence": "0.2.0",
"proxy-addr": "2.0.3",
"pug": "2.0.3",
"punycode": "^2.1.0",
"punycode": "2.1.0",
"qrcode": "1.2.0",
"ratelimiter": "3.0.3",
"recaptcha-promise": "0.1.3",
@ -181,10 +183,10 @@
"tcp-port-used": "0.1.2",
"textarea-caret": "3.1.0",
"tmp": "0.0.33",
"ts-loader": "4.0.1",
"ts-loader": "4.1.0",
"ts-node": "5.0.1",
"tslint": "5.9.1",
"typescript": "2.7.2",
"typescript": "2.8.1",
"typescript-eslint-parser": "14.0.0",
"uglify-es": "3.3.9",
"url-loader": "1.0.1",
@ -195,13 +197,13 @@
"vue-cropperjs": "2.2.0",
"vue-js-modal": "1.3.12",
"vue-json-tree-view": "2.1.3",
"vue-loader": "14.2.1",
"vue-loader": "14.2.2",
"vue-router": "3.0.1",
"vue-template-compiler": "2.5.16",
"vuedraggable": "2.16.0",
"web-push": "3.3.0",
"webfinger.js": "^2.6.6",
"webpack": "4.2.0",
"webfinger.js": "2.6.6",
"webpack": "4.3.0",
"webpack-cli": "2.0.13",
"webpack-replace-loader": "1.3.0",
"websocket": "1.0.25",

View File

@ -67,7 +67,7 @@ export default class BotCore extends EventEmitter {
return await this.context.q(query);
}
if (/^@[a-zA-Z0-9-]+$/.test(query)) {
if (/^@[a-zA-Z0-9_]+$/.test(query)) {
return await this.showUserCommand(query);
}

View File

@ -89,7 +89,6 @@ function workerMain() {
*/
async function init(): Promise<Config> {
Logger.info('Welcome to Misskey!');
Logger.info(chalk.bold('Misskey <aoi>'));
Logger.info('Initializing...');
EnvironmentInfo.show();

View File

@ -1,7 +1,7 @@
<template>
<form class="mk-signin" :class="{ signing }" @submit.prevent="onSubmit">
<label class="user-name">
<input v-model="username" type="text" pattern="^[a-zA-Z0-9-]+$" placeholder="%i18n:common.tags.mk-signin.username%" autofocus required @change="onUsernameChange"/>%fa:at%
<input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" placeholder="%i18n:common.tags.mk-signin.username%" autofocus required @change="onUsernameChange"/>%fa:at%
</label>
<label class="password">
<input v-model="password" type="password" placeholder="%i18n:common.tags.mk-signin.password%" required/>%fa:lock%

View File

@ -2,7 +2,7 @@
<form class="mk-signup" @submit.prevent="onSubmit" autocomplete="off">
<label class="username">
<p class="caption">%fa:at%%i18n:common.tags.mk-signup.username%</p>
<input v-model="username" type="text" pattern="^[a-zA-Z0-9-]{3,20}$" placeholder="a~z、A~Z、0~9、-" autocomplete="off" required @input="onChangeUsername"/>
<input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{3,20}$" placeholder="a~z、A~Z、0~9、-" autocomplete="off" required @input="onChangeUsername"/>
<p class="profile-page-url-preview" v-if="shouldShowProfileUrl">{{ `${url}/@${username}` }}</p>
<p class="info" v-if="usernameState == 'wait'" style="color:#999">%fa:spinner .pulse .fw%%i18n:common.tags.mk-signup.checking%</p>
<p class="info" v-if="usernameState == 'ok'" style="color:#3CB7B5">%fa:check .fw%%i18n:common.tags.mk-signup.available%</p>

View File

@ -77,7 +77,7 @@ class Autocomplete {
if (mentionIndex != -1 && mentionIndex > emojiIndex) {
const username = text.substr(mentionIndex + 1);
if (username != '' && username.match(/^[a-zA-Z0-9-]+$/)) {
if (username != '' && username.match(/^[a-zA-Z0-9_]+$/)) {
this.open('user', username);
opened = true;
}

View File

@ -1,16 +1,17 @@
<template>
<p>ver {{ v }} ( aoi)</p>
<p>ver {{ version }} ({{ codename }})</p>
</template>
<script lang="ts">
import { version } from '../../../config';
import { version, codename } from '../../../config';
import define from '../../../common/define-widget';
export default define({
name: 'version'
}).extend({
data() {
return {
v: version
version,
codename
};
}
});

View File

@ -7,13 +7,13 @@ declare const _DOCS_URL_: string;
declare const _STATS_URL_: string;
declare const _STATUS_URL_: string;
declare const _DEV_URL_: string;
declare const _CH_URL_: string;
declare const _LANG_: string;
declare const _RECAPTCHA_SITEKEY_: string;
declare const _SW_PUBLICKEY_: string;
declare const _THEME_COLOR_: string;
declare const _COPYRIGHT_: string;
declare const _VERSION_: string;
declare const _CODENAME_: string;
declare const _LICENSE_: string;
declare const _GOOGLE_MAPS_API_KEY_: string;
@ -26,12 +26,12 @@ export const docsUrl = _DOCS_URL_;
export const statsUrl = _STATS_URL_;
export const statusUrl = _STATUS_URL_;
export const devUrl = _DEV_URL_;
export const chUrl = _CH_URL_;
export const lang = _LANG_;
export const recaptchaSitekey = _RECAPTCHA_SITEKEY_;
export const swPublickey = _SW_PUBLICKEY_;
export const themeColor = _THEME_COLOR_;
export const copyright = _COPYRIGHT_;
export const version = _VERSION_;
export const codename = _CODENAME_;
export const license = _LICENSE_;
export const googleMapsApiKey = _GOOGLE_MAPS_API_KEY_;

View File

@ -6,12 +6,12 @@
<b-form-input v-model="name" type="text" placeholder="ex) Misskey for iOS" autocomplete="off" required/>
</b-form-group>
<b-form-group label="ID" description="あなたのアプリのID。">
<b-input v-model="nid" type="text" pattern="^[a-zA-Z0-9-]{3,30}$" placeholder="ex) misskey-for-ios" autocomplete="off" required/>
<b-input v-model="nid" type="text" pattern="^[a-zA-Z0-9_]{3,30}$" placeholder="ex) misskey-for-ios" autocomplete="off" required/>
<p class="info" v-if="nidState == 'wait'" style="color:#999">%fa:spinner .pulse .fw%確認しています...</p>
<p class="info" v-if="nidState == 'ok'" style="color:#3CB7B5">%fa:fw check%利用できます</p>
<p class="info" v-if="nidState == 'unavailable'" style="color:#FF1161">%fa:fw exclamation-triangle%既に利用されています</p>
<p class="info" v-if="nidState == 'error'" style="color:#FF1161">%fa:fw exclamation-triangle%通信エラー</p>
<p class="info" v-if="nidState == 'invalid-format'" style="color:#FF1161">%fa:fw exclamation-triangle%a~zA~Z0~9-(ハイフン)が使えます</p>
<p class="info" v-if="nidState == 'invalid-format'" style="color:#FF1161">%fa:fw exclamation-triangle%a~zA~Z0~9_が使えます</p>
<p class="info" v-if="nidState == 'min-range'" style="color:#FF1161">%fa:fw exclamation-triangle%3文字以上でお願いします</p>
<p class="info" v-if="nidState == 'max-range'" style="color:#FF1161">%fa:fw exclamation-triangle%30文字以内でお願いします</p>
</b-form-group>

View File

@ -14,7 +14,7 @@ import ElementLocaleJa from 'element-ui/lib/locale/lang/ja';
import App from './app.vue';
import checkForUpdate from './common/scripts/check-for-update';
import MiOS, { API } from './common/mios';
import { version, hostname, lang } from './config';
import { version, codename, hostname, lang } from './config';
let elementLocale;
switch (lang) {
@ -51,7 +51,7 @@ Vue.mixin({
* APP ENTRY POINT!
*/
console.info(`Misskey v${version} (葵 aoi)`);
console.info(`Misskey v${version} (${codename})`);
console.info(
'%cここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。',
'color: red; background: yellow; font-size: 16px; font-weight: bold;');

View File

@ -12,19 +12,20 @@
<ul>
<li><a @click="signout">%fa:power-off%%i18n:mobile.tags.mk-settings-page.signout%</a></li>
</ul>
<p><small>ver {{ v }} ( aoi)</small></p>
<p><small>ver {{ version }} ({{ codename }})</small></p>
</div>
</mk-ui>
</template>
<script lang="ts">
import Vue from 'vue';
import { version } from '../../../config';
import { version, codename } from '../../../config';
export default Vue.extend({
data() {
return {
v: version
version,
codename
};
},
mounted() {

View File

@ -6,7 +6,7 @@
<p>%fa:lock% ログイン</p>
<div>
<form @submit.prevent="onSubmit">
<input v-model="username" type="text" pattern="^[a-zA-Z0-9-]+$" placeholder="ユーザー名" autofocus required @change="onUsernameChange"/>
<input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" placeholder="ユーザー名" autofocus required @change="onUsernameChange"/>
<input v-model="password" type="password" placeholder="パスワード" required/>
<input v-if="user && user.account.two_factor_enabled" v-model="token" type="number" placeholder="トークン" required/>
<button type="submit" :disabled="signing">{{ signing ? 'ログインしています' : 'ログイン' }}</button>

View File

@ -23,7 +23,7 @@ const defaultSwagger = {
"swagger": "2.0",
"info": {
"title": "Misskey API",
"version": "aoi"
"version": "nighthike"
},
"host": "api.misskey.xyz",
"schemes": [

View File

@ -0,0 +1,40 @@
// for Node.js interpret
const { default: App } = require('../../built/api/models/app');
const { generate } = require('../../built/crypto_key');
const { default: zip } = require('@prezzemolo/zip')
const migrate = async (app) => {
const result = await User.update(app._id, {
$set: {
'name_id': app.name_id.replace(/\-/g, '_'),
'name_id_lower': app.name_id_lower.replace(/\-/g, '_')
}
});
return result.ok === 1;
}
async function main() {
const count = await App.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 App.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)

View File

@ -0,0 +1,40 @@
// for Node.js interpret
const { default: User } = require('../../built/api/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, {
$set: {
'username': user.username.replace(/\-/g, '_'),
'username_lower': user.username_lower.replace(/\-/g, '_')
}
});
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)

View File

@ -20,6 +20,7 @@ import { licenseHtml } from './src/common/build/license';
import locales from './locales';
const meta = require('./package.json');
const version = meta.version;
const codename = meta.codename;
//#region Replacer definitions
global['faReplacement'] = faReplacement;
@ -76,13 +77,13 @@ module.exports = entries.map(x => {
_THEME_COLOR_: constants.themeColor,
_COPYRIGHT_: constants.copyright,
_VERSION_: version,
_CODENAME_: codename,
_STATUS_URL_: config.status_url,
_STATS_URL_: config.stats_url,
_DOCS_URL_: config.docs_url,
_API_URL_: config.api_url,
_WS_URL_: config.ws_url,
_DEV_URL_: config.dev_url,
_CH_URL_: config.ch_url,
_LANG_: lang,
_HOST_: config.host,
_HOSTNAME_: config.hostname,