From a59ab79da083feeec57b60d4d3bfb6849147ecf1 Mon Sep 17 00:00:00 2001 From: Satsuki Yanagi <17376330+u1-liquid@users.noreply.github.com> Date: Tue, 9 Jul 2019 17:38:14 +0900 Subject: Fix drive browser showing false empty (#5127) --- src/client/app/desktop/views/components/drive.vue | 6 +++--- src/client/app/mobile/views/components/drive.vue | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client/app/desktop/views/components/drive.vue b/src/client/app/desktop/views/components/drive.vue index a78c0040c3..ff4ff18e6e 100644 --- a/src/client/app/desktop/views/components/drive.vue +++ b/src/client/app/desktop/views/components/drive.vue @@ -22,19 +22,19 @@ >
-
+
{{ $t('@.load-more') }}
-
+
{{ $t('@.load-more') }}
-
+

{{ $t('empty-draghover') }}

{{ $t('empty-drive') }}
{{ $t('empty-drive-description') }}

{{ $t('empty-folder') }}

diff --git a/src/client/app/mobile/views/components/drive.vue b/src/client/app/mobile/views/components/drive.vue index 2613cfff99..f24c8492e5 100644 --- a/src/client/app/mobile/views/components/drive.vue +++ b/src/client/app/mobile/views/components/drive.vue @@ -25,17 +25,17 @@

-
+

{{ $t('@.load-more') }}

-
+
-
+

{{ $t('nothing-in-drive') }}

{{ $t('folder-is-empty') }}

-- cgit v1.2.3-freya From a091cbb93aa4f204b2c8af6574b5b5c62eafd853 Mon Sep 17 00:00:00 2001 From: MeiMei <30769358+mei23@users.noreply.github.com> Date: Wed, 10 Jul 2019 03:47:07 +0900 Subject: Prevent duplicate user registration (#5129) --- src/client/app/common/views/components/signup.vue | 8 +++++++- src/server/api/private/signup.ts | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/app/common/views/components/signup.vue b/src/client/app/common/views/components/signup.vue index 421d09a4dd..893f6575fb 100644 --- a/src/client/app/common/views/components/signup.vue +++ b/src/client/app/common/views/components/signup.vue @@ -43,7 +43,7 @@
- {{ $t('create') }} + {{ $t('create') }} @@ -70,6 +70,7 @@ export default Vue.extend({ passwordStrength: '', passwordRetypeState: null, meta: {}, + submitting: false, ToSAgreement: false } }, @@ -145,6 +146,9 @@ export default Vue.extend({ }, onSubmit() { + if (this.submitting) return; + this.submitting = true; + this.$root.api('signup', { username: this.username, password: this.password, @@ -159,6 +163,8 @@ export default Vue.extend({ location.href = '/'; }); }).catch(() => { + this.submitting = false; + this.$root.dialog({ type: 'error', text: this.$t('some-error') diff --git a/src/server/api/private/signup.ts b/src/server/api/private/signup.ts index ca197a6611..ac99ea0d33 100644 --- a/src/server/api/private/signup.ts +++ b/src/server/api/private/signup.ts @@ -104,6 +104,13 @@ export default async (ctx: Koa.BaseContext) => { // Start transaction await getConnection().transaction(async transactionalEntityManager => { + const exist = await transactionalEntityManager.findOne(User, { + usernameLower: username.toLowerCase(), + host: null + }); + + if (exist) throw 'already registered'; + account = await transactionalEntityManager.save(new User({ id: genId(), createdAt: new Date(), -- cgit v1.2.3-freya From feec5e88fcb0b0d89931dba1c2032ea315b553bf Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 10 Jul 2019 18:30:51 +0900 Subject: Pages: Implement radio button --- locales/ja-JP.yml | 7 +++ src/client/app/common/scripts/collect-page-vars.ts | 6 +++ .../common/views/components/page/page.block.vue | 3 +- .../views/components/page/page.radio-button.vue | 37 +++++++++++++++ .../els/page-editor.el.radio-button.vue | 53 ++++++++++++++++++++++ .../views/pages/page-editor/page-editor.blocks.vue | 3 +- .../common/views/pages/page-editor/page-editor.vue | 1 + 7 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 src/client/app/common/views/components/page/page.radio-button.vue create mode 100644 src/client/app/common/views/pages/page-editor/els/page-editor.el.radio-button.vue (limited to 'src') diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index d2776c45b1..2efe8461ea 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2066,6 +2066,13 @@ pages: variable: "送信する変数" no-variable: "なし" + radioButton: "選択肢" + _radioButton: + name: "変数名" + title: "タイトル" + values: "改行で区切った選択肢" + default: "デフォルト値" + script: categories: flow: "制御" diff --git a/src/client/app/common/scripts/collect-page-vars.ts b/src/client/app/common/scripts/collect-page-vars.ts index 4c40d5d88e..a4096fb2c2 100644 --- a/src/client/app/common/scripts/collect-page-vars.ts +++ b/src/client/app/common/scripts/collect-page-vars.ts @@ -32,6 +32,12 @@ export function collectPageVars(content) { type: 'number', value: 0 }); + } else if (x.type === 'radioButton') { + pageVars.push({ + name: x.name, + type: 'string', + value: x.default || '' + }); } else if (x.children) { collect(x.children); } diff --git a/src/client/app/common/views/components/page/page.block.vue b/src/client/app/common/views/components/page/page.block.vue index 1c421fc2c0..56d1822013 100644 --- a/src/client/app/common/views/components/page/page.block.vue +++ b/src/client/app/common/views/components/page/page.block.vue @@ -16,10 +16,11 @@ import XIf from './page.if.vue'; import XTextarea from './page.textarea.vue'; import XPost from './page.post.vue'; import XCounter from './page.counter.vue'; +import XRadioButton from './page.radio-button.vue'; export default Vue.extend({ components: { - XText, XSection, XImage, XButton, XNumberInput, XTextInput, XTextareaInput, XTextarea, XPost, XSwitch, XIf, XCounter + XText, XSection, XImage, XButton, XNumberInput, XTextInput, XTextareaInput, XTextarea, XPost, XSwitch, XIf, XCounter, XRadioButton }, props: { diff --git a/src/client/app/common/views/components/page/page.radio-button.vue b/src/client/app/common/views/components/page/page.radio-button.vue new file mode 100644 index 0000000000..27c11bebad --- /dev/null +++ b/src/client/app/common/views/components/page/page.radio-button.vue @@ -0,0 +1,37 @@ + + + + + diff --git a/src/client/app/common/views/pages/page-editor/els/page-editor.el.radio-button.vue b/src/client/app/common/views/pages/page-editor/els/page-editor.el.radio-button.vue new file mode 100644 index 0000000000..3401c46f47 --- /dev/null +++ b/src/client/app/common/views/pages/page-editor/els/page-editor.el.radio-button.vue @@ -0,0 +1,53 @@ + + + diff --git a/src/client/app/common/views/pages/page-editor/page-editor.blocks.vue b/src/client/app/common/views/pages/page-editor/page-editor.blocks.vue index c5f3419e7b..4d7293231f 100644 --- a/src/client/app/common/views/pages/page-editor/page-editor.blocks.vue +++ b/src/client/app/common/views/pages/page-editor/page-editor.blocks.vue @@ -19,10 +19,11 @@ import XSwitch from './els/page-editor.el.switch.vue'; import XIf from './els/page-editor.el.if.vue'; import XPost from './els/page-editor.el.post.vue'; import XCounter from './els/page-editor.el.counter.vue'; +import XRadioButton from './els/page-editor.el.radio-button.vue'; export default Vue.extend({ components: { - XDraggable, XSection, XText, XImage, XButton, XTextarea, XTextInput, XTextareaInput, XNumberInput, XSwitch, XIf, XPost, XCounter + XDraggable, XSection, XText, XImage, XButton, XTextarea, XTextInput, XTextareaInput, XNumberInput, XSwitch, XIf, XPost, XCounter, XRadioButton }, props: { diff --git a/src/client/app/common/views/pages/page-editor/page-editor.vue b/src/client/app/common/views/pages/page-editor/page-editor.vue index ade7d86991..0162915c38 100644 --- a/src/client/app/common/views/pages/page-editor/page-editor.vue +++ b/src/client/app/common/views/pages/page-editor/page-editor.vue @@ -342,6 +342,7 @@ export default Vue.extend({ label: this.$t('input-blocks'), items: [ { value: 'button', text: this.$t('blocks.button') }, + { value: 'radioButton', text: this.$t('blocks.radioButton') }, { value: 'textInput', text: this.$t('blocks.textInput') }, { value: 'textareaInput', text: this.$t('blocks.textareaInput') }, { value: 'numberInput', text: this.$t('blocks.numberInput') }, -- cgit v1.2.3-freya From b2030e840318445751c44fd11d41518e2c4507df Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 12 Jul 2019 00:40:10 +0900 Subject: :art: --- src/client/app/common/views/components/reaction-picker.vue | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/client/app/common/views/components/reaction-picker.vue b/src/client/app/common/views/components/reaction-picker.vue index 970d430069..ff534d37ce 100644 --- a/src/client/app/common/views/components/reaction-picker.vue +++ b/src/client/app/common/views/components/reaction-picker.vue @@ -276,6 +276,7 @@ export default Vue.extend({ font-size 14px color var(--popupFg) border-bottom solid var(--lineWidth) var(--faceDivider) + line-height 20px > .buttons padding 4px 4px 8px 4px -- cgit v1.2.3-freya From ebbf5268ac96157780c5a591e07c5a8381652c9e Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 12 Jul 2019 02:08:13 +0900 Subject: Improve usability --- src/client/app/common/views/components/url-preview.vue | 1 + src/client/app/common/views/components/url.vue | 1 + 2 files changed, 2 insertions(+) (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 476c671e77..80aae5999d 100644 --- a/src/client/app/common/views/components/url-preview.vue +++ b/src/client/app/common/views/components/url-preview.vue @@ -66,6 +66,7 @@ export default Vue.extend({ (this.url.substr(local.length) === '/') || this.url.substr(local.length).startsWith('/@') || this.url.substr(local.length).startsWith('/notes/') || + this.url.substr(local.length).startsWith('/tags/') || this.url.substr(local.length).startsWith('/pages/'); return { local, diff --git a/src/client/app/common/views/components/url.vue b/src/client/app/common/views/components/url.vue index b1ca3f285c..3a304ad6e7 100644 --- a/src/client/app/common/views/components/url.vue +++ b/src/client/app/common/views/components/url.vue @@ -28,6 +28,7 @@ export default Vue.extend({ (this.url.substr(local.length) === '/') || this.url.substr(local.length).startsWith('/@') || this.url.substr(local.length).startsWith('/notes/') || + this.url.substr(local.length).startsWith('/tags/') || this.url.substr(local.length).startsWith('/pages/')); return { local, -- cgit v1.2.3-freya From 2cb032b0e01b166cda372ea217b60b6705cf4c33 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 12 Jul 2019 03:17:31 +0900 Subject: Fix #5140 --- src/models/repositories/abuse-user-report.ts | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/models/repositories/abuse-user-report.ts b/src/models/repositories/abuse-user-report.ts index 61d0d6e229..bff64c770c 100644 --- a/src/models/repositories/abuse-user-report.ts +++ b/src/models/repositories/abuse-user-report.ts @@ -14,6 +14,7 @@ export class AbuseUserReportRepository extends Repository { return await awaitAll({ id: report.id, createdAt: report.createdAt, + comment: report.comment, reporterId: report.reporterId, userId: report.userId, reporter: Users.pack(report.reporter || report.reporterId, null, { -- cgit v1.2.3-freya From 70691e1523d63c51fc14b80b5107864cffd634ec Mon Sep 17 00:00:00 2001 From: MeiMei <30769358+mei23@users.noreply.github.com> Date: Fri, 12 Jul 2019 22:21:47 +0900 Subject: Fix: proxy-media後のContent-Typeが違う (#5143) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/server/proxy/proxy-media.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/proxy/proxy-media.ts b/src/server/proxy/proxy-media.ts index eadfab54a3..415eef6c34 100644 --- a/src/server/proxy/proxy-media.ts +++ b/src/server/proxy/proxy-media.ts @@ -33,7 +33,7 @@ export async function proxyMedia(ctx: Koa.BaseContext) { }; } - ctx.set('Content-Type', type); + ctx.set('Content-Type', image.type); ctx.set('Cache-Control', 'max-age=31536000, immutable'); ctx.body = image.data; } catch (e) { -- cgit v1.2.3-freya From b3c6e28717dca26d4b35fad311b74956019b7689 Mon Sep 17 00:00:00 2001 From: Satsuki Yanagi <17376330+u1-liquid@users.noreply.github.com> Date: Fri, 12 Jul 2019 22:24:29 +0900 Subject: Improve usability (#5142) Fix #3862 --- locales/ja-JP.yml | 2 ++ .../common/views/components/settings/app-type.vue | 19 ++++++++++- .../common/views/components/settings/settings.vue | 39 ++++++++++++++-------- 3 files changed, 46 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 2efe8461ea..19bbec2de9 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -290,6 +290,8 @@ common: load-raw-images: "添付された画像を高画質で表示する" load-remote-media: "リモートサーバーのメディアを表示する" sync: "同期" + save: "保存" + saved: "保存しました" home-profile: "ホームのプロファイル" deck-profile: "デッキのプロファイル" diff --git a/src/client/app/common/views/components/settings/app-type.vue b/src/client/app/common/views/components/settings/app-type.vue index 90ff28803b..d163f1e746 100644 --- a/src/client/app/common/views/components/settings/app-type.vue +++ b/src/client/app/common/views/components/settings/app-type.vue @@ -29,8 +29,25 @@ export default Vue.extend({ computed: { appTypeForce: { get() { return this.$store.state.device.appTypeForce; }, - set(value) { this.$store.commit('device/set', { key: 'appTypeForce', value }); } + set(value) { + this.$store.commit('device/set', { key: 'appTypeForce', value }); + this.reload(); + } }, }, + + methods: { + reload() { + this.$root.dialog({ + type: 'warning', + text: this.$t('@.reload-to-apply-the-setting'), + showCancelButton: true + }).then(({ canceled }) => { + if (!canceled) { + location.reload(); + } + }); + }, + } }); diff --git a/src/client/app/common/views/components/settings/settings.vue b/src/client/app/common/views/components/settings/settings.vue index 281524979e..401d9423ae 100644 --- a/src/client/app/common/views/components/settings/settings.vue +++ b/src/client/app/common/views/components/settings/settings.vue @@ -143,13 +143,17 @@ {{ $t('@._settings.web-search-engine') }} + {{ $t('@._settings.save') }}
{{ $t('@._settings.paste') }}
{{ $t('@._settings.pasted-file-name') }} - + + + {{ $t('@._settings.save') }} + {{ $t('@._settings.paste-dialog') }} @@ -289,6 +293,8 @@ import XNotification from './notification.vue'; import { url, version } from '../../../../config'; import checkForUpdate from '../../../scripts/check-for-update'; +import { formatTimeString } from '../../../../../../misc/format-time-string'; +import { faSave } from '@fortawesome/free-regular-svg-icons'; export default Vue.extend({ i18n: i18n(), @@ -319,8 +325,11 @@ export default Vue.extend({ return { meta: null, version, + webSearchEngine: this.$store.state.settings.webSearchEngine, + pastedFileName : this.$store.state.settings.pastedFileName, latestVersion: undefined, - checkingForUpdate: false + checkingForUpdate: false, + faSave }; }, computed: { @@ -419,16 +428,6 @@ export default Vue.extend({ set(value) { this.$store.dispatch('settings/set', { key: 'defaultNoteVisibility', value }); } }, - webSearchEngine: { - get() { return this.$store.state.settings.webSearchEngine; }, - set(value) { this.$store.dispatch('settings/set', { key: 'webSearchEngine', value }); } - }, - - pastedFileName: { - get() { return this.$store.state.settings.pastedFileName; }, - set(value) { this.$store.dispatch('settings/set', { key: 'pastedFileName', value }); } - }, - pasteDialog: { get() { return this.$store.state.settings.pasteDialog; }, set(value) { this.$store.dispatch('settings/set', { key: 'pasteDialog', value }); } @@ -565,6 +564,17 @@ export default Vue.extend({ } }); }, + save(key, value) { + this.$store.dispatch('settings/set', { + key, + value + }).then(() => { + this.$root.dialog({ + type: 'success', + text: this.$t('@._settings.saved') + }) + }); + }, customizeHome() { location.href = '/?customize'; }, @@ -600,7 +610,10 @@ export default Vue.extend({ const sound = new Audio(`${url}/assets/message.mp3`); sound.volume = this.$store.state.device.soundVolume; sound.play(); - } + }, + pastedFileNamePreview() { + return `${formatTimeString(new Date(), this.pastedFileName).replace(/{{number}}/g, `1`)}.png` + }, } }); -- cgit v1.2.3-freya From b34c1379e9aac1c8612a62afa849a48069d19d74 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 14 Jul 2019 03:18:45 +0900 Subject: Resolve #3238 --- locales/ja-JP.yml | 6 +++ migration/1562869971568-ModerationLog.ts | 17 ++++++++ src/client/app/admin/views/moderators.vue | 50 +++++++++++++++++++++- src/db/postgre.ts | 2 + src/models/entities/moderation-log.ts | 32 ++++++++++++++ src/models/index.ts | 2 + src/models/repositories/moderation-logs.ts | 31 ++++++++++++++ src/server/api/endpoints/admin/emoji/add.ts | 7 ++- src/server/api/endpoints/admin/emoji/remove.ts | 7 ++- src/server/api/endpoints/admin/queue/clear.ts | 5 ++- .../api/endpoints/admin/show-moderation-logs.ts | 35 +++++++++++++++ src/server/api/endpoints/admin/silence-user.ts | 7 ++- src/server/api/endpoints/admin/suspend-user.ts | 7 ++- src/server/api/endpoints/admin/unsilence-user.ts | 7 ++- src/server/api/endpoints/admin/unsuspend-user.ts | 7 ++- src/server/api/endpoints/admin/update-meta.ts | 5 ++- src/server/api/endpoints/admin/vacuum.ts | 5 ++- src/services/insert-moderation-log.ts | 13 ++++++ 18 files changed, 234 insertions(+), 11 deletions(-) create mode 100644 migration/1562869971568-ModerationLog.ts create mode 100644 src/models/entities/moderation-log.ts create mode 100644 src/models/repositories/moderation-logs.ts create mode 100644 src/server/api/endpoints/admin/show-moderation-logs.ts create mode 100644 src/services/insert-moderation-log.ts (limited to 'src') diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 19bbec2de9..3e315153cb 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1529,6 +1529,12 @@ admin/views/moderators.vue: added: "モデレーターを登録しました" remove: "解除" removed: "モデレーター登録を解除しました" + logs: + title: "ログ" + moderator: "モデレーター" + type: "操作" + at: "日時" + info: "情報" admin/views/emoji.vue: add-emoji: diff --git a/migration/1562869971568-ModerationLog.ts b/migration/1562869971568-ModerationLog.ts new file mode 100644 index 0000000000..b37f38ee5d --- /dev/null +++ b/migration/1562869971568-ModerationLog.ts @@ -0,0 +1,17 @@ +import {MigrationInterface, QueryRunner} from "typeorm"; + +export class ModerationLog1562869971568 implements MigrationInterface { + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE TABLE "moderation_log" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "type" character varying(128) NOT NULL, "info" jsonb NOT NULL, CONSTRAINT "PK_d0adca6ecfd068db83e4526cc26" PRIMARY KEY ("id"))`); + await queryRunner.query(`CREATE INDEX "IDX_a08ad074601d204e0f69da9a95" ON "moderation_log" ("userId") `); + await queryRunner.query(`ALTER TABLE "moderation_log" ADD CONSTRAINT "FK_a08ad074601d204e0f69da9a954" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "moderation_log" DROP CONSTRAINT "FK_a08ad074601d204e0f69da9a954"`); + await queryRunner.query(`DROP INDEX "IDX_a08ad074601d204e0f69da9a95"`); + await queryRunner.query(`DROP TABLE "moderation_log"`); + } + +} diff --git a/src/client/app/admin/views/moderators.vue b/src/client/app/admin/views/moderators.vue index bf7d951fc7..8ceab02d97 100644 --- a/src/client/app/admin/views/moderators.vue +++ b/src/client/app/admin/views/moderators.vue @@ -12,6 +12,31 @@
+ + + +
+ +
+ + + {{ $t('logs.moderator') }} + + + {{ $t('logs.type') }} + + + {{ $t('logs.at') }} + + + + {{ $t('logs.info') }} + +
+
+ {{ $t('@.load-more') }} +
+
@@ -26,10 +51,17 @@ export default Vue.extend({ data() { return { username: '', - changing: false + changing: false, + logs: [], + untilLogId: null, + existMoreLogs: false }; }, + created() { + this.fetchLogs(); + }, + methods: { async add() { this.changing = true; @@ -74,6 +106,22 @@ export default Vue.extend({ this.changing = false; }, + + fetchLogs() { + this.$root.api('admin/show-moderation-logs', { + untilId: this.untilId, + limit: 10 + 1 + }).then(logs => { + if (logs.length == 10 + 1) { + logs.pop(); + this.existMoreLogs = true; + } else { + this.existMoreLogs = false; + } + this.logs = this.logs.concat(logs); + this.untilLogId = this.logs[this.logs.length - 1].id; + }); + }, } }); diff --git a/src/db/postgre.ts b/src/db/postgre.ts index 638d5720b7..16cfbd2b2f 100644 --- a/src/db/postgre.ts +++ b/src/db/postgre.ts @@ -47,6 +47,7 @@ import { UserSecurityKey } from '../models/entities/user-security-key'; import { AttestationChallenge } from '../models/entities/attestation-challenge'; import { Page } from '../models/entities/page'; import { PageLike } from '../models/entities/page-like'; +import { ModerationLog } from '../models/entities/moderation-log'; const sqlLogger = dbLogger.createSubLogger('sql', 'white', false); @@ -124,6 +125,7 @@ export const entities = [ RegistrationTicket, MessagingMessage, Signin, + ModerationLog, ReversiGame, ReversiMatching, ...charts as any diff --git a/src/models/entities/moderation-log.ts b/src/models/entities/moderation-log.ts new file mode 100644 index 0000000000..33d3d683ae --- /dev/null +++ b/src/models/entities/moderation-log.ts @@ -0,0 +1,32 @@ +import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; +import { User } from './user'; +import { id } from '../id'; + +@Entity() +export class ModerationLog { + @PrimaryColumn(id()) + public id: string; + + @Column('timestamp with time zone', { + comment: 'The created date of the ModerationLog.' + }) + public createdAt: Date; + + @Index() + @Column(id()) + public userId: User['id']; + + @ManyToOne(type => User, { + onDelete: 'CASCADE' + }) + @JoinColumn() + public user: User | null; + + @Column('varchar', { + length: 128, + }) + public type: string; + + @Column('jsonb') + public info: Record; +} diff --git a/src/models/index.ts b/src/models/index.ts index 888fd53f36..388bdc8f6f 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -42,6 +42,7 @@ import { UserSecurityKey } from './entities/user-security-key'; import { HashtagRepository } from './repositories/hashtag'; import { PageRepository } from './repositories/page'; import { PageLikeRepository } from './repositories/page-like'; +import { ModerationLogRepository } from './repositories/moderation-logs'; export const Apps = getCustomRepository(AppRepository); export const Notes = getCustomRepository(NoteRepository); @@ -86,3 +87,4 @@ export const ReversiMatchings = getCustomRepository(ReversiMatchingRepository); export const Logs = getRepository(Log); export const Pages = getCustomRepository(PageRepository); export const PageLikes = getCustomRepository(PageLikeRepository); +export const ModerationLogs = getCustomRepository(ModerationLogRepository); diff --git a/src/models/repositories/moderation-logs.ts b/src/models/repositories/moderation-logs.ts new file mode 100644 index 0000000000..d6e04795bb --- /dev/null +++ b/src/models/repositories/moderation-logs.ts @@ -0,0 +1,31 @@ +import { EntityRepository, Repository } from 'typeorm'; +import { Users } from '..'; +import { ModerationLog } from '../entities/moderation-log'; +import { ensure } from '../../prelude/ensure'; +import { awaitAll } from '../../prelude/await-all'; + +@EntityRepository(ModerationLog) +export class ModerationLogRepository extends Repository { + public async pack( + src: ModerationLog['id'] | ModerationLog, + ) { + const log = typeof src === 'object' ? src : await this.findOne(src).then(ensure); + + return await awaitAll({ + id: log.id, + createdAt: log.createdAt, + type: log.type, + info: log.info, + userId: log.userId, + user: Users.pack(log.user || log.userId, null, { + detail: true + }), + }); + } + + public packMany( + reports: any[], + ) { + return Promise.all(reports.map(x => this.pack(x))); + } +} diff --git a/src/server/api/endpoints/admin/emoji/add.ts b/src/server/api/endpoints/admin/emoji/add.ts index 5ba00afde8..8c21b1c73e 100644 --- a/src/server/api/endpoints/admin/emoji/add.ts +++ b/src/server/api/endpoints/admin/emoji/add.ts @@ -4,6 +4,7 @@ import { detectUrlMine } from '../../../../../misc/detect-url-mine'; import { Emojis } from '../../../../../models'; import { genId } from '../../../../../misc/gen-id'; import { getConnection } from 'typeorm'; +import { insertModerationLog } from '../../../../../services/insert-moderation-log'; export const meta = { desc: { @@ -31,7 +32,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const type = await detectUrlMine(ps.url); const emoji = await Emojis.save({ @@ -46,6 +47,10 @@ export default define(meta, async (ps) => { await getConnection().queryResultCache!.remove(['meta_emojis']); + insertModerationLog(me, 'addEmoji', { + emojiId: emoji.id + }); + return { id: emoji.id }; diff --git a/src/server/api/endpoints/admin/emoji/remove.ts b/src/server/api/endpoints/admin/emoji/remove.ts index 3ebf933bc6..92c5f5f8c6 100644 --- a/src/server/api/endpoints/admin/emoji/remove.ts +++ b/src/server/api/endpoints/admin/emoji/remove.ts @@ -3,6 +3,7 @@ import define from '../../../define'; import { ID } from '../../../../../misc/cafy-id'; import { Emojis } from '../../../../../models'; import { getConnection } from 'typeorm'; +import { insertModerationLog } from '../../../../../services/insert-moderation-log'; export const meta = { desc: { @@ -21,7 +22,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const emoji = await Emojis.findOne(ps.id); if (emoji == null) throw new Error('emoji not found'); @@ -29,4 +30,8 @@ export default define(meta, async (ps) => { await Emojis.delete(emoji.id); await getConnection().queryResultCache!.remove(['meta_emojis']); + + insertModerationLog(me, 'removeEmoji', { + emoji: emoji + }); }); diff --git a/src/server/api/endpoints/admin/queue/clear.ts b/src/server/api/endpoints/admin/queue/clear.ts index f0fd00f1ad..03c1ae8463 100644 --- a/src/server/api/endpoints/admin/queue/clear.ts +++ b/src/server/api/endpoints/admin/queue/clear.ts @@ -1,5 +1,6 @@ import define from '../../../define'; import { destroy } from '../../../../../queue'; +import { insertModerationLog } from '../../../../../services/insert-moderation-log'; export const meta = { tags: ['admin'], @@ -10,8 +11,8 @@ export const meta = { params: {} }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { destroy(); - return; + insertModerationLog(me, 'clearQueue'); }); diff --git a/src/server/api/endpoints/admin/show-moderation-logs.ts b/src/server/api/endpoints/admin/show-moderation-logs.ts new file mode 100644 index 0000000000..bc67b3e55b --- /dev/null +++ b/src/server/api/endpoints/admin/show-moderation-logs.ts @@ -0,0 +1,35 @@ +import $ from 'cafy'; +import { ID } from '../../../../misc/cafy-id'; +import define from '../../define'; +import { ModerationLogs } from '../../../../models'; +import { makePaginationQuery } from '../../common/make-pagination-query'; + +export const meta = { + tags: ['admin'], + + requireCredential: true, + requireModerator: true, + + params: { + limit: { + validator: $.optional.num.range(1, 100), + default: 10 + }, + + sinceId: { + validator: $.optional.type(ID), + }, + + untilId: { + validator: $.optional.type(ID), + }, + } +}; + +export default define(meta, async (ps) => { + const query = makePaginationQuery(ModerationLogs.createQueryBuilder('report'), ps.sinceId, ps.untilId); + + const reports = await query.take(ps.limit!).getMany(); + + return await ModerationLogs.packMany(reports); +}); diff --git a/src/server/api/endpoints/admin/silence-user.ts b/src/server/api/endpoints/admin/silence-user.ts index 83aa88012a..8cc84aa1cc 100644 --- a/src/server/api/endpoints/admin/silence-user.ts +++ b/src/server/api/endpoints/admin/silence-user.ts @@ -2,6 +2,7 @@ import $ from 'cafy'; import { ID } from '../../../../misc/cafy-id'; import define from '../../define'; import { Users } from '../../../../models'; +import { insertModerationLog } from '../../../../services/insert-moderation-log'; export const meta = { desc: { @@ -25,7 +26,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const user = await Users.findOne(ps.userId as string); if (user == null) { @@ -39,4 +40,8 @@ export default define(meta, async (ps) => { await Users.update(user.id, { isSilenced: true }); + + insertModerationLog(me, 'silence', { + targetId: user.id, + }); }); diff --git a/src/server/api/endpoints/admin/suspend-user.ts b/src/server/api/endpoints/admin/suspend-user.ts index fa4d378708..09fdbb070e 100644 --- a/src/server/api/endpoints/admin/suspend-user.ts +++ b/src/server/api/endpoints/admin/suspend-user.ts @@ -4,6 +4,7 @@ import define from '../../define'; import deleteFollowing from '../../../../services/following/delete'; import { Users, Followings } from '../../../../models'; import { User } from '../../../../models/entities/user'; +import { insertModerationLog } from '../../../../services/insert-moderation-log'; export const meta = { desc: { @@ -27,7 +28,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const user = await Users.findOne(ps.userId as string); if (user == null) { @@ -46,6 +47,10 @@ export default define(meta, async (ps) => { isSuspended: true }); + insertModerationLog(me, 'suspend', { + targetId: user.id, + }); + unFollowAll(user); }); diff --git a/src/server/api/endpoints/admin/unsilence-user.ts b/src/server/api/endpoints/admin/unsilence-user.ts index f9b173366b..607c9b699a 100644 --- a/src/server/api/endpoints/admin/unsilence-user.ts +++ b/src/server/api/endpoints/admin/unsilence-user.ts @@ -2,6 +2,7 @@ import $ from 'cafy'; import { ID } from '../../../../misc/cafy-id'; import define from '../../define'; import { Users } from '../../../../models'; +import { insertModerationLog } from '../../../../services/insert-moderation-log'; export const meta = { desc: { @@ -25,7 +26,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const user = await Users.findOne(ps.userId as string); if (user == null) { @@ -35,4 +36,8 @@ export default define(meta, async (ps) => { await Users.update(user.id, { isSilenced: false }); + + insertModerationLog(me, 'unsilence', { + targetId: user.id, + }); }); diff --git a/src/server/api/endpoints/admin/unsuspend-user.ts b/src/server/api/endpoints/admin/unsuspend-user.ts index 08dae034d3..a1c80d3121 100644 --- a/src/server/api/endpoints/admin/unsuspend-user.ts +++ b/src/server/api/endpoints/admin/unsuspend-user.ts @@ -2,6 +2,7 @@ import $ from 'cafy'; import { ID } from '../../../../misc/cafy-id'; import define from '../../define'; import { Users } from '../../../../models'; +import { insertModerationLog } from '../../../../services/insert-moderation-log'; export const meta = { desc: { @@ -25,7 +26,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const user = await Users.findOne(ps.userId as string); if (user == null) { @@ -35,4 +36,8 @@ export default define(meta, async (ps) => { await Users.update(user.id, { isSuspended: false }); + + insertModerationLog(me, 'unsuspend', { + targetId: user.id, + }); }); diff --git a/src/server/api/endpoints/admin/update-meta.ts b/src/server/api/endpoints/admin/update-meta.ts index 8e98d203ff..834faa42b9 100644 --- a/src/server/api/endpoints/admin/update-meta.ts +++ b/src/server/api/endpoints/admin/update-meta.ts @@ -2,6 +2,7 @@ import $ from 'cafy'; import define from '../../define'; import { getConnection } from 'typeorm'; import { Meta } from '../../../../models/entities/meta'; +import { insertModerationLog } from '../../../../services/insert-moderation-log'; export const meta = { desc: { @@ -401,7 +402,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const set = {} as Partial; if (ps.announcements) { @@ -653,4 +654,6 @@ export default define(meta, async (ps) => { await transactionalEntityManager.save(Meta, set); } }); + + insertModerationLog(me, 'updateMeta'); }); diff --git a/src/server/api/endpoints/admin/vacuum.ts b/src/server/api/endpoints/admin/vacuum.ts index 6990706282..4921e228e5 100644 --- a/src/server/api/endpoints/admin/vacuum.ts +++ b/src/server/api/endpoints/admin/vacuum.ts @@ -1,6 +1,7 @@ import $ from 'cafy'; import define from '../../define'; import { getConnection } from 'typeorm'; +import { insertModerationLog } from '../../../../services/insert-moderation-log'; export const meta = { tags: ['admin'], @@ -18,7 +19,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const params: string[] = []; if (ps.full) { @@ -30,4 +31,6 @@ export default define(meta, async (ps) => { } getConnection().query('VACUUM ' + params.join(' ')); + + insertModerationLog(me, 'vacuum', ps); }); diff --git a/src/services/insert-moderation-log.ts b/src/services/insert-moderation-log.ts new file mode 100644 index 0000000000..33dab97259 --- /dev/null +++ b/src/services/insert-moderation-log.ts @@ -0,0 +1,13 @@ +import { ILocalUser } from '../models/entities/user'; +import { ModerationLogs } from '../models'; +import { genId } from '../misc/gen-id'; + +export async function insertModerationLog(moderator: ILocalUser, type: string, info?: Record) { + await ModerationLogs.save({ + id: genId(), + createdAt: new Date(), + userId: moderator.id, + type: type, + info: info || {} + }); +} -- cgit v1.2.3-freya From f37f22b16335bbd24b62980172182a4db443671f Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 14 Jul 2019 03:53:45 +0900 Subject: Fix bug --- src/server/api/endpoints/federation/instances.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/server/api/endpoints/federation/instances.ts b/src/server/api/endpoints/federation/instances.ts index 3c4e0037d6..bc0eb9a1d7 100644 --- a/src/server/api/endpoints/federation/instances.ts +++ b/src/server/api/endpoints/federation/instances.ts @@ -43,12 +43,12 @@ export default define(meta, async (ps, me) => { switch (ps.sort) { case '+notes': query.orderBy('instance.notesCount', 'DESC'); break; case '-notes': query.orderBy('instance.notesCount', 'ASC'); break; - case '+usersCount': query.orderBy('instance.usersCount', 'DESC'); break; - case '-usersCount': query.orderBy('instance.usersCount', 'ASC'); break; - case '+followingCount': query.orderBy('instance.followingCount', 'DESC'); break; - case '-followingCount': query.orderBy('instance.followingCount', 'ASC'); break; - case '+followersCount': query.orderBy('instance.followersCount', 'DESC'); break; - case '-followersCount': query.orderBy('instance.followersCount', 'ASC'); break; + case '+users': query.orderBy('instance.usersCount', 'DESC'); break; + case '-users': query.orderBy('instance.usersCount', 'ASC'); break; + case '+following': query.orderBy('instance.followingCount', 'DESC'); break; + case '-following': query.orderBy('instance.followingCount', 'ASC'); break; + case '+followers': query.orderBy('instance.followersCount', 'DESC'); break; + case '-followers': query.orderBy('instance.followersCount', 'ASC'); break; case '+caughtAt': query.orderBy('instance.caughtAt', 'DESC'); break; case '-caughtAt': query.orderBy('instance.caughtAt', 'ASC'); break; case '+lastCommunicatedAt': query.orderBy('instance.lastCommunicatedAt', 'DESC'); break; -- cgit v1.2.3-freya From b7273c90aead0c2d3ff51785ba336a32acf1a104 Mon Sep 17 00:00:00 2001 From: Satsuki Yanagi <17376330+u1-liquid@users.noreply.github.com> Date: Sun, 14 Jul 2019 03:56:34 +0900 Subject: Fix #5128 (#5153) --- src/server/api/endpoints/hashtags/users.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/server/api/endpoints/hashtags/users.ts b/src/server/api/endpoints/hashtags/users.ts index 59210f4604..28a78ff8e6 100644 --- a/src/server/api/endpoints/hashtags/users.ts +++ b/src/server/api/endpoints/hashtags/users.ts @@ -59,7 +59,7 @@ export const meta = { export default define(meta, async (ps, me) => { const query = Users.createQueryBuilder('user') - .where(':tag = ANY(user.tags)', { tag: ps.tag }); + .where(':tag = ANY(user.tags)', { tag: ps.tag.toLowerCase() }); const recent = new Date(Date.now() - (1000 * 60 * 60 * 24 * 5)); -- cgit v1.2.3-freya From 01e7716170aff833c9432184e16162a274390d44 Mon Sep 17 00:00:00 2001 From: Satsuki Yanagi <17376330+u1-liquid@users.noreply.github.com> Date: Mon, 15 Jul 2019 02:28:30 +0900 Subject: (コ`・ヘ・´ケ) (#5156) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/client/app/common/scripts/get-face.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/app/common/scripts/get-face.ts b/src/client/app/common/scripts/get-face.ts index b523948bd3..19f2bdb064 100644 --- a/src/client/app/common/scripts/get-face.ts +++ b/src/client/app/common/scripts/get-face.ts @@ -4,7 +4,8 @@ const faces = [ '🐡( \'-\' 🐡 )フグパンチ!!!!', '✌️(´・_・`)✌️', '(。>﹏<。)', - '(Δ・x・Δ)' + '(Δ・x・Δ)', + '(コ`・ヘ・´ケ)' ]; export default () => faces[Math.floor(Math.random() * faces.length)]; -- cgit v1.2.3-freya From 9ca36021b05b448f969568fa6cb1118b70cb4230 Mon Sep 17 00:00:00 2001 From: Satsuki Yanagi <17376330+u1-liquid@users.noreply.github.com> Date: Wed, 17 Jul 2019 13:28:27 +0900 Subject: Fix #5172 (#5174) --- locales/ja-JP.yml | 4 ++++ .../common/views/components/settings/profile.vue | 23 ++++++++++++++++++++++ src/client/app/desktop/api/update-avatar.ts | 15 ++++++++++++++ src/client/app/desktop/api/update-banner.ts | 15 ++++++++++++++ 4 files changed, 57 insertions(+) (limited to 'src') diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 3e315153cb..1c3f22dc2c 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -782,6 +782,9 @@ common/views/components/profile-editor.vue: saved: "プロフィールを保存しました" uploading: "アップロード中" upload-failed: "アップロードに失敗しました" + unable-to-process: "操作を完了できません" + avatar-not-an-image: "アイコンとして指定したファイルは画像ではありません" + banner-not-an-image: "バナーとして指定したファイルは画像ではありません" email: "メール設定" email-address: "メールアドレス" email-verified: "メールアドレスが確認されました" @@ -927,6 +930,7 @@ desktop: uploading-avatar: "新しいアバターをアップロードしています" avatar-updated: "アバターを更新しました" choose-avatar: "アバターにする画像を選択" + unable-to-process: "操作を完了できません" invalid-filetype: "この形式のファイルはサポートされていません" desktop/views/components/activity.chart.vue: diff --git a/src/client/app/common/views/components/settings/profile.vue b/src/client/app/common/views/components/settings/profile.vue index a22fd6df98..52ec8ceda3 100644 --- a/src/client/app/common/views/components/settings/profile.vue +++ b/src/client/app/common/views/components/settings/profile.vue @@ -265,6 +265,29 @@ export default Vue.extend({ text: this.$t('saved') }); } + }).catch(err => { + this.saving = false; + switch(err.id) { + case 'f419f9f8-2f4d-46b1-9fb4-49d3a2fd7191': + this.$root.dialog({ + type: 'error', + title: this.$t('unable-to-process'), + text: this.$t('avatar-not-an-image') + }); + break; + case '75aedb19-2afd-4e6d-87fc-67941256fa60': + this.$root.dialog({ + type: 'error', + title: this.$t('unable-to-process'), + text: this.$t('banner-not-an-image') + }); + break; + default: + this.$root.dialog({ + type: 'error', + text: this.$t('unable-to-process') + }); + } }); }, diff --git a/src/client/app/desktop/api/update-avatar.ts b/src/client/app/desktop/api/update-avatar.ts index a095491b69..dad720827b 100644 --- a/src/client/app/desktop/api/update-avatar.ts +++ b/src/client/app/desktop/api/update-avatar.ts @@ -83,6 +83,21 @@ export default ($root: any) => { }); return i; + }).catch(err => { + switch(err.id) { + case 'f419f9f8-2f4d-46b1-9fb4-49d3a2fd7191': + $root.dialog({ + type: 'error', + title: locale['desktop']['unable-to-process'], + text: locale['desktop']['invalid-filetype'] + }); + break; + default: + $root.dialog({ + type: 'error', + text: locale['desktop']['unable-to-process'] + }); + } }); }; diff --git a/src/client/app/desktop/api/update-banner.ts b/src/client/app/desktop/api/update-banner.ts index c23a325364..79d130f94b 100644 --- a/src/client/app/desktop/api/update-banner.ts +++ b/src/client/app/desktop/api/update-banner.ts @@ -83,6 +83,21 @@ export default ($root: any) => { }); return i; + }).catch(err => { + switch(err.id) { + case '75aedb19-2afd-4e6d-87fc-67941256fa60': + $root.dialog({ + type: 'error', + title: locale['desktop']['unable-to-process'], + text: locale['desktop']['invalid-filetype'] + }); + break; + default: + $root.dialog({ + type: 'error', + text: locale['desktop']['unable-to-process'] + }); + } }); }; -- cgit v1.2.3-freya From 9a09ed62902f4cb27c602993f53e465febd531e4 Mon Sep 17 00:00:00 2001 From: Satsuki Yanagi <17376330+u1-liquid@users.noreply.github.com> Date: Wed, 17 Jul 2019 17:13:38 +0900 Subject: Cleanup source (#5177) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Cleanup source * 🙏 --- package.json | 2 +- src/client/app/desktop/api/update-avatar.ts | 2 +- src/client/app/desktop/api/update-banner.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/package.json b/package.json index 6729a11f74..8d275fcb8a 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,6 @@ "@fortawesome/free-solid-svg-icons": "5.9.0", "@fortawesome/vue-fontawesome": "0.1.6", "@koa/cors": "3.0.0", - "@typescript-eslint/parser": "1.11.0", "@types/bcryptjs": "2.4.2", "@types/bull": "3.5.15", "@types/cbor": "2.0.0", @@ -99,6 +98,7 @@ "@types/webpack-stream": "3.2.10", "@types/websocket": "0.0.40", "@types/ws": "6.0.1", + "@typescript-eslint/parser": "1.11.0", "animejs": "3.0.1", "apexcharts": "3.8.2", "autobind-decorator": "2.4.0", diff --git a/src/client/app/desktop/api/update-avatar.ts b/src/client/app/desktop/api/update-avatar.ts index dad720827b..6b88b51ef1 100644 --- a/src/client/app/desktop/api/update-avatar.ts +++ b/src/client/app/desktop/api/update-avatar.ts @@ -84,7 +84,7 @@ export default ($root: any) => { return i; }).catch(err => { - switch(err.id) { + switch (err.id) { case 'f419f9f8-2f4d-46b1-9fb4-49d3a2fd7191': $root.dialog({ type: 'error', diff --git a/src/client/app/desktop/api/update-banner.ts b/src/client/app/desktop/api/update-banner.ts index 79d130f94b..09632b1941 100644 --- a/src/client/app/desktop/api/update-banner.ts +++ b/src/client/app/desktop/api/update-banner.ts @@ -84,7 +84,7 @@ export default ($root: any) => { return i; }).catch(err => { - switch(err.id) { + switch (err.id) { case '75aedb19-2afd-4e6d-87fc-67941256fa60': $root.dialog({ type: 'error', -- cgit v1.2.3-freya From 8e4ad4b9195f168d66d3ce09a12afe736ceb481c Mon Sep 17 00:00:00 2001 From: Satsuki Yanagi <17376330+u1-liquid@users.noreply.github.com> Date: Wed, 17 Jul 2019 18:59:10 +0900 Subject: Improve usability of users view (#5176) * Improve usability of users view Resolve #5173 * Fix query * Follow review and fix * Follow review --- locales/ja-JP.yml | 2 ++ src/client/app/admin/views/users.user.vue | 4 ++-- src/client/app/admin/views/users.vue | 33 +++++++++++++++++++++++----- src/server/api/endpoints/admin/show-users.ts | 18 +++++++++++++++ 4 files changed, 50 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 1c3f22dc2c..76fc26381f 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1502,6 +1502,8 @@ admin/views/users.vue: remote-user-updated: "リモートユーザー情報を更新しました" delete-all-files: "すべてのファイルを削除" delete-all-files-confirm: "すべてのファイルを削除しますか?" + username: "ユーザー名" + host: "ホスト" users: title: "ユーザー" sort: diff --git a/src/client/app/admin/views/users.user.vue b/src/client/app/admin/views/users.user.vue index 929fc8f4b3..25ae0f3f52 100644 --- a/src/client/app/admin/views/users.user.vue +++ b/src/client/app/admin/views/users.user.vue @@ -1,5 +1,5 @@