summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2019-07-14 03:18:45 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2019-07-14 03:18:45 +0900
commitb34c1379e9aac1c8612a62afa849a48069d19d74 (patch)
treee6f96c78c8183ff2768ae4843981b909549e3a27 /src
parentNew translations ja-JP.yml (Chinese Simplified) (#5149) (diff)
downloadmisskey-b34c1379e9aac1c8612a62afa849a48069d19d74.tar.gz
misskey-b34c1379e9aac1c8612a62afa849a48069d19d74.tar.bz2
misskey-b34c1379e9aac1c8612a62afa849a48069d19d74.zip
Resolve #3238
Diffstat (limited to 'src')
-rw-r--r--src/client/app/admin/views/moderators.vue50
-rw-r--r--src/db/postgre.ts2
-rw-r--r--src/models/entities/moderation-log.ts32
-rw-r--r--src/models/index.ts2
-rw-r--r--src/models/repositories/moderation-logs.ts31
-rw-r--r--src/server/api/endpoints/admin/emoji/add.ts7
-rw-r--r--src/server/api/endpoints/admin/emoji/remove.ts7
-rw-r--r--src/server/api/endpoints/admin/queue/clear.ts5
-rw-r--r--src/server/api/endpoints/admin/show-moderation-logs.ts35
-rw-r--r--src/server/api/endpoints/admin/silence-user.ts7
-rw-r--r--src/server/api/endpoints/admin/suspend-user.ts7
-rw-r--r--src/server/api/endpoints/admin/unsilence-user.ts7
-rw-r--r--src/server/api/endpoints/admin/unsuspend-user.ts7
-rw-r--r--src/server/api/endpoints/admin/update-meta.ts5
-rw-r--r--src/server/api/endpoints/admin/vacuum.ts5
-rw-r--r--src/services/insert-moderation-log.ts13
16 files changed, 211 insertions, 11 deletions
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 @@
</ui-horizon-group>
</section>
</ui-card>
+
+ <ui-card>
+ <template #title>{{ $t('logs.title') }}</template>
+ <section class="fit-top">
+ <sequential-entrance animation="entranceFromTop" delay="25">
+ <div v-for="log in logs" :key="log.id" class="">
+ <ui-horizon-group inputs>
+ <ui-input :value="log.user | acct" type="text" readonly>
+ <span>{{ $t('logs.moderator') }}</span>
+ </ui-input>
+ <ui-input :value="log.type" type="text" readonly>
+ <span>{{ $t('logs.type') }}</span>
+ </ui-input>
+ <ui-input :value="log.createdAt | date" type="text" readonly>
+ <span>{{ $t('logs.at') }}</span>
+ </ui-input>
+ </ui-horizon-group>
+ <ui-textarea :value="JSON.stringify(log.info, null, 4)" readonly>
+ <span>{{ $t('logs.info') }}</span>
+ </ui-textarea>
+ </div>
+ </sequential-entrance>
+ <ui-button v-if="existMoreLogs" @click="fetchLogs">{{ $t('@.load-more') }}</ui-button>
+ </section>
+ </ui-card>
</div>
</template>
@@ -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;
+ });
+ },
}
});
</script>
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<string, any>;
+}
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<ModerationLog> {
+ 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<Meta>;
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<string, any>) {
+ await ModerationLogs.save({
+ id: genId(),
+ createdAt: new Date(),
+ userId: moderator.id,
+ type: type,
+ info: info || {}
+ });
+}