From 4535ab4c434ba5961e5d8b5ec3957d4e05cd99eb Mon Sep 17 00:00:00 2001 From: sei0o Date: Fri, 17 Aug 2018 16:35:04 +0900 Subject: [PATCH 01/56] fix #2266 --- .../app/common/views/components/visibility-chooser.vue | 8 +++++++- src/client/app/desktop/views/components/post-form.vue | 5 ++--- src/client/app/mobile/views/components/post-form.vue | 5 ++--- src/client/app/store.ts | 4 ++++ 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/client/app/common/views/components/visibility-chooser.vue b/src/client/app/common/views/components/visibility-chooser.vue index cc9c75095..8be3ddb8f 100644 --- a/src/client/app/common/views/components/visibility-chooser.vue +++ b/src/client/app/common/views/components/visibility-chooser.vue @@ -44,7 +44,12 @@ import Vue from 'vue'; import * as anime from 'animejs'; export default Vue.extend({ - props: ['source', 'compact', 'v'], + data() { + return { + v: this.$store.state.device.visibility + } + }, + props: ['source', 'compact'], mounted() { this.$nextTick(() => { const popover = this.$refs.popover as any; @@ -92,6 +97,7 @@ export default Vue.extend({ }, methods: { choose(visibility) { + this.$store.commit('device/setVisibility', visibility); this.$emit('chosen', visibility); this.$destroy(); }, diff --git a/src/client/app/desktop/views/components/post-form.vue b/src/client/app/desktop/views/components/post-form.vue index ea5114417..6b833f8d0 100644 --- a/src/client/app/desktop/views/components/post-form.vue +++ b/src/client/app/desktop/views/components/post-form.vue @@ -99,7 +99,7 @@ export default Vue.extend({ useCw: false, cw: null, geo: null, - visibility: 'public', + visibility: this.$store.state.device.visibility, visibleUsers: [], autocomplete: null, draghover: false, @@ -326,8 +326,7 @@ export default Vue.extend({ setVisibility() { const w = (this as any).os.new(MkVisibilityChooser, { - source: this.$refs.visibilityButton, - v: this.visibility + source: this.$refs.visibilityButton }); w.$once('chosen', v => { this.visibility = v; diff --git a/src/client/app/mobile/views/components/post-form.vue b/src/client/app/mobile/views/components/post-form.vue index 702bc4c9e..cb3b59b2c 100644 --- a/src/client/app/mobile/views/components/post-form.vue +++ b/src/client/app/mobile/views/components/post-form.vue @@ -94,7 +94,7 @@ export default Vue.extend({ files: [], poll: false, geo: null, - visibility: 'public', + visibility: this.$store.state.device.visibility, visibleUsers: [], useCw: false, cw: null, @@ -240,8 +240,7 @@ export default Vue.extend({ setVisibility() { const w = (this as any).os.new(MkVisibilityChooser, { source: this.$refs.visibilityButton, - compact: true, - v: this.visibility + compact: true }); w.$once('chosen', v => { this.visibility = v; diff --git a/src/client/app/store.ts b/src/client/app/store.ts index f85253a28..7e2cc3976 100644 --- a/src/client/app/store.ts +++ b/src/client/app/store.ts @@ -110,6 +110,10 @@ export default (os: MiOS) => new Vuex.Store({ src: x.src, arg: x.arg }; + }, + + setVisibility(state, visibility) { + state.visibility = visibility; } } }, From e4b8c688bb98770084003fa3f9d666788908cc83 Mon Sep 17 00:00:00 2001 From: sei0o Date: Fri, 17 Aug 2018 17:16:27 +0900 Subject: [PATCH 02/56] =?UTF-8?q?fix=20#2266:=20=E3=83=87=E3=83=95?= =?UTF-8?q?=E3=82=A9=E3=83=AB=E3=83=88=E5=80=A4=E3=82=92=E8=A8=AD=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/client/app/desktop/views/components/post-form.vue | 2 +- src/client/app/mobile/views/components/post-form.vue | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/app/desktop/views/components/post-form.vue b/src/client/app/desktop/views/components/post-form.vue index 6b833f8d0..d5d160bd8 100644 --- a/src/client/app/desktop/views/components/post-form.vue +++ b/src/client/app/desktop/views/components/post-form.vue @@ -99,7 +99,7 @@ export default Vue.extend({ useCw: false, cw: null, geo: null, - visibility: this.$store.state.device.visibility, + visibility: this.$store.state.device.visibility || 'public', visibleUsers: [], autocomplete: null, draghover: false, diff --git a/src/client/app/mobile/views/components/post-form.vue b/src/client/app/mobile/views/components/post-form.vue index cb3b59b2c..466ca393d 100644 --- a/src/client/app/mobile/views/components/post-form.vue +++ b/src/client/app/mobile/views/components/post-form.vue @@ -94,7 +94,7 @@ export default Vue.extend({ files: [], poll: false, geo: null, - visibility: this.$store.state.device.visibility, + visibility: this.$store.state.device.visibility || 'public', visibleUsers: [], useCw: false, cw: null, From 86503f2d6961f065881e12593cb6d851c24ba933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Fri, 17 Aug 2018 18:33:49 +0900 Subject: [PATCH 03/56] Create README.head.md --- .autogen/README.head.md | 45 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 .autogen/README.head.md diff --git a/.autogen/README.head.md b/.autogen/README.head.md new file mode 100644 index 000000000..39390dd90 --- /dev/null +++ b/.autogen/README.head.md @@ -0,0 +1,45 @@ + + +[![Misskey](/assets/title.png)](https://misskey.xyz/) +================================================================ + +[![][travis-badge]][travis-link] +[![][dependencies-badge]][dependencies-link] +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) [![Greenkeeper badge](https://badges.greenkeeper.io/syuilo/misskey.svg)](https://greenkeeper.io/) + +**Microblogging. Redefined.** + +**[Misskey](https://misskey.xyz)** is a completely open source, +ultimately sophisticated professional microblogging software. + +Become a Patron! + +![](https://ja.mstdn.wiki/images/e/ed/Deck.jpg) + +:sparkles: Features +---------------------------------------------------------------- +* Rich text contents +* Reactions +* User lists +* Customizable column view (called MisskeyDeck) + * and widgets! +* Private messages +* ActivityPub support + +and more! You can see it with your own eyes at [misskey.xyz](https://misskey.xyz). + +:package: Create your instance +---------------------------------------------------------------- +If you want to run your own instance of Misskey, +please see [Setup and installation guide](./docs/setup.en.md). + +:wrench: Contribute +---------------------------------------------------------------- +**[PR](https://github.com/syuilo/misskey/pulls)s welcome!** + +If you want to... +* i18n ... please see [Translation guide](./docs/translate.en.md). +* l10n ... please visit https://crowdin.com/project/misskey + +:heart: Backers & Sponsors +---------------------------------------------------------------- From 59bec546e4267bab193e9497b9250ed8c49be17e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Fri, 17 Aug 2018 18:34:35 +0900 Subject: [PATCH 04/56] Create README.foot.md --- .autogen/README.foot.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .autogen/README.foot.md diff --git a/.autogen/README.foot.md b/.autogen/README.foot.md new file mode 100644 index 000000000..a02552d7b --- /dev/null +++ b/.autogen/README.foot.md @@ -0,0 +1,25 @@ +:four_leaf_clover: Copyright +---------------------------------------------------------------- +> Copyright (c) 2014-2018 syuilo + +Misskey is an open-source software licensed under the [GNU AGPLv3](LICENSE). + +[![][agpl-3.0-badge]][AGPL-3.0] + +[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 +[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-badge]: https://img.shields.io/david/syuilo/misskey.svg?style=flat-square + +[backer-url]: #backers +[backer-badge]: https://opencollective.com/misskey/backers/badge.svg +[backers-image]: https://opencollective.com/misskey/backers.svg +[sponsor-url]: #sponsors +[sponsor-badge]: https://opencollective.com/misskey/sponsors/badge.svg +[sponsors-image]: https://opencollective.com/misskey/sponsors.svg +[support-url]: https://opencollective.com/misskey#support + +[syuilo-link]: https://syuilo.com +[syuilo-icon]: https://avatars2.githubusercontent.com/u/4439005?v=3&s=70 From 2c8f962889f9231238dbdaa5990f00646e8060f3 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 17 Aug 2018 19:17:23 +0900 Subject: [PATCH 05/56] #2214 #2155 --- locales/ja.yml | 2 + .../app/common/views/components/signup.vue | 15 ++++- .../views/pages/admin/admin.dashboard.vue | 14 ++++- src/models/meta.ts | 1 + src/models/registration-tickets.ts | 12 ++++ src/server/api/endpoints/admin/invite.ts | 26 ++++++++ .../api/endpoints/admin/suspend-user.ts | 60 +++++++++---------- src/server/api/endpoints/meta.ts | 3 +- src/server/api/private/signup.ts | 24 ++++++++ 9 files changed, 124 insertions(+), 33 deletions(-) create mode 100644 src/models/registration-tickets.ts create mode 100644 src/server/api/endpoints/admin/invite.ts diff --git a/locales/ja.yml b/locales/ja.yml index 310a73a64..acc4efe89 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -317,6 +317,8 @@ common/views/components/signin.vue: login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。" common/views/components/signup.vue: + invitation-code: "招待コード" + invitation-info: "招待コードをお持ちでない方は、管理者までご連絡ください。" username: "ユーザー名" checking: "確認しています..." available: "利用できます" diff --git a/src/client/app/common/views/components/signup.vue b/src/client/app/common/views/components/signup.vue index 45a183e14..1d3370215 100644 --- a/src/client/app/common/views/components/signup.vue +++ b/src/client/app/common/views/components/signup.vue @@ -1,5 +1,10 @@ @@ -16,13 +20,21 @@ import Vue from "vue"; export default Vue.extend({ data() { return { - stats: null + stats: null, + inviteCode: null }; }, created() { (this as any).api('stats').then(stats => { this.stats = stats; }); + }, + methods: { + invite() { + (this as any).api('admin/invite').then(x => { + this.inviteCode = x.code; + }); + } } }); diff --git a/src/models/meta.ts b/src/models/meta.ts index 11b9b186c..aef0163df 100644 --- a/src/models/meta.ts +++ b/src/models/meta.ts @@ -11,4 +11,5 @@ export type IMeta = { usersCount: number; originalUsersCount: number; }; + disableRegistration: boolean; }; diff --git a/src/models/registration-tickets.ts b/src/models/registration-tickets.ts new file mode 100644 index 000000000..846acefed --- /dev/null +++ b/src/models/registration-tickets.ts @@ -0,0 +1,12 @@ +import * as mongo from 'mongodb'; +import db from '../db/mongodb'; + +const RegistrationTicket = db.get('registrationTickets'); +RegistrationTicket.createIndex('code', { unique: true }); +export default RegistrationTicket; + +export interface IRegistrationTicket { + _id: mongo.ObjectID; + createdAt: Date; + code: string; +} diff --git a/src/server/api/endpoints/admin/invite.ts b/src/server/api/endpoints/admin/invite.ts new file mode 100644 index 000000000..77608e715 --- /dev/null +++ b/src/server/api/endpoints/admin/invite.ts @@ -0,0 +1,26 @@ +import rndstr from 'rndstr'; +import RegistrationTicket from '../../../../models/registration-tickets'; + +export const meta = { + desc: { + ja: '招待コードを発行します。' + }, + + requireCredential: true, + requireAdmin: true, + + params: {} +}; + +export default (params: any) => new Promise(async (res, rej) => { + const code = rndstr({ length: 5, chars: '0-9' }); + + await RegistrationTicket.insert({ + createdAt: new Date(), + code: code + }); + + res({ + code: code + }); +}); diff --git a/src/server/api/endpoints/admin/suspend-user.ts b/src/server/api/endpoints/admin/suspend-user.ts index 8698120cd..9c32ba987 100644 --- a/src/server/api/endpoints/admin/suspend-user.ts +++ b/src/server/api/endpoints/admin/suspend-user.ts @@ -4,43 +4,43 @@ import getParams from '../../get-params'; import User from '../../../../models/user'; export const meta = { - desc: { - ja: '指定したユーザーを凍結します。', - en: 'Suspend a user.' - }, + desc: { + ja: '指定したユーザーを凍結します。', + en: 'Suspend a user.' + }, - requireCredential: true, - requireAdmin: true, + requireCredential: true, + requireAdmin: true, - params: { - userId: $.type(ID).note({ - desc: { - ja: '対象のユーザーID', - en: 'The user ID which you want to suspend' - } - }), - } + params: { + userId: $.type(ID).note({ + desc: { + ja: '対象のユーザーID', + en: 'The user ID which you want to suspend' + } + }), + } }; export default (params: any) => new Promise(async (res, rej) => { - const [ps, psErr] = getParams(meta, params); - if (psErr) return rej(psErr); + const [ps, psErr] = getParams(meta, params); + if (psErr) return rej(psErr); - const user = await User.findOne({ - _id: ps.userId - }); + const user = await User.findOne({ + _id: ps.userId + }); - if (user == null) { - return rej('user not found'); - } + if (user == null) { + return rej('user not found'); + } - await User.findOneAndUpdate({ - _id: user._id - }, { - $set: { - isSuspended: true - } - }); + await User.findOneAndUpdate({ + _id: user._id + }, { + $set: { + isSuspended: true + } + }); - res(); + res(); }); diff --git a/src/server/api/endpoints/meta.ts b/src/server/api/endpoints/meta.ts index c2d93997a..000a56024 100644 --- a/src/server/api/endpoints/meta.ts +++ b/src/server/api/endpoints/meta.ts @@ -28,6 +28,7 @@ export default () => new Promise(async (res, rej) => { model: os.cpus()[0].model, cores: os.cpus().length }, - broadcasts: meta.broadcasts + broadcasts: meta.broadcasts, + disableRegistration: meta.disableRegistration }); }); diff --git a/src/server/api/private/signup.ts b/src/server/api/private/signup.ts index 16ec33bcb..2bf56a979 100644 --- a/src/server/api/private/signup.ts +++ b/src/server/api/private/signup.ts @@ -6,6 +6,7 @@ import User, { IUser, validateUsername, validatePassword, pack } from '../../../ import generateUserToken from '../common/generate-native-user-token'; import config from '../../../config'; import Meta from '../../../models/meta'; +import RegistrationTicket from '../../../models/registration-tickets'; if (config.recaptcha) { recaptcha.init({ @@ -29,6 +30,29 @@ export default async (ctx: Koa.Context) => { const username = body['username']; const password = body['password']; + const invitationCode = body['invitationCode']; + + const meta = await Meta.findOne({}); + + if (meta.disableRegistration) { + if (invitationCode == null || typeof invitationCode != 'string') { + ctx.status = 400; + return; + } + + const ticket = await RegistrationTicket.findOne({ + code: invitationCode + }); + + if (ticket == null) { + ctx.status = 400; + return; + } + + RegistrationTicket.remove({ + _id: ticket._id + }); + } // Validate username if (!validateUsername(username)) { From 8d3f71d490dca290b19e2e35c44cb29280907b36 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 17 Aug 2018 19:35:05 +0900 Subject: [PATCH 06/56] Fix bug --- src/client/app/common/views/components/visibility-chooser.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/app/common/views/components/visibility-chooser.vue b/src/client/app/common/views/components/visibility-chooser.vue index 8be3ddb8f..4691604e5 100644 --- a/src/client/app/common/views/components/visibility-chooser.vue +++ b/src/client/app/common/views/components/visibility-chooser.vue @@ -44,12 +44,12 @@ import Vue from 'vue'; import * as anime from 'animejs'; export default Vue.extend({ + props: ['source', 'compact'], data() { return { - v: this.$store.state.device.visibility + v: this.$store.state.device.visibility || 'public' } }, - props: ['source', 'compact'], mounted() { this.$nextTick(() => { const popover = this.$refs.popover as any; From 35a1fa5bf0c7d97ff87623cf7e9d07fe6c5b92fc Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 17 Aug 2018 19:37:06 +0900 Subject: [PATCH 07/56] 6.3.0 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 3d8df6aae..1a13e07ed 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "misskey", "author": "syuilo ", - "version": "6.2.0", - "clientVersion": "1.0.8417", + "version": "6.3.0", + "clientVersion": "1.0.8483", "codename": "nighthike", "main": "./built/index.js", "private": true, From fbf43c1450ecdf851e0549045854afda694ea85e Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 17 Aug 2018 19:38:39 +0900 Subject: [PATCH 08/56] Fix bug --- src/client/app/dev/views/new-app.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/app/dev/views/new-app.vue b/src/client/app/dev/views/new-app.vue index bf19e6da5..87b35db25 100644 --- a/src/client/app/dev/views/new-app.vue +++ b/src/client/app/dev/views/new-app.vue @@ -95,7 +95,7 @@ export default Vue.extend({ callbackUrl: this.cb, permission: this.permission }).then(() => { - location.href = '/apps'; + location.href = '/dev/apps'; }).catch(() => { alert('アプリの作成に失敗しました。再度お試しください。'); }); From ad0d06c0d890e7daf9e5bc294cb873924b53b0c5 Mon Sep 17 00:00:00 2001 From: Aya Morisawa Date: Fri, 17 Aug 2018 21:29:06 +0900 Subject: [PATCH 09/56] #332 --- locales/ja.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/locales/ja.yml b/locales/ja.yml index acc4efe89..13ccce048 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -914,6 +914,7 @@ desktop/views/pages/admin/admin.dashboard.vue: original-users: "このインスタンスのユーザー" all-notes: "全てのノート" original-notes: "このインスタンスのノート" + invite: "招待" desktop/views/pages/admin/admin.suspend-user.vue: suspend-user: "ユーザーの凍結" From 9f4c6a3aef13016fbd8f8f91ba4562c1c35e14aa Mon Sep 17 00:00:00 2001 From: Aya Morisawa Date: Fri, 17 Aug 2018 21:40:08 +0900 Subject: [PATCH 10/56] Resolve #2271 --- locales/ja.yml | 5 ++ .../views/pages/admin/admin.verify-user.vue | 51 +++++++++++++++++++ .../app/desktop/views/pages/admin/admin.vue | 5 +- src/server/api/endpoints/admin/verify-user.ts | 46 +++++++++++++++++ 4 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 src/client/app/desktop/views/pages/admin/admin.verify-user.vue create mode 100644 src/server/api/endpoints/admin/verify-user.ts diff --git a/locales/ja.yml b/locales/ja.yml index 13ccce048..37d6ab5c4 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -926,6 +926,11 @@ desktop/views/pages/admin/admin.unsuspend-user.vue: unsuspend: "凍結の解除" unsuspended: "凍結を解除しました" +desktop/views/pages/admin/admin.verify-user.vue: + verify-user: "ユーザーの公式アカウント設定" + verify: "公式アカウントにする" + verified: "公式アカウントにしました" + desktop/views/pages/deck/deck.tl-column.vue: is-media-only: "メディア投稿のみ" is-media-view: "メディアビュー" diff --git a/src/client/app/desktop/views/pages/admin/admin.verify-user.vue b/src/client/app/desktop/views/pages/admin/admin.verify-user.vue new file mode 100644 index 000000000..c9a81fae9 --- /dev/null +++ b/src/client/app/desktop/views/pages/admin/admin.verify-user.vue @@ -0,0 +1,51 @@ + + + + + diff --git a/src/client/app/desktop/views/pages/admin/admin.vue b/src/client/app/desktop/views/pages/admin/admin.vue index b581bea46..29b6093c9 100644 --- a/src/client/app/desktop/views/pages/admin/admin.vue +++ b/src/client/app/desktop/views/pages/admin/admin.vue @@ -15,6 +15,7 @@
+
@@ -27,12 +28,14 @@ import Vue from "vue"; import XDashboard from "./admin.dashboard.vue"; import XSuspendUser from "./admin.suspend-user.vue"; import XUnsuspendUser from "./admin.unsuspend-user.vue"; +import XVerifyUser from "./admin.verify-user.vue"; export default Vue.extend({ components: { XDashboard, XSuspendUser, - XUnsuspendUser + XUnsuspendUser, + XVerifyUser }, data() { return { diff --git a/src/server/api/endpoints/admin/verify-user.ts b/src/server/api/endpoints/admin/verify-user.ts new file mode 100644 index 000000000..5b826eb1c --- /dev/null +++ b/src/server/api/endpoints/admin/verify-user.ts @@ -0,0 +1,46 @@ +import $ from 'cafy'; +import ID from '../../../../misc/cafy-id'; +import getParams from '../../get-params'; +import User from '../../../../models/user'; + +export const meta = { + desc: { + ja: '指定したユーザーを公式アカウントにします。', + en: 'Mark a user as verified.' + }, + + requireCredential: true, + requireAdmin: true, + + params: { + userId: $.type(ID).note({ + desc: { + ja: '対象のユーザーID', + en: 'The user ID which you want to verify' + } + }), + } +}; + +export default (params: any) => new Promise(async (res, rej) => { + const [ps, psErr] = getParams(meta, params); + if (psErr) return rej(psErr); + + const user = await User.findOne({ + _id: ps.userId + }); + + if (user == null) { + return rej('user not found'); + } + + await User.findOneAndUpdate({ + _id: user._id + }, { + $set: { + isVerified: true + } + }); + + res(); +}); From 0dd6494ab9bdd3b922df5b62233c457b15458128 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Fri, 17 Aug 2018 11:49:41 +0000 Subject: [PATCH 11/56] fix(package): update url-loader to version 1.1.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1a13e07ed..a378f0856 100644 --- a/package.json +++ b/package.json @@ -201,7 +201,7 @@ "typescript": "2.9.2", "typescript-eslint-parser": "18.0.0", "uglify-es": "3.3.9", - "url-loader": "1.1.0", + "url-loader": "1.1.1", "uuid": "3.3.2", "v-animate-css": "0.0.2", "vue": "2.5.17", From d058eff59aa0128a056225d14daf2877c4c8add8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Fri, 17 Aug 2018 22:36:38 +0900 Subject: [PATCH 12/56] Update and rename README.head.md to README.md --- .autogen/{README.head.md => README.md} | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) rename .autogen/{README.head.md => README.md} (60%) diff --git a/.autogen/README.head.md b/.autogen/README.md similarity index 60% rename from .autogen/README.head.md rename to .autogen/README.md index 39390dd90..3a8b0d473 100644 --- a/.autogen/README.head.md +++ b/.autogen/README.md @@ -43,3 +43,30 @@ If you want to... :heart: Backers & Sponsors ---------------------------------------------------------------- + + +:four_leaf_clover: Copyright +---------------------------------------------------------------- +> Copyright (c) 2014-2018 syuilo + +Misskey is an open-source software licensed under the [GNU AGPLv3](LICENSE). + +[![][agpl-3.0-badge]][AGPL-3.0] + +[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 +[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-badge]: https://img.shields.io/david/syuilo/misskey.svg?style=flat-square + +[backer-url]: #backers +[backer-badge]: https://opencollective.com/misskey/backers/badge.svg +[backers-image]: https://opencollective.com/misskey/backers.svg +[sponsor-url]: #sponsors +[sponsor-badge]: https://opencollective.com/misskey/sponsors/badge.svg +[sponsors-image]: https://opencollective.com/misskey/sponsors.svg +[support-url]: https://opencollective.com/misskey#support + +[syuilo-link]: https://syuilo.com +[syuilo-icon]: https://avatars2.githubusercontent.com/u/4439005?v=3&s=70 From 6781b68d3320f978437429a7c2beb16366c48898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Fri, 17 Aug 2018 22:37:11 +0900 Subject: [PATCH 13/56] Delete README.foot.md --- .autogen/README.foot.md | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 .autogen/README.foot.md diff --git a/.autogen/README.foot.md b/.autogen/README.foot.md deleted file mode 100644 index a02552d7b..000000000 --- a/.autogen/README.foot.md +++ /dev/null @@ -1,25 +0,0 @@ -:four_leaf_clover: Copyright ----------------------------------------------------------------- -> Copyright (c) 2014-2018 syuilo - -Misskey is an open-source software licensed under the [GNU AGPLv3](LICENSE). - -[![][agpl-3.0-badge]][AGPL-3.0] - -[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 -[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-badge]: https://img.shields.io/david/syuilo/misskey.svg?style=flat-square - -[backer-url]: #backers -[backer-badge]: https://opencollective.com/misskey/backers/badge.svg -[backers-image]: https://opencollective.com/misskey/backers.svg -[sponsor-url]: #sponsors -[sponsor-badge]: https://opencollective.com/misskey/sponsors/badge.svg -[sponsors-image]: https://opencollective.com/misskey/sponsors.svg -[support-url]: https://opencollective.com/misskey#support - -[syuilo-link]: https://syuilo.com -[syuilo-icon]: https://avatars2.githubusercontent.com/u/4439005?v=3&s=70 From 71657ddb98b3cbdc0774a35984a02ed989df194c Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 17 Aug 2018 23:06:58 +0900 Subject: [PATCH 14/56] :art: --- src/client/app/desktop/views/pages/admin/admin.vue | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/client/app/desktop/views/pages/admin/admin.vue b/src/client/app/desktop/views/pages/admin/admin.vue index 29b6093c9..2a524bb26 100644 --- a/src/client/app/desktop/views/pages/admin/admin.vue +++ b/src/client/app/desktop/views/pages/admin/admin.vue @@ -93,6 +93,14 @@ export default Vue.extend({ width 100% padding 16px 32px + > div + > div + margin-bottom 16px + padding 32px + max-width 800px + background #fff + box-shadow 0 2px 8px rgba(#000, 0.1) + header margin 10px 0 From 9ca9757418b8efc314c63a38d6a43f95ee7164dd Mon Sep 17 00:00:00 2001 From: Aya Morisawa Date: Fri, 17 Aug 2018 23:18:14 +0900 Subject: [PATCH 15/56] :v::sunny::umbrella::cloud::snowflake::v: --- .autogen/README.md | 5 +---- README.md | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.autogen/README.md b/.autogen/README.md index 3a8b0d473..4eea50655 100644 --- a/.autogen/README.md +++ b/.autogen/README.md @@ -7,10 +7,7 @@ [![][dependencies-badge]][dependencies-link] [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) [![Greenkeeper badge](https://badges.greenkeeper.io/syuilo/misskey.svg)](https://greenkeeper.io/) -**Microblogging. Redefined.** - -**[Misskey](https://misskey.xyz)** is a completely open source, -ultimately sophisticated professional microblogging software. +[Misskey](https://misskey.xyz) is an **advanced**, **redefined**, and ultimately **sophisticated** microblogging platform. Become a Patron! diff --git a/README.md b/README.md index a52ead65a..759d7b0a2 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,7 @@ **Microblogging. Redefined.** -**[Misskey](https://misskey.xyz)** is a completely open source, -ultimately sophisticated professional microblogging software. +[Misskey](https://misskey.xyz) is an **advanced**, **redefined**, and ultimately **sophisticated** microblogging platform. Become a Patron! From 9f8d21b2bc0d3816fc82fb24e41580ae86cf31ac Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 18 Aug 2018 03:36:13 +0900 Subject: [PATCH 16/56] Fix #2298 --- src/server/api/private/signup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/api/private/signup.ts b/src/server/api/private/signup.ts index 2bf56a979..79e5e6ec4 100644 --- a/src/server/api/private/signup.ts +++ b/src/server/api/private/signup.ts @@ -34,7 +34,7 @@ export default async (ctx: Koa.Context) => { const meta = await Meta.findOne({}); - if (meta.disableRegistration) { + if (meta && meta.disableRegistration) { if (invitationCode == null || typeof invitationCode != 'string') { ctx.status = 400; return; From ae9c13df66a137634f9dfeaa5d58bda4f62dbf49 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 18 Aug 2018 03:37:10 +0900 Subject: [PATCH 17/56] 6.3.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a378f0856..31e056661 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "misskey", "author": "syuilo ", - "version": "6.3.0", + "version": "6.3.1", "clientVersion": "1.0.8483", "codename": "nighthike", "main": "./built/index.js", From 98f25c915991b296e2fb5a9773b004d53b0ab22b Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 18 Aug 2018 03:37:56 +0900 Subject: [PATCH 18/56] 6.3.2 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 31e056661..2876f8031 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "misskey", "author": "syuilo ", - "version": "6.3.1", - "clientVersion": "1.0.8483", + "version": "6.3.2", + "clientVersion": "1.0.8498", "codename": "nighthike", "main": "./built/index.js", "private": true, From bc34ac82cf4effe2baba8471315ea4a78dae416a Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 18 Aug 2018 03:52:24 +0900 Subject: [PATCH 19/56] Show some charts in control panel --- .../views/pages/admin/admin.dashboard.vue | 39 ++++--- .../pages/admin/admin.notes-chart.chart.vue | 81 +++++++++++++ .../views/pages/admin/admin.notes-chart.vue | 33 ++++++ .../views/pages/admin/admin.suspend-user.vue | 12 -- .../pages/admin/admin.users-chart.chart.vue | 53 +++++++++ .../views/pages/admin/admin.users-chart.vue | 33 ++++++ .../app/desktop/views/pages/admin/admin.vue | 24 ++-- src/server/api/endpoints/aggregation/notes.ts | 110 ++++++++++++++++++ src/server/api/endpoints/aggregation/posts.ts | 84 ------------- src/server/api/endpoints/aggregation/users.ts | 95 ++++++++++----- 10 files changed, 413 insertions(+), 151 deletions(-) create mode 100644 src/client/app/desktop/views/pages/admin/admin.notes-chart.chart.vue create mode 100644 src/client/app/desktop/views/pages/admin/admin.notes-chart.vue create mode 100644 src/client/app/desktop/views/pages/admin/admin.users-chart.chart.vue create mode 100644 src/client/app/desktop/views/pages/admin/admin.users-chart.vue create mode 100644 src/server/api/endpoints/aggregation/notes.ts delete mode 100644 src/server/api/endpoints/aggregation/posts.ts diff --git a/src/client/app/desktop/views/pages/admin/admin.dashboard.vue b/src/client/app/desktop/views/pages/admin/admin.dashboard.vue index d0f11e73b..182d97460 100644 --- a/src/client/app/desktop/views/pages/admin/admin.dashboard.vue +++ b/src/client/app/desktop/views/pages/admin/admin.dashboard.vue @@ -1,11 +1,11 @@ @@ -20,15 +20,10 @@ export default Vue.extend({ components: { XChart }, - data() { - return { - data: null - }; - }, - created() { - (this as any).api('aggregation/notes').then(res => { - this.data = res; - }); + props: { + chart: { + required: true + } } }); diff --git a/src/client/app/desktop/views/pages/admin/admin.users-chart.chart.vue b/src/client/app/desktop/views/pages/admin/admin.users-chart.chart.vue index 10eab8527..c2ab4a78e 100644 --- a/src/client/app/desktop/views/pages/admin/admin.users-chart.chart.vue +++ b/src/client/app/desktop/views/pages/admin/admin.users-chart.chart.vue @@ -13,7 +13,7 @@ import Vue from 'vue'; export default Vue.extend({ props: { - data: { + chart: { required: true }, type: { @@ -23,21 +23,19 @@ export default Vue.extend({ }, data() { return { - chart: this.data, viewBoxX: 365, viewBoxY: 70, points: null }; }, created() { - this.chart.forEach(d => { - d.count = this.type == 'local' ? d.local : d.remote; - }); - - const peak = Math.max.apply(null, this.chart.map(d => d.count)); + const peak = Math.max.apply(null, this.chart.map(d => this.type == 'local' ? d.users.local.diff : d.users.remote.diff)); if (peak != 0) { - const data = this.chart.slice().reverse(); + const data = this.chart.slice().reverse().map(x => ({ + count: this.type == 'local' ? x.users.local.diff : x.users.remote.diff + })); + this.points = data.map((d, i) => `${i},${(1 - (d.count / peak)) * this.viewBoxY}`).join(' '); } } diff --git a/src/client/app/desktop/views/pages/admin/admin.users-chart.vue b/src/client/app/desktop/views/pages/admin/admin.users-chart.vue index bbd342e51..e62001270 100644 --- a/src/client/app/desktop/views/pages/admin/admin.users-chart.vue +++ b/src/client/app/desktop/views/pages/admin/admin.users-chart.vue @@ -3,11 +3,11 @@
%i18n:@title%
%i18n:@local%
- +
%i18n:@remote%
- +
@@ -20,15 +20,10 @@ export default Vue.extend({ components: { XChart }, - data() { - return { - data: null - }; - }, - created() { - (this as any).api('aggregation/users').then(res => { - this.data = res; - }); + props: { + chart: { + required: true + } } }); diff --git a/src/client/app/desktop/views/pages/admin/admin.vue b/src/client/app/desktop/views/pages/admin/admin.vue index 7c1dace78..add95a1a0 100644 --- a/src/client/app/desktop/views/pages/admin/admin.vue +++ b/src/client/app/desktop/views/pages/admin/admin.vue @@ -11,8 +11,8 @@
- - + +
@@ -48,9 +48,15 @@ export default Vue.extend({ }, data() { return { - page: 'dashboard' + page: 'dashboard', + chart: null }; }, + created() { + (this as any).api('admin/chart').then(chart => { + this.chart = chart; + }); + }, methods: { nav(page: string) { this.page = page; diff --git a/src/client/app/stats/style.styl b/src/client/app/stats/style.styl deleted file mode 100644 index 5ae230ea5..000000000 --- a/src/client/app/stats/style.styl +++ /dev/null @@ -1,10 +0,0 @@ -@import "../app" -@import "../reset" - -html - color #456267 - background #fff - -body - margin 0 - padding 0 diff --git a/src/client/app/stats/tags/index.tag b/src/client/app/stats/tags/index.tag deleted file mode 100644 index f8944c083..000000000 --- a/src/client/app/stats/tags/index.tag +++ /dev/null @@ -1,209 +0,0 @@ - -

MisskeyStatistics

-
- - -
- - - -
- - -

%i18n:stats.notes-count% { stats.notesCount }

- - - -
- - -

%i18n:stats.users-count% { stats.usersCount }

- - - -
- - - - Black ... Total
Blue ... Notes
Red ... Replies
Green ... Renotes
- - - - -
- - -
- - - - - - - - - diff --git a/src/client/app/stats/tags/index.ts b/src/client/app/stats/tags/index.ts deleted file mode 100644 index f41151949..000000000 --- a/src/client/app/stats/tags/index.ts +++ /dev/null @@ -1 +0,0 @@ -require('./index.tag'); diff --git a/src/client/app/status/style.styl b/src/client/app/status/style.styl deleted file mode 100644 index 5ae230ea5..000000000 --- a/src/client/app/status/style.styl +++ /dev/null @@ -1,10 +0,0 @@ -@import "../app" -@import "../reset" - -html - color #456267 - background #fff - -body - margin 0 - padding 0 diff --git a/src/client/app/status/tags/index.tag b/src/client/app/status/tags/index.tag deleted file mode 100644 index 899467097..000000000 --- a/src/client/app/status/tags/index.tag +++ /dev/null @@ -1,201 +0,0 @@ - -

MisskeyStatus

-

%fa:info-circle%%i18n:status.all-systems-maybe-operational%

-
- - -
- - - -
- - -

CPU { percentage }%

- - - -
- - -

MEM { percentage }%

- - - -
- - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/client/app/status/tags/index.ts b/src/client/app/status/tags/index.ts deleted file mode 100644 index f41151949..000000000 --- a/src/client/app/status/tags/index.ts +++ /dev/null @@ -1 +0,0 @@ -require('./index.tag'); diff --git a/src/models/chart.ts b/src/models/stats.ts similarity index 94% rename from src/models/chart.ts rename to src/models/stats.ts index a2154be4f..7bff475c6 100644 --- a/src/models/chart.ts +++ b/src/models/stats.ts @@ -1,11 +1,11 @@ import * as mongo from 'mongodb'; import db from '../db/mongodb'; -const Chart = db.get('chart'); -Chart.createIndex('date', { unique: true }); -export default Chart; +const Stats = db.get('stats'); +Stats.createIndex({ date: -1 }, { unique: true }); +export default Stats; -export interface IChart { +export interface IStats { _id: mongo.ObjectID; date: Date; diff --git a/src/server/api/endpoints/admin/chart.ts b/src/server/api/endpoints/admin/chart.ts new file mode 100644 index 000000000..4ad29a701 --- /dev/null +++ b/src/server/api/endpoints/admin/chart.ts @@ -0,0 +1,97 @@ +import Stats, { IStats } from '../../../../models/stats'; + +type Omit = Pick>; + +export const meta = { + requireCredential: true, + requireAdmin: true +}; + +export default (params: any) => new Promise(async (res, rej) => { + const now = new Date(); + const y = now.getFullYear(); + const m = now.getMonth(); + const d = now.getDate(); + + const stats = await Stats.find({ + date: { + $gt: new Date(y - 1, m, d) + } + }, { + sort: { + date: -1 + }, + fields: { + _id: 0 + } + }); + + const chart: Array> = []; + + for (let i = 364; i >= 0; i--) { + const day = new Date(y, m, d - i); + + const stat = stats.find(s => s.date.getTime() == day.getTime()); + + if (stat) { + chart.push(stat); + } else { // 隙間埋め + const mostRecent = stats.find(s => s.date.getTime() < day.getTime()); + if (mostRecent) { + chart.push(Object.assign({}, mostRecent, { + date: day + })); + } else { + chart.push({ + date: day, + users: { + local: { + total: 0, + diff: 0 + }, + remote: { + total: 0, + diff: 0 + } + }, + notes: { + local: { + total: 0, + diff: 0, + diffs: { + normal: 0, + reply: 0, + renote: 0 + } + }, + remote: { + total: 0, + diff: 0, + diffs: { + normal: 0, + reply: 0, + renote: 0 + } + } + }, + drive: { + local: { + totalCount: 0, + totalSize: 0, + diffCount: 0, + diffSize: 0 + }, + remote: { + totalCount: 0, + totalSize: 0, + diffCount: 0, + diffSize: 0 + } + } + }); + } + } + } + + res(chart); +}); diff --git a/src/server/api/endpoints/aggregation/notes.ts b/src/server/api/endpoints/aggregation/notes.ts deleted file mode 100644 index 77ed07ef4..000000000 --- a/src/server/api/endpoints/aggregation/notes.ts +++ /dev/null @@ -1,116 +0,0 @@ -import Note from '../../../../models/note'; - -export const meta = { - requireCredential: true, - requireAdmin: true -}; - -/** - * Aggregate notes - */ -export default (params: any) => new Promise(async (res, rej) => { - const query = [{ - $match: { - createdAt: { - $gt: new Date(new Date().setFullYear(new Date().getFullYear() - 1)) - } - } - }, { - $project: { - renoteId: '$renoteId', - replyId: '$replyId', - user: '$_user', - createdAt: { $add: ['$createdAt', 9 * 60 * 60 * 1000] } // Convert into JST - } - }, { - $project: { - date: { - year: { $year: '$createdAt' }, - month: { $month: '$createdAt' }, - day: { $dayOfMonth: '$createdAt' } - }, - type: { - $cond: { - if: { $ne: ['$renoteId', null] }, - then: 'renote', - else: { - $cond: { - if: { $ne: ['$replyId', null] }, - then: 'reply', - else: 'note' - } - } - } - }, - origin: { - $cond: { - if: { $eq: ['$user.host', null] }, - then: 'local', - else: 'remote' - } - } - } - }, { - $group: { - _id: { - date: '$date', - type: '$type', - origin: '$origin' - }, - count: { $sum: 1 } - } - }, { - $group: { - _id: '$_id.date', - data: { - $addToSet: { - type: '$_id.type', - origin: '$_id.origin', - count: '$count' - } - } - } - }] as any; - - const datas = await Note.aggregate(query); - - datas.forEach((data: any) => { - data.date = data._id; - delete data._id; - - data.localNotes = (data.data.filter((x: any) => x.type == 'note' && x.origin == 'local')[0] || { count: 0 }).count; - data.localRenotes = (data.data.filter((x: any) => x.type == 'renote' && x.origin == 'local')[0] || { count: 0 }).count; - data.localReplies = (data.data.filter((x: any) => x.type == 'reply' && x.origin == 'local')[0] || { count: 0 }).count; - data.remoteNotes = (data.data.filter((x: any) => x.type == 'note' && x.origin == 'remote')[0] || { count: 0 }).count; - data.remoteRenotes = (data.data.filter((x: any) => x.type == 'renote' && x.origin == 'remote')[0] || { count: 0 }).count; - data.remoteReplies = (data.data.filter((x: any) => x.type == 'reply' && x.origin == 'remote')[0] || { count: 0 }).count; - - delete data.data; - }); - - const graph = []; - - for (let i = 0; i < 365; i++) { - const day = new Date(new Date().setDate(new Date().getDate() - i)); - - const data = datas.filter((d: any) => - d.date.year == day.getFullYear() && d.date.month == day.getMonth() + 1 && d.date.day == day.getDate() - )[0]; - - if (data) { - graph.push(data); - } else { - graph.push({ - date: { year: day.getFullYear(), month: day.getMonth() + 1, day: day.getDate() }, - localNotes: 0, - localRenotes: 0, - localReplies: 0, - remoteNotes: 0, - remoteRenotes: 0, - remoteReplies: 0 - }); - } - } - - res(graph); -}); diff --git a/src/server/api/endpoints/aggregation/users.ts b/src/server/api/endpoints/aggregation/users.ts deleted file mode 100644 index d01648423..000000000 --- a/src/server/api/endpoints/aggregation/users.ts +++ /dev/null @@ -1,92 +0,0 @@ -import User from '../../../../models/user'; - -export const meta = { - requireCredential: true, - requireAdmin: true -}; - -/** - * Aggregate users - */ -export default (params: any) => new Promise(async (res, rej) => { - const query = [{ - $match: { - createdAt: { - $gt: new Date(new Date().setFullYear(new Date().getFullYear() - 1)) - } - } - }, { - $project: { - host: '$host', - createdAt: { $add: ['$createdAt', 9 * 60 * 60 * 1000] } // Convert into JST - } - }, { - $project: { - date: { - year: { $year: '$createdAt' }, - month: { $month: '$createdAt' }, - day: { $dayOfMonth: '$createdAt' } - }, - origin: { - $cond: { - if: { $eq: ['$host', null] }, - then: 'local', - else: 'remote' - } - } - } - }, { - $group: { - _id: { - date: '$date', - origin: '$origin' - }, - count: { $sum: 1 } - } - }, { - $group: { - _id: '$_id.date', - data: { - $addToSet: { - type: '$_id.type', - origin: '$_id.origin', - count: '$count' - } - } - } - }] as any; - - const datas = await User.aggregate(query); - - datas.forEach((data: any) => { - data.date = data._id; - delete data._id; - - data.local = (data.data.filter((x: any) => x.origin == 'local')[0] || { count: 0 }).count; - data.remote = (data.data.filter((x: any) => x.origin == 'remote')[0] || { count: 0 }).count; - - delete data.data; - }); - - const graph = []; - - for (let i = 0; i < 365; i++) { - const day = new Date(new Date().setDate(new Date().getDate() - i)); - - const data = datas.filter((d: any) => - d.date.year == day.getFullYear() && d.date.month == day.getMonth() + 1 && d.date.day == day.getDate() - )[0]; - - if (data) { - graph.push(data); - } else { - graph.push({ - date: { year: day.getFullYear(), month: day.getMonth() + 1, day: day.getDate() }, - local: 0, - remote: 0 - }); - } - } - - res(graph); -}); diff --git a/src/services/update-chart.ts b/src/services/update-chart.ts index 9175d61f7..7998baca9 100644 --- a/src/services/update-chart.ts +++ b/src/services/update-chart.ts @@ -1,11 +1,11 @@ import { INote } from '../models/note'; -import Chart, { IChart } from '../models/chart'; +import Stats, { IStats } from '../models/stats'; import { isLocalUser, IUser } from '../models/user'; import { IDriveFile } from '../models/drive-file'; type Omit = Pick>; -async function getTodayStats(): Promise { +async function getTodayStats(): Promise { const now = new Date(); const y = now.getFullYear(); const m = now.getMonth(); @@ -13,7 +13,7 @@ async function getTodayStats(): Promise { const today = new Date(y, m, d); // 今日の統計 - const todayStats = await Chart.findOne({ + const todayStats = await Stats.findOne({ date: today }); @@ -23,7 +23,7 @@ async function getTodayStats(): Promise { // * 昨日何もチャートを更新するような出来事がなかった場合は、 // 統計がそもそも作られずドキュメントが存在しないということがあり得るため、 // 「昨日の」と決め打ちせずに「もっとも最近の」とします - const mostRecentStats = await Chart.findOne({}, { + const mostRecentStats = await Stats.findOne({}, { sort: { date: -1 } @@ -33,7 +33,7 @@ async function getTodayStats(): Promise { // * Misskeyインスタンスを建てて初めてのチャート更新時など if (mostRecentStats == null) { // 空の統計を作成 - const chart: Omit = { + const chart: Omit = { date: today, users: { local: { @@ -81,12 +81,12 @@ async function getTodayStats(): Promise { } }; - const stats = await Chart.insert(chart); + const stats = await Stats.insert(chart); return stats; } else { // 今日の統計を初期挿入 - const chart: Omit = { + const chart: Omit = { date: today, users: { local: { @@ -134,7 +134,7 @@ async function getTodayStats(): Promise { } }; - const stats = await Chart.insert(chart); + const stats = await Stats.insert(chart); return stats; } @@ -146,7 +146,7 @@ async function getTodayStats(): Promise { async function update(inc: any) { const stats = await getTodayStats(); - await Chart.findOneAndUpdate({ + await Stats.findOneAndUpdate({ _id: stats._id }, { $inc: inc From 7aac2c4e297593b2a89a2fdc3a25f8a20267b9c3 Mon Sep 17 00:00:00 2001 From: Aya Morisawa Date: Sun, 19 Aug 2018 00:31:25 +0900 Subject: [PATCH 54/56] Clean up --- src/mfm/html.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/mfm/html.ts b/src/mfm/html.ts index 1544ac34f..c798ee410 100644 --- a/src/mfm/html.ts +++ b/src/mfm/html.ts @@ -5,6 +5,10 @@ import config from '../config'; import { INote } from '../models/note'; import { TextElement } from './parse'; +function intersperse(sep: T, xs: T[]): T[] { + return [].concat(...xs.map(x => [sep, x])).slice(1); +} + const handlers: { [key: string]: (window: any, token: any, mentionedRemoteUsers: INote['mentionedRemoteUsers']) => void } = { bold({ document }, { bold }) { const b = document.createElement('b'); @@ -80,12 +84,9 @@ const handlers: { [key: string]: (window: any, token: any, mentionedRemoteUsers: }, text({ document }, { content }) { - const t = content.split('\n'); - for (let i = 0; i < t.length; i++) { - document.body.appendChild(document.createTextNode(t[i])); - if (i != t.length - 1) { - document.body.appendChild(document.createElement('br')); - } + const nodes = (content as string).split('\n').map(x => document.createTextNode(x)); + for (const x of intersperse(document.createElement('br'), nodes)) { + document.body.appendChild(x); } }, From f59c68022ff75f2e77dd804b21f57748fcf4fdce Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 19 Aug 2018 00:42:09 +0900 Subject: [PATCH 55/56] Fix bug --- .../views/pages/admin/admin.notes-chart.chart.vue | 8 ++++---- src/server/api/endpoints/admin/chart.ts | 10 +++++++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/client/app/desktop/views/pages/admin/admin.notes-chart.chart.vue b/src/client/app/desktop/views/pages/admin/admin.notes-chart.chart.vue index 3e9462f03..83c61c131 100644 --- a/src/client/app/desktop/views/pages/admin/admin.notes-chart.chart.vue +++ b/src/client/app/desktop/views/pages/admin/admin.notes-chart.chart.vue @@ -53,14 +53,14 @@ export default Vue.extend({ if (peak != 0) { const data = this.chart.slice().reverse().map(x => ({ normal: this.type == 'local' ? x.notes.local.diffs.normal : x.notes.remote.diffs.normal, - replies: this.type == 'local' ? x.notes.local.diffs.replies : x.notes.remote.diffs.replies, - renotes: this.type == 'local' ? x.notes.local.diffs.renotes : x.notes.remote.diffs.renotes, + reply: this.type == 'local' ? x.notes.local.diffs.reply : x.notes.remote.diffs.reply, + renote: this.type == 'local' ? x.notes.local.diffs.renote : x.notes.remote.diffs.renote, total: this.type == 'local' ? x.notes.local.diff : x.notes.remote.diff })); this.pointsNote = data.map((d, i) => `${i},${(1 - (d.normal / peak)) * this.viewBoxY}`).join(' '); - this.pointsReply = data.map((d, i) => `${i},${(1 - (d.replies / peak)) * this.viewBoxY}`).join(' '); - this.pointsRenote = data.map((d, i) => `${i},${(1 - (d.renotes / peak)) * this.viewBoxY}`).join(' '); + this.pointsReply = data.map((d, i) => `${i},${(1 - (d.reply / peak)) * this.viewBoxY}`).join(' '); + this.pointsRenote = data.map((d, i) => `${i},${(1 - (d.renote / peak)) * this.viewBoxY}`).join(' '); this.pointsTotal = data.map((d, i) => `${i},${(1 - (d.total / peak)) * this.viewBoxY}`).join(' '); } } diff --git a/src/server/api/endpoints/admin/chart.ts b/src/server/api/endpoints/admin/chart.ts index 4ad29a701..a0566b11f 100644 --- a/src/server/api/endpoints/admin/chart.ts +++ b/src/server/api/endpoints/admin/chart.ts @@ -34,15 +34,15 @@ export default (params: any) => new Promise(async (res, rej) => { const stat = stats.find(s => s.date.getTime() == day.getTime()); if (stat) { - chart.push(stat); + chart.unshift(stat); } else { // 隙間埋め const mostRecent = stats.find(s => s.date.getTime() < day.getTime()); if (mostRecent) { - chart.push(Object.assign({}, mostRecent, { + chart.unshift(Object.assign({}, mostRecent, { date: day })); } else { - chart.push({ + chart.unshift({ date: day, users: { local: { @@ -93,5 +93,9 @@ export default (params: any) => new Promise(async (res, rej) => { } } + chart.forEach(x => { + delete x.date; + }); + res(chart); }); From 8ecf3db608bf488c13695b62f691e4c269f46361 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 19 Aug 2018 00:45:54 +0900 Subject: [PATCH 56/56] Add drive chart --- locales/ja.yml | 5 ++ .../pages/admin/admin.drive-chart.chart.vue | 51 +++++++++++++++++++ .../views/pages/admin/admin.drive-chart.vue | 34 +++++++++++++ .../app/desktop/views/pages/admin/admin.vue | 5 +- 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 src/client/app/desktop/views/pages/admin/admin.drive-chart.chart.vue create mode 100644 src/client/app/desktop/views/pages/admin/admin.drive-chart.vue diff --git a/locales/ja.yml b/locales/ja.yml index 55c37fab6..5d5ef76ea 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -946,6 +946,11 @@ desktop/views/pages/admin/admin.users-chart.vue: local: "ローカル" remote: "リモート" +desktop/views/pages/admin/admin.drive-chart.vue: + title: "ドライブ" + local: "ローカル" + remote: "リモート" + desktop/views/pages/deck/deck.tl-column.vue: is-media-only: "メディア投稿のみ" is-media-view: "メディアビュー" diff --git a/src/client/app/desktop/views/pages/admin/admin.drive-chart.chart.vue b/src/client/app/desktop/views/pages/admin/admin.drive-chart.chart.vue new file mode 100644 index 000000000..3c537d8d6 --- /dev/null +++ b/src/client/app/desktop/views/pages/admin/admin.drive-chart.chart.vue @@ -0,0 +1,51 @@ + + + + + diff --git a/src/client/app/desktop/views/pages/admin/admin.drive-chart.vue b/src/client/app/desktop/views/pages/admin/admin.drive-chart.vue new file mode 100644 index 000000000..4f94fd237 --- /dev/null +++ b/src/client/app/desktop/views/pages/admin/admin.drive-chart.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/src/client/app/desktop/views/pages/admin/admin.vue b/src/client/app/desktop/views/pages/admin/admin.vue index add95a1a0..cbb1890cc 100644 --- a/src/client/app/desktop/views/pages/admin/admin.vue +++ b/src/client/app/desktop/views/pages/admin/admin.vue @@ -13,6 +13,7 @@ +
@@ -35,6 +36,7 @@ import XVerifyUser from "./admin.verify-user.vue"; import XUnverifyUser from "./admin.unverify-user.vue"; import XUsersChart from "./admin.users-chart.vue"; import XNotesChart from "./admin.notes-chart.vue"; +import XDriveChart from "./admin.drive-chart.vue"; export default Vue.extend({ components: { @@ -44,7 +46,8 @@ export default Vue.extend({ XVerifyUser, XUnverifyUser, XUsersChart, - XNotesChart + XNotesChart, + XDriveChart }, data() { return {