Merge branch 'develop' into twemoji

This commit is contained in:
Acid Chicken (硫酸鶏) 2018-11-05 11:21:34 +09:00 committed by GitHub
commit 136f23c7ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 69 additions and 76 deletions

View file

@ -167,6 +167,3 @@ drive:
# external: true # external: true
# engine: http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}} # engine: http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}
# timeout: 300000 # timeout: 300000
# Max allowed note text length in charactors
maxNoteTextLength: 1000

View file

@ -1,41 +0,0 @@
# travis file
# https://docs.travis-ci.com/user/customizing-the-build
notifications:
email: false
branches:
except:
- l10n_master
language: node_js
node_js:
- 11.0.0
env:
- CXX=g++-4.8 NODE_ENV=production
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
cache:
directories:
- node_modules
services:
- mongodb
- redis-server
before_script:
- npm install
# 設定ファイルを配置
- cp ./.ci/default.yml ./.config
- cp ./.ci/test.yml ./.config
- travis_wait npm run build

View file

@ -23,5 +23,5 @@ Please use [Crowdin](https://crowdin.com/project/misskey) for localization.
* Test codes are located in `/test`. * Test codes are located in `/test`.
## Continuous integration ## Continuous integration
Misskey uses Travis for automated test. Misskey uses CircleCI for automated test.
Configuration files are located in `/.travis`. Configuration files are located in `/.circleci`.

View file

@ -4,7 +4,6 @@
================================================================ ================================================================
[![CircleCI](https://circleci.com/gh/syuilo/misskey.svg?style=svg)](https://circleci.com/gh/syuilo/misskey) [![CircleCI](https://circleci.com/gh/syuilo/misskey.svg?style=svg)](https://circleci.com/gh/syuilo/misskey)
[![][travis-badge]][travis-link]
[![][dependencies-badge]][dependencies-link] [![][dependencies-badge]][dependencies-link]
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
@ -124,8 +123,6 @@ Misskey is an open-source software licensed under the [GNU AGPLv3](LICENSE).
[agpl-3.0]: https://www.gnu.org/licenses/agpl-3.0.en.html [agpl-3.0]: https://www.gnu.org/licenses/agpl-3.0.en.html
[agpl-3.0-badge]: https://img.shields.io/badge/license-AGPL--3.0-444444.svg?style=flat-square [agpl-3.0-badge]: https://img.shields.io/badge/license-AGPL--3.0-444444.svg?style=flat-square
[travis-link]: https://travis-ci.org/syuilo/misskey
[travis-badge]: http://img.shields.io/travis/syuilo/misskey/master.svg?style=flat-square
[dependencies-link]: https://david-dm.org/syuilo/misskey [dependencies-link]: https://david-dm.org/syuilo/misskey
[dependencies-badge]: https://img.shields.io/david/syuilo/misskey.svg?style=flat-square [dependencies-badge]: https://img.shields.io/david/syuilo/misskey.svg?style=flat-square

View file

@ -22,7 +22,7 @@ adduser --disabled-password --disabled-login misskey
Please install and setup these softwares: Please install and setup these softwares:
#### Dependencies :package: #### Dependencies :package:
* **[Node.js](https://nodejs.org/en/)** * **[Node.js](https://nodejs.org/en/)** >= 10.0.0
* **[MongoDB](https://www.mongodb.com/)** >= 3.6 * **[MongoDB](https://www.mongodb.com/)** >= 3.6
##### Optional ##### Optional

View file

@ -22,7 +22,7 @@ adduser --disabled-password --disabled-login misskey
これらのソフトウェアをインストール・設定してください: これらのソフトウェアをインストール・設定してください:
#### 依存関係 :package: #### 依存関係 :package:
* **[Node.js](https://nodejs.org/en/)** * **[Node.js](https://nodejs.org/en/)** (10.0.0以上)
* **[MongoDB](https://www.mongodb.com/)** (3.6以上) * **[MongoDB](https://www.mongodb.com/)** (3.6以上)
##### オプション ##### オプション

View file

@ -1077,8 +1077,9 @@ admin/views/instance.vue:
instance-name: "インスタンス名" instance-name: "インスタンス名"
instance-description: "インスタンスの紹介" instance-description: "インスタンスの紹介"
banner-url: "バナー画像URL" banner-url: "バナー画像URL"
disableRegistration: "ユーザー登録の受付を停止する" max-note-text-length: "投稿の最大文字数"
disableLocalTimeline: "ローカルタイムラインを無効にする" disable-registration: "ユーザー登録の受付を停止する"
disable-local-timeline: "ローカルタイムラインを無効にする"
invite: "招待" invite: "招待"
save: "保存" save: "保存"
saved: "保存しました" saved: "保存しました"
@ -1151,6 +1152,9 @@ admin/views/announcements.vue:
title: "タイトル" title: "タイトル"
text: "内容" text: "内容"
saved: "保存しました" saved: "保存しました"
_remove:
are-you-sure: "「$1」を削除しますか"
removed: "削除しました"
admin/views/hashtags.vue: admin/views/hashtags.vue:
hided-tags: "Hidden Tags" hided-tags: "Hidden Tags"

View file

@ -1,8 +1,8 @@
{ {
"name": "misskey", "name": "misskey",
"author": "syuilo <i@syuilo.com>", "author": "syuilo <i@syuilo.com>",
"version": "10.38.6", "version": "10.38.7",
"clientVersion": "1.0.11516", "clientVersion": "1.0.11530",
"codename": "nighthike", "codename": "nighthike",
"main": "./built/index.js", "main": "./built/index.js",
"private": true, "private": true,

View file

@ -10,7 +10,7 @@
<span>%i18n:@text%</span> <span>%i18n:@text%</span>
</ui-textarea> </ui-textarea>
<ui-horizon-group> <ui-horizon-group>
<ui-button @click="save">%fa:save R% %i18n:@save%</ui-button> <ui-button @click="save()">%fa:save R% %i18n:@save%</ui-button>
<ui-button @click="remove(i)">%fa:trash-alt R% %i18n:@remove%</ui-button> <ui-button @click="remove(i)">%fa:trash-alt R% %i18n:@remove%</ui-button>
</ui-horizon-group> </ui-horizon-group>
</section> </section>
@ -46,18 +46,31 @@ export default Vue.extend({
}, },
remove(i) { remove(i) {
this.announcements = this.announcements.filter((_, j) => j !== i); this.$swal({
this.save(); type: 'warning',
text: '%i18n:@_remove.are-you-sure%'.replace('$1', this.announcements.find((_, j) => j == i).title),
showCancelButton: true
}).then(res => {
if (!res.value) return;
this.announcements = this.announcements.filter((_, j) => j !== i);
this.save(true);
this.$swal({
type: 'success',
text: '%i18n:@_remove.removed%'
});
});
}, },
save() { save(silent) {
(this as any).api('admin/update-meta', { (this as any).api('admin/update-meta', {
broadcasts: this.announcements broadcasts: this.announcements
}).then(() => { }).then(() => {
this.$swal({ if (!silent) {
type: 'success', this.$swal({
text: '%i18n:@saved%' type: 'success',
}); text: '%i18n:@saved%'
});
}
}).catch(e => { }).catch(e => {
this.$swal({ this.$swal({
type: 'error', type: 'error',

View file

@ -6,6 +6,7 @@
<ui-input v-model="name">%i18n:@instance-name%</ui-input> <ui-input v-model="name">%i18n:@instance-name%</ui-input>
<ui-textarea v-model="description">%i18n:@instance-description%</ui-textarea> <ui-textarea v-model="description">%i18n:@instance-description%</ui-textarea>
<ui-input v-model="bannerUrl">%i18n:@banner-url%</ui-input> <ui-input v-model="bannerUrl">%i18n:@banner-url%</ui-input>
<ui-input v-model="maxNoteTextLength">%i18n:@max-note-text-length%</ui-input>
<ui-button @click="updateMeta">%i18n:@save%</ui-button> <ui-button @click="updateMeta">%i18n:@save%</ui-button>
</section> </section>
</ui-card> </ui-card>
@ -39,6 +40,7 @@ export default Vue.extend({
bannerUrl: null, bannerUrl: null,
name: null, name: null,
description: null, description: null,
maxNoteTextLength: null,
inviteCode: null, inviteCode: null,
}; };
}, },
@ -48,6 +50,7 @@ export default Vue.extend({
this.bannerUrl = meta.bannerUrl; this.bannerUrl = meta.bannerUrl;
this.name = meta.name; this.name = meta.name;
this.description = meta.description; this.description = meta.description;
this.maxNoteTextLength = meta.maxNoteTextLength;
}); });
}, },
@ -69,7 +72,8 @@ export default Vue.extend({
disableLocalTimeline: this.disableLocalTimeline, disableLocalTimeline: this.disableLocalTimeline,
bannerUrl: this.bannerUrl, bannerUrl: this.bannerUrl,
name: this.name, name: this.name,
description: this.description description: this.description,
maxNoteTextLength: parseInt(this.maxNoteTextLength, 10)
}).then(() => { }).then(() => {
this.$swal({ this.$swal({
type: 'success', type: 'success',

View file

@ -49,8 +49,6 @@ export default function load() {
if (config.localDriveCapacityMb == null) config.localDriveCapacityMb = 256; if (config.localDriveCapacityMb == null) config.localDriveCapacityMb = 256;
if (config.remoteDriveCapacityMb == null) config.remoteDriveCapacityMb = 8; if (config.remoteDriveCapacityMb == null) config.remoteDriveCapacityMb = 8;
if (config.maxNoteTextLength == null) config.maxNoteTextLength = 1000;
return Object.assign(config, mixin); return Object.assign(config, mixin);
} }

View file

@ -107,8 +107,6 @@ export type Source = {
engine: string; engine: string;
timeout: number; timeout: number;
}; };
maxNoteTextLength?: number;
}; };
/** /**

View file

@ -43,4 +43,9 @@ export type IMeta = {
disableLocalTimeline?: boolean; disableLocalTimeline?: boolean;
hidedTags?: string[]; hidedTags?: string[];
bannerUrl?: string; bannerUrl?: string;
/**
* Max allowed note text length in charactors
*/
maxNoteTextLength?: number;
}; };

View file

@ -11,7 +11,6 @@ import Reaction from './note-reaction';
import { packMany as packFileMany, IDriveFile } from './drive-file'; import { packMany as packFileMany, IDriveFile } from './drive-file';
import Favorite from './favorite'; import Favorite from './favorite';
import Following from './following'; import Following from './following';
import config from '../config';
import Emoji from './emoji'; import Emoji from './emoji';
const Note = db.get<INote>('notes'); const Note = db.get<INote>('notes');
@ -27,10 +26,6 @@ Note.createIndex({ createdAt: -1 });
Note.createIndex({ score: -1 }, { sparse: true }); Note.createIndex({ score: -1 }, { sparse: true });
export default Note; export default Note;
export function isValidText(text: string): boolean {
return length(text.trim()) <= config.maxNoteTextLength && text.trim() != '';
}
export function isValidCw(text: string): boolean { export function isValidCw(text: string): boolean {
return length(text.trim()) <= 100; return length(text.trim()) <= 100;
} }

View file

@ -59,6 +59,13 @@ export const meta = {
'ja-JP': 'インスタンスの紹介文' 'ja-JP': 'インスタンスの紹介文'
} }
}, },
maxNoteTextLength: {
validator: $.num.optional.min(1),
desc: {
'ja-JP': '投稿の最大文字数'
}
}
} }
}; };
@ -93,6 +100,10 @@ export default define(meta, (ps) => new Promise(async (res, rej) => {
set.description = ps.description; set.description = ps.description;
} }
if (ps.maxNoteTextLength) {
set.maxNoteTextLength = ps.maxNoteTextLength;
}
await Meta.update({}, { await Meta.update({}, {
$set: set $set: set
}, { upsert: true }); }, { upsert: true });

View file

@ -62,7 +62,7 @@ export default define(meta, (ps, me) => new Promise(async (res, rej) => {
swPublickey: config.sw ? config.sw.public_key : null, swPublickey: config.sw ? config.sw.public_key : null,
hidedTags: (me && me.isAdmin) ? met.hidedTags : undefined, hidedTags: (me && me.isAdmin) ? met.hidedTags : undefined,
bannerUrl: met.bannerUrl, bannerUrl: met.bannerUrl,
maxNoteTextLength: config.maxNoteTextLength, maxNoteTextLength: met.maxNoteTextLength || 1000,
emojis: emojis, emojis: emojis,

View file

@ -1,10 +1,20 @@
import $ from 'cafy'; import ID, { transform, transformMany } from '../../../../misc/cafy-id'; import $ from 'cafy'; import ID, { transform, transformMany } from '../../../../misc/cafy-id';
const ms = require('ms'); const ms = require('ms');
import Note, { INote, isValidText, isValidCw, pack } from '../../../../models/note'; import { length } from 'stringz';
import Note, { INote, isValidCw, pack } from '../../../../models/note';
import User, { IUser } from '../../../../models/user'; import User, { IUser } from '../../../../models/user';
import DriveFile, { IDriveFile } from '../../../../models/drive-file'; import DriveFile, { IDriveFile } from '../../../../models/drive-file';
import create from '../../../../services/note/create'; import create from '../../../../services/note/create';
import define from '../../define'; import define from '../../define';
import Meta from '../../../../models/meta';
let maxNoteTextLength = 1000;
setInterval(() => {
Meta.findOne({}).then(m => {
if (m.maxNoteTextLength) maxNoteTextLength = m.maxNoteTextLength;
});
}, 3000);
export const meta = { export const meta = {
stability: 'stable', stability: 'stable',
@ -40,7 +50,9 @@ export const meta = {
}, },
text: { text: {
validator: $.str.optional.nullable.pipe(isValidText), validator: $.str.optional.nullable.pipe(text =>
length(text.trim()) <= maxNoteTextLength && text.trim() != ''
),
default: null as any, default: null as any,
desc: { desc: {
'ja-JP': '投稿内容' 'ja-JP': '投稿内容'