From 8dc9ec06f806bc8a2e6f128e99aa76af3e9b4647 Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 23 Aug 2018 01:37:05 +0900 Subject: 良い感じに MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/client/app/boot.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/client/app/boot.js b/src/client/app/boot.js index 952881f6cb..6bcceec217 100644 --- a/src/client/app/boot.js +++ b/src/client/app/boot.js @@ -38,12 +38,18 @@ //#endregion //#region Detect the user language - let lang = navigator.language; + let lang = null; - if (!LANGS.includes(lang)) lang = lang.split('-')[0]; + if (LANGS.includes(navigator.language)) { + lang = navigator.language; + } else { + lang = LANGS.find(x => x.split('-')[0] == lang); - // The default language is English - if (!LANGS.includes(lang)) lang = 'en'; + if (lang == null) { + // Fallback + lang = 'en-US'; + } + } if (settings) { if (settings.device.lang) lang = settings.device.lang; -- cgit v1.2.3-freya From 1b9c69f7939391afb536abe10b02572584ed564f Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 23 Aug 2018 01:55:39 +0900 Subject: Fix bug --- src/client/app/boot.js | 2 +- src/misc/i18n.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/client/app/boot.js b/src/client/app/boot.js index 6bcceec217..86d48faf1a 100644 --- a/src/client/app/boot.js +++ b/src/client/app/boot.js @@ -43,7 +43,7 @@ if (LANGS.includes(navigator.language)) { lang = navigator.language; } else { - lang = LANGS.find(x => x.split('-')[0] == lang); + lang = LANGS.find(x => x.split('-')[0] == navigator.language); if (lang == null) { // Fallback diff --git a/src/misc/i18n.ts b/src/misc/i18n.ts index a07af3e939..8379b2f538 100644 --- a/src/misc/i18n.ts +++ b/src/misc/i18n.ts @@ -30,7 +30,7 @@ export default class Replacer { if (text.hasOwnProperty(path)) { text = text[path]; } else { - if (this.lang === 'ja') console.warn(`path '${path}' not found`); + if (this.lang === 'ja-JP') console.warn(`path '${path}' not found`); return key; // Fallback } } @@ -46,10 +46,10 @@ export default class Replacer { }); if (error) { - if (this.lang === 'ja') console.warn(`key '${key}' not found in '${path}'`); + if (this.lang === 'ja-JP') console.warn(`key '${key}' not found in '${path}'`); return key; // Fallback } else if (typeof text !== 'string') { - if (this.lang === 'ja') console.warn(`key '${key}' is not string in '${path}'`); + if (this.lang === 'ja-JP') console.warn(`key '${key}' is not string in '${path}'`); return key; // Fallback } else { return text; -- cgit v1.2.3-freya From d129151fdf32de7134cdcee57d255fef82caf796 Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 23 Aug 2018 02:28:58 +0900 Subject: Fix #2410 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit なぜか .ts という拡張子で来るのかは不明 --- src/misc/i18n.ts | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/misc/i18n.ts b/src/misc/i18n.ts index 8379b2f538..3dbfd7fe7b 100644 --- a/src/misc/i18n.ts +++ b/src/misc/i18n.ts @@ -27,6 +27,8 @@ export default class Replacer { let text = texts; if (path) { + path = path.replace('.ts', ''); + if (text.hasOwnProperty(path)) { text = text[path]; } else { -- cgit v1.2.3-freya From d98c67e13c1d9a12921f436c1434b902b66e34c8 Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 23 Aug 2018 02:47:12 +0900 Subject: Add control panel link in nav --- locales/ja-JP.yml | 2 ++ src/client/app/desktop/views/components/ui.header.account.vue | 11 +++++++---- src/client/app/mobile/views/components/ui.nav.vue | 1 + 3 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index dc93c9dddc..dfcdb59e1c 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -857,6 +857,7 @@ desktop/views/components/ui.header.account.vue: lists: "リスト" follow-requests: "フォロー申請" customize: "ホームのカスタマイズ" + admin: "管理" settings: "設定" signout: "サインアウト" dark: "闇に飲まれる" @@ -1214,6 +1215,7 @@ mobile/views/components/ui.nav.vue: game: "ゲーム" darkmode: "ダークモード" settings: "設定" + admin: "管理" about: "Misskeyについて" mobile/views/components/user-timeline.vue: diff --git a/src/client/app/desktop/views/components/ui.header.account.vue b/src/client/app/desktop/views/components/ui.header.account.vue index 4e0fc1cf1a..5e26389d89 100644 --- a/src/client/app/desktop/views/components/ui.header.account.vue +++ b/src/client/app/desktop/views/components/ui.header.account.vue @@ -30,10 +30,8 @@
  • %fa:cog%%i18n:@settings%%fa:angle-right%

  • - -
      -
    • -

      %fa:power-off%%i18n:@signout%

      +
    • + %fa:terminal%%i18n:@admin%%fa:angle-right%
      @@ -41,6 +39,11 @@

      %i18n:@dark%

    +
      +
    • +

      %fa:power-off%%i18n:@signout%

      +
    • +
    diff --git a/src/client/app/mobile/views/components/ui.nav.vue b/src/client/app/mobile/views/components/ui.nav.vue index 74564a48bb..39ea513b76 100644 --- a/src/client/app/mobile/views/components/ui.nav.vue +++ b/src/client/app/mobile/views/components/ui.nav.vue @@ -30,6 +30,7 @@ -- cgit v1.2.3-freya From 8ba178f795c771fd84739f4ff5ce65f135ca69ca Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 23 Aug 2018 03:19:57 +0900 Subject: コントロールパネルから招待制のオンオフを切り替えられるように MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../desktop/views/pages/admin/admin.dashboard.vue | 14 ++++++++ src/server/api/endpoints/admin/update-meta.ts | 37 ++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 src/server/api/endpoints/admin/update-meta.ts (limited to 'src') 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 3567585cb8..e0d23331b8 100644 --- a/src/client/app/desktop/views/pages/admin/admin.dashboard.vue +++ b/src/client/app/desktop/views/pages/admin/admin.dashboard.vue @@ -11,6 +11,10 @@
    +

    Code: {{ inviteCode }}

    @@ -28,6 +32,7 @@ export default Vue.extend({ data() { return { stats: null, + disableRegistration: false, inviteCode: null, connection: null, connectionId: null @@ -37,6 +42,10 @@ export default Vue.extend({ this.connection = (this as any).os.streams.serverStatsStream.getConnection(); this.connectionId = (this as any).os.streams.serverStatsStream.use(); + (this as any).os.getMeta().then(meta => { + this.disableRegistration = meta.disableRegistration; + }); + (this as any).api('stats').then(stats => { this.stats = stats; }); @@ -49,6 +58,11 @@ export default Vue.extend({ (this as any).api('admin/invite').then(x => { this.inviteCode = x.code; }); + }, + updateMeta() { + (this as any).api('admin/update-meta', { + disableRegistration: this.disableRegistration + }); } } }); diff --git a/src/server/api/endpoints/admin/update-meta.ts b/src/server/api/endpoints/admin/update-meta.ts new file mode 100644 index 0000000000..bfcab9d6a6 --- /dev/null +++ b/src/server/api/endpoints/admin/update-meta.ts @@ -0,0 +1,37 @@ +import $ from 'cafy'; +import Meta from '../../../../models/meta'; +import getParams from '../../get-params'; + +export const meta = { + desc: { + ja: 'インスタンスの設定を更新します。' + }, + + requireCredential: true, + requireAdmin: true, + + params: { + disableRegistration: $.bool.optional.nullable.note({ + desc: { + ja: '招待制か否か' + } + }), + } +}; + +export default (params: any) => new Promise(async (res, rej) => { + const [ps, psErr] = getParams(meta, params); + if (psErr) return rej(psErr); + + const set = {} as any; + + if (ps.disableRegistration === true || ps.disableRegistration === false) { + set.disableRegistration = ps.disableRegistration; + } + + await Meta.update({}, { + $set: set + }, { upsert: true }); + + res(); +}); -- cgit v1.2.3-freya From 4fb7ee760aacdd2d52e8c43b3156fc0ef6deb11e Mon Sep 17 00:00:00 2001 From: rinsuki <428rinsuki+git@gmail.com> Date: Thu, 23 Aug 2018 11:58:44 +0900 Subject: https://misskey.xyz/notes/5b7e20bd248403003019b860 の修正 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/remote/resolve-user.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/remote/resolve-user.ts b/src/remote/resolve-user.ts index 1e8fc5d750..e199b6f147 100644 --- a/src/remote/resolve-user.ts +++ b/src/remote/resolve-user.ts @@ -15,7 +15,7 @@ export default async (username: string, _host: string, option?: any): Promise Date: Thu, 23 Aug 2018 14:56:39 +0900 Subject: Fix bug: Check following request existance --- src/server/api/endpoints/following/requests/cancel.ts | 6 +++++- src/services/following/requests/cancel.ts | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/api/endpoints/following/requests/cancel.ts b/src/server/api/endpoints/following/requests/cancel.ts index 9bfc40ce65..c46b948d29 100644 --- a/src/server/api/endpoints/following/requests/cancel.ts +++ b/src/server/api/endpoints/following/requests/cancel.ts @@ -27,7 +27,11 @@ export default (params: any, user: ILocalUser) => new Promise(async (res, rej) = return rej('followee not found'); } - await cancelFollowRequest(followee, user); + try { + await cancelFollowRequest(followee, user); + } catch (e) { + return rej(e); + } // Send response res(await pack(followee._id, user)); diff --git a/src/services/following/requests/cancel.ts b/src/services/following/requests/cancel.ts index b0b574da58..26e4544d5c 100644 --- a/src/services/following/requests/cancel.ts +++ b/src/services/following/requests/cancel.ts @@ -12,6 +12,15 @@ export default async function(followee: IUser, follower: IUser) { deliver(follower as ILocalUser, content, followee.inbox); } + const request = await FollowRequest.findOne({ + followeeId: followee._id, + followerId: follower._id + }); + + if (request == null) { + throw 'request not found'; + } + await FollowRequest.remove({ followeeId: followee._id, followerId: follower._id -- cgit v1.2.3-freya From 8fc1e07136d5ee203cbd1a1bc2ec00dfeb0e8cf0 Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 23 Aug 2018 15:40:24 +0900 Subject: 1時間単位での集計を追加 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cli/migration/8.0.0.js | 144 ++++++++++++++++++++++++++++++++ package.json | 2 +- src/models/stats.ts | 2 + src/server/api/endpoints/admin/chart.ts | 2 + src/services/update-chart.ts | 106 +++++++++++++---------- 5 files changed, 212 insertions(+), 44 deletions(-) create mode 100644 cli/migration/8.0.0.js (limited to 'src') diff --git a/cli/migration/8.0.0.js b/cli/migration/8.0.0.js new file mode 100644 index 0000000000..fd6cb24525 --- /dev/null +++ b/cli/migration/8.0.0.js @@ -0,0 +1,144 @@ +const { default: Stats } = require('../../built/models/stats'); +const { default: User } = require('../../built/models/user'); +const { default: Note } = require('../../built/models/note'); +const { default: DriveFile } = require('../../built/models/drive-file'); + +const now = new Date(); +const y = now.getFullYear(); +const m = now.getMonth(); +const d = now.getDate(); +const h = now.getHours(); +const date = new Date(y, m, d, h); + +async function main() { + await Stats.update({}, { + $set: { + span: 'day' + } + }, { + multi: true + }); + + const localUsersCount = await User.count({ + host: null + }); + + const remoteUsersCount = await User.count({ + host: { $ne: null } + }); + + const localNotesCount = await Note.count({ + '_user.host': null + }); + + const remoteNotesCount = await Note.count({ + '_user.host': { $ne: null } + }); + + const localDriveFilesCount = await DriveFile.count({ + 'metadata._user.host': null + }); + + const remoteDriveFilesCount = await DriveFile.count({ + 'metadata._user.host': { $ne: null } + }); + + const localDriveFilesSize = await DriveFile + .aggregate([{ + $match: { + 'metadata._user.host': null, + 'metadata.deletedAt': { $exists: false } + } + }, { + $project: { + length: true + } + }, { + $group: { + _id: null, + usage: { $sum: '$length' } + } + }]) + .then(aggregates => { + if (aggregates.length > 0) { + return aggregates[0].usage; + } + return 0; + }); + + const remoteDriveFilesSize = await DriveFile + .aggregate([{ + $match: { + 'metadata._user.host': { $ne: null }, + 'metadata.deletedAt': { $exists: false } + } + }, { + $project: { + length: true + } + }, { + $group: { + _id: null, + usage: { $sum: '$length' } + } + }]) + .then(aggregates => { + if (aggregates.length > 0) { + return aggregates[0].usage; + } + return 0; + }); + + await Stats.insert({ + date: date, + span: 'hour', + users: { + local: { + total: localUsersCount, + diff: 0 + }, + remote: { + total: remoteUsersCount, + diff: 0 + } + }, + notes: { + local: { + total: localNotesCount, + diff: 0, + diffs: { + normal: 0, + reply: 0, + renote: 0 + } + }, + remote: { + total: remoteNotesCount, + diff: 0, + diffs: { + normal: 0, + reply: 0, + renote: 0 + } + } + }, + drive: { + local: { + totalCount: localDriveFilesCount, + totalSize: localDriveFilesSize, + diffCount: 0, + diffSize: 0 + }, + remote: { + totalCount: remoteDriveFilesCount, + totalSize: remoteDriveFilesSize, + diffCount: 0, + diffSize: 0 + } + } + }); + + console.log('done'); +} + +main(); diff --git a/package.json b/package.json index 03f63a029d..077d30b96a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "misskey", "author": "syuilo ", - "version": "7.4.1", + "version": "8.0.0", "clientVersion": "1.0.8790", "codename": "nighthike", "main": "./built/index.js", diff --git a/src/models/stats.ts b/src/models/stats.ts index 7bff475c63..c481c3196e 100644 --- a/src/models/stats.ts +++ b/src/models/stats.ts @@ -10,6 +10,8 @@ export interface IStats { date: Date; + span: 'day' | 'hour'; + /** * ユーザーに関する統計 */ diff --git a/src/server/api/endpoints/admin/chart.ts b/src/server/api/endpoints/admin/chart.ts index a0566b11f5..c351c7167d 100644 --- a/src/server/api/endpoints/admin/chart.ts +++ b/src/server/api/endpoints/admin/chart.ts @@ -14,6 +14,7 @@ export default (params: any) => new Promise(async (res, rej) => { const d = now.getDate(); const stats = await Stats.find({ + span: 'day', date: { $gt: new Date(y - 1, m, d) } @@ -44,6 +45,7 @@ export default (params: any) => new Promise(async (res, rej) => { } else { chart.unshift({ date: day, + span: 'day', users: { local: { total: 0, diff --git a/src/services/update-chart.ts b/src/services/update-chart.ts index 6b69adbdc3..0a0f58bb92 100644 --- a/src/services/update-chart.ts +++ b/src/services/update-chart.ts @@ -5,49 +5,59 @@ import { IDriveFile } from '../models/drive-file'; type Omit = Pick>; -async function getTodayStats(): Promise { +async function getCurrentStats(span: 'day' | 'hour'): Promise { const now = new Date(); const y = now.getFullYear(); const m = now.getMonth(); const d = now.getDate(); - const today = new Date(y, m, d); + const h = now.getHours(); - // 今日の統計 - const todayStats = await Stats.findOne({ - date: today + const current = + span == 'day' ? new Date(y, m, d) : + span == 'hour' ? new Date(y, m, d, h) : + null; + + // 現在(今日または今のHour)の統計 + const currentStats = await Stats.findOne({ + span: span, + date: current }); - // 日付が変わってから、初めてのチャート更新なら - if (todayStats == null) { + if (currentStats) { + return currentStats; + } else { + // 集計期間が変わってから、初めてのチャート更新なら // 最も最近の統計を持ってくる + // * 例えば集計期間が「日」である場合で考えると、 // * 昨日何もチャートを更新するような出来事がなかった場合は、 - // 統計がそもそも作られずドキュメントが存在しないということがあり得るため、 - // 「昨日の」と決め打ちせずに「もっとも最近の」とします - const mostRecentStats = await Stats.findOne({}, { + // * 統計がそもそも作られずドキュメントが存在しないということがあり得るため、 + // * 「昨日の」と決め打ちせずに「もっとも最近の」とします + const mostRecentStats = await Stats.findOne({ + span: span + }, { sort: { date: -1 } }); - // 統計が存在しなかったら - // * Misskeyインスタンスを建てて初めてのチャート更新時など - if (mostRecentStats == null) { - // 空の統計を作成 + if (mostRecentStats) { + // 現在の統計を初期挿入 const data: Omit = { - date: today, + span: span, + date: current, users: { local: { - total: 0, + total: mostRecentStats.users.local.total, diff: 0 }, remote: { - total: 0, + total: mostRecentStats.users.remote.total, diff: 0 } }, notes: { local: { - total: 0, + total: mostRecentStats.notes.local.total, diff: 0, diffs: { normal: 0, @@ -56,7 +66,7 @@ async function getTodayStats(): Promise { } }, remote: { - total: 0, + total: mostRecentStats.notes.remote.total, diff: 0, diffs: { normal: 0, @@ -67,14 +77,14 @@ async function getTodayStats(): Promise { }, drive: { local: { - totalCount: 0, - totalSize: 0, + totalCount: mostRecentStats.drive.local.totalCount, + totalSize: mostRecentStats.drive.local.totalSize, diffCount: 0, diffSize: 0 }, remote: { - totalCount: 0, - totalSize: 0, + totalCount: mostRecentStats.drive.remote.totalCount, + totalSize: mostRecentStats.drive.remote.totalSize, diffCount: 0, diffSize: 0 } @@ -85,22 +95,26 @@ async function getTodayStats(): Promise { return stats; } else { - // 今日の統計を初期挿入 - const data: Omit = { - date: today, + // 統計が存在しなかったら + // * Misskeyインスタンスを建てて初めてのチャート更新時など + + // 空の統計を作成 + const emptyStat: Omit = { + span: span, + date: current, users: { local: { - total: mostRecentStats.users.local.total, + total: 0, diff: 0 }, remote: { - total: mostRecentStats.users.remote.total, + total: 0, diff: 0 } }, notes: { local: { - total: mostRecentStats.notes.local.total, + total: 0, diff: 0, diffs: { normal: 0, @@ -109,7 +123,7 @@ async function getTodayStats(): Promise { } }, remote: { - total: mostRecentStats.notes.remote.total, + total: 0, diff: 0, diffs: { normal: 0, @@ -120,36 +134,42 @@ async function getTodayStats(): Promise { }, drive: { local: { - totalCount: mostRecentStats.drive.local.totalCount, - totalSize: mostRecentStats.drive.local.totalSize, + totalCount: 0, + totalSize: 0, diffCount: 0, diffSize: 0 }, remote: { - totalCount: mostRecentStats.drive.remote.totalCount, - totalSize: mostRecentStats.drive.remote.totalSize, + totalCount: 0, + totalSize: 0, diffCount: 0, diffSize: 0 } } }; - const stats = await Stats.insert(data); + const stats = await Stats.insert(emptyStat); return stats; } - } else { - return todayStats; } } -async function update(inc: any) { - const stats = await getTodayStats(); +function update(inc: any) { + getCurrentStats('day').then(stats => { + Stats.findOneAndUpdate({ + _id: stats._id + }, { + $inc: inc + }); + }); - await Stats.findOneAndUpdate({ - _id: stats._id - }, { - $inc: inc + getCurrentStats('hour').then(stats => { + Stats.findOneAndUpdate({ + _id: stats._id + }, { + $inc: inc + }); }); } -- cgit v1.2.3-freya From 774834a31fbf621785824d43cc4cc1023cdbe888 Mon Sep 17 00:00:00 2001 From: "Acid Chicken (硫酸鶏)" Date: Thu, 23 Aug 2018 16:25:36 +0900 Subject: Update url-preview.vue --- src/client/app/common/views/components/url-preview.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/app/common/views/components/url-preview.vue b/src/client/app/common/views/components/url-preview.vue index be69012737..4ddc137ed1 100644 --- a/src/client/app/common/views/components/url-preview.vue +++ b/src/client/app/common/views/components/url-preview.vue @@ -176,7 +176,7 @@ export default Vue.extend({ 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 deleted file mode 100644 index 97f05571c3..0000000000 --- a/src/client/app/desktop/views/pages/admin/admin.drive-chart.chart.vue +++ /dev/null @@ -1,74 +0,0 @@ - - - - - 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 deleted file mode 100644 index 4f94fd2372..0000000000 --- a/src/client/app/desktop/views/pages/admin/admin.drive-chart.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - - - 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 deleted file mode 100644 index fabb3f1bd1..0000000000 --- a/src/client/app/desktop/views/pages/admin/admin.notes-chart.chart.vue +++ /dev/null @@ -1,99 +0,0 @@ - - - - - diff --git a/src/client/app/desktop/views/pages/admin/admin.notes-chart.vue b/src/client/app/desktop/views/pages/admin/admin.notes-chart.vue deleted file mode 100644 index e4d396d9c6..0000000000 --- a/src/client/app/desktop/views/pages/admin/admin.notes-chart.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - - - 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 deleted file mode 100644 index 45ecc13929..0000000000 --- a/src/client/app/desktop/views/pages/admin/admin.users-chart.chart.vue +++ /dev/null @@ -1,74 +0,0 @@ - - - - - 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 deleted file mode 100644 index e620012702..0000000000 --- a/src/client/app/desktop/views/pages/admin/admin.users-chart.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - - - diff --git a/src/client/app/desktop/views/pages/admin/admin.vue b/src/client/app/desktop/views/pages/admin/admin.vue index cbb1890cc3..066c1a4f4f 100644 --- a/src/client/app/desktop/views/pages/admin/admin.vue +++ b/src/client/app/desktop/views/pages/admin/admin.vue @@ -11,9 +11,7 @@
    - - - +
    @@ -34,9 +32,7 @@ import XSuspendUser from "./admin.suspend-user.vue"; import XUnsuspendUser from "./admin.unsuspend-user.vue"; 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"; +import XChart from "./admin.chart.vue"; export default Vue.extend({ components: { @@ -45,9 +41,7 @@ export default Vue.extend({ XUnsuspendUser, XVerifyUser, XUnverifyUser, - XUsersChart, - XNotesChart, - XDriveChart + XChart }, data() { return { diff --git a/src/server/api/endpoints/admin/chart.ts b/src/server/api/endpoints/admin/chart.ts index 1897879d65..1b88af00bd 100644 --- a/src/server/api/endpoints/admin/chart.ts +++ b/src/server/api/endpoints/admin/chart.ts @@ -8,7 +8,7 @@ export const meta = { }; export default (params: any) => new Promise(async (res, rej) => { - const daysRange = 365; + const daysRange = 90; const hoursRange = 24; const now = new Date(); @@ -123,7 +123,6 @@ export default (params: any) => new Promise(async (res, rej) => { } chart.forEach(x => { - delete x.date; delete (x as any).span; }); -- cgit v1.2.3-freya From 5b5de6a89c26f2f32dc4f32a9657975994a8c503 Mon Sep 17 00:00:00 2001 From: mei23 Date: Fri, 24 Aug 2018 05:41:03 +0900 Subject: ベースHTMLは immutableキャッシュしないようにする MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/server/web/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/server/web/index.ts b/src/server/web/index.ts index 7291f8a0a5..452e36fe95 100644 --- a/src/server/web/index.ts +++ b/src/server/web/index.ts @@ -122,8 +122,7 @@ router.get('/notes/:note', async ctx => { router.get('*', async ctx => { await send(ctx, `app/base.html`, { root: client, - maxage: ms('3 days'), - immutable: true + maxage: ms('5m') }); }); -- cgit v1.2.3-freya From a294a881ec479b1a90b2c3ade4a160ddd2a03dac Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 24 Aug 2018 06:41:53 +0900 Subject: Improve chart --- locales/ja-JP.yml | 9 +++ .../desktop/views/pages/admin/admin.chart.chart.ts | 5 -- .../app/desktop/views/pages/admin/admin.chart.vue | 76 +++++++++++++++++----- 3 files changed, 70 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 31b81f1d7e..a74da8cd9a 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -941,6 +941,11 @@ desktop/views/pages/admin/admin.unverify-user.vue: desktop/views/pages/admin/admin.chart.vue: title: "チャート" + per-day: "1時間ごと" + per-hour: "1日ごと" + notes: "投稿" + users: "ユーザー" + drive: "ドライブ" local-notes: "ローカルの投稿" remote-notes: "リモートの投稿" local-notes-total: "ローカルの投稿 (累計)" @@ -953,6 +958,10 @@ desktop/views/pages/admin/admin.chart.vue: remote-drive: "リモートのドライブ使用量" local-drive-total: "ローカルのドライブ使用量 (累計)" remote-drive-total: "リモートのドライブ使用量 (累計)" + local-drive-files: "ローカルのドライブのファイル数" + remote-drive-files: "リモートのドライブのファイル数" + local-drive-files-total: "ローカルのドライブのファイル数 (累計)" + remote-drive-files-total: "リモートのドライブのファイル数 (累計)" desktop/views/pages/deck/deck.tl-column.vue: is-media-only: "メディア投稿のみ" diff --git a/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts b/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts index 62043b21dc..d79b0ba192 100644 --- a/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts +++ b/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts @@ -26,11 +26,6 @@ export default Vue.extend({ scales: { xAxes: [{ type: 'time', - time: { - displayFormats: { - quarter: 'YYYY/MM/D h:mm' - } - }, distribution: 'series' }] } diff --git a/src/client/app/desktop/views/pages/admin/admin.chart.vue b/src/client/app/desktop/views/pages/admin/admin.chart.vue index c92caeb2f0..4e0050e8b9 100644 --- a/src/client/app/desktop/views/pages/admin/admin.chart.vue +++ b/src/client/app/desktop/views/pages/admin/admin.chart.vue @@ -3,21 +3,31 @@
    %i18n:@title%:
    @@ -59,6 +69,10 @@ export default Vue.extend({ case 'remote-drive': return this.driveChart(false, false); case 'local-drive-total': return this.driveChart(true, true); case 'remote-drive-total': return this.driveChart(false, true); + case 'local-drive-files': return this.driveFilesChart(true, false); + case 'remote-drive-files': return this.driveFilesChart(false, false); + case 'local-drive-files-total': return this.driveFilesChart(true, true); + case 'remote-drive-files-total': return this.driveFilesChart(false, true); } }, stats(): any[] { @@ -76,11 +90,19 @@ export default Vue.extend({ normal: local ? x.notes.local.diffs.normal : x.notes.remote.diffs.normal, reply: local ? x.notes.local.diffs.reply : x.notes.remote.diffs.reply, renote: local ? x.notes.local.diffs.renote : x.notes.remote.diffs.renote, - total: local ? x.notes.local.diff : x.notes.remote.diff + all: local ? x.notes.local.diff : x.notes.remote.diff })); return [{ datasets: [{ + label: 'All', + fill: false, + borderColor: '#555', + borderWidth: 2, + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.all })) + }, { label: 'Normal', fill: false, borderColor: '#41ddde', @@ -107,6 +129,7 @@ export default Vue.extend({ }] }]; }, + notesTotalChart(local: boolean): any { const data = this.stats.slice().reverse().map(x => ({ date: new Date(x.date), @@ -125,6 +148,7 @@ export default Vue.extend({ }] }]; }, + usersChart(local: boolean, total: boolean): any { const data = this.stats.slice().reverse().map(x => ({ date: new Date(x.date), @@ -145,6 +169,7 @@ export default Vue.extend({ }] }]; }, + driveChart(local: boolean, total: boolean): any { const data = this.stats.slice().reverse().map(x => ({ date: new Date(x.date), @@ -174,7 +199,28 @@ export default Vue.extend({ }] } }]; - } + }, + + driveFilesChart(local: boolean, total: boolean): any { + const data = this.stats.slice().reverse().map(x => ({ + date: new Date(x.date), + count: local ? + total ? x.drive.local.totalCount : x.drive.local.diffCount : + total ? x.drive.remote.totalCount : x.drive.remote.diffCount + })); + + return [{ + datasets: [{ + label: local ? 'Local Drive Files' : 'Remote Drive Files', + fill: false, + borderColor: '#f6584f', + borderWidth: 2, + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.count })) + }] + }]; + }, } }); -- cgit v1.2.3-freya From fa3299840f505c2e03eedfe420e57365030547d3 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 24 Aug 2018 07:02:27 +0900 Subject: Refactor --- src/client/app/desktop/views/pages/admin/admin.chart.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/app/desktop/views/pages/admin/admin.chart.vue b/src/client/app/desktop/views/pages/admin/admin.chart.vue index 4e0050e8b9..8db54174ff 100644 --- a/src/client/app/desktop/views/pages/admin/admin.chart.vue +++ b/src/client/app/desktop/views/pages/admin/admin.chart.vue @@ -173,7 +173,7 @@ export default Vue.extend({ driveChart(local: boolean, total: boolean): any { const data = this.stats.slice().reverse().map(x => ({ date: new Date(x.date), - count: local ? + size: local ? total ? x.drive.local.totalSize : x.drive.local.diffSize : total ? x.drive.remote.totalSize : x.drive.remote.diffSize })); @@ -186,7 +186,7 @@ export default Vue.extend({ borderWidth: 2, pointBackgroundColor: '#fff', lineTension: 0, - data: data.map(x => ({ t: x.date, y: x.count })) + data: data.map(x => ({ t: x.date, y: x.size })) }] }, { scales: { -- cgit v1.2.3-freya From 92cf205c6669abde283ae13491cd1a07da32a98a Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 24 Aug 2018 07:02:52 +0900 Subject: Fix bug --- package.json | 1 + src/client/app/desktop/views/pages/admin/admin.chart.chart.ts | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/package.json b/package.json index 99a672e636..e362adbfe3 100644 --- a/package.json +++ b/package.json @@ -150,6 +150,7 @@ "loader-utils": "1.1.0", "lodash.assign": "4.2.0", "mecab-async": "0.1.2", + "merge-options": "1.0.1", "minio": "7.0.0", "mkdirp": "0.5.1", "mocha": "5.2.0", diff --git a/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts b/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts index d79b0ba192..c09dc6dd8c 100644 --- a/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts +++ b/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts @@ -1,5 +1,6 @@ import Vue from 'vue'; import { Line } from 'vue-chartjs'; +import * as mergeOptions from 'merge-options'; export default Vue.extend({ extends: Line, @@ -21,7 +22,7 @@ export default Vue.extend({ }, methods: { render() { - this.renderChart(this.data, Object.assign({ + this.renderChart(this.data, mergeOptions({ responsive: false, scales: { xAxes: [{ -- cgit v1.2.3-freya From 3f7d2486847ef8f3229adad024316ad01da251ae Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 24 Aug 2018 07:17:17 +0900 Subject: Improve chart --- locales/ja-JP.yml | 32 +++++++++++----------- .../desktop/views/pages/admin/admin.chart.chart.ts | 3 +- .../app/desktop/views/pages/admin/admin.chart.vue | 15 +++++++--- 3 files changed, 29 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index b7f4aace64..3755f55f36 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -946,22 +946,22 @@ desktop/views/pages/admin/admin.chart.vue: notes: "投稿" users: "ユーザー" drive: "ドライブ" - local-notes: "ローカルの投稿" - remote-notes: "リモートの投稿" - local-notes-total: "ローカルの投稿 (累計)" - remote-notes-total: "リモートの投稿 (累計)" - local-users: "ローカルのユーザー" - remote-users: "リモートのユーザー" - local-users-total: "ローカルのユーザー (累計)" - remote-users-total: "リモートのユーザー (累計)" - local-drive: "ローカルのドライブ使用量" - remote-drive: "リモートのドライブ使用量" - local-drive-total: "ローカルのドライブ使用量 (累計)" - remote-drive-total: "リモートのドライブ使用量 (累計)" - local-drive-files: "ローカルのドライブのファイル数" - remote-drive-files: "リモートのドライブのファイル数" - local-drive-files-total: "ローカルのドライブのファイル数 (累計)" - remote-drive-files-total: "リモートのドライブのファイル数 (累計)" + local-notes: "ローカルの投稿の増減" + remote-notes: "リモートの投稿の増減" + local-notes-total: "ローカルの投稿の累計" + remote-notes-total: "リモートの投稿の累計" + local-users: "ローカルのユーザーの増減" + remote-users: "リモートのユーザーの増減" + local-users-total: "ローカルのユーザーの累計" + remote-users-total: "リモートのユーザーの累計" + local-drive: "ローカルのドライブ使用量の増減" + remote-drive: "リモートのドライブ使用量の増減" + local-drive-total: "ローカルのドライブ使用量の累計" + remote-drive-total: "リモートのドライブ使用量の累計" + local-drive-files: "ローカルのドライブのファイル数の増減" + remote-drive-files: "リモートのドライブのファイル数の増減" + local-drive-files-total: "ローカルのドライブのファイル数の累計" + remote-drive-files-total: "リモートのドライブのファイル数の累計" desktop/views/pages/deck/deck.tl-column.vue: is-media-only: "メディア投稿のみ" diff --git a/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts b/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts index c09dc6dd8c..4ba348fb0f 100644 --- a/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts +++ b/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts @@ -23,7 +23,8 @@ export default Vue.extend({ methods: { render() { this.renderChart(this.data, mergeOptions({ - responsive: false, + responsive: true, + maintainAspectRatio: false, scales: { xAxes: [{ type: 'time', diff --git a/src/client/app/desktop/views/pages/admin/admin.chart.vue b/src/client/app/desktop/views/pages/admin/admin.chart.vue index 8db54174ff..f40f89b2e0 100644 --- a/src/client/app/desktop/views/pages/admin/admin.chart.vue +++ b/src/client/app/desktop/views/pages/admin/admin.chart.vue @@ -30,7 +30,9 @@ %i18n:@per-day% | %i18n:@per-hour%
    - +
    + +
    @@ -139,7 +141,7 @@ export default Vue.extend({ return [{ datasets: [{ label: local ? 'Local Notes' : 'Remote Notes', - fill: false, + fill: true, borderColor: '#f6584f', borderWidth: 2, pointBackgroundColor: '#fff', @@ -160,7 +162,7 @@ export default Vue.extend({ return [{ datasets: [{ label: local ? 'Local Users' : 'Remote Users', - fill: false, + fill: true, borderColor: '#f6584f', borderWidth: 2, pointBackgroundColor: '#fff', @@ -181,7 +183,7 @@ export default Vue.extend({ return [{ datasets: [{ label: local ? 'Local Drive Usage' : 'Remote Drive Usage', - fill: false, + fill: true, borderColor: '#f6584f', borderWidth: 2, pointBackgroundColor: '#fff', @@ -238,4 +240,9 @@ export default Vue.extend({ > *:last-child margin-left auto + > div + > * + display block + height 300px + -- cgit v1.2.3-freya From b21287262e85e3e09e19217ba4168b83e4fdf4a7 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 24 Aug 2018 07:23:04 +0900 Subject: チャート取得APIを誰でも利用できるようにするなど MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/desktop/views/pages/admin/admin.chart.vue | 11 +- src/client/app/desktop/views/pages/admin/admin.vue | 7 +- src/server/api/endpoints/admin/chart.ts | 136 --------------------- src/server/api/endpoints/chart.ts | 134 ++++++++++++++++++++ 4 files changed, 141 insertions(+), 147 deletions(-) delete mode 100644 src/server/api/endpoints/admin/chart.ts create mode 100644 src/server/api/endpoints/chart.ts (limited to 'src') diff --git a/src/client/app/desktop/views/pages/admin/admin.chart.vue b/src/client/app/desktop/views/pages/admin/admin.chart.vue index f40f89b2e0..b02f6c31b7 100644 --- a/src/client/app/desktop/views/pages/admin/admin.chart.vue +++ b/src/client/app/desktop/views/pages/admin/admin.chart.vue @@ -44,13 +44,9 @@ export default Vue.extend({ components: { XChart }, - props: { - chart: { - required: true - } - }, data() { return { + chart: null, chartType: 'local-notes', span: 'hour' }; @@ -85,6 +81,11 @@ export default Vue.extend({ ); } }, + created() { + (this as any).api('chart').then(chart => { + this.chart = chart; + }); + }, methods: { notesChart(local: boolean): any { const data = this.stats.slice().reverse().map(x => ({ diff --git a/src/client/app/desktop/views/pages/admin/admin.vue b/src/client/app/desktop/views/pages/admin/admin.vue index 066c1a4f4f..0bb5ed0a0f 100644 --- a/src/client/app/desktop/views/pages/admin/admin.vue +++ b/src/client/app/desktop/views/pages/admin/admin.vue @@ -11,7 +11,7 @@
    - +
    @@ -49,11 +49,6 @@ export default Vue.extend({ 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/server/api/endpoints/admin/chart.ts b/src/server/api/endpoints/admin/chart.ts deleted file mode 100644 index 1b88af00bd..0000000000 --- a/src/server/api/endpoints/admin/chart.ts +++ /dev/null @@ -1,136 +0,0 @@ -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 daysRange = 90; - const hoursRange = 24; - - const now = new Date(); - const y = now.getFullYear(); - const m = now.getMonth(); - const d = now.getDate(); - const h = now.getHours(); - - const [statsPerDay, statsPerHour] = await Promise.all([ - Stats.find({ - span: 'day', - date: { - $gt: new Date(y, m, d - daysRange) - } - }, { - sort: { - date: -1 - }, - fields: { - _id: 0 - } - }), - Stats.find({ - span: 'hour', - date: { - $gt: new Date(y, m, d, h - hoursRange) - } - }, { - sort: { - date: -1 - }, - fields: { - _id: 0 - } - }), - ]); - - const format = (src: IStats[], span: 'day' | 'hour') => { - const chart: Array, 'span'>> = []; - - const range = - span == 'day' ? daysRange : - span == 'hour' ? hoursRange : - null; - - for (let i = (range - 1); i >= 0; i--) { - const current = - span == 'day' ? new Date(y, m, d - i) : - span == 'hour' ? new Date(y, m, d, h - i) : - null; - - const stat = src.find(s => s.date.getTime() == current.getTime()); - - if (stat) { - chart.unshift(stat); - } else { // 隙間埋め - const mostRecent = src.find(s => s.date.getTime() < current.getTime()); - if (mostRecent) { - chart.unshift(Object.assign({}, mostRecent, { - date: current - })); - } else { - chart.unshift({ - date: current, - 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 - } - } - }); - } - } - } - - chart.forEach(x => { - delete (x as any).span; - }); - - return chart; - }; - - res({ - perDay: format(statsPerDay, 'day'), - perHour: format(statsPerHour, 'hour') - }); -}); diff --git a/src/server/api/endpoints/chart.ts b/src/server/api/endpoints/chart.ts new file mode 100644 index 0000000000..a58f0b163e --- /dev/null +++ b/src/server/api/endpoints/chart.ts @@ -0,0 +1,134 @@ +import Stats, { IStats } from '../../../models/stats'; + +type Omit = Pick>; + +export const meta = { +}; + +export default (params: any) => new Promise(async (res, rej) => { + const daysRange = 90; + const hoursRange = 24; + + const now = new Date(); + const y = now.getFullYear(); + const m = now.getMonth(); + const d = now.getDate(); + const h = now.getHours(); + + const [statsPerDay, statsPerHour] = await Promise.all([ + Stats.find({ + span: 'day', + date: { + $gt: new Date(y, m, d - daysRange) + } + }, { + sort: { + date: -1 + }, + fields: { + _id: 0 + } + }), + Stats.find({ + span: 'hour', + date: { + $gt: new Date(y, m, d, h - hoursRange) + } + }, { + sort: { + date: -1 + }, + fields: { + _id: 0 + } + }), + ]); + + const format = (src: IStats[], span: 'day' | 'hour') => { + const chart: Array, 'span'>> = []; + + const range = + span == 'day' ? daysRange : + span == 'hour' ? hoursRange : + null; + + for (let i = (range - 1); i >= 0; i--) { + const current = + span == 'day' ? new Date(y, m, d - i) : + span == 'hour' ? new Date(y, m, d, h - i) : + null; + + const stat = src.find(s => s.date.getTime() == current.getTime()); + + if (stat) { + chart.unshift(stat); + } else { // 隙間埋め + const mostRecent = src.find(s => s.date.getTime() < current.getTime()); + if (mostRecent) { + chart.unshift(Object.assign({}, mostRecent, { + date: current + })); + } else { + chart.unshift({ + date: current, + 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 + } + } + }); + } + } + } + + chart.forEach(x => { + delete (x as any).span; + }); + + return chart; + }; + + res({ + perDay: format(statsPerDay, 'day'), + perHour: format(statsPerHour, 'hour') + }); +}); -- cgit v1.2.3-freya From fc180f030f666815c932a8e42751c6a2fa00a2f6 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 24 Aug 2018 08:35:01 +0900 Subject: Fix bug --- src/services/drive/add-file.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/services/drive/add-file.ts b/src/services/drive/add-file.ts index b090d56cee..a60d1acbbe 100644 --- a/src/services/drive/add-file.ts +++ b/src/services/drive/add-file.ts @@ -40,7 +40,7 @@ async function save(path: string, name: string, type: string, hash: string, size const thumbnailKey = `${config.drive.prefix}/${uuid.v4()}/${name}.thumbnail.jpg`; const baseUrl = config.drive.baseUrl - || `${ config.drive.config.secure ? 'https' : 'http' }://${ config.drive.config.endPoint }${ config.drive.config.port ? ':' + config.drive.config.port : '' }/${ config.drive.bucket }`; + || `${ config.drive.config.useSSL ? 'https' : 'http' }://${ config.drive.config.endPoint }${ config.drive.config.port ? ':' + config.drive.config.port : '' }/${ config.drive.bucket }`; await minio.putObject(config.drive.bucket, key, fs.createReadStream(path), size, { 'Content-Type': type, -- cgit v1.2.3-freya From 8b37fc47724a1356c870bb660ddf97454639abf1 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 24 Aug 2018 08:56:57 +0900 Subject: Improve chart --- src/client/app/common/views/filters/bytes.ts | 8 +++++--- .../desktop/views/pages/admin/admin.chart.chart.ts | 3 +++ .../app/desktop/views/pages/admin/admin.chart.vue | 24 ++++++++++++++++++---- 3 files changed, 28 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client/app/common/views/filters/bytes.ts b/src/client/app/common/views/filters/bytes.ts index 3afb11e9ae..f7a1b2690f 100644 --- a/src/client/app/common/views/filters/bytes.ts +++ b/src/client/app/common/views/filters/bytes.ts @@ -1,8 +1,10 @@ import Vue from 'vue'; Vue.filter('bytes', (v, digits = 0) => { - const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; - if (v == 0) return '0Byte'; + const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; + if (v == 0) return '0'; + const isMinus = v < 0; + if (isMinus) v = -v; const i = Math.floor(Math.log(v) / Math.log(1024)); - return (v / Math.pow(1024, i)).toFixed(digits).replace(/\.0+$/, '') + sizes[i]; + return (isMinus ? '-' : '') + (v / Math.pow(1024, i)).toFixed(digits).replace(/\.0+$/, '') + sizes[i]; }); diff --git a/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts b/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts index 4ba348fb0f..9fb18fd039 100644 --- a/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts +++ b/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts @@ -30,6 +30,9 @@ export default Vue.extend({ type: 'time', distribution: 'series' }] + }, + tooltips: { + intersect: false } }, this.opts || {})); } diff --git a/src/client/app/desktop/views/pages/admin/admin.chart.vue b/src/client/app/desktop/views/pages/admin/admin.chart.vue index b02f6c31b7..caaeeaeda1 100644 --- a/src/client/app/desktop/views/pages/admin/admin.chart.vue +++ b/src/client/app/desktop/views/pages/admin/admin.chart.vue @@ -107,7 +107,8 @@ export default Vue.extend({ data: data.map(x => ({ t: x.date, y: x.all })) }, { label: 'Normal', - fill: false, + fill: true, + backgroundColor: 'rgba(65, 221, 222, 0.1)', borderColor: '#41ddde', borderWidth: 2, pointBackgroundColor: '#fff', @@ -115,7 +116,8 @@ export default Vue.extend({ data: data.map(x => ({ t: x.date, y: x.normal })) }, { label: 'Replies', - fill: false, + fill: true, + backgroundColor: 'rgba(247, 121, 108, 0.1)', borderColor: '#f7796c', borderWidth: 2, pointBackgroundColor: '#fff', @@ -123,7 +125,8 @@ export default Vue.extend({ data: data.map(x => ({ t: x.date, y: x.reply })) }, { label: 'Renotes', - fill: false, + fill: true, + backgroundColor: 'rgba(161, 222, 65, 0.1)', borderColor: '#a1de41', borderWidth: 2, pointBackgroundColor: '#fff', @@ -143,6 +146,7 @@ export default Vue.extend({ datasets: [{ label: local ? 'Local Notes' : 'Remote Notes', fill: true, + backgroundColor: 'rgba(246, 88, 79, 0.1)', borderColor: '#f6584f', borderWidth: 2, pointBackgroundColor: '#fff', @@ -164,6 +168,7 @@ export default Vue.extend({ datasets: [{ label: local ? 'Local Users' : 'Remote Users', fill: true, + backgroundColor: 'rgba(246, 88, 79, 0.1)', borderColor: '#f6584f', borderWidth: 2, pointBackgroundColor: '#fff', @@ -185,6 +190,7 @@ export default Vue.extend({ datasets: [{ label: local ? 'Local Drive Usage' : 'Remote Drive Usage', fill: true, + backgroundColor: 'rgba(246, 88, 79, 0.1)', borderColor: '#f6584f', borderWidth: 2, pointBackgroundColor: '#fff', @@ -195,11 +201,18 @@ export default Vue.extend({ scales: { yAxes: [{ ticks: { - callback: (value) => { + callback: value => { return Vue.filter('bytes')(value); } } }] + }, + tooltips: { + callbacks: { + label: tooltipItem => { + return Vue.filter('bytes')(tooltipItem.yLabel); + } + } } }]; }, @@ -232,6 +245,9 @@ export default Vue.extend({ @import '~const.styl' .gkgckalzgidaygcxnugepioremxvxvpt + * + user-select none + > header display flex -- cgit v1.2.3-freya From 9c4a7bf94c4aefcd6f42bac7372b6deb899268b1 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 24 Aug 2018 09:39:16 +0900 Subject: Improve chart --- src/client/app/desktop/views/pages/admin/admin.chart.chart.ts | 4 +++- src/client/app/desktop/views/pages/admin/admin.chart.vue | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts b/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts index 9fb18fd039..6a241631e9 100644 --- a/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts +++ b/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts @@ -32,7 +32,9 @@ export default Vue.extend({ }] }, tooltips: { - intersect: false + intersect: false, + mode: 'x', + position: 'nearest' } }, this.opts || {})); } diff --git a/src/client/app/desktop/views/pages/admin/admin.chart.vue b/src/client/app/desktop/views/pages/admin/admin.chart.vue index caaeeaeda1..4301f9978b 100644 --- a/src/client/app/desktop/views/pages/admin/admin.chart.vue +++ b/src/client/app/desktop/views/pages/admin/admin.chart.vue @@ -102,6 +102,7 @@ export default Vue.extend({ fill: false, borderColor: '#555', borderWidth: 2, + borderDash: [4, 4], pointBackgroundColor: '#fff', lineTension: 0, data: data.map(x => ({ t: x.date, y: x.all })) @@ -228,7 +229,8 @@ export default Vue.extend({ return [{ datasets: [{ label: local ? 'Local Drive Files' : 'Remote Drive Files', - fill: false, + fill: true, + backgroundColor: 'rgba(246, 88, 79, 0.1)', borderColor: '#f6584f', borderWidth: 2, pointBackgroundColor: '#fff', -- cgit v1.2.3-freya From 9502586c8b8c925f5c664d002ac82a1b24e37275 Mon Sep 17 00:00:00 2001 From: mei23 Date: Fri, 24 Aug 2018 14:52:53 +0900 Subject: ActivityPub Renote/Replyで 対象Noteを添付しないようにする MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/services/note/create.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/services/note/create.ts b/src/services/note/create.ts index d8f0f57b63..268bfa5bbe 100644 --- a/src/services/note/create.ts +++ b/src/services/note/create.ts @@ -239,8 +239,8 @@ export default async (user: IUser, data: Option, silent = false) => new Promise< async function renderActivity(data: Option, note: INote) { const content = data.renote && data.text == null - ? renderAnnounce(data.renote.uri ? data.renote.uri : await renderNote(data.renote), note) - : renderCreate(await renderNote(note)); + ? renderAnnounce(data.renote.uri ? data.renote.uri : `${config.url}/notes/${data.renote._id}`, note) + : renderCreate(await renderNote(note, false)); return packAp(content); } -- cgit v1.2.3-freya From 13624ea7c25870162d1c60e82c3a0e064e8478da Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 24 Aug 2018 14:55:58 +0900 Subject: バグ修正など MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/ja-JP.yml | 27 +- .../app/desktop/views/pages/admin/admin.chart.vue | 280 +++++++++++++++------ src/server/api/endpoints/chart.ts | 54 +++- 3 files changed, 268 insertions(+), 93 deletions(-) (limited to 'src') diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 3755f55f36..c44254439c 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -946,22 +946,17 @@ desktop/views/pages/admin/admin.chart.vue: notes: "投稿" users: "ユーザー" drive: "ドライブ" - local-notes: "ローカルの投稿の増減" - remote-notes: "リモートの投稿の増減" - local-notes-total: "ローカルの投稿の累計" - remote-notes-total: "リモートの投稿の累計" - local-users: "ローカルのユーザーの増減" - remote-users: "リモートのユーザーの増減" - local-users-total: "ローカルのユーザーの累計" - remote-users-total: "リモートのユーザーの累計" - local-drive: "ローカルのドライブ使用量の増減" - remote-drive: "リモートのドライブ使用量の増減" - local-drive-total: "ローカルのドライブ使用量の累計" - remote-drive-total: "リモートのドライブ使用量の累計" - local-drive-files: "ローカルのドライブのファイル数の増減" - remote-drive-files: "リモートのドライブのファイル数の増減" - local-drive-files-total: "ローカルのドライブのファイル数の累計" - remote-drive-files-total: "リモートのドライブのファイル数の累計" + charts: + notes: "投稿の増減 (統合)" + local-notes: "投稿の増減 (ローカル)" + remote-notes: "投稿の増減 (リモート)" + notes-total: "投稿の累計" + users: "ユーザーの増減" + users-total: "ユーザーの累計" + drive: "ドライブ使用量の増減" + drive-total: "ドライブ使用量の累計" + drive-files: "ドライブのファイル数の増減" + drive-files-total: "ドライブのファイル数の累計" desktop/views/pages/deck/deck.tl-column.vue: is-media-only: "メディア投稿のみ" diff --git a/src/client/app/desktop/views/pages/admin/admin.chart.vue b/src/client/app/desktop/views/pages/admin/admin.chart.vue index 4301f9978b..89e61d4c74 100644 --- a/src/client/app/desktop/views/pages/admin/admin.chart.vue +++ b/src/client/app/desktop/views/pages/admin/admin.chart.vue @@ -4,30 +4,24 @@ %i18n:@title%:
    - %i18n:@per-day% | %i18n:@per-hour% + %i18n:@per-day% | %i18n:@per-hour%
    @@ -47,7 +41,7 @@ export default Vue.extend({ data() { return { chart: null, - chartType: 'local-notes', + chartType: 'notes', span: 'hour' }; }, @@ -55,22 +49,16 @@ export default Vue.extend({ data(): any { if (this.chart == null) return null; switch (this.chartType) { - case 'local-users': return this.usersChart(true, false); - case 'remote-users': return this.usersChart(false, false); - case 'local-users-total': return this.usersChart(true, true); - case 'remote-users-total': return this.usersChart(false, true); - case 'local-notes': return this.notesChart(true); - case 'remote-notes': return this.notesChart(false); - case 'local-notes-total': return this.notesTotalChart(true); - case 'remote-notes-total': return this.notesTotalChart(false); - case 'local-drive': return this.driveChart(true, false); - case 'remote-drive': return this.driveChart(false, false); - case 'local-drive-total': return this.driveChart(true, true); - case 'remote-drive-total': return this.driveChart(false, true); - case 'local-drive-files': return this.driveFilesChart(true, false); - case 'remote-drive-files': return this.driveFilesChart(false, false); - case 'local-drive-files-total': return this.driveFilesChart(true, true); - case 'remote-drive-files-total': return this.driveFilesChart(false, true); + case 'users': return this.usersChart(false); + case 'users-total': return this.usersChart(true); + case 'notes': return this.notesChart('combined'); + case 'local-notes': return this.notesChart('local'); + case 'remote-notes': return this.notesChart('remote'); + case 'notes-total': return this.notesTotalChart(); + case 'drive': return this.driveChart(false); + case 'drive-total': return this.driveChart(true); + case 'drive-files': return this.driveFilesChart(false); + case 'drive-files-total': return this.driveFilesChart(true); } }, stats(): any[] { @@ -87,13 +75,13 @@ export default Vue.extend({ }); }, methods: { - notesChart(local: boolean): any { + notesChart(type: string): any { const data = this.stats.slice().reverse().map(x => ({ date: new Date(x.date), - normal: local ? x.notes.local.diffs.normal : x.notes.remote.diffs.normal, - reply: local ? x.notes.local.diffs.reply : x.notes.remote.diffs.reply, - renote: local ? x.notes.local.diffs.renote : x.notes.remote.diffs.renote, - all: local ? x.notes.local.diff : x.notes.remote.diff + normal: type == 'local' ? x.notes.local.diffs.normal : type == 'remote' ? x.notes.remote.diffs.normal : x.notes.local.diffs.normal + x.notes.remote.diffs.normal, + reply: type == 'local' ? x.notes.local.diffs.reply : type == 'remote' ? x.notes.remote.diffs.reply : x.notes.local.diffs.reply + x.notes.remote.diffs.reply, + renote: type == 'local' ? x.notes.local.diffs.renote : type == 'remote' ? x.notes.remote.diffs.renote : x.notes.local.diffs.renote + x.notes.remote.diffs.renote, + all: type == 'local' ? x.notes.local.diff : type == 'remote' ? x.notes.remote.diff : x.notes.local.diff + x.notes.remote.diff })); return [{ @@ -107,14 +95,14 @@ export default Vue.extend({ lineTension: 0, data: data.map(x => ({ t: x.date, y: x.all })) }, { - label: 'Normal', + label: 'Renotes', fill: true, - backgroundColor: 'rgba(65, 221, 222, 0.1)', - borderColor: '#41ddde', + backgroundColor: 'rgba(161, 222, 65, 0.1)', + borderColor: '#a1de41', borderWidth: 2, pointBackgroundColor: '#fff', lineTension: 0, - data: data.map(x => ({ t: x.date, y: x.normal })) + data: data.map(x => ({ t: x.date, y: x.renote })) }, { label: 'Replies', fill: true, @@ -125,78 +113,185 @@ export default Vue.extend({ lineTension: 0, data: data.map(x => ({ t: x.date, y: x.reply })) }, { - label: 'Renotes', + label: 'Normal', fill: true, - backgroundColor: 'rgba(161, 222, 65, 0.1)', - borderColor: '#a1de41', + backgroundColor: 'rgba(65, 221, 222, 0.1)', + borderColor: '#41ddde', borderWidth: 2, pointBackgroundColor: '#fff', lineTension: 0, - data: data.map(x => ({ t: x.date, y: x.renote })) + data: data.map(x => ({ t: x.date, y: x.normal })) }] + }, { + scales: { + yAxes: [{ + ticks: { + callback: value => { + return Vue.filter('number')(value); + } + } + }] + }, + tooltips: { + callbacks: { + label: (tooltipItem, data) => { + const label = data.datasets[tooltipItem.datasetIndex].label || ''; + return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`; + } + } + } }]; }, - notesTotalChart(local: boolean): any { + notesTotalChart(): any { const data = this.stats.slice().reverse().map(x => ({ date: new Date(x.date), - count: local ? x.notes.local.total : x.notes.remote.total, + localCount: x.notes.local.total, + remoteCount: x.notes.remote.total })); return [{ datasets: [{ - label: local ? 'Local Notes' : 'Remote Notes', + label: 'Notes', + fill: false, + borderColor: '#555', + borderWidth: 2, + borderDash: [4, 4], + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.remoteCount + x.localCount })) + }, { + label: 'Remote Notes', + fill: true, + backgroundColor: 'rgba(65, 221, 222, 0.1)', + borderColor: '#41ddde', + borderWidth: 2, + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.remoteCount })) + }, { + label: 'Local Notes', fill: true, backgroundColor: 'rgba(246, 88, 79, 0.1)', borderColor: '#f6584f', borderWidth: 2, pointBackgroundColor: '#fff', lineTension: 0, - data: data.map(x => ({ t: x.date, y: x.count })) + data: data.map(x => ({ t: x.date, y: x.localCount })) }] + }, { + scales: { + yAxes: [{ + ticks: { + callback: value => { + return Vue.filter('number')(value); + } + } + }] + }, + tooltips: { + callbacks: { + label: (tooltipItem, data) => { + const label = data.datasets[tooltipItem.datasetIndex].label || ''; + return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`; + } + } + } }]; }, - usersChart(local: boolean, total: boolean): any { + usersChart(total: boolean): any { const data = this.stats.slice().reverse().map(x => ({ date: new Date(x.date), - count: local ? - total ? x.users.local.total : x.users.local.diff : - total ? x.users.remote.total : x.users.remote.diff + localCount: total ? x.users.local.total : x.users.local.diff, + remoteCount: total ? x.users.remote.total : x.users.remote.diff })); return [{ datasets: [{ - label: local ? 'Local Users' : 'Remote Users', + label: 'Users', + fill: false, + borderColor: '#555', + borderWidth: 2, + borderDash: [4, 4], + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.remoteCount + x.localCount })) + }, { + label: 'Remote Users', + fill: true, + backgroundColor: 'rgba(65, 221, 222, 0.1)', + borderColor: '#41ddde', + borderWidth: 2, + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.remoteCount })) + }, { + label: 'Local Users', fill: true, backgroundColor: 'rgba(246, 88, 79, 0.1)', borderColor: '#f6584f', borderWidth: 2, pointBackgroundColor: '#fff', lineTension: 0, - data: data.map(x => ({ t: x.date, y: x.count })) + data: data.map(x => ({ t: x.date, y: x.localCount })) }] + }, { + scales: { + yAxes: [{ + ticks: { + callback: value => { + return Vue.filter('number')(value); + } + } + }] + }, + tooltips: { + callbacks: { + label: (tooltipItem, data) => { + const label = data.datasets[tooltipItem.datasetIndex].label || ''; + return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`; + } + } + } }]; }, - driveChart(local: boolean, total: boolean): any { + driveChart(total: boolean): any { const data = this.stats.slice().reverse().map(x => ({ date: new Date(x.date), - size: local ? - total ? x.drive.local.totalSize : x.drive.local.diffSize : - total ? x.drive.remote.totalSize : x.drive.remote.diffSize + localSize: total ? x.drive.local.totalSize : x.drive.local.diffSize, + remoteSize: total ? x.drive.remote.totalSize : x.drive.remote.diffSize })); return [{ datasets: [{ - label: local ? 'Local Drive Usage' : 'Remote Drive Usage', + label: 'Drive Usage', + fill: false, + borderColor: '#555', + borderWidth: 2, + borderDash: [4, 4], + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.remoteSize + x.localSize })) + }, { + label: 'Remote Drive Usage', + fill: true, + backgroundColor: 'rgba(65, 221, 222, 0.1)', + borderColor: '#41ddde', + borderWidth: 2, + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.remoteSize })) + }, { + label: 'Local Drive Usage', fill: true, backgroundColor: 'rgba(246, 88, 79, 0.1)', borderColor: '#f6584f', borderWidth: 2, pointBackgroundColor: '#fff', lineTension: 0, - data: data.map(x => ({ t: x.date, y: x.size })) + data: data.map(x => ({ t: x.date, y: x.localSize })) }] }, { scales: { @@ -210,35 +305,71 @@ export default Vue.extend({ }, tooltips: { callbacks: { - label: tooltipItem => { - return Vue.filter('bytes')(tooltipItem.yLabel); + label: (tooltipItem, data) => { + const label = data.datasets[tooltipItem.datasetIndex].label || ''; + return `${label}: ${Vue.filter('bytes')(tooltipItem.yLabel)}`; } } } }]; }, - driveFilesChart(local: boolean, total: boolean): any { + driveFilesChart(total: boolean): any { const data = this.stats.slice().reverse().map(x => ({ date: new Date(x.date), - count: local ? - total ? x.drive.local.totalCount : x.drive.local.diffCount : - total ? x.drive.remote.totalCount : x.drive.remote.diffCount + localCount: total ? x.drive.local.totalCount : x.drive.local.diffCount, + remoteCount: total ? x.drive.remote.totalCount : x.drive.remote.diffCount })); return [{ datasets: [{ - label: local ? 'Local Drive Files' : 'Remote Drive Files', + label: 'Drive Files', + fill: false, + borderColor: '#555', + borderWidth: 2, + borderDash: [4, 4], + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.remoteCount + x.localCount })) + }, { + label: 'Remote Drive Files', + fill: true, + backgroundColor: 'rgba(65, 221, 222, 0.1)', + borderColor: '#41ddde', + borderWidth: 2, + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.remoteCount })) + }, { + label: 'Local Drive Files', fill: true, backgroundColor: 'rgba(246, 88, 79, 0.1)', borderColor: '#f6584f', borderWidth: 2, pointBackgroundColor: '#fff', lineTension: 0, - data: data.map(x => ({ t: x.date, y: x.count })) + data: data.map(x => ({ t: x.date, y: x.localCount })) }] + }, { + scales: { + yAxes: [{ + ticks: { + callback: value => { + return Vue.filter('number')(value); + } + } + }] + }, + tooltips: { + callbacks: { + label: (tooltipItem, data) => { + const label = data.datasets[tooltipItem.datasetIndex].label || ''; + return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`; + } + } + } }]; - }, + } } }); @@ -259,6 +390,11 @@ export default Vue.extend({ > *:last-child margin-left auto + * + &:not(.active) + color $theme-color + cursor pointer + > div > * display block diff --git a/src/server/api/endpoints/chart.ts b/src/server/api/endpoints/chart.ts index a58f0b163e..da3476f067 100644 --- a/src/server/api/endpoints/chart.ts +++ b/src/server/api/endpoints/chart.ts @@ -6,8 +6,8 @@ export const meta = { }; export default (params: any) => new Promise(async (res, rej) => { - const daysRange = 90; - const hoursRange = 24; + const daysRange = 30; + const hoursRange = 30; const now = new Date(); const y = now.getFullYear(); @@ -65,9 +65,53 @@ export default (params: any) => new Promise(async (res, rej) => { } else { // 隙間埋め const mostRecent = src.find(s => s.date.getTime() < current.getTime()); if (mostRecent) { - chart.unshift(Object.assign({}, mostRecent, { - date: current - })); + chart.unshift({ + date: current, + users: { + local: { + total: mostRecent.users.local.total, + diff: 0 + }, + remote: { + total: mostRecent.users.remote.total, + diff: 0 + } + }, + notes: { + local: { + total: mostRecent.notes.local.total, + diff: 0, + diffs: { + normal: 0, + reply: 0, + renote: 0 + } + }, + remote: { + total: mostRecent.notes.remote.total, + diff: 0, + diffs: { + normal: 0, + reply: 0, + renote: 0 + } + } + }, + drive: { + local: { + totalCount: mostRecent.drive.local.totalCount, + totalSize: mostRecent.drive.local.totalSize, + diffCount: 0, + diffSize: 0 + }, + remote: { + totalCount: mostRecent.drive.remote.totalCount, + totalSize: mostRecent.drive.remote.totalSize, + diffCount: 0, + diffSize: 0 + } + } + }); } else { chart.unshift({ date: current, -- cgit v1.2.3-freya From 8b51428347932da09e8fb9636a1ccbae0e9df8f6 Mon Sep 17 00:00:00 2001 From: mei23 Date: Sat, 25 Aug 2018 06:50:35 +0900 Subject: ActivityPub resolve で 添付のNoteを使用しないように MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/remote/activitypub/models/note.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/remote/activitypub/models/note.ts b/src/remote/activitypub/models/note.ts index 02bce6fec7..1dfeebfdf7 100644 --- a/src/remote/activitypub/models/note.ts +++ b/src/remote/activitypub/models/note.ts @@ -131,5 +131,7 @@ export async function resolveNote(value: string | IObject, resolver?: Resolver): //#endregion // リモートサーバーからフェッチしてきて登録 - return await createNote(value, resolver); + // ここでuriの代わりに添付されてきたNote Objectが指定されていると、サーバーフェッチを経ずにノートが生成されるが + // 添付されてきたNote Objectは偽装されている可能性があるため、常にuriを指定してサーバーフェッチを行う。 + return await createNote(uri, resolver); } -- cgit v1.2.3-freya From 7b6e55047f0bdf02ba0cafd5b90147737a75b556 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 25 Aug 2018 08:35:41 +0900 Subject: #2460 --- .../app/desktop/views/pages/admin/admin.chart.vue | 206 ++++++++++++++++++--- src/models/stats.ts | 106 ++++++++--- src/server/api/endpoints/chart.ts | 77 ++++++-- src/services/update-chart.ts | 88 +++++---- 4 files changed, 374 insertions(+), 103 deletions(-) (limited to 'src') diff --git a/src/client/app/desktop/views/pages/admin/admin.chart.vue b/src/client/app/desktop/views/pages/admin/admin.chart.vue index 89e61d4c74..4310ce03d6 100644 --- a/src/client/app/desktop/views/pages/admin/admin.chart.vue +++ b/src/client/app/desktop/views/pages/admin/admin.chart.vue @@ -55,10 +55,10 @@ export default Vue.extend({ case 'local-notes': return this.notesChart('local'); case 'remote-notes': return this.notesChart('remote'); case 'notes-total': return this.notesTotalChart(); - case 'drive': return this.driveChart(false); - case 'drive-total': return this.driveChart(true); - case 'drive-files': return this.driveFilesChart(false); - case 'drive-files-total': return this.driveFilesChart(true); + case 'drive': return this.driveChart(); + case 'drive-total': return this.driveTotalChart(); + case 'drive-files': return this.driveFilesChart(); + case 'drive-files-total': return this.driveFilesTotalChart(); } }, stats(): any[] { @@ -81,7 +81,7 @@ export default Vue.extend({ normal: type == 'local' ? x.notes.local.diffs.normal : type == 'remote' ? x.notes.remote.diffs.normal : x.notes.local.diffs.normal + x.notes.remote.diffs.normal, reply: type == 'local' ? x.notes.local.diffs.reply : type == 'remote' ? x.notes.remote.diffs.reply : x.notes.local.diffs.reply + x.notes.remote.diffs.reply, renote: type == 'local' ? x.notes.local.diffs.renote : type == 'remote' ? x.notes.remote.diffs.renote : x.notes.local.diffs.renote + x.notes.remote.diffs.renote, - all: type == 'local' ? x.notes.local.diff : type == 'remote' ? x.notes.remote.diff : x.notes.local.diff + x.notes.remote.diff + all: type == 'local' ? (x.notes.local.inc + -x.notes.local.dec) : type == 'remote' ? (x.notes.remote.inc + -x.notes.remote.dec) : (x.notes.local.inc + -x.notes.local.dec) + (x.notes.remote.inc + -x.notes.remote.dec) })); return [{ @@ -152,7 +152,7 @@ export default Vue.extend({ return [{ datasets: [{ - label: 'Notes', + label: 'Combined', fill: false, borderColor: '#555', borderWidth: 2, @@ -161,7 +161,7 @@ export default Vue.extend({ lineTension: 0, data: data.map(x => ({ t: x.date, y: x.remoteCount + x.localCount })) }, { - label: 'Remote Notes', + label: 'Remote', fill: true, backgroundColor: 'rgba(65, 221, 222, 0.1)', borderColor: '#41ddde', @@ -170,7 +170,7 @@ export default Vue.extend({ lineTension: 0, data: data.map(x => ({ t: x.date, y: x.remoteCount })) }, { - label: 'Local Notes', + label: 'Local', fill: true, backgroundColor: 'rgba(246, 88, 79, 0.1)', borderColor: '#f6584f', @@ -203,13 +203,13 @@ export default Vue.extend({ usersChart(total: boolean): any { const data = this.stats.slice().reverse().map(x => ({ date: new Date(x.date), - localCount: total ? x.users.local.total : x.users.local.diff, - remoteCount: total ? x.users.remote.total : x.users.remote.diff + localCount: total ? x.users.local.total : (x.users.local.inc + -x.users.local.dec), + remoteCount: total ? x.users.remote.total : (x.users.remote.inc + -x.users.remote.dec) })); return [{ datasets: [{ - label: 'Users', + label: 'Combined', fill: false, borderColor: '#555', borderWidth: 2, @@ -218,7 +218,7 @@ export default Vue.extend({ lineTension: 0, data: data.map(x => ({ t: x.date, y: x.remoteCount + x.localCount })) }, { - label: 'Remote Users', + label: 'Remote', fill: true, backgroundColor: 'rgba(65, 221, 222, 0.1)', borderColor: '#41ddde', @@ -227,7 +227,7 @@ export default Vue.extend({ lineTension: 0, data: data.map(x => ({ t: x.date, y: x.remoteCount })) }, { - label: 'Local Users', + label: 'Local', fill: true, backgroundColor: 'rgba(246, 88, 79, 0.1)', borderColor: '#f6584f', @@ -257,16 +257,93 @@ export default Vue.extend({ }]; }, - driveChart(total: boolean): any { + driveChart(): any { const data = this.stats.slice().reverse().map(x => ({ date: new Date(x.date), - localSize: total ? x.drive.local.totalSize : x.drive.local.diffSize, - remoteSize: total ? x.drive.remote.totalSize : x.drive.remote.diffSize + localInc: x.drive.local.incSize, + localDec: -x.drive.local.decSize, + remoteInc: x.drive.remote.incSize, + remoteDec: -x.drive.remote.decSize, })); return [{ datasets: [{ - label: 'Drive Usage', + label: 'All', + fill: false, + borderColor: '#555', + borderWidth: 2, + borderDash: [4, 4], + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.localInc + x.localDec + x.remoteInc + x.remoteDec })) + }, { + label: 'Remote +', + fill: true, + backgroundColor: 'rgba(65, 221, 222, 0.1)', + borderColor: '#41ddde', + borderWidth: 2, + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.remoteInc })) + }, { + label: 'Remote -', + fill: true, + backgroundColor: 'rgba(65, 221, 222, 0.1)', + borderColor: '#41ddde', + borderWidth: 2, + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.remoteDec })) + }, { + label: 'Local +', + fill: true, + backgroundColor: 'rgba(246, 88, 79, 0.1)', + borderColor: '#f6584f', + borderWidth: 2, + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.localInc })) + }, { + label: 'Local -', + fill: true, + backgroundColor: 'rgba(246, 88, 79, 0.1)', + borderColor: '#f6584f', + borderWidth: 2, + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.localDec })) + }] + }, { + scales: { + yAxes: [{ + ticks: { + callback: value => { + return Vue.filter('bytes')(value); + } + } + }] + }, + tooltips: { + callbacks: { + label: (tooltipItem, data) => { + const label = data.datasets[tooltipItem.datasetIndex].label || ''; + return `${label}: ${Vue.filter('bytes')(tooltipItem.yLabel)}`; + } + } + } + }]; + }, + + driveTotalChart(): any { + const data = this.stats.slice().reverse().map(x => ({ + date: new Date(x.date), + localSize: x.drive.local.totalSize, + remoteSize: x.drive.remote.totalSize + })); + + return [{ + datasets: [{ + label: 'Combined', fill: false, borderColor: '#555', borderWidth: 2, @@ -275,7 +352,7 @@ export default Vue.extend({ lineTension: 0, data: data.map(x => ({ t: x.date, y: x.remoteSize + x.localSize })) }, { - label: 'Remote Drive Usage', + label: 'Remote', fill: true, backgroundColor: 'rgba(65, 221, 222, 0.1)', borderColor: '#41ddde', @@ -284,7 +361,7 @@ export default Vue.extend({ lineTension: 0, data: data.map(x => ({ t: x.date, y: x.remoteSize })) }, { - label: 'Local Drive Usage', + label: 'Local', fill: true, backgroundColor: 'rgba(246, 88, 79, 0.1)', borderColor: '#f6584f', @@ -314,25 +391,102 @@ export default Vue.extend({ }]; }, - driveFilesChart(total: boolean): any { + driveFilesChart(): any { const data = this.stats.slice().reverse().map(x => ({ date: new Date(x.date), - localCount: total ? x.drive.local.totalCount : x.drive.local.diffCount, - remoteCount: total ? x.drive.remote.totalCount : x.drive.remote.diffCount + localInc: x.drive.local.incCount, + localDec: -x.drive.local.decCount, + remoteInc: x.drive.remote.incCount, + remoteDec: -x.drive.remote.decCount })); return [{ datasets: [{ - label: 'Drive Files', + label: 'All', fill: false, borderColor: '#555', borderWidth: 2, borderDash: [4, 4], pointBackgroundColor: '#fff', lineTension: 0, - data: data.map(x => ({ t: x.date, y: x.remoteCount + x.localCount })) + data: data.map(x => ({ t: x.date, y: x.localInc + x.localDec + x.remoteInc + x.remoteDec })) + }, { + label: 'Remote +', + fill: true, + backgroundColor: 'rgba(65, 221, 222, 0.1)', + borderColor: '#41ddde', + borderWidth: 2, + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.remoteInc })) + }, { + label: 'Remote -', + fill: true, + backgroundColor: 'rgba(65, 221, 222, 0.1)', + borderColor: '#41ddde', + borderWidth: 2, + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.remoteDec })) + }, { + label: 'Local +', + fill: true, + backgroundColor: 'rgba(246, 88, 79, 0.1)', + borderColor: '#f6584f', + borderWidth: 2, + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.localInc })) + }, { + label: 'Local -', + fill: true, + backgroundColor: 'rgba(246, 88, 79, 0.1)', + borderColor: '#f6584f', + borderWidth: 2, + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.localDec })) + }] + }, { + scales: { + yAxes: [{ + ticks: { + callback: value => { + return Vue.filter('number')(value); + } + } + }] + }, + tooltips: { + callbacks: { + label: (tooltipItem, data) => { + const label = data.datasets[tooltipItem.datasetIndex].label || ''; + return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`; + } + } + } + }]; + }, + + driveFilesTotalChart(): any { + const data = this.stats.slice().reverse().map(x => ({ + date: new Date(x.date), + localCount: x.drive.local.totalCount, + remoteCount: x.drive.remote.totalCount, + })); + + return [{ + datasets: [{ + label: 'Combined', + fill: false, + borderColor: '#555', + borderWidth: 2, + borderDash: [4, 4], + pointBackgroundColor: '#fff', + lineTension: 0, + data: data.map(x => ({ t: x.date, y: x.localCount + x.remoteCount })) }, { - label: 'Remote Drive Files', + label: 'Remote', fill: true, backgroundColor: 'rgba(65, 221, 222, 0.1)', borderColor: '#41ddde', @@ -341,7 +495,7 @@ export default Vue.extend({ lineTension: 0, data: data.map(x => ({ t: x.date, y: x.remoteCount })) }, { - label: 'Local Drive Files', + label: 'Local', fill: true, backgroundColor: 'rgba(246, 88, 79, 0.1)', borderColor: '#f6584f', diff --git a/src/models/stats.ts b/src/models/stats.ts index c481c3196e..3041d3852b 100644 --- a/src/models/stats.ts +++ b/src/models/stats.ts @@ -8,8 +8,14 @@ export default Stats; export interface IStats { _id: mongo.ObjectID; + /** + * 集計日時 + */ date: Date; + /** + * 集計期間 + */ span: 'day' | 'hour'; /** @@ -18,26 +24,36 @@ export interface IStats { users: { local: { /** - * この日時点での、ローカルのユーザーの総計 + * 集計期間時点での、全ユーザー数 (ローカル) */ total: number; /** - * ローカルのユーザー数の前日比 + * 増加したユーザー数 (ローカル) + */ + inc: number; + + /** + * 減少したユーザー数 (ローカル) */ - diff: number; + dec: number; }; remote: { /** - * この日時点での、リモートのユーザーの総計 + * 集計期間時点での、全ユーザー数 (リモート) */ total: number; /** - * リモートのユーザー数の前日比 + * 増加したユーザー数 (リモート) */ - diff: number; + inc: number; + + /** + * 減少したユーザー数 (リモート) + */ + dec: number; }; }; @@ -47,28 +63,33 @@ export interface IStats { notes: { local: { /** - * この日時点での、ローカルの投稿の総計 + * 集計期間時点での、全投稿数 (ローカル) */ total: number; /** - * ローカルの投稿数の前日比 + * 増加した投稿数 (ローカル) */ - diff: number; + inc: number; + + /** + * 減少した投稿数 (ローカル) + */ + dec: number; diffs: { /** - * ローカルの通常の投稿数の前日比 + * 通常の投稿数の差分 (ローカル) */ normal: number; /** - * ローカルのリプライの投稿数の前日比 + * リプライの投稿数の差分 (ローカル) */ reply: number; /** - * ローカルのRenoteの投稿数の前日比 + * Renoteの投稿数の差分 (ローカル) */ renote: number; }; @@ -76,28 +97,33 @@ export interface IStats { remote: { /** - * この日時点での、リモートの投稿の総計 + * 集計期間時点での、全投稿数 (リモート) */ total: number; /** - * リモートの投稿数の前日比 + * 増加した投稿数 (リモート) + */ + inc: number; + + /** + * 減少した投稿数 (リモート) */ - diff: number; + dec: number; diffs: { /** - * リモートの通常の投稿数の前日比 + * 通常の投稿数の差分 (リモート) */ normal: number; /** - * リモートのリプライの投稿数の前日比 + * リプライの投稿数の差分 (リモート) */ reply: number; /** - * リモートのRenoteの投稿数の前日比 + * Renoteの投稿数の差分 (リモート) */ renote: number; }; @@ -110,46 +136,66 @@ export interface IStats { drive: { local: { /** - * この日時点での、ローカルのドライブファイル数の総計 + * 集計期間時点での、全ドライブファイル数 (ローカル) */ totalCount: number; /** - * この日時点での、ローカルのドライブファイルサイズの総計 + * 集計期間時点での、全ドライブファイルの合計サイズ (ローカル) */ totalSize: number; /** - * ローカルのドライブファイル数の前日比 + * 増加したドライブファイル数 (ローカル) + */ + incCount: number; + + /** + * 増加したドライブ使用量 (ローカル) + */ + incSize: number; + + /** + * 減少したドライブファイル数 (ローカル) */ - diffCount: number; + decCount: number; /** - * ローカルのドライブファイルサイズの前日比 + * 減少したドライブ使用量 (ローカル) */ - diffSize: number; + decSize: number; }; remote: { /** - * この日時点での、リモートのドライブファイル数の総計 + * 集計期間時点での、全ドライブファイル数 (リモート) */ totalCount: number; /** - * この日時点での、リモートのドライブファイルサイズの総計 + * 集計期間時点での、全ドライブファイルの合計サイズ (リモート) */ totalSize: number; /** - * リモートのドライブファイル数の前日比 + * 増加したドライブファイル数 (リモート) + */ + incCount: number; + + /** + * 増加したドライブ使用量 (リモート) + */ + incSize: number; + + /** + * 減少したドライブファイル数 (リモート) */ - diffCount: number; + decCount: number; /** - * リモートのドライブファイルサイズの前日比 + * 減少したドライブ使用量 (リモート) */ - diffSize: number; + decSize: number; }; }; } diff --git a/src/server/api/endpoints/chart.ts b/src/server/api/endpoints/chart.ts index da3476f067..514bacaa84 100644 --- a/src/server/api/endpoints/chart.ts +++ b/src/server/api/endpoints/chart.ts @@ -2,6 +2,31 @@ import Stats, { IStats } from '../../../models/stats'; type Omit = Pick>; +function migrateStats(stats: IStats[]) { + stats.forEach(stat => { + const isOldData = stat.users.local.inc == null; + + if (!isOldData) return; + + stat.users.local.inc = (stat as any).users.local.diff; + stat.users.local.dec = 0; + stat.users.remote.inc = (stat as any).users.remote.diff; + stat.users.remote.dec = 0; + stat.notes.local.inc = (stat as any).notes.local.diff; + stat.notes.local.dec = 0; + stat.notes.remote.inc = (stat as any).notes.remote.diff; + stat.notes.remote.dec = 0; + stat.drive.local.incCount = (stat as any).drive.local.diffCount; + stat.drive.local.decCount = 0; + stat.drive.local.incSize = (stat as any).drive.local.diffSize; + stat.drive.local.decSize = 0; + stat.drive.remote.incCount = (stat as any).drive.remote.diffCount; + stat.drive.remote.decCount = 0; + stat.drive.remote.incSize = (stat as any).drive.remote.diffSize; + stat.drive.remote.decSize = 0; + }); +} + export const meta = { }; @@ -44,6 +69,10 @@ export default (params: any) => new Promise(async (res, rej) => { }), ]); + // 後方互換性のため + migrateStats(statsPerDay); + migrateStats(statsPerHour); + const format = (src: IStats[], span: 'day' | 'hour') => { const chart: Array, 'span'>> = []; @@ -70,17 +99,20 @@ export default (params: any) => new Promise(async (res, rej) => { users: { local: { total: mostRecent.users.local.total, - diff: 0 + inc: 0, + dec: 0 }, remote: { total: mostRecent.users.remote.total, - diff: 0 + inc: 0, + dec: 0 } }, notes: { local: { total: mostRecent.notes.local.total, - diff: 0, + inc: 0, + dec: 0, diffs: { normal: 0, reply: 0, @@ -89,7 +121,8 @@ export default (params: any) => new Promise(async (res, rej) => { }, remote: { total: mostRecent.notes.remote.total, - diff: 0, + inc: 0, + dec: 0, diffs: { normal: 0, reply: 0, @@ -101,14 +134,18 @@ export default (params: any) => new Promise(async (res, rej) => { local: { totalCount: mostRecent.drive.local.totalCount, totalSize: mostRecent.drive.local.totalSize, - diffCount: 0, - diffSize: 0 + incCount: 0, + incSize: 0, + decCount: 0, + decSize: 0 }, remote: { totalCount: mostRecent.drive.remote.totalCount, totalSize: mostRecent.drive.remote.totalSize, - diffCount: 0, - diffSize: 0 + incCount: 0, + incSize: 0, + decCount: 0, + decSize: 0 } } }); @@ -118,17 +155,20 @@ export default (params: any) => new Promise(async (res, rej) => { users: { local: { total: 0, - diff: 0 + inc: 0, + dec: 0 }, remote: { total: 0, - diff: 0 + inc: 0, + dec: 0 } }, notes: { local: { total: 0, - diff: 0, + inc: 0, + dec: 0, diffs: { normal: 0, reply: 0, @@ -137,7 +177,8 @@ export default (params: any) => new Promise(async (res, rej) => { }, remote: { total: 0, - diff: 0, + inc: 0, + dec: 0, diffs: { normal: 0, reply: 0, @@ -149,14 +190,18 @@ export default (params: any) => new Promise(async (res, rej) => { local: { totalCount: 0, totalSize: 0, - diffCount: 0, - diffSize: 0 + incCount: 0, + incSize: 0, + decCount: 0, + decSize: 0 }, remote: { totalCount: 0, totalSize: 0, - diffCount: 0, - diffSize: 0 + incCount: 0, + incSize: 0, + decCount: 0, + decSize: 0 } } }); diff --git a/src/services/update-chart.ts b/src/services/update-chart.ts index 0a0f58bb92..1f8da6be9f 100644 --- a/src/services/update-chart.ts +++ b/src/services/update-chart.ts @@ -48,17 +48,20 @@ async function getCurrentStats(span: 'day' | 'hour'): Promise { users: { local: { total: mostRecentStats.users.local.total, - diff: 0 + inc: 0, + dec: 0 }, remote: { total: mostRecentStats.users.remote.total, - diff: 0 + inc: 0, + dec: 0 } }, notes: { local: { total: mostRecentStats.notes.local.total, - diff: 0, + inc: 0, + dec: 0, diffs: { normal: 0, reply: 0, @@ -67,7 +70,8 @@ async function getCurrentStats(span: 'day' | 'hour'): Promise { }, remote: { total: mostRecentStats.notes.remote.total, - diff: 0, + inc: 0, + dec: 0, diffs: { normal: 0, reply: 0, @@ -79,14 +83,18 @@ async function getCurrentStats(span: 'day' | 'hour'): Promise { local: { totalCount: mostRecentStats.drive.local.totalCount, totalSize: mostRecentStats.drive.local.totalSize, - diffCount: 0, - diffSize: 0 + incCount: 0, + incSize: 0, + decCount: 0, + decSize: 0 }, remote: { totalCount: mostRecentStats.drive.remote.totalCount, totalSize: mostRecentStats.drive.remote.totalSize, - diffCount: 0, - diffSize: 0 + incCount: 0, + incSize: 0, + decCount: 0, + decSize: 0 } } }; @@ -105,17 +113,20 @@ async function getCurrentStats(span: 'day' | 'hour'): Promise { users: { local: { total: 0, - diff: 0 + inc: 0, + dec: 0 }, remote: { total: 0, - diff: 0 + inc: 0, + dec: 0 } }, notes: { local: { total: 0, - diff: 0, + inc: 0, + dec: 0, diffs: { normal: 0, reply: 0, @@ -124,7 +135,8 @@ async function getCurrentStats(span: 'day' | 'hour'): Promise { }, remote: { total: 0, - diff: 0, + inc: 0, + dec: 0, diffs: { normal: 0, reply: 0, @@ -136,14 +148,18 @@ async function getCurrentStats(span: 'day' | 'hour'): Promise { local: { totalCount: 0, totalSize: 0, - diffCount: 0, - diffSize: 0 + incCount: 0, + incSize: 0, + decCount: 0, + decSize: 0 }, remote: { totalCount: 0, totalSize: 0, - diffCount: 0, - diffSize: 0 + incCount: 0, + incSize: 0, + decCount: 0, + decSize: 0 } } }; @@ -174,46 +190,56 @@ function update(inc: any) { } export async function updateUserStats(user: IUser, isAdditional: boolean) { - const amount = isAdditional ? 1 : -1; const origin = isLocalUser(user) ? 'local' : 'remote'; const inc = {} as any; - inc[`users.${origin}.total`] = amount; - inc[`users.${origin}.diff`] = amount; + inc[`users.${origin}.total`] = isAdditional ? 1 : -1; + if (isAdditional) { + inc[`users.${origin}.inc`] = 1; + } else { + inc[`users.${origin}.dec`] = 1; + } await update(inc); } export async function updateNoteStats(note: INote, isAdditional: boolean) { - const amount = isAdditional ? 1 : -1; const origin = isLocalUser(note._user) ? 'local' : 'remote'; const inc = {} as any; - inc[`notes.${origin}.total`] = amount; - inc[`notes.${origin}.diff`] = amount; + inc[`notes.${origin}.total`] = isAdditional ? 1 : -1; + + if (isAdditional) { + inc[`notes.${origin}.inc`] = 1; + } else { + inc[`notes.${origin}.dec`] = 1; + } if (note.replyId != null) { - inc[`notes.${origin}.diffs.reply`] = amount; + inc[`notes.${origin}.diffs.reply`] = isAdditional ? 1 : -1; } else if (note.renoteId != null) { - inc[`notes.${origin}.diffs.renote`] = amount; + inc[`notes.${origin}.diffs.renote`] = isAdditional ? 1 : -1; } else { - inc[`notes.${origin}.diffs.normal`] = amount; + inc[`notes.${origin}.diffs.normal`] = isAdditional ? 1 : -1; } await update(inc); } export async function updateDriveStats(file: IDriveFile, isAdditional: boolean) { - const amount = isAdditional ? 1 : -1; - const size = isAdditional ? file.length : -file.length; const origin = isLocalUser(file.metadata._user) ? 'local' : 'remote'; const inc = {} as any; - inc[`drive.${origin}.totalCount`] = amount; - inc[`drive.${origin}.diffCount`] = amount; - inc[`drive.${origin}.totalSize`] = size; - inc[`drive.${origin}.diffSize`] = size; + inc[`drive.${origin}.totalCount`] = isAdditional ? 1 : -1; + inc[`drive.${origin}.totalSize`] = isAdditional ? file.length : -file.length; + if (isAdditional) { + inc[`drive.${origin}.incCount`] = 1; + inc[`drive.${origin}.incSize`] = file.length; + } else { + inc[`drive.${origin}.decCount`] = 1; + inc[`drive.${origin}.decSize`] = file.length; + } await update(inc); } -- cgit v1.2.3-freya From 88c71c2998f257646586b8dcfe4b427e08dd2e80 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 25 Aug 2018 08:39:12 +0900 Subject: #2451 --- src/client/app/desktop/script.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/app/desktop/script.ts b/src/client/app/desktop/script.ts index 8dc0482191..7f4a2d0b00 100644 --- a/src/client/app/desktop/script.ts +++ b/src/client/app/desktop/script.ts @@ -94,7 +94,7 @@ init(async (launch) => { /** * Init Notification */ - if ('Notification' in window) { + if ('Notification' in window && os.store.getters.isSignedIn) { // 許可を得ていなかったらリクエスト if ((Notification as any).permission == 'default') { await Notification.requestPermission(); -- cgit v1.2.3-freya From 4e8033d5a40f0908b37bf679b0cd823d0393459f Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 25 Aug 2018 10:28:09 +0900 Subject: Fix bug --- src/services/drive/add-file.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/services/drive/add-file.ts b/src/services/drive/add-file.ts index a60d1acbbe..1da0f49a24 100644 --- a/src/services/drive/add-file.ts +++ b/src/services/drive/add-file.ts @@ -116,7 +116,8 @@ async function deleteOldFile(user: IRemoteUser) { const oldFile = await DriveFile.findOne({ _id: { $nin: [user.avatarId, user.bannerId] - } + }, + 'metadata.userId': user._id }, { sort: { _id: 1 -- cgit v1.2.3-freya From ef57f5907b115b8047e798f7486bb9ee73d465aa Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 25 Aug 2018 11:10:27 +0900 Subject: Fix bug --- src/server/api/endpoints/chart.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/api/endpoints/chart.ts b/src/server/api/endpoints/chart.ts index 514bacaa84..406ad39946 100644 --- a/src/server/api/endpoints/chart.ts +++ b/src/server/api/endpoints/chart.ts @@ -4,7 +4,23 @@ type Omit = Pick>; function migrateStats(stats: IStats[]) { stats.forEach(stat => { - const isOldData = stat.users.local.inc == null; + const isOldData = + stat.users.local.inc == null || + stat.users.local.dec == null || + stat.users.remote.inc == null || + stat.users.remote.dec == null || + stat.notes.local.inc == null || + stat.notes.local.dec == null || + stat.notes.remote.inc == null || + stat.notes.remote.dec == null || + stat.drive.local.incCount == null || + stat.drive.local.decCount == null || + stat.drive.local.incSize == null || + stat.drive.local.decSize == null || + stat.drive.remote.incCount == null || + stat.drive.remote.decCount == null || + stat.drive.remote.incSize == null || + stat.drive.remote.decSize == null; if (!isOldData) return; -- cgit v1.2.3-freya From 1c1e3009e9fe6263ac074629b0d7d753c78d0c8f Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 25 Aug 2018 12:14:36 +0900 Subject: :v: --- src/client/app/desktop/views/pages/admin/admin.chart.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/app/desktop/views/pages/admin/admin.chart.vue b/src/client/app/desktop/views/pages/admin/admin.chart.vue index 4310ce03d6..cca05fec28 100644 --- a/src/client/app/desktop/views/pages/admin/admin.chart.vue +++ b/src/client/app/desktop/views/pages/admin/admin.chart.vue @@ -318,7 +318,7 @@ export default Vue.extend({ yAxes: [{ ticks: { callback: value => { - return Vue.filter('bytes')(value); + return Vue.filter('bytes')(value, 1); } } }] @@ -327,7 +327,7 @@ export default Vue.extend({ callbacks: { label: (tooltipItem, data) => { const label = data.datasets[tooltipItem.datasetIndex].label || ''; - return `${label}: ${Vue.filter('bytes')(tooltipItem.yLabel)}`; + return `${label}: ${Vue.filter('bytes')(tooltipItem.yLabel, 1)}`; } } } -- cgit v1.2.3-freya From 47a5f3bc67adb4e95f027e5aa2d14b5a8bb6c697 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 25 Aug 2018 12:28:05 +0900 Subject: チャートコンポーネントを分離するなど MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/ja-JP.yml | 38 +- src/client/app/desktop/script.ts | 2 + .../app/desktop/views/components/charts.chart.ts | 42 ++ src/client/app/desktop/views/components/charts.vue | 566 +++++++++++++++++++++ .../desktop/views/pages/admin/admin.chart.chart.ts | 42 -- .../app/desktop/views/pages/admin/admin.chart.vue | 557 -------------------- src/client/app/desktop/views/pages/admin/admin.vue | 9 +- src/client/app/desktop/views/pages/stats/stats.vue | 29 ++ 8 files changed, 662 insertions(+), 623 deletions(-) create mode 100644 src/client/app/desktop/views/components/charts.chart.ts create mode 100644 src/client/app/desktop/views/components/charts.vue delete mode 100644 src/client/app/desktop/views/pages/admin/admin.chart.chart.ts delete mode 100644 src/client/app/desktop/views/pages/admin/admin.chart.vue create mode 100644 src/client/app/desktop/views/pages/stats/stats.vue (limited to 'src') diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index c44254439c..fae257480c 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -473,6 +473,25 @@ desktop/views/components/calendar.vue: next: "次の月" go: "クリックして時間遡行" +desktop/views/components/charts.vue: + title: "チャート" + per-day: "1日ごと" + per-hour: "1時間ごと" + notes: "投稿" + users: "ユーザー" + drive: "ドライブ" + charts: + notes: "投稿の増減 (統合)" + local-notes: "投稿の増減 (ローカル)" + remote-notes: "投稿の増減 (リモート)" + notes-total: "投稿の累計" + users: "ユーザーの増減" + users-total: "ユーザーの累計" + drive: "ドライブ使用量の増減" + drive-total: "ドライブ使用量の累計" + drive-files: "ドライブのファイル数の増減" + drive-files-total: "ドライブのファイル数の累計" + desktop/views/components/choose-file-from-drive-window.vue: choose-file: "ファイル選択中" upload: "PCからドライブにファイルをアップロード" @@ -939,25 +958,6 @@ desktop/views/pages/admin/admin.unverify-user.vue: unverify: "公式アカウントを解除する" unverified: "公式アカウントを解除しました" -desktop/views/pages/admin/admin.chart.vue: - title: "チャート" - per-day: "1日ごと" - per-hour: "1時間ごと" - notes: "投稿" - users: "ユーザー" - drive: "ドライブ" - charts: - notes: "投稿の増減 (統合)" - local-notes: "投稿の増減 (ローカル)" - remote-notes: "投稿の増減 (リモート)" - notes-total: "投稿の累計" - users: "ユーザーの増減" - users-total: "ユーザーの累計" - drive: "ドライブ使用量の増減" - drive-total: "ドライブ使用量の累計" - drive-files: "ドライブのファイル数の増減" - drive-files-total: "ドライブのファイル数の累計" - desktop/views/pages/deck/deck.tl-column.vue: is-media-only: "メディア投稿のみ" is-media-view: "メディアビュー" diff --git a/src/client/app/desktop/script.ts b/src/client/app/desktop/script.ts index 7f4a2d0b00..f0e8a42662 100644 --- a/src/client/app/desktop/script.ts +++ b/src/client/app/desktop/script.ts @@ -25,6 +25,7 @@ import updateBanner from './api/update-banner'; import MkIndex from './views/pages/index.vue'; import MkDeck from './views/pages/deck/deck.vue'; import MkAdmin from './views/pages/admin/admin.vue'; +import MkStats from './views/pages/stats/stats.vue'; import MkUser from './views/pages/user/user.vue'; import MkFavorites from './views/pages/favorites.vue'; import MkSelectDrive from './views/pages/selectdrive.vue'; @@ -57,6 +58,7 @@ init(async (launch) => { { path: '/', name: 'index', component: MkIndex }, { path: '/deck', name: 'deck', component: MkDeck }, { path: '/admin', name: 'admin', component: MkAdmin }, + { path: '/stats', name: 'stats', component: MkStats }, { path: '/i/customize-home', component: MkHomeCustomize }, { path: '/i/favorites', component: MkFavorites }, { path: '/i/messaging/:user', component: MkMessagingRoom }, diff --git a/src/client/app/desktop/views/components/charts.chart.ts b/src/client/app/desktop/views/components/charts.chart.ts new file mode 100644 index 0000000000..6a241631e9 --- /dev/null +++ b/src/client/app/desktop/views/components/charts.chart.ts @@ -0,0 +1,42 @@ +import Vue from 'vue'; +import { Line } from 'vue-chartjs'; +import * as mergeOptions from 'merge-options'; + +export default Vue.extend({ + extends: Line, + props: { + data: { + required: true + }, + opts: { + required: false + } + }, + watch: { + data() { + this.render(); + } + }, + mounted() { + this.render(); + }, + methods: { + render() { + this.renderChart(this.data, mergeOptions({ + responsive: true, + maintainAspectRatio: false, + scales: { + xAxes: [{ + type: 'time', + distribution: 'series' + }] + }, + tooltips: { + intersect: false, + mode: 'x', + position: 'nearest' + } + }, this.opts || {})); + } + } +}); diff --git a/src/client/app/desktop/views/components/charts.vue b/src/client/app/desktop/views/components/charts.vue new file mode 100644 index 0000000000..ff41639a10 --- /dev/null +++ b/src/client/app/desktop/views/components/charts.vue @@ -0,0 +1,566 @@ + + + + + diff --git a/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts b/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts deleted file mode 100644 index 6a241631e9..0000000000 --- a/src/client/app/desktop/views/pages/admin/admin.chart.chart.ts +++ /dev/null @@ -1,42 +0,0 @@ -import Vue from 'vue'; -import { Line } from 'vue-chartjs'; -import * as mergeOptions from 'merge-options'; - -export default Vue.extend({ - extends: Line, - props: { - data: { - required: true - }, - opts: { - required: false - } - }, - watch: { - data() { - this.render(); - } - }, - mounted() { - this.render(); - }, - methods: { - render() { - this.renderChart(this.data, mergeOptions({ - responsive: true, - maintainAspectRatio: false, - scales: { - xAxes: [{ - type: 'time', - distribution: 'series' - }] - }, - tooltips: { - intersect: false, - mode: 'x', - position: 'nearest' - } - }, this.opts || {})); - } - } -}); diff --git a/src/client/app/desktop/views/pages/admin/admin.chart.vue b/src/client/app/desktop/views/pages/admin/admin.chart.vue deleted file mode 100644 index cca05fec28..0000000000 --- a/src/client/app/desktop/views/pages/admin/admin.chart.vue +++ /dev/null @@ -1,557 +0,0 @@ - - - - - diff --git a/src/client/app/desktop/views/pages/admin/admin.vue b/src/client/app/desktop/views/pages/admin/admin.vue index 0bb5ed0a0f..e669b0d2a9 100644 --- a/src/client/app/desktop/views/pages/admin/admin.vue +++ b/src/client/app/desktop/views/pages/admin/admin.vue @@ -11,7 +11,7 @@
    - +
    @@ -32,7 +32,7 @@ import XSuspendUser from "./admin.suspend-user.vue"; import XUnsuspendUser from "./admin.unsuspend-user.vue"; import XVerifyUser from "./admin.verify-user.vue"; import XUnverifyUser from "./admin.unverify-user.vue"; -import XChart from "./admin.chart.vue"; +import XCharts from "../../components/charts.vue"; export default Vue.extend({ components: { @@ -41,12 +41,11 @@ export default Vue.extend({ XUnsuspendUser, XVerifyUser, XUnverifyUser, - XChart + XCharts }, data() { return { - page: 'dashboard', - chart: null + page: 'dashboard' }; }, methods: { diff --git a/src/client/app/desktop/views/pages/stats/stats.vue b/src/client/app/desktop/views/pages/stats/stats.vue new file mode 100644 index 0000000000..18dca85f0d --- /dev/null +++ b/src/client/app/desktop/views/pages/stats/stats.vue @@ -0,0 +1,29 @@ + + + + + -- cgit v1.2.3-freya From 1f53d1a149e2f2f3ac37fc332c62dc8f012beb52 Mon Sep 17 00:00:00 2001 From: mei23 Date: Sat, 25 Aug 2018 12:32:31 +0900 Subject: Send Content-Type in ActivityPub request --- src/remote/activitypub/request.ts | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/remote/activitypub/request.ts b/src/remote/activitypub/request.ts index 585c1c0ce8..cebce8c48a 100644 --- a/src/remote/activitypub/request.ts +++ b/src/remote/activitypub/request.ts @@ -19,6 +19,9 @@ export default (user: ILocalUser, url: string, object: any) => new Promise((reso port, method: 'POST', path: pathname + search, + headers: { + 'Content-Type': 'application/activity+json' + } }, res => { log(`${url} --> ${res.statusCode}`); -- cgit v1.2.3-freya From 1c45cc808b12f9e8c8f2e32a3c7aa684d5f11289 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 25 Aug 2018 12:43:18 +0900 Subject: Improve stats page --- locales/ja-JP.yml | 6 ++++ src/client/app/desktop/views/pages/stats/stats.vue | 37 +++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index fae257480c..bce6ddb24e 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -968,6 +968,12 @@ desktop/views/pages/deck/deck.note.vue: private: "この投稿は非公開です" deleted: "この投稿は削除されました" +desktop/views/pages/stats/stats.vue: + all-users: "全てのユーザー" + original-users: "このインスタンスのユーザー" + all-notes: "全てのノート" + original-notes: "このインスタンスのノート" + desktop/views/pages/welcome.vue: about: "詳しく..." gotit: "わかった" diff --git a/src/client/app/desktop/views/pages/stats/stats.vue b/src/client/app/desktop/views/pages/stats/stats.vue index 18dca85f0d..77ef8ca457 100644 --- a/src/client/app/desktop/views/pages/stats/stats.vue +++ b/src/client/app/desktop/views/pages/stats/stats.vue @@ -1,5 +1,11 @@