Resolve #3238
This commit is contained in:
		
							parent
							
								
									0fc965f342
								
							
						
					
					
						commit
						b34c1379e9
					
				
					 18 changed files with 234 additions and 11 deletions
				
			
		|  | @ -1529,6 +1529,12 @@ admin/views/moderators.vue: | ||||||
|     added: "モデレーターを登録しました" |     added: "モデレーターを登録しました" | ||||||
|     remove: "解除" |     remove: "解除" | ||||||
|     removed: "モデレーター登録を解除しました" |     removed: "モデレーター登録を解除しました" | ||||||
|  |   logs: | ||||||
|  |     title: "ログ" | ||||||
|  |     moderator: "モデレーター" | ||||||
|  |     type: "操作" | ||||||
|  |     at: "日時" | ||||||
|  |     info: "情報" | ||||||
| 
 | 
 | ||||||
| admin/views/emoji.vue: | admin/views/emoji.vue: | ||||||
|   add-emoji: |   add-emoji: | ||||||
|  |  | ||||||
							
								
								
									
										17
									
								
								migration/1562869971568-ModerationLog.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								migration/1562869971568-ModerationLog.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | import {MigrationInterface, QueryRunner} from "typeorm"; | ||||||
|  | 
 | ||||||
|  | export class ModerationLog1562869971568 implements MigrationInterface { | ||||||
|  | 
 | ||||||
|  |     public async up(queryRunner: QueryRunner): Promise<any> { | ||||||
|  |         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<any> { | ||||||
|  |         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"`); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -12,6 +12,31 @@ | ||||||
| 			</ui-horizon-group> | 			</ui-horizon-group> | ||||||
| 		</section> | 		</section> | ||||||
| 	</ui-card> | 	</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> | </div> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
|  | @ -26,10 +51,17 @@ export default Vue.extend({ | ||||||
| 	data() { | 	data() { | ||||||
| 		return { | 		return { | ||||||
| 			username: '', | 			username: '', | ||||||
| 			changing: false | 			changing: false, | ||||||
|  | 			logs: [], | ||||||
|  | 			untilLogId: null, | ||||||
|  | 			existMoreLogs: false | ||||||
| 		}; | 		}; | ||||||
| 	}, | 	}, | ||||||
| 
 | 
 | ||||||
|  | 	created() { | ||||||
|  | 		this.fetchLogs(); | ||||||
|  | 	}, | ||||||
|  | 
 | ||||||
| 	methods: { | 	methods: { | ||||||
| 		async add() { | 		async add() { | ||||||
| 			this.changing = true; | 			this.changing = true; | ||||||
|  | @ -74,6 +106,22 @@ export default Vue.extend({ | ||||||
| 
 | 
 | ||||||
| 			this.changing = false; | 			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> | </script> | ||||||
|  |  | ||||||
|  | @ -47,6 +47,7 @@ import { UserSecurityKey } from '../models/entities/user-security-key'; | ||||||
| import { AttestationChallenge } from '../models/entities/attestation-challenge'; | import { AttestationChallenge } from '../models/entities/attestation-challenge'; | ||||||
| import { Page } from '../models/entities/page'; | import { Page } from '../models/entities/page'; | ||||||
| import { PageLike } from '../models/entities/page-like'; | import { PageLike } from '../models/entities/page-like'; | ||||||
|  | import { ModerationLog } from '../models/entities/moderation-log'; | ||||||
| 
 | 
 | ||||||
| const sqlLogger = dbLogger.createSubLogger('sql', 'white', false); | const sqlLogger = dbLogger.createSubLogger('sql', 'white', false); | ||||||
| 
 | 
 | ||||||
|  | @ -124,6 +125,7 @@ export const entities = [ | ||||||
| 	RegistrationTicket, | 	RegistrationTicket, | ||||||
| 	MessagingMessage, | 	MessagingMessage, | ||||||
| 	Signin, | 	Signin, | ||||||
|  | 	ModerationLog, | ||||||
| 	ReversiGame, | 	ReversiGame, | ||||||
| 	ReversiMatching, | 	ReversiMatching, | ||||||
| 	...charts as any | 	...charts as any | ||||||
|  |  | ||||||
							
								
								
									
										32
									
								
								src/models/entities/moderation-log.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/models/entities/moderation-log.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -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>; | ||||||
|  | } | ||||||
|  | @ -42,6 +42,7 @@ import { UserSecurityKey } from './entities/user-security-key'; | ||||||
| import { HashtagRepository } from './repositories/hashtag'; | import { HashtagRepository } from './repositories/hashtag'; | ||||||
| import { PageRepository } from './repositories/page'; | import { PageRepository } from './repositories/page'; | ||||||
| import { PageLikeRepository } from './repositories/page-like'; | import { PageLikeRepository } from './repositories/page-like'; | ||||||
|  | import { ModerationLogRepository } from './repositories/moderation-logs'; | ||||||
| 
 | 
 | ||||||
| export const Apps = getCustomRepository(AppRepository); | export const Apps = getCustomRepository(AppRepository); | ||||||
| export const Notes = getCustomRepository(NoteRepository); | export const Notes = getCustomRepository(NoteRepository); | ||||||
|  | @ -86,3 +87,4 @@ export const ReversiMatchings = getCustomRepository(ReversiMatchingRepository); | ||||||
| export const Logs = getRepository(Log); | export const Logs = getRepository(Log); | ||||||
| export const Pages = getCustomRepository(PageRepository); | export const Pages = getCustomRepository(PageRepository); | ||||||
| export const PageLikes = getCustomRepository(PageLikeRepository); | export const PageLikes = getCustomRepository(PageLikeRepository); | ||||||
|  | export const ModerationLogs = getCustomRepository(ModerationLogRepository); | ||||||
|  |  | ||||||
							
								
								
									
										31
									
								
								src/models/repositories/moderation-logs.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/models/repositories/moderation-logs.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -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))); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -4,6 +4,7 @@ import { detectUrlMine } from '../../../../../misc/detect-url-mine'; | ||||||
| import { Emojis } from '../../../../../models'; | import { Emojis } from '../../../../../models'; | ||||||
| import { genId } from '../../../../../misc/gen-id'; | import { genId } from '../../../../../misc/gen-id'; | ||||||
| import { getConnection } from 'typeorm'; | import { getConnection } from 'typeorm'; | ||||||
|  | import { insertModerationLog } from '../../../../../services/insert-moderation-log'; | ||||||
| 
 | 
 | ||||||
| export const meta = { | export const meta = { | ||||||
| 	desc: { | 	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 type = await detectUrlMine(ps.url); | ||||||
| 
 | 
 | ||||||
| 	const emoji = await Emojis.save({ | 	const emoji = await Emojis.save({ | ||||||
|  | @ -46,6 +47,10 @@ export default define(meta, async (ps) => { | ||||||
| 
 | 
 | ||||||
| 	await getConnection().queryResultCache!.remove(['meta_emojis']); | 	await getConnection().queryResultCache!.remove(['meta_emojis']); | ||||||
| 
 | 
 | ||||||
|  | 	insertModerationLog(me, 'addEmoji', { | ||||||
|  | 		emojiId: emoji.id | ||||||
|  | 	}); | ||||||
|  | 
 | ||||||
| 	return { | 	return { | ||||||
| 		id: emoji.id | 		id: emoji.id | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ import define from '../../../define'; | ||||||
| import { ID } from '../../../../../misc/cafy-id'; | import { ID } from '../../../../../misc/cafy-id'; | ||||||
| import { Emojis } from '../../../../../models'; | import { Emojis } from '../../../../../models'; | ||||||
| import { getConnection } from 'typeorm'; | import { getConnection } from 'typeorm'; | ||||||
|  | import { insertModerationLog } from '../../../../../services/insert-moderation-log'; | ||||||
| 
 | 
 | ||||||
| export const meta = { | export const meta = { | ||||||
| 	desc: { | 	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); | 	const emoji = await Emojis.findOne(ps.id); | ||||||
| 
 | 
 | ||||||
| 	if (emoji == null) throw new Error('emoji not found'); | 	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 Emojis.delete(emoji.id); | ||||||
| 
 | 
 | ||||||
| 	await getConnection().queryResultCache!.remove(['meta_emojis']); | 	await getConnection().queryResultCache!.remove(['meta_emojis']); | ||||||
|  | 
 | ||||||
|  | 	insertModerationLog(me, 'removeEmoji', { | ||||||
|  | 		emoji: emoji | ||||||
|  | 	}); | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| import define from '../../../define'; | import define from '../../../define'; | ||||||
| import { destroy } from '../../../../../queue'; | import { destroy } from '../../../../../queue'; | ||||||
|  | import { insertModerationLog } from '../../../../../services/insert-moderation-log'; | ||||||
| 
 | 
 | ||||||
| export const meta = { | export const meta = { | ||||||
| 	tags: ['admin'], | 	tags: ['admin'], | ||||||
|  | @ -10,8 +11,8 @@ export const meta = { | ||||||
| 	params: {} | 	params: {} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export default define(meta, async (ps) => { | export default define(meta, async (ps, me) => { | ||||||
| 	destroy(); | 	destroy(); | ||||||
| 
 | 
 | ||||||
| 	return; | 	insertModerationLog(me, 'clearQueue'); | ||||||
| }); | }); | ||||||
|  |  | ||||||
							
								
								
									
										35
									
								
								src/server/api/endpoints/admin/show-moderation-logs.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/server/api/endpoints/admin/show-moderation-logs.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -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); | ||||||
|  | }); | ||||||
|  | @ -2,6 +2,7 @@ import $ from 'cafy'; | ||||||
| import { ID } from '../../../../misc/cafy-id'; | import { ID } from '../../../../misc/cafy-id'; | ||||||
| import define from '../../define'; | import define from '../../define'; | ||||||
| import { Users } from '../../../../models'; | import { Users } from '../../../../models'; | ||||||
|  | import { insertModerationLog } from '../../../../services/insert-moderation-log'; | ||||||
| 
 | 
 | ||||||
| export const meta = { | export const meta = { | ||||||
| 	desc: { | 	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); | 	const user = await Users.findOne(ps.userId as string); | ||||||
| 
 | 
 | ||||||
| 	if (user == null) { | 	if (user == null) { | ||||||
|  | @ -39,4 +40,8 @@ export default define(meta, async (ps) => { | ||||||
| 	await Users.update(user.id, { | 	await Users.update(user.id, { | ||||||
| 		isSilenced: true | 		isSilenced: true | ||||||
| 	}); | 	}); | ||||||
|  | 
 | ||||||
|  | 	insertModerationLog(me, 'silence', { | ||||||
|  | 		targetId: user.id, | ||||||
|  | 	}); | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | @ -4,6 +4,7 @@ import define from '../../define'; | ||||||
| import deleteFollowing from '../../../../services/following/delete'; | import deleteFollowing from '../../../../services/following/delete'; | ||||||
| import { Users, Followings } from '../../../../models'; | import { Users, Followings } from '../../../../models'; | ||||||
| import { User } from '../../../../models/entities/user'; | import { User } from '../../../../models/entities/user'; | ||||||
|  | import { insertModerationLog } from '../../../../services/insert-moderation-log'; | ||||||
| 
 | 
 | ||||||
| export const meta = { | export const meta = { | ||||||
| 	desc: { | 	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); | 	const user = await Users.findOne(ps.userId as string); | ||||||
| 
 | 
 | ||||||
| 	if (user == null) { | 	if (user == null) { | ||||||
|  | @ -46,6 +47,10 @@ export default define(meta, async (ps) => { | ||||||
| 		isSuspended: true | 		isSuspended: true | ||||||
| 	}); | 	}); | ||||||
| 
 | 
 | ||||||
|  | 	insertModerationLog(me, 'suspend', { | ||||||
|  | 		targetId: user.id, | ||||||
|  | 	}); | ||||||
|  | 
 | ||||||
| 	unFollowAll(user); | 	unFollowAll(user); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ import $ from 'cafy'; | ||||||
| import { ID } from '../../../../misc/cafy-id'; | import { ID } from '../../../../misc/cafy-id'; | ||||||
| import define from '../../define'; | import define from '../../define'; | ||||||
| import { Users } from '../../../../models'; | import { Users } from '../../../../models'; | ||||||
|  | import { insertModerationLog } from '../../../../services/insert-moderation-log'; | ||||||
| 
 | 
 | ||||||
| export const meta = { | export const meta = { | ||||||
| 	desc: { | 	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); | 	const user = await Users.findOne(ps.userId as string); | ||||||
| 
 | 
 | ||||||
| 	if (user == null) { | 	if (user == null) { | ||||||
|  | @ -35,4 +36,8 @@ export default define(meta, async (ps) => { | ||||||
| 	await Users.update(user.id, { | 	await Users.update(user.id, { | ||||||
| 		isSilenced: false | 		isSilenced: false | ||||||
| 	}); | 	}); | ||||||
|  | 
 | ||||||
|  | 	insertModerationLog(me, 'unsilence', { | ||||||
|  | 		targetId: user.id, | ||||||
|  | 	}); | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ import $ from 'cafy'; | ||||||
| import { ID } from '../../../../misc/cafy-id'; | import { ID } from '../../../../misc/cafy-id'; | ||||||
| import define from '../../define'; | import define from '../../define'; | ||||||
| import { Users } from '../../../../models'; | import { Users } from '../../../../models'; | ||||||
|  | import { insertModerationLog } from '../../../../services/insert-moderation-log'; | ||||||
| 
 | 
 | ||||||
| export const meta = { | export const meta = { | ||||||
| 	desc: { | 	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); | 	const user = await Users.findOne(ps.userId as string); | ||||||
| 
 | 
 | ||||||
| 	if (user == null) { | 	if (user == null) { | ||||||
|  | @ -35,4 +36,8 @@ export default define(meta, async (ps) => { | ||||||
| 	await Users.update(user.id, { | 	await Users.update(user.id, { | ||||||
| 		isSuspended: false | 		isSuspended: false | ||||||
| 	}); | 	}); | ||||||
|  | 
 | ||||||
|  | 	insertModerationLog(me, 'unsuspend', { | ||||||
|  | 		targetId: user.id, | ||||||
|  | 	}); | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ import $ from 'cafy'; | ||||||
| import define from '../../define'; | import define from '../../define'; | ||||||
| import { getConnection } from 'typeorm'; | import { getConnection } from 'typeorm'; | ||||||
| import { Meta } from '../../../../models/entities/meta'; | import { Meta } from '../../../../models/entities/meta'; | ||||||
|  | import { insertModerationLog } from '../../../../services/insert-moderation-log'; | ||||||
| 
 | 
 | ||||||
| export const meta = { | export const meta = { | ||||||
| 	desc: { | 	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>; | 	const set = {} as Partial<Meta>; | ||||||
| 
 | 
 | ||||||
| 	if (ps.announcements) { | 	if (ps.announcements) { | ||||||
|  | @ -653,4 +654,6 @@ export default define(meta, async (ps) => { | ||||||
| 			await transactionalEntityManager.save(Meta, set); | 			await transactionalEntityManager.save(Meta, set); | ||||||
| 		} | 		} | ||||||
| 	}); | 	}); | ||||||
|  | 
 | ||||||
|  | 	insertModerationLog(me, 'updateMeta'); | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| import $ from 'cafy'; | import $ from 'cafy'; | ||||||
| import define from '../../define'; | import define from '../../define'; | ||||||
| import { getConnection } from 'typeorm'; | import { getConnection } from 'typeorm'; | ||||||
|  | import { insertModerationLog } from '../../../../services/insert-moderation-log'; | ||||||
| 
 | 
 | ||||||
| export const meta = { | export const meta = { | ||||||
| 	tags: ['admin'], | 	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[] = []; | 	const params: string[] = []; | ||||||
| 
 | 
 | ||||||
| 	if (ps.full) { | 	if (ps.full) { | ||||||
|  | @ -30,4 +31,6 @@ export default define(meta, async (ps) => { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	getConnection().query('VACUUM ' + params.join(' ')); | 	getConnection().query('VACUUM ' + params.join(' ')); | ||||||
|  | 
 | ||||||
|  | 	insertModerationLog(me, 'vacuum', ps); | ||||||
| }); | }); | ||||||
|  |  | ||||||
							
								
								
									
										13
									
								
								src/services/insert-moderation-log.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/services/insert-moderation-log.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 || {} | ||||||
|  | 	}); | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue