From 3b9111392eef3b98bf76be9108fe84248c2d4e93 Mon Sep 17 00:00:00 2001 From: FatttSnake Date: Thu, 4 Jan 2024 17:55:41 +0800 Subject: [PATCH] Add sensitive word filter --- .../controller/system/SettingsController.kt | 66 +++++++++++++++++-- .../api/converter/system/SettingsConverter.kt | 26 ++++++++ .../oxygen/api/entity/common/ResponseCode.kt | 1 + .../oxygen/api/entity/system/SensitiveWord.kt | 63 ++++++++++++++++++ .../exception/MatchSensitiveWordException.kt | 3 + .../oxygen/api/handler/ExceptionHandler.kt | 22 ++++++- .../api/mapper/system/SensitiveWordMapper.kt | 14 ++++ .../param/api/v1/avatar/AvatarBaseParam.kt | 4 +- .../api/param/system/ActiveInfoGetParam.kt | 1 + .../api/param/system/OnlineInfoGetParam.kt | 1 + .../api/param/system/SensitiveWordAddParam.kt | 43 ++++++++++++ .../param/system/SensitiveWordUpdateParam.kt | 15 +++++ .../impl/AuthenticationServiceImpl.kt | 4 ++ .../api/service/system/IEventLogService.kt | 7 ++ .../service/system/ISensitiveWordService.kt | 58 ++++++++++++++++ .../system/impl/EventLogServiceImpl.kt | 6 ++ .../system/impl/SensitiveWordServiceImpl.kt | 66 +++++++++++++++++++ .../system/impl/StatisticsLogServiceImpl.kt | 6 ++ .../oxygen/api/vo/system/SensitiveWordVo.kt | 52 +++++++++++++++ .../db/migration/master/R__Basic_data.sql | 8 ++- ...0_240103__Add_table_‘t_sensitive_word'.sql | 9 +++ 21 files changed, 466 insertions(+), 9 deletions(-) create mode 100644 src/main/kotlin/top/fatweb/oxygen/api/converter/system/SettingsConverter.kt create mode 100644 src/main/kotlin/top/fatweb/oxygen/api/entity/system/SensitiveWord.kt create mode 100644 src/main/kotlin/top/fatweb/oxygen/api/exception/MatchSensitiveWordException.kt create mode 100644 src/main/kotlin/top/fatweb/oxygen/api/mapper/system/SensitiveWordMapper.kt create mode 100644 src/main/kotlin/top/fatweb/oxygen/api/param/system/SensitiveWordAddParam.kt create mode 100644 src/main/kotlin/top/fatweb/oxygen/api/param/system/SensitiveWordUpdateParam.kt create mode 100644 src/main/kotlin/top/fatweb/oxygen/api/service/system/ISensitiveWordService.kt create mode 100644 src/main/kotlin/top/fatweb/oxygen/api/service/system/impl/SensitiveWordServiceImpl.kt create mode 100644 src/main/kotlin/top/fatweb/oxygen/api/vo/system/SensitiveWordVo.kt create mode 100644 src/main/resources/db/migration/sqlite/V1_0_0_240103__Add_table_‘t_sensitive_word'.sql diff --git a/src/main/kotlin/top/fatweb/oxygen/api/controller/system/SettingsController.kt b/src/main/kotlin/top/fatweb/oxygen/api/controller/system/SettingsController.kt index 9602e56..8da32a9 100644 --- a/src/main/kotlin/top/fatweb/oxygen/api/controller/system/SettingsController.kt +++ b/src/main/kotlin/top/fatweb/oxygen/api/controller/system/SettingsController.kt @@ -3,18 +3,21 @@ package top.fatweb.oxygen.api.controller.system import io.swagger.v3.oas.annotations.Operation import jakarta.validation.Valid import org.springframework.security.access.prepost.PreAuthorize +import org.springframework.web.bind.annotation.DeleteMapping import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.PutMapping import org.springframework.web.bind.annotation.RequestBody import top.fatweb.oxygen.api.annotation.BaseController +import top.fatweb.oxygen.api.entity.common.ResponseCode import top.fatweb.oxygen.api.entity.common.ResponseResult -import top.fatweb.oxygen.api.param.system.BaseSettingsParam -import top.fatweb.oxygen.api.param.system.MailSendParam -import top.fatweb.oxygen.api.param.system.MailSettingsParam +import top.fatweb.oxygen.api.param.system.* +import top.fatweb.oxygen.api.service.system.ISensitiveWordService import top.fatweb.oxygen.api.service.system.ISettingsService import top.fatweb.oxygen.api.vo.system.BaseSettingsVo import top.fatweb.oxygen.api.vo.system.MailSettingsVo +import top.fatweb.oxygen.api.vo.system.SensitiveWordVo /** * System settings controller @@ -25,7 +28,8 @@ import top.fatweb.oxygen.api.vo.system.MailSettingsVo */ @BaseController(path = ["/system/settings"], name = "系统设置", description = "系统设置相关接口") class SettingsController( - private val settingsService: ISettingsService + private val settingsService: ISettingsService, + private val sensitiveWordService: ISensitiveWordService ) { /** * Get base settings @@ -97,4 +101,58 @@ class SettingsController( settingsService.sendMail(mailSendParam) return ResponseResult.success() } + + /** + * Get sensitive word settings + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + @Operation(summary = "获取敏感词配置") + @GetMapping("/sensitive") + @PreAuthorize("hasAnyAuthority('system:settings:query:sensitive')") + fun getSensitive(): ResponseResult> = + ResponseResult.databaseSuccess(ResponseCode.DATABASE_SELECT_SUCCESS, data = sensitiveWordService.get()) + + /** + * Add sensitive word + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + @Operation(summary = "添加敏感词") + @PostMapping("/sensitive") + @PreAuthorize("hasAnyAuthority('system:settings:modify:sensitive')") + fun addSensitive(@RequestBody @Valid sensitiveWordAddParam: SensitiveWordAddParam): ResponseResult { + sensitiveWordService.add(sensitiveWordAddParam) + return ResponseResult.databaseSuccess(ResponseCode.DATABASE_INSERT_SUCCESS) + } + + /** + * Update sensitive word + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + @Operation(summary = "修改敏感词") + @PutMapping("/sensitive") + @PreAuthorize("hasAnyAuthority('system:settings:modify:sensitive')") + fun updateSensitive(@RequestBody sensitiveWordUpdateParam: SensitiveWordUpdateParam): ResponseResult { + sensitiveWordService.update(sensitiveWordUpdateParam) + return ResponseResult.databaseSuccess(ResponseCode.DATABASE_UPDATE_SUCCESS) + } + + /** + * Delete sensitive word + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + @Operation(summary = "删除敏感词") + @DeleteMapping("/sensitive/{id}") + @PreAuthorize("hasAnyAuthority('system:settings:modify:sensitive')") + fun deleteSensitive(@PathVariable id: Long): ResponseResult { + sensitiveWordService.delete(id) + return ResponseResult.databaseSuccess(ResponseCode.DATABASE_DELETE_SUCCESS) + } } \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/oxygen/api/converter/system/SettingsConverter.kt b/src/main/kotlin/top/fatweb/oxygen/api/converter/system/SettingsConverter.kt new file mode 100644 index 0000000..a9f29bb --- /dev/null +++ b/src/main/kotlin/top/fatweb/oxygen/api/converter/system/SettingsConverter.kt @@ -0,0 +1,26 @@ +package top.fatweb.oxygen.api.converter.system + +import top.fatweb.oxygen.api.entity.system.SensitiveWord +import top.fatweb.oxygen.api.param.system.SensitiveWordAddParam +import top.fatweb.oxygen.api.vo.system.SensitiveWordVo + +/** + * Settings converter + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ +object SettingsConverter { + fun sensitiveWordToSensitiveWordVo(sensitiveWord: SensitiveWord) = SensitiveWordVo( + id = sensitiveWord.id, + word = sensitiveWord.word, + useFor = sensitiveWord.useFor?.map(SensitiveWord.Use::valueOf)?.toSet(), + enable = sensitiveWord.enable == 1 + ) + + fun sensitiveWordAddParamToSensitiveWord(sensitiveWordAddParam: SensitiveWordAddParam) = SensitiveWord().apply { + word = sensitiveWordAddParam.word + useFor = sensitiveWordAddParam.useFor.map(SensitiveWord.Use::code).toSet() + enable = if (sensitiveWordAddParam.enable) 1 else 0 + } +} \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/oxygen/api/entity/common/ResponseCode.kt b/src/main/kotlin/top/fatweb/oxygen/api/entity/common/ResponseCode.kt index ef3ad98..4e3032c 100644 --- a/src/main/kotlin/top/fatweb/oxygen/api/entity/common/ResponseCode.kt +++ b/src/main/kotlin/top/fatweb/oxygen/api/entity/common/ResponseCode.kt @@ -15,6 +15,7 @@ enum class ResponseCode(val code: Int) { SYSTEM_ARGUMENT_NOT_VALID(BusinessCode.SYSTEM, 53), SYSTEM_INVALID_CAPTCHA_CODE(BusinessCode.SYSTEM, 54), SYSTEM_REQUEST_TOO_FREQUENT(BusinessCode.SYSTEM, 55), + SYSTEM_MATCH_SENSITIVE_WORD(BusinessCode.SYSTEM, 56), PERMISSION_LOGIN_SUCCESS(BusinessCode.PERMISSION, 0), PERMISSION_PASSWORD_CHANGE_SUCCESS(BusinessCode.PERMISSION, 1), diff --git a/src/main/kotlin/top/fatweb/oxygen/api/entity/system/SensitiveWord.kt b/src/main/kotlin/top/fatweb/oxygen/api/entity/system/SensitiveWord.kt new file mode 100644 index 0000000..a38413a --- /dev/null +++ b/src/main/kotlin/top/fatweb/oxygen/api/entity/system/SensitiveWord.kt @@ -0,0 +1,63 @@ +package top.fatweb.oxygen.api.entity.system + +import com.baomidou.mybatisplus.annotation.EnumValue +import com.baomidou.mybatisplus.annotation.TableField +import com.baomidou.mybatisplus.annotation.TableId +import com.baomidou.mybatisplus.annotation.TableName +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler +import com.fasterxml.jackson.annotation.JsonValue +import java.io.Serializable + +/** + * Sensitive word entity + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ +@TableName("t_sensitive_word", autoResultMap = true) +class SensitiveWord : Serializable { + enum class Use(@field:EnumValue @field:JsonValue val code: String) { + USERNAME("USERNAME"), TITLE("TITLE"); + } + + /** + * ID + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + @TableId("id") + var id: Long? = null + + /** + * Word + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + @TableField("word") + var word: String? = null + + /** + * Use for + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + @TableField(value = "use_for", typeHandler = JacksonTypeHandler::class) + @JvmField + var useFor: Set? = null + + /** + * Enable + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + @TableField("enable") + var enable: Int? = null + + override fun toString(): String { + return "SensitiveWord(id=$id, word=$word, useFor=$useFor, enable=$enable)" + } +} \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/oxygen/api/exception/MatchSensitiveWordException.kt b/src/main/kotlin/top/fatweb/oxygen/api/exception/MatchSensitiveWordException.kt new file mode 100644 index 0000000..d428efb --- /dev/null +++ b/src/main/kotlin/top/fatweb/oxygen/api/exception/MatchSensitiveWordException.kt @@ -0,0 +1,3 @@ +package top.fatweb.oxygen.api.exception + +class MatchSensitiveWordException: RuntimeException("Match sensitive word") \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/oxygen/api/handler/ExceptionHandler.kt b/src/main/kotlin/top/fatweb/oxygen/api/handler/ExceptionHandler.kt index 7b39df0..a47a3c3 100644 --- a/src/main/kotlin/top/fatweb/oxygen/api/handler/ExceptionHandler.kt +++ b/src/main/kotlin/top/fatweb/oxygen/api/handler/ExceptionHandler.kt @@ -8,6 +8,7 @@ import org.slf4j.LoggerFactory import org.springframework.dao.DuplicateKeyException import org.springframework.http.converter.HttpMessageNotReadableException import org.springframework.jdbc.BadSqlGrammarException +import org.springframework.jdbc.UncategorizedSQLException import org.springframework.security.access.AccessDeniedException import org.springframework.security.authentication.* import org.springframework.web.HttpRequestMethodNotSupportedException @@ -43,6 +44,7 @@ class ExceptionHandler { @ExceptionHandler(value = [Exception::class]) fun exceptionHandler(e: Exception): ResponseResult<*> { return when (e) { + /* Request */ is HttpRequestMethodNotSupportedException, is NoResourceFoundException -> { logger.debug(e.localizedMessage, e) ResponseResult.fail(ResponseCode.SYSTEM_REQUEST_ILLEGAL, e.localizedMessage, null) @@ -64,6 +66,7 @@ class ExceptionHandler { ResponseResult.fail(ResponseCode.SYSTEM_REQUEST_TOO_FREQUENT, e.localizedMessage, null) } + /* Authentication */ is InsufficientAuthenticationException -> { logger.debug(e.localizedMessage, e) ResponseResult.fail(ResponseCode.PERMISSION_UNAUTHORIZED, e.localizedMessage, null) @@ -162,7 +165,7 @@ class ExceptionHandler { ResponseResult.fail(ResponseCode.SYSTEM_INVALID_CAPTCHA_CODE, e.localizedMessage, null) } - + /* SQL */ is BadSqlGrammarException -> { logger.debug(e.localizedMessage, e) ResponseResult.fail(ResponseCode.DATABASE_EXECUTE_ERROR, "Incorrect SQL syntax", null) @@ -178,6 +181,23 @@ class ExceptionHandler { ResponseResult.fail(ResponseCode.DATABASE_NO_RECORD_FOUND, e.localizedMessage, null) } + is UncategorizedSQLException -> { + if (e.localizedMessage.contains("SQLITE_CONSTRAINT_UNIQUE")) { + logger.debug(e.localizedMessage, e) + return ResponseResult.fail(ResponseCode.DATABASE_DUPLICATE_KEY, "Duplicate key", null) + } + + logger.error(e.localizedMessage, e) + ResponseResult.fail(ResponseCode.DATABASE_EXECUTE_ERROR, e.localizedMessage, null) + } + + /* Other */ + is MatchSensitiveWordException -> { + logger.debug(e.localizedMessage, e) + ResponseResult.fail(ResponseCode.SYSTEM_MATCH_SENSITIVE_WORD, e.localizedMessage, null) + } + + /* API */ is AvatarException -> { logger.debug(e.localizedMessage, e) ResponseResult.fail(ResponseCode.API_AVATAR_ERROR, e.localizedMessage, null) diff --git a/src/main/kotlin/top/fatweb/oxygen/api/mapper/system/SensitiveWordMapper.kt b/src/main/kotlin/top/fatweb/oxygen/api/mapper/system/SensitiveWordMapper.kt new file mode 100644 index 0000000..c9dfd82 --- /dev/null +++ b/src/main/kotlin/top/fatweb/oxygen/api/mapper/system/SensitiveWordMapper.kt @@ -0,0 +1,14 @@ +package top.fatweb.oxygen.api.mapper.system + +import com.baomidou.mybatisplus.core.mapper.BaseMapper +import org.apache.ibatis.annotations.Mapper +import top.fatweb.oxygen.api.entity.system.SensitiveWord + +/** + * Sensitive word mapper + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ +@Mapper +interface SensitiveWordMapper : BaseMapper \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/oxygen/api/param/api/v1/avatar/AvatarBaseParam.kt b/src/main/kotlin/top/fatweb/oxygen/api/param/api/v1/avatar/AvatarBaseParam.kt index 390e4d1..c949017 100644 --- a/src/main/kotlin/top/fatweb/oxygen/api/param/api/v1/avatar/AvatarBaseParam.kt +++ b/src/main/kotlin/top/fatweb/oxygen/api/param/api/v1/avatar/AvatarBaseParam.kt @@ -54,7 +54,7 @@ open class AvatarBaseParam { * @author FatttSnake, fatttsnake@gmail.com * @since 1.0.0 */ - @Schema(defaultValue = "颜色列表", example = "#FFFFFFAA") + @Schema(description = "颜色列表", example = "#FFFFFFAA") var colors: List? = null /** @@ -63,7 +63,7 @@ open class AvatarBaseParam { * @author FatttSnake, fatttsnake@gmail.com * @since 1.0.0 */ - @Schema(defaultValue = "背景颜色", example = "#FFFFFFAA") + @Schema(description = "背景颜色", example = "#FFFFFFAA") @field:Pattern(regexp = "^#[0-9a-fA-F]{6}|#[0-9a-fA-F]{8}$", message = "Background color must be a hex color code") var background: String? = null } diff --git a/src/main/kotlin/top/fatweb/oxygen/api/param/system/ActiveInfoGetParam.kt b/src/main/kotlin/top/fatweb/oxygen/api/param/system/ActiveInfoGetParam.kt index 51e45b9..c085c80 100644 --- a/src/main/kotlin/top/fatweb/oxygen/api/param/system/ActiveInfoGetParam.kt +++ b/src/main/kotlin/top/fatweb/oxygen/api/param/system/ActiveInfoGetParam.kt @@ -10,6 +10,7 @@ import io.swagger.v3.oas.annotations.media.Schema * @author FatttSnake, fatttsnake@gmail.com * @since 1.0.0 */ +@Schema(description = "用户活跃信息请求参数") data class ActiveInfoGetParam( /** * Scope diff --git a/src/main/kotlin/top/fatweb/oxygen/api/param/system/OnlineInfoGetParam.kt b/src/main/kotlin/top/fatweb/oxygen/api/param/system/OnlineInfoGetParam.kt index 1e42833..932f10e 100644 --- a/src/main/kotlin/top/fatweb/oxygen/api/param/system/OnlineInfoGetParam.kt +++ b/src/main/kotlin/top/fatweb/oxygen/api/param/system/OnlineInfoGetParam.kt @@ -10,6 +10,7 @@ import io.swagger.v3.oas.annotations.media.Schema * @author FatttSnake, fatttsnake@gmail.com * @since 1.0.0 */ +@Schema(description = "在线信息请求参数") data class OnlineInfoGetParam( /** * Scope diff --git a/src/main/kotlin/top/fatweb/oxygen/api/param/system/SensitiveWordAddParam.kt b/src/main/kotlin/top/fatweb/oxygen/api/param/system/SensitiveWordAddParam.kt new file mode 100644 index 0000000..6071bf2 --- /dev/null +++ b/src/main/kotlin/top/fatweb/oxygen/api/param/system/SensitiveWordAddParam.kt @@ -0,0 +1,43 @@ +package top.fatweb.oxygen.api.param.system + +import io.swagger.v3.oas.annotations.media.Schema +import jakarta.validation.constraints.NotBlank +import top.fatweb.oxygen.api.entity.system.SensitiveWord + +/** + * Add sensitive word settings parameters + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ +@Schema(defaultValue = "敏感词添加请求参数") +data class SensitiveWordAddParam( + /** + * Word + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + @Schema(description = "词", required = true) + @field:NotBlank(message = "Word can not be blank") + val word: String?, + + /** + * Use for + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + * @see SensitiveWord.Use + */ + @Schema(description = "用于", allowableValues = ["USERNAME"]) + val useFor: Set = emptySet(), + + /** + * Enable + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + @Schema(description = "启用", allowableValues = ["true", "false"], defaultValue = "true") + val enable: Boolean = true +) diff --git a/src/main/kotlin/top/fatweb/oxygen/api/param/system/SensitiveWordUpdateParam.kt b/src/main/kotlin/top/fatweb/oxygen/api/param/system/SensitiveWordUpdateParam.kt new file mode 100644 index 0000000..1faf759 --- /dev/null +++ b/src/main/kotlin/top/fatweb/oxygen/api/param/system/SensitiveWordUpdateParam.kt @@ -0,0 +1,15 @@ +package top.fatweb.oxygen.api.param.system + +import io.swagger.v3.oas.annotations.media.Schema + +/** + * Update sensitive word settings parameters + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ +@Schema(defaultValue = "敏感词修改请求参数") +data class SensitiveWordUpdateParam( + @Schema(description = "ID 列表") + val ids: Set = emptySet() +) diff --git a/src/main/kotlin/top/fatweb/oxygen/api/service/permission/impl/AuthenticationServiceImpl.kt b/src/main/kotlin/top/fatweb/oxygen/api/service/permission/impl/AuthenticationServiceImpl.kt index 5bb7f3f..dc6fd10 100644 --- a/src/main/kotlin/top/fatweb/oxygen/api/service/permission/impl/AuthenticationServiceImpl.kt +++ b/src/main/kotlin/top/fatweb/oxygen/api/service/permission/impl/AuthenticationServiceImpl.kt @@ -26,6 +26,7 @@ import top.fatweb.oxygen.api.service.api.v1.IAvatarService import top.fatweb.oxygen.api.service.permission.IAuthenticationService import top.fatweb.oxygen.api.service.permission.IUserInfoService import top.fatweb.oxygen.api.service.permission.IUserService +import top.fatweb.oxygen.api.service.system.ISensitiveWordService import top.fatweb.oxygen.api.settings.BaseSettings import top.fatweb.oxygen.api.settings.SettingsOperator import top.fatweb.oxygen.api.util.JwtUtil @@ -60,6 +61,7 @@ class AuthenticationServiceImpl( private val turnstileApi: TurnstileApi, private val userService: IUserService, private val userInfoService: IUserInfoService, + private val sensitiveWordService: ISensitiveWordService, private val avatarService: IAvatarService ) : IAuthenticationService { private val logger: Logger = LoggerFactory.getLogger(this::class.java) @@ -68,6 +70,7 @@ class AuthenticationServiceImpl( @Transactional override fun register(request: HttpServletRequest, registerParam: RegisterParam): RegisterVo { verifyCaptcha(registerParam.captchaCode!!) + sensitiveWordService.checkSensitiveWord(registerParam.username!!) val user = User().apply { username = registerParam.username @@ -132,6 +135,7 @@ class AuthenticationServiceImpl( if (verifyParam.nickname.isNullOrBlank() || verifyParam.avatar.isNullOrBlank()) { throw AccountNeedInitException() } + sensitiveWordService.checkSensitiveWord(verifyParam.nickname) userService.update( KtUpdateWrapper(User()).eq(User::id, user.id).set(User::verify, null) diff --git a/src/main/kotlin/top/fatweb/oxygen/api/service/system/IEventLogService.kt b/src/main/kotlin/top/fatweb/oxygen/api/service/system/IEventLogService.kt index 9925086..ca2693c 100644 --- a/src/main/kotlin/top/fatweb/oxygen/api/service/system/IEventLogService.kt +++ b/src/main/kotlin/top/fatweb/oxygen/api/service/system/IEventLogService.kt @@ -11,5 +11,12 @@ import top.fatweb.oxygen.api.entity.system.EventLog * @since 1.0.0 */ interface IEventLogService : IService { + /** + * Save event + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + * @see EventLogRecord + */ fun saveEvent(annotation: EventLogRecord, userId: Long) } \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/oxygen/api/service/system/ISensitiveWordService.kt b/src/main/kotlin/top/fatweb/oxygen/api/service/system/ISensitiveWordService.kt new file mode 100644 index 0000000..c51606e --- /dev/null +++ b/src/main/kotlin/top/fatweb/oxygen/api/service/system/ISensitiveWordService.kt @@ -0,0 +1,58 @@ +package top.fatweb.oxygen.api.service.system + +import com.baomidou.mybatisplus.extension.service.IService +import top.fatweb.oxygen.api.entity.system.SensitiveWord +import top.fatweb.oxygen.api.param.system.SensitiveWordAddParam +import top.fatweb.oxygen.api.param.system.SensitiveWordUpdateParam +import top.fatweb.oxygen.api.vo.system.SensitiveWordVo + +/** + * Sensitive word service interface + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ +interface ISensitiveWordService : IService { + /** + * Get sensitive word settings + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + * @see SensitiveWordVo + */ + fun get(): List + + /** + * Add sensitive word settings item + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + * @see SensitiveWordAddParam + */ + fun add(sensitiveWordAddParam: SensitiveWordAddParam) + + /** + * Update sensitive word settings + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + * @see SensitiveWordUpdateParam + */ + fun update(sensitiveWordUpdateParam: SensitiveWordUpdateParam) + + /** + * Delete sensitive word settings item + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + fun delete(id: Long) + + /** + * Check sensitive word + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + fun checkSensitiveWord(str: String) +} \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/oxygen/api/service/system/impl/EventLogServiceImpl.kt b/src/main/kotlin/top/fatweb/oxygen/api/service/system/impl/EventLogServiceImpl.kt index 845b1b6..b2d51d6 100644 --- a/src/main/kotlin/top/fatweb/oxygen/api/service/system/impl/EventLogServiceImpl.kt +++ b/src/main/kotlin/top/fatweb/oxygen/api/service/system/impl/EventLogServiceImpl.kt @@ -12,6 +12,12 @@ import top.fatweb.oxygen.api.entity.system.EventLog import top.fatweb.oxygen.api.mapper.system.EventLogMapper import top.fatweb.oxygen.api.service.system.IEventLogService +/** + * Event log service implement + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ @DS("sqlite") @Service class EventLogServiceImpl : ServiceImpl(), IEventLogService { diff --git a/src/main/kotlin/top/fatweb/oxygen/api/service/system/impl/SensitiveWordServiceImpl.kt b/src/main/kotlin/top/fatweb/oxygen/api/service/system/impl/SensitiveWordServiceImpl.kt new file mode 100644 index 0000000..f95a233 --- /dev/null +++ b/src/main/kotlin/top/fatweb/oxygen/api/service/system/impl/SensitiveWordServiceImpl.kt @@ -0,0 +1,66 @@ +package top.fatweb.oxygen.api.service.system.impl + +import com.baomidou.dynamic.datasource.annotation.DS +import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper +import com.baomidou.mybatisplus.extension.kotlin.KtUpdateWrapper +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Propagation +import org.springframework.transaction.annotation.Transactional +import top.fatweb.oxygen.api.converter.system.SettingsConverter +import top.fatweb.oxygen.api.entity.system.SensitiveWord +import top.fatweb.oxygen.api.exception.MatchSensitiveWordException +import top.fatweb.oxygen.api.mapper.system.SensitiveWordMapper +import top.fatweb.oxygen.api.param.system.SensitiveWordAddParam +import top.fatweb.oxygen.api.param.system.SensitiveWordUpdateParam +import top.fatweb.oxygen.api.service.system.ISensitiveWordService +import top.fatweb.oxygen.api.vo.system.SensitiveWordVo + +/** + * Sensitive word service implement + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ +@DS("sqlite") +@Service +class SensitiveWordServiceImpl : ServiceImpl(), ISensitiveWordService { + @Transactional(propagation = Propagation.REQUIRES_NEW) + override fun get(): List = this.list().map(SettingsConverter::sensitiveWordToSensitiveWordVo) + + @Transactional(propagation = Propagation.REQUIRES_NEW) + override fun add(sensitiveWordAddParam: SensitiveWordAddParam) { + checkSensitiveWord(sensitiveWordAddParam.word!!) + this.save(SettingsConverter.sensitiveWordAddParamToSensitiveWord(sensitiveWordAddParam)) + } + + @Transactional(propagation = Propagation.REQUIRES_NEW) + override fun update(sensitiveWordUpdateParam: SensitiveWordUpdateParam) { + this.update(KtUpdateWrapper(SensitiveWord()).set(SensitiveWord::enable, false)) + this.update( + KtUpdateWrapper(SensitiveWord()).`in`(SensitiveWord::id, sensitiveWordUpdateParam.ids) + .set(SensitiveWord::enable, true) + ) + } + + @Transactional(propagation = Propagation.REQUIRES_NEW) + override fun delete(id: Long) { + this.removeById(id) + } + + @Transactional(propagation = Propagation.REQUIRES_NEW) + override fun checkSensitiveWord(str: String) { + this.list(KtQueryWrapper(SensitiveWord()).eq(SensitiveWord::enable, 1)).map(SensitiveWord::word).forEach { + it ?: let { return@forEach } + + try { + if (Regex(it, RegexOption.IGNORE_CASE).matches(str)) { + throw MatchSensitiveWordException() + } + } catch (e: MatchSensitiveWordException) { + throw e + } catch (_: Exception) { + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/oxygen/api/service/system/impl/StatisticsLogServiceImpl.kt b/src/main/kotlin/top/fatweb/oxygen/api/service/system/impl/StatisticsLogServiceImpl.kt index ada1265..b7faec6 100644 --- a/src/main/kotlin/top/fatweb/oxygen/api/service/system/impl/StatisticsLogServiceImpl.kt +++ b/src/main/kotlin/top/fatweb/oxygen/api/service/system/impl/StatisticsLogServiceImpl.kt @@ -7,6 +7,12 @@ import top.fatweb.oxygen.api.entity.system.StatisticsLog import top.fatweb.oxygen.api.mapper.system.StatisticsLogMapper import top.fatweb.oxygen.api.service.system.IStatisticsLogService +/** + * Statistics log service implement + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ @DS("sqlite") @Service class StatisticsLogServiceImpl : ServiceImpl(), IStatisticsLogService \ No newline at end of file diff --git a/src/main/kotlin/top/fatweb/oxygen/api/vo/system/SensitiveWordVo.kt b/src/main/kotlin/top/fatweb/oxygen/api/vo/system/SensitiveWordVo.kt new file mode 100644 index 0000000..926e4e1 --- /dev/null +++ b/src/main/kotlin/top/fatweb/oxygen/api/vo/system/SensitiveWordVo.kt @@ -0,0 +1,52 @@ +package top.fatweb.oxygen.api.vo.system + +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer +import io.swagger.v3.oas.annotations.media.Schema +import top.fatweb.oxygen.api.entity.system.SensitiveWord + +/** + * Sensitive word settings value object + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ +@Schema(defaultValue = "敏感词设置返回参数") +data class SensitiveWordVo( + /** + * ID + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + @JsonSerialize(using = ToStringSerializer::class) + val id: Long?, + + /** + * Word + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + @Schema(description = "词") + val word: String?, + + /** + * Use for + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + * @see SensitiveWord.Use + */ + @Schema(description = "用于") + val useFor: Set?, + + /** + * Enable + * + * @author FatttSnake, fatttsnake@gmail.com + * @since 1.0.0 + */ + @Schema(description = "启用") + val enable: Boolean +) diff --git a/src/main/resources/db/migration/master/R__Basic_data.sql b/src/main/resources/db/migration/master/R__Basic_data.sql index 0199971..ce4e4a4 100644 --- a/src/main/resources/db/migration/master/R__Basic_data.sql +++ b/src/main/resources/db/migration/master/R__Basic_data.sql @@ -63,8 +63,10 @@ insert into t_power (id, type_id) (1520101, 4), (1530101, 4), (1530102, 4), + (1530103, 4), (1530301, 4), - (1530302, 4) + (1530302, 4), + (1530303, 4) as new_value on duplicate key update type_id = new_value.type_id; @@ -139,8 +141,10 @@ insert into t_operation(id, name, code, func_id) (1520101, '全部', 'system:log:query:all', 1520100), (1530101, '基础', 'system:settings:query:base', 1530100), (1530102, '邮件', 'system:settings:query:mail', 1530100), + (1530103, '敏感词', 'system:settings:query:sensitive', 1530100), (1530301, '基础', 'system:settings:modify:base', 1530300), - (1530302, '邮件', 'system:settings:modify:mail', 1530300) as new_value + (1530302, '邮件', 'system:settings:modify:mail', 1530300), + (1530303, '敏感词', 'system:settings:modify:sensitive', 1530300) as new_value on duplicate key update name=new_value.name, code=new_value.code, func_id=new_value.func_id; \ No newline at end of file diff --git a/src/main/resources/db/migration/sqlite/V1_0_0_240103__Add_table_‘t_sensitive_word'.sql b/src/main/resources/db/migration/sqlite/V1_0_0_240103__Add_table_‘t_sensitive_word'.sql new file mode 100644 index 0000000..d078b41 --- /dev/null +++ b/src/main/resources/db/migration/sqlite/V1_0_0_240103__Add_table_‘t_sensitive_word'.sql @@ -0,0 +1,9 @@ +drop table if exists t_sensitive_word; + +create table if not exists t_sensitive_word -- 敏感词表 +( + id integer not null primary key, + word text not null unique, -- 词 + use_for text null, -- 用于 + enable integer not null default 1 -- 启用 +);