Complete core functions #9

Merged
FatttSnake merged 171 commits from FatttSnake into dev 2024-02-23 11:56:35 +08:00
10 changed files with 226 additions and 58 deletions
Showing only changes of commit 7aca58f1de - Show all commits

View File

@@ -2,14 +2,12 @@ package top.fatweb.oxygen.api.controller.tool
import io.swagger.v3.oas.annotations.Operation
import jakarta.validation.Valid
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.RequestBody
import org.springframework.web.bind.annotation.*
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.tool.ToolCreateParam
import top.fatweb.oxygen.api.param.tool.ToolUpgradeParam
import top.fatweb.oxygen.api.service.tool.IEditService
import top.fatweb.oxygen.api.vo.tool.ToolCategoryVo
import top.fatweb.oxygen.api.vo.tool.ToolTemplateVo
@@ -79,6 +77,17 @@ class EditController(
fun create(@RequestBody @Valid toolCreateParam: ToolCreateParam): ResponseResult<ToolVo> =
ResponseResult.databaseSuccess(ResponseCode.DATABASE_INSERT_SUCCESS, data = editService.create(toolCreateParam))
/**
* Upgrade tool
*
* @author FatttSnake, fatttsnake@gmail.com
* @since 1.0.0
*/
@Operation(summary = "更新工具")
@PatchMapping
fun upgrade(@RequestBody @Valid toolUpgradeParam: ToolUpgradeParam): ResponseResult<ToolVo> =
ResponseResult.databaseSuccess(ResponseCode.DATABASE_UPDATE_SUCCESS, data = editService.upgrade(toolUpgradeParam))
/**
* Get personal tool
*
@@ -103,4 +112,16 @@ class EditController(
ResponseCode.DATABASE_SELECT_SUCCESS,
data = editService.detail(username, toolId, ver)
)
/**
* Delete tool
*
* @author FatttSnake, fatttsnake@gmail.com
* @since 1.0.0
*/
@Operation(summary = "删除工具")
@DeleteMapping("/{id}")
fun delete(@PathVariable id: Long): ResponseResult<Nothing> =
if (editService.delete(id)) ResponseResult.databaseSuccess(ResponseCode.DATABASE_DELETE_SUCCESS)
else ResponseResult.databaseFail(ResponseCode.DATABASE_DELETE_FAILED)
}

View File

@@ -31,6 +31,14 @@ enum class BusinessCode(val code: Int) {
*/
DATABASE(300),
/**
* Tool
*
* @author FatttSnake, fatttsnake@gmail.com
* @since 1.0.0
*/
TOOL(400),
/**
* Avatar API
*

View File

@@ -58,6 +58,8 @@ enum class ResponseCode(val code: Int) {
DATABASE_DUPLICATE_KEY(BusinessCode.DATABASE, 51),
DATABASE_NO_RECORD_FOUND(BusinessCode.DATABASE, 52),
TOOL_ILLEGAL_VERSION(BusinessCode.TOOL, 50),
API_AVATAR_SUCCESS(BusinessCode.API_AVATAR, 0),
API_AVATAR_ERROR(BusinessCode.API_AVATAR, 50);

View File

@@ -0,0 +1,3 @@
package top.fatweb.oxygen.api.exception
class IllegalVersionException : RuntimeException("Illegal Version")

View File

@@ -211,6 +211,12 @@ class ExceptionHandler {
ResponseResult.fail(ResponseCode.DATABASE_EXECUTE_ERROR, e.localizedMessage, null)
}
/* Tool */
is IllegalVersionException -> {
logger.debug(e.localizedMessage, e)
ResponseResult.fail(ResponseCode.TOOL_ILLEGAL_VERSION, e.localizedMessage, null)
}
/* Other */
is MatchSensitiveWordException -> {
logger.debug(e.localizedMessage, e)

View File

@@ -0,0 +1,39 @@
package top.fatweb.oxygen.api.param.tool
import io.swagger.v3.oas.annotations.media.Schema
import jakarta.validation.constraints.NotBlank
import jakarta.validation.constraints.Pattern
/**
* Upgrade tool parameters
*
* @author FatttSnake, fatttsnake@gmail.com
* @since 1.0.0
*/
@Schema(description = "更新工具请求参数")
data class ToolUpgradeParam(
/**
* Tool ID
*
* @author FatttSnake, fatttsnake@gmail.com
* @since 1.0.0
*/
@Schema(description = "工具唯一 ID", required = true, example = "tool_a")
@field: NotBlank(message = "ToolId can not be blank")
@field: Pattern(
regexp = "^[a-zA-Z-_][0-9a-zA-Z-_]{2,19}\$",
message = "Ver can only match '^[a-zA-Z-_][0-9a-zA-Z-_]{2,19}\$'"
)
val toolId: String?,
/**
* Version
*
* @author FatttSnake, fatttsnake@gmail.com
* @since 1.0.0
*/
@Schema(description = "版本", required = true, example = "1.0.3")
@field: NotBlank(message = "Ver can not be blank")
@field: Pattern(regexp = "^\\d+\\.\\d+\\.\\d+\$", message = "Ver can only match '<number>.<number>.<number>'")
val ver: String?
)

View File

@@ -99,7 +99,7 @@ class AuthenticationServiceImpl(
@Transactional
override fun resend() {
val user = userService.getById(WebUtil.getLoginUserId()) ?: throw AccessDeniedException("Access Denied")
val user = userService.getById(WebUtil.getLoginUserId())
user.verify ?: throw NoVerificationRequiredException()
@@ -124,7 +124,7 @@ class AuthenticationServiceImpl(
@EventLogRecord(EventLog.Event.VERIFY)
@Transactional
override fun verify(verifyParam: VerifyParam) {
val user = userService.getById(WebUtil.getLoginUserId()) ?: throw AccessDeniedException("Access Denied")
val user = userService.getById(WebUtil.getLoginUserId())
user.verify ?: throw NoVerificationRequiredException()
if (LocalDateTime.ofInstant(Instant.ofEpochMilli(user.verify!!.split("-").first().toLong()), ZoneOffset.UTC)
.isBefore(LocalDateTime.now(ZoneOffset.UTC).minusHours(2)) || user.verify != verifyParam.code

View File

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService
import top.fatweb.oxygen.api.entity.tool.Tool
import top.fatweb.oxygen.api.param.tool.ToolCreateParam
import top.fatweb.oxygen.api.param.tool.ToolUpdateParam
import top.fatweb.oxygen.api.param.tool.ToolUpgradeParam
import top.fatweb.oxygen.api.vo.tool.ToolCategoryVo
import top.fatweb.oxygen.api.vo.tool.ToolTemplateVo
import top.fatweb.oxygen.api.vo.tool.ToolVo
@@ -51,6 +52,7 @@ interface IEditService : IService<Tool> {
/**
* Get tool by ID
*
* @param
* @author FatttSnake, fatttsnake@gmail.com
* @since 1.0.0
*/
@@ -64,6 +66,16 @@ interface IEditService : IService<Tool> {
*/
fun create(toolCreateParam: ToolCreateParam): ToolVo
/**
* Upgrade tool
*
* @author FatttSnake, fatttsnake@gmail.com
* @since 1.0.0
* @see ToolUpgradeParam
* @see ToolVo
*/
fun upgrade(toolUpgradeParam: ToolUpgradeParam): ToolVo
/**
* Update tool
*
@@ -87,4 +99,12 @@ interface IEditService : IService<Tool> {
* @since 1.0.0
*/
fun detail(username: String, toolId: String, ver: String): ToolVo
/**
* Delete tool
*
* @author FatttSnake, fatttsnake@gmail.com
* @since 1.0.0
*/
fun delete(id: Long): Boolean
}

View File

@@ -2,17 +2,19 @@ package top.fatweb.oxygen.api.service.tool.impl
import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
import org.springframework.dao.DuplicateKeyException
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import top.fatweb.oxygen.api.converter.tool.ToolCategoryConverter
import top.fatweb.oxygen.api.converter.tool.ToolConverter
import top.fatweb.oxygen.api.converter.tool.ToolTemplateConverter
import top.fatweb.oxygen.api.entity.tool.*
import top.fatweb.oxygen.api.exception.IllegalVersionException
import top.fatweb.oxygen.api.exception.NoRecordFoundException
import top.fatweb.oxygen.api.exception.UserNotFoundException
import top.fatweb.oxygen.api.mapper.tool.EditMapper
import top.fatweb.oxygen.api.param.tool.ToolCreateParam
import top.fatweb.oxygen.api.param.tool.ToolUpdateParam
import top.fatweb.oxygen.api.param.tool.ToolUpgradeParam
import top.fatweb.oxygen.api.service.tool.*
import top.fatweb.oxygen.api.util.WebUtil
import top.fatweb.oxygen.api.vo.tool.ToolCategoryVo
@@ -49,11 +51,15 @@ class EditServiceImpl(
.map(ToolCategoryConverter::toolCategoryToToolCategoryVo)
override fun getOne(id: Long): ToolVo =
baseMapper.selectOne(id, WebUtil.getLoginUserId() ?: throw UserNotFoundException())
baseMapper.selectOne(id, WebUtil.getLoginUserId()!!)
?.let(ToolConverter::toolToToolVo) ?: throw NoRecordFoundException()
@Transactional
override fun create(toolCreateParam: ToolCreateParam): ToolVo {
baseMapper.selectOne(
KtQueryWrapper(Tool()).eq(Tool::toolId, toolCreateParam.toolId!!)
.eq(Tool::authorId, WebUtil.getLoginUserId()!!)
)?.let { throw DuplicateKeyException("Duplicate Key") }
val template = this.getTemplate(toolCreateParam.templateId!!)
val newSource = ToolData().apply { data = template.source!!.data }
val newDist = ToolData().apply { data = "" }
@@ -65,11 +71,12 @@ class EditServiceImpl(
icon = toolCreateParam.icon
description = toolCreateParam.description
baseId = template.base!!.id
authorId = WebUtil.getLoginUserId() ?: throw UserNotFoundException()
authorId = WebUtil.getLoginUserId()!!
ver = toolCreateParam.ver!!.split(".").map(String::toLong).joinToString(".")
keywords = toolCreateParam.keywords
sourceId = newSource.id
distId = newDist.id
entryPoint = template.entryPoint
}
this.save(tool)
@@ -85,13 +92,60 @@ class EditServiceImpl(
return this.getOne(tool.id!!)
}
@Transactional
override fun upgrade(toolUpgradeParam: ToolUpgradeParam): ToolVo {
val originalTool = this.detail("!", toolUpgradeParam.toolId!!, "latest")
val originalVersion = originalTool.ver!!
if (originalVersion.split(".").map(String::toLong).joinToString(".") == toolUpgradeParam.ver!!.split(".")
.map(String::toLong).joinToString(".")
) {
throw IllegalVersionException()
}
originalVersion.split(".").forEachIndexed { index, s ->
if ((toolUpgradeParam.ver.split(".")[index].toLong() < s.toLong())) {
throw IllegalVersionException()
}
}
val newSource = ToolData().apply { data = originalTool.source!!.data }
val newDist = ToolData().apply { data = "" }
toolDataService.saveBatch(listOf(newSource, newDist))
val tool = Tool().apply {
name = originalTool.name!!
toolId = originalTool.toolId
icon = originalTool.icon
description = originalTool.description
baseId = originalTool.base!!.id
authorId = WebUtil.getLoginUserId()!!
ver = toolUpgradeParam.ver.split(".").map(String::toLong).joinToString(".")
keywords = originalTool.keywords
sourceId = newSource.id
distId = newDist.id
entryPoint = originalTool.entryPoint
}
this.save(tool)
originalTool.categories!!.forEach {
toolCategoryService.getById(it.id) ?: throw NoRecordFoundException()
rToolCategoryService.save(RToolCategory().apply {
toolId = tool.id
categoryId = it.id
})
}
return this.getOne(tool.id!!)
}
@Transactional
override fun update(toolUpdateParam: ToolUpdateParam): ToolVo {
TODO("Not yet implemented")
}
override fun get(): List<ToolVo> =
baseMapper.selectPersonal(WebUtil.getLoginUserId() ?: throw UserNotFoundException())
baseMapper.selectPersonal(WebUtil.getLoginUserId()!!)
.map(ToolConverter::toolToToolVo)
override fun detail(username: String, toolId: String, ver: String): ToolVo {
@@ -102,4 +156,16 @@ class EditServiceImpl(
return baseMapper.detail(username, toolId, ver, WebUtil.getLoginUsername())?.let(ToolConverter::toolToToolVo)
?: throw NoRecordFoundException()
}
@Transactional
override fun delete(id: Long): Boolean {
val tool = baseMapper.selectOne(
KtQueryWrapper(Tool()).eq(Tool::id, id)
.eq(Tool::authorId, WebUtil.getLoginUserId()!!)
) ?: throw NoRecordFoundException()
toolDataService.removeBatchByIds(listOf(tool.sourceId, tool.distId))
rToolCategoryService.remove(KtQueryWrapper(RToolCategory()).eq(RToolCategory::toolId, tool.id))
return this.removeById(id)
}
}

View File

@@ -31,50 +31,50 @@
</select>
<select id="selectOne" resultMap="toolWithDataMap">
select t_b_tool_main.id as tool_id,
t_b_tool_main.name as tool_name,
t_b_tool_main.tool_id as tool_tool_id,
t_b_tool_main.icon as tool_icon,
t_b_tool_main.description as tool_description,
t_b_tool_main.base_id as tool_base_id,
t_b_tool_main.author_id as tool_author_id,
t_b_tool_main.ver as tool_ver,
t_b_tool_main.keywords as tool_keywords,
t_b_tool_main.source_id as tool_source_id,
t_b_tool_main.dist_id as tool_dist_id,
t_b_tool_main.entry_point as tool_entry_point,
t_b_tool_main.publish as tool_publish,
t_b_tool_main.review as tool_review,
t_b_tool_main.create_time as tool_create_time,
t_b_tool_main.update_time as tool_update_time,
t_b_tool_main.deleted as tool_deleted,
t_b_tool_main.version as tool_version,
tsu.id as user_id,
tsu.username as user_username,
tsui.id as user_info_id,
tsui.nickname as user_info_nickname,
tsui.avatar as user_info_avatar,
tsui.email as user_info_email,
tbtb.name as tool_base_name,
tbtb.dist_id as tool_base_dist_id,
tbtbd.data as tool_base_dist_data,
tbts.data as tool_source_data,
tbts.create_time as tool_source_create_time,
tbts.update_time as tool_source_update_time,
tbts.deleted as tool_source_deleted,
tbts.version as tool_source_version,
tbtd.data as tool_dist_data,
tbtd.create_time as tool_dist_create_time,
tbtd.update_time as tool_dist_update_time,
tbtd.deleted as tool_dist_deleted,
tbtd.version as tool_dist_version,
tbtc.id as tool_category_id,
tbtc.name as tool_category_name,
tbtc.enable as tool_category_enable,
tbtc.create_time as tool_category_create_time,
tbtc.update_time as tool_category_update_time,
tbtc.deleted as tool_category_deleted,
tbtc.version as tool_category_version
select t_b_tool_main.id as tool_id,
t_b_tool_main.name as tool_name,
t_b_tool_main.tool_id as tool_tool_id,
t_b_tool_main.icon as tool_icon,
t_b_tool_main.description as tool_description,
t_b_tool_main.base_id as tool_base_id,
t_b_tool_main.author_id as tool_author_id,
t_b_tool_main.ver as tool_ver,
t_b_tool_main.keywords as tool_keywords,
t_b_tool_main.source_id as tool_source_id,
t_b_tool_main.dist_id as tool_dist_id,
t_b_tool_main.entry_point as tool_entry_point,
t_b_tool_main.publish as tool_publish,
t_b_tool_main.review as tool_review,
t_b_tool_main.create_time as tool_create_time,
t_b_tool_main.update_time as tool_update_time,
t_b_tool_main.deleted as tool_deleted,
t_b_tool_main.version as tool_version,
tsu.id as user_id,
tsu.username as user_username,
tsui.id as user_info_id,
tsui.nickname as user_info_nickname,
tsui.avatar as user_info_avatar,
tsui.email as user_info_email,
tbtb.name as tool_base_name,
tbtb.dist_id as tool_base_dist_id,
tbtbd.data as tool_base_dist_data,
tbts.data as tool_source_data,
tbts.create_time as tool_source_create_time,
tbts.update_time as tool_source_update_time,
tbts.deleted as tool_source_deleted,
tbts.version as tool_source_version,
tbtd.data as tool_dist_data,
tbtd.create_time as tool_dist_create_time,
tbtd.update_time as tool_dist_update_time,
tbtd.deleted as tool_dist_deleted,
tbtd.version as tool_dist_version,
tbtc.id as tool_category_id,
tbtc.name as tool_category_name,
tbtc.enable as tool_category_enable,
tbtc.create_time as tool_category_create_time,
tbtc.update_time as tool_category_update_time,
tbtc.deleted as tool_category_deleted,
tbtc.version as tool_category_version
from t_b_tool_main
left join (select * from t_s_user where deleted = 0) as tsu on tsu.id = t_b_tool_main.author_id
left join (select * from t_s_user_info where deleted = 0) as tsui
@@ -125,7 +125,7 @@
on tbtc.id = trtmc.category_id
where t_b_tool_main.deleted = 0
and t_b_tool_main.author_id = #{userId}
order by t_b_tool_main.tool_id desc
order by t_b_tool_main.id desc
</select>
<select id="detail" resultMap="toolWithDataMap">
@@ -208,9 +208,11 @@
</choose>
</where>
order by t_b_tool_main.id desc
limit 1
</select>
<resultMap id="toolTemplateWithBaseDataMap" type="toolTemplate" extends="top.fatweb.oxygen.api.mapper.tool.ToolTemplateMapper.toolTemplateWithDataMap">
<resultMap id="toolTemplateWithBaseDataMap" type="toolTemplate"
extends="top.fatweb.oxygen.api.mapper.tool.ToolTemplateMapper.toolTemplateWithDataMap">
<association property="base">
<id property="id" column="tool_template_base_id"/>
<result property="name" column="tool_template_base_name"/>
@@ -236,8 +238,9 @@
<result property="createTime" column="tool_create_time"/>
<result property="deleted" column="tool_deleted"/>
<result property="version" column="tool_version"/>
<collection property="keywords" ofType="string" column="tool_keywords"/>
<collection property="categories" resultMap="top.fatweb.oxygen.api.mapper.tool.ToolCategoryMapper.toolCategoryMap"/>
<result property="keywords" column="tool_keywords" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
<collection property="categories"
resultMap="top.fatweb.oxygen.api.mapper.tool.ToolCategoryMapper.toolCategoryMap"/>
</resultMap>
<resultMap id="toolWithAuthor" type="tool" extends="toolMap">