refactor: 拆分接口文档分组配置及 controller 到各自模块

This commit is contained in:
2025-06-14 22:12:05 +08:00
parent f1a87b4c23
commit 93bd70dc5c
32 changed files with 257 additions and 80 deletions

View File

@@ -1,124 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.auth;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import com.xkcoding.justauth.autoconfigure.JustAuthProperties;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import me.zhyd.oauth.AuthRequestBuilder;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import top.continew.admin.auth.model.req.LoginReq;
import top.continew.admin.auth.model.resp.LoginResp;
import top.continew.admin.auth.model.resp.RouteResp;
import top.continew.admin.auth.model.resp.SocialAuthAuthorizeResp;
import top.continew.admin.auth.model.resp.UserInfoResp;
import top.continew.admin.auth.service.AuthService;
import top.continew.admin.common.context.UserContext;
import top.continew.admin.common.context.UserContextHolder;
import top.continew.admin.system.model.resp.user.UserDetailResp;
import top.continew.admin.system.service.UserService;
import top.continew.starter.core.exception.BadRequestException;
import top.continew.starter.log.annotation.Log;
import java.util.List;
/**
* 认证 API
*
* @author Charles7c
* @since 2022/12/21 20:37
*/
@Tag(name = "认证 API")
@Log(module = "登录")
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("/auth")
public class AuthController {
private final AuthService authService;
private final UserService userService;
private final JustAuthProperties authProperties;
@SaIgnore
@Operation(summary = "登录", description = "用户登录")
@PostMapping("/login")
public LoginResp login(@Validated @RequestBody LoginReq req, HttpServletRequest request) {
return authService.login(req, request);
}
@Operation(summary = "登出", description = "注销用户的当前登录")
@Parameter(name = "Authorization", description = "令牌", required = true, example = "Bearer xxxx-xxxx-xxxx-xxxx", in = ParameterIn.HEADER)
@PostMapping("/logout")
public Object logout() {
Object loginId = StpUtil.getLoginId(-1L);
StpUtil.logout();
return loginId;
}
@SaIgnore
@Operation(summary = "三方账号登录授权", description = "三方账号登录授权")
@Parameter(name = "source", description = "来源", example = "gitee", in = ParameterIn.PATH)
@GetMapping("/{source}")
public SocialAuthAuthorizeResp authorize(@PathVariable String source) {
AuthRequest authRequest = this.getAuthRequest(source);
return SocialAuthAuthorizeResp.builder()
.authorizeUrl(authRequest.authorize(AuthStateUtils.createState()))
.build();
}
@Log(ignore = true)
@Operation(summary = "获取用户信息", description = "获取登录用户信息")
@GetMapping("/user/info")
public UserInfoResp getUserInfo() {
UserContext userContext = UserContextHolder.getContext();
UserDetailResp userDetailResp = userService.get(userContext.getId());
UserInfoResp userInfoResp = BeanUtil.copyProperties(userDetailResp, UserInfoResp.class);
userInfoResp.setPermissions(userContext.getPermissions());
userInfoResp.setRoles(userContext.getRoleCodes());
userInfoResp.setPwdExpired(userContext.isPasswordExpired());
return userInfoResp;
}
@Log(ignore = true)
@Operation(summary = "获取路由信息", description = "获取登录用户的路由信息")
@GetMapping("/user/route")
public List<RouteResp> listRoute() {
return authService.buildRouteTree(UserContextHolder.getUserId());
}
private AuthRequest getAuthRequest(String source) {
try {
AuthConfig authConfig = authProperties.getType().get(source.toUpperCase());
return AuthRequestBuilder.builder().source(source).authConfig(authConfig).build();
} catch (Exception e) {
throw new BadRequestException("暂不支持 [%s] 平台账号登录".formatted(source));
}
}
}

View File

@@ -1,123 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.code;
import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import top.continew.admin.generator.model.entity.FieldConfigDO;
import top.continew.admin.generator.model.entity.GenConfigDO;
import top.continew.admin.generator.model.query.GenConfigQuery;
import top.continew.admin.generator.model.req.GenConfigReq;
import top.continew.admin.generator.model.resp.GeneratePreviewResp;
import top.continew.admin.generator.service.GeneratorService;
import top.continew.admin.system.service.DictService;
import top.continew.starter.extension.crud.model.query.PageQuery;
import top.continew.starter.extension.crud.model.resp.LabelValueResp;
import top.continew.starter.extension.crud.model.resp.PageResp;
import java.sql.SQLException;
import java.util.List;
/**
* 代码生成 API
*
* @author Charles7c
* @since 2023/8/3 22:58
*/
@Tag(name = "代码生成 API")
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("/code/generator")
public class GeneratorController {
private final GeneratorService baseService;
private final DictService dictService;
@Operation(summary = "分页查询生成配置", description = "分页查询生成配置列表")
@SaCheckPermission("code:generator:list")
@GetMapping("/config")
public PageResp<GenConfigDO> pageGenConfig(GenConfigQuery query, @Validated PageQuery pageQuery) {
return baseService.pageGenConfig(query, pageQuery);
}
@Operation(summary = "查询生成配置信息", description = "查询生成配置信息")
@Parameter(name = "tableName", description = "表名称", required = true, example = "sys_user", in = ParameterIn.PATH)
@SaCheckPermission("code:generator:list")
@GetMapping("/config/{tableName}")
public GenConfigDO getGenConfig(@PathVariable String tableName) throws SQLException {
return baseService.getGenConfig(tableName);
}
@Operation(summary = "查询字段配置列表", description = "查询字段配置列表")
@Parameter(name = "tableName", description = "表名称", required = true, example = "sys_user", in = ParameterIn.PATH)
@Parameter(name = "requireSync", description = "是否需要同步", example = "false", in = ParameterIn.QUERY)
@SaCheckPermission("code:generator:config")
@GetMapping("/field/{tableName}")
public List<FieldConfigDO> listFieldConfig(@PathVariable String tableName,
@RequestParam(required = false, defaultValue = "false") Boolean requireSync) {
return baseService.listFieldConfig(tableName, requireSync);
}
@Operation(summary = "保存配置信息", description = "保存配置信息")
@Parameter(name = "tableName", description = "表名称", required = true, example = "sys_user", in = ParameterIn.PATH)
@SaCheckPermission("code:generator:config")
@PostMapping("/config/{tableName}")
public void saveConfig(@Validated @RequestBody GenConfigReq req, @PathVariable String tableName) {
baseService.saveConfig(req, tableName);
}
@Operation(summary = "生成预览", description = "预览生成代码")
@Parameter(name = "tableNames", description = "表名称", required = true, example = "sys_user", in = ParameterIn.PATH)
@SaCheckPermission("code:generator:preview")
@GetMapping("/preview/{tableNames}")
public List<GeneratePreviewResp> preview(@PathVariable List<String> tableNames) {
return baseService.preview(tableNames);
}
@Operation(summary = "生成下载代码", description = "生成下载代码")
@Parameter(name = "tableNames", description = "表名称", required = true, example = "sys_user", in = ParameterIn.PATH)
@SaCheckPermission("code:generator:generate")
@PostMapping("/{tableNames}/download")
public void downloadCode(@PathVariable List<String> tableNames, HttpServletResponse response) {
baseService.downloadCode(tableNames, response);
}
@Operation(summary = "生成代码", description = "生成代码")
@Parameter(name = "tableNames", description = "表名称", required = true, example = "sys_user", in = ParameterIn.PATH)
@SaCheckPermission("code:generator:generate")
@PostMapping("/{tableNames}")
public void generateCode(@PathVariable List<String> tableNames) {
baseService.generateCode(tableNames);
}
@Operation(summary = "查询字典", description = "查询字典列表")
@SaCheckPermission("code:generator:config")
@GetMapping("/dict")
public List<LabelValueResp> listDict() {
List<LabelValueResp> dictList = dictService.listDict(null, null);
dictList.addAll(dictService.listEnumDict());
return dictList;
}
}

View File

@@ -1,67 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.open;
import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import top.continew.admin.common.controller.BaseController;
import top.continew.admin.open.model.query.AppQuery;
import top.continew.admin.open.model.req.AppReq;
import top.continew.admin.open.model.resp.AppDetailResp;
import top.continew.admin.open.model.resp.AppResp;
import top.continew.admin.open.model.resp.AppSecretResp;
import top.continew.admin.open.service.AppService;
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
import top.continew.starter.extension.crud.enums.Api;
/**
* 应用管理 API
*
* @author chengzi
* @author Charles7c
* @since 2024/10/17 16:03
*/
@Tag(name = "应用管理 API")
@RestController
@RequiredArgsConstructor
@CrudRequestMapping(value = "/open/app", api = {Api.PAGE, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE, Api.EXPORT})
public class AppController extends BaseController<AppService, AppResp, AppDetailResp, AppQuery, AppReq> {
@Operation(summary = "获取密钥", description = "获取应用密钥")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("open:app:secret")
@GetMapping("/{id}/secret")
public AppSecretResp getSecret(@PathVariable Long id) {
return baseService.getSecret(id);
}
@Operation(summary = "重置密钥", description = "重置应用密钥")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("open:app:resetSecret")
@PatchMapping("/{id}/secret")
public void resetSecret(@PathVariable Long id) {
baseService.resetSecret(id);
}
}

View File

@@ -1,109 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.schedule;
import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import top.continew.admin.schedule.model.query.JobQuery;
import top.continew.admin.schedule.model.req.JobReq;
import top.continew.admin.schedule.model.req.JobStatusReq;
import top.continew.admin.schedule.model.req.JobTriggerReq;
import top.continew.admin.schedule.model.resp.JobResp;
import top.continew.admin.schedule.service.JobService;
import top.continew.starter.extension.crud.model.resp.PageResp;
import top.continew.starter.extension.crud.validation.CrudValidationGroup;
import top.continew.starter.log.annotation.Log;
import java.util.List;
/**
* 任务 API
*
* @author KAI
* @author Charles7c
* @since 2024/6/25 22:24
*/
@Tag(name = " 任务 API")
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("/schedule/job")
public class JobController {
private final JobService baseService;
@Operation(summary = "分页查询任务列表", description = "分页查询任务列表")
@SaCheckPermission("schedule:job:list")
@GetMapping
public PageResp<JobResp> page(JobQuery query) {
return baseService.page(query);
}
@Operation(summary = "新增任务", description = "新增任务")
@SaCheckPermission("schedule:job:create")
@PostMapping
public void create(@Validated(CrudValidationGroup.Create.class) @RequestBody JobReq req) {
baseService.create(req);
}
@Operation(summary = "修改任务", description = "修改任务")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("schedule:job:update")
@PutMapping("/{id}")
public void update(@Validated(CrudValidationGroup.Update.class) @RequestBody JobReq req, @PathVariable Long id) {
baseService.update(req, id);
}
@Operation(summary = "修改任务状态", description = "修改任务状态")
@SaCheckPermission("schedule:job:update")
@PatchMapping("/{id}/status")
public void updateStatus(@Validated @RequestBody JobStatusReq req, @PathVariable Long id) {
baseService.updateStatus(req, id);
}
@Operation(summary = "删除任务", description = "删除任务")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("schedule:job:delete")
@DeleteMapping("/{id}")
public void delete(@PathVariable Long id) {
baseService.delete(id);
}
@Operation(summary = "执行任务", description = "执行任务")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("schedule:job:trigger")
@PostMapping("/trigger/{id}")
public void trigger(@PathVariable Long id) {
JobTriggerReq req = new JobTriggerReq();
req.setJobId(id);
baseService.trigger(req);
}
@Log(ignore = true)
@Operation(summary = "查询任务分组列表", description = "查询任务分组列表")
@SaCheckPermission("schedule:job:list")
@GetMapping("/group")
public List<String> listGroup() {
return baseService.listGroup();
}
}

View File

@@ -1,90 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.schedule;
import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import top.continew.admin.schedule.model.JobInstanceLogPageResult;
import top.continew.admin.schedule.model.query.JobInstanceLogQuery;
import top.continew.admin.schedule.model.query.JobInstanceQuery;
import top.continew.admin.schedule.model.query.JobLogQuery;
import top.continew.admin.schedule.model.resp.JobInstanceResp;
import top.continew.admin.schedule.model.resp.JobLogResp;
import top.continew.admin.schedule.service.JobLogService;
import top.continew.starter.extension.crud.model.resp.PageResp;
import java.util.List;
/**
* 任务日志 API
*
* @author KAI
* @author Charles7c
* @since 2024/6/27 22:24
*/
@Tag(name = " 任务日志 API")
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("/schedule/log")
public class JobLogController {
private final JobLogService baseService;
@Operation(summary = "分页查询任务日志列表", description = "分页查询任务日志列表")
@SaCheckPermission("schedule:log:list")
@GetMapping
public PageResp<JobLogResp> page(JobLogQuery query) {
return baseService.page(query);
}
@Operation(summary = "停止任务", description = "停止任务")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("schedule:log:stop")
@PostMapping("/stop/{id}")
public void stop(@PathVariable Long id) {
baseService.stop(id);
}
@Operation(summary = "重试任务", description = "重试任务")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("schedule:log:retry")
@PostMapping("/retry/{id}")
public void retry(@PathVariable Long id) {
baseService.retry(id);
}
@Operation(summary = "查询任务实例列表", description = "查询任务实例列表")
@SaCheckPermission("schedule:log:list")
@GetMapping("/instance")
public List<JobInstanceResp> listInstance(JobInstanceQuery query) {
return baseService.listInstance(query);
}
@Operation(summary = "分页查询任务实例日志列表", description = "分页查询任务实例日志列表")
@SaCheckPermission("schedule:log:list")
@GetMapping("/instance/log")
public JobInstanceLogPageResult pageInstanceLog(JobInstanceLogQuery query) {
return baseService.pageInstanceLog(query);
}
}

View File

@@ -1,39 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.system;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.RestController;
import top.continew.admin.common.controller.BaseController;
import top.continew.admin.system.model.query.ClientQuery;
import top.continew.admin.system.model.req.ClientReq;
import top.continew.admin.system.model.resp.ClientResp;
import top.continew.admin.system.service.ClientService;
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
import top.continew.starter.extension.crud.enums.Api;
/**
* 客户端管理 API
*
* @author KAI
* @since 2024/12/03 16:04
*/
@Tag(name = "客户端管理 API")
@RestController
@CrudRequestMapping(value = "/system/client", api = {Api.PAGE, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE})
public class ClientController extends BaseController<ClientService, ClientResp, ClientResp, ClientQuery, ClientReq> {
}

View File

@@ -1,39 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.system;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.RestController;
import top.continew.admin.common.controller.BaseController;
import top.continew.admin.system.model.query.DeptQuery;
import top.continew.admin.system.model.req.DeptReq;
import top.continew.admin.system.model.resp.DeptResp;
import top.continew.admin.system.service.DeptService;
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
import top.continew.starter.extension.crud.enums.Api;
/**
* 部门管理 API
*
* @author Charles7c
* @since 2023/1/22 17:50
*/
@Tag(name = "部门管理 API")
@RestController
@CrudRequestMapping(value = "/system/dept", api = {Api.TREE, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE, Api.EXPORT})
public class DeptController extends BaseController<DeptService, DeptResp, DeptResp, DeptQuery, DeptReq> {
}

View File

@@ -1,52 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.system;
import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import top.continew.admin.common.constant.CacheConstants;
import top.continew.admin.common.controller.BaseController;
import top.continew.admin.system.model.query.DictQuery;
import top.continew.admin.system.model.req.DictReq;
import top.continew.admin.system.model.resp.DictResp;
import top.continew.admin.system.service.DictService;
import top.continew.starter.cache.redisson.util.RedisUtils;
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
import top.continew.starter.extension.crud.enums.Api;
/**
* 字典管理 API
*
* @author Charles7c
* @since 2023/9/11 21:29
*/
@Tag(name = "字典管理 API")
@RestController
@CrudRequestMapping(value = "/system/dict", api = {Api.LIST, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE})
public class DictController extends BaseController<DictService, DictResp, DictResp, DictQuery, DictReq> {
@Operation(summary = "清除缓存", description = "清除缓存")
@SaCheckPermission("system:dict:clearCache")
@DeleteMapping("/cache/{code}")
public void clearCache(@PathVariable String code) {
RedisUtils.deleteByPattern(CacheConstants.DICT_KEY_PREFIX + code);
}
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.system;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.RestController;
import top.continew.admin.common.controller.BaseController;
import top.continew.admin.system.model.query.DictItemQuery;
import top.continew.admin.system.model.req.DictItemReq;
import top.continew.admin.system.model.resp.DictItemResp;
import top.continew.admin.system.service.DictItemService;
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
import top.continew.starter.extension.crud.enums.Api;
import top.continew.starter.log.annotation.Log;
/**
* 字典项管理 API
*
* @author Charles7c
* @since 2023/9/11 21:29
*/
@Log(module = "字典管理")
@Tag(name = "字典项管理 API")
@RestController
@CrudRequestMapping(value = "/system/dict/item", api = {Api.PAGE, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE})
public class DictItemController extends BaseController<DictItemService, DictItemResp, DictItemResp, DictItemQuery, DictItemReq> {
}

View File

@@ -1,115 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.system;
import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.x.file.storage.core.FileInfo;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import top.continew.admin.common.controller.BaseController;
import top.continew.admin.system.model.query.FileQuery;
import top.continew.admin.system.model.req.FileReq;
import top.continew.admin.system.model.resp.file.FileDirCalcSizeResp;
import top.continew.admin.system.model.resp.file.FileResp;
import top.continew.admin.system.model.resp.file.FileStatisticsResp;
import top.continew.admin.system.model.resp.file.FileUploadResp;
import top.continew.admin.system.service.FileService;
import top.continew.starter.core.validation.ValidationUtils;
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
import top.continew.starter.extension.crud.enums.Api;
import top.continew.starter.extension.crud.model.resp.IdResp;
import top.continew.starter.log.annotation.Log;
import java.io.IOException;
/**
* 文件管理 API
*
* @author Charles7c
* @since 2023/12/23 10:38
*/
@Tag(name = "文件管理 API")
@RestController
@RequiredArgsConstructor
@CrudRequestMapping(value = "/system/file", api = {Api.PAGE, Api.UPDATE, Api.DELETE})
public class FileController extends BaseController<FileService, FileResp, FileResp, FileQuery, FileReq> {
/**
* 上传文件
* <p>
* 公共上传文件请使用 {@link top.continew.admin.controller.common.CommonController#upload}
* </p>
*
* @param file 文件
* @param parentPath 上级目录
* @return 文件上传响应参数
* @throws IOException /
*/
@Operation(summary = "上传文件", description = "上传文件")
@Parameter(name = "parentPath", description = "上级目录", example = "/", in = ParameterIn.QUERY)
@SaCheckPermission("system:file:upload")
@PostMapping("/upload")
public FileUploadResp upload(@NotNull(message = "文件不能为空") @RequestPart MultipartFile file,
@RequestParam(required = false) String parentPath) throws IOException {
ValidationUtils.throwIf(file::isEmpty, "文件不能为空");
FileInfo fileInfo = baseService.upload(file, parentPath);
return FileUploadResp.builder()
.id(fileInfo.getId())
.url(fileInfo.getUrl())
.thUrl(fileInfo.getThUrl())
.metadata(fileInfo.getMetadata())
.build();
}
@Operation(summary = "创建文件夹", description = "创建文件夹")
@SaCheckPermission("system:file:createDir")
@PostMapping("/dir")
public IdResp<Long> createDir(@Valid @RequestBody FileReq req) {
ValidationUtils.throwIfBlank(req.getParentPath(), "上级目录不能为空");
return new IdResp<>(baseService.createDir(req));
}
@Operation(summary = "计算文件夹大小", description = "计算文件夹大小")
@SaCheckPermission("system:file:calcDirSize")
@GetMapping("/dir/{id}/size")
public FileDirCalcSizeResp calcDirSize(@PathVariable Long id) {
return new FileDirCalcSizeResp(baseService.calcDirSize(id));
}
@Log(ignore = true)
@Operation(summary = "查询文件资源统计", description = "查询文件资源统计")
@SaCheckPermission("system:file:list")
@GetMapping("/statistics")
public FileStatisticsResp statistics() {
return baseService.statistics();
}
@Log(ignore = true)
@Operation(summary = "检测文件是否存在", description = "检测文件是否存在")
@SaCheckPermission("system:file:check")
@GetMapping("/check")
public FileResp checkFile(String fileHash) {
return baseService.check(fileHash);
}
}

View File

@@ -1,87 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.system;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.feiniaojin.gracefulresponse.api.ExcludeFromGracefulResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import top.continew.admin.system.model.query.LogQuery;
import top.continew.admin.system.model.resp.log.LogDetailResp;
import top.continew.admin.system.model.resp.log.LogResp;
import top.continew.admin.system.service.LogService;
import top.continew.starter.extension.crud.model.query.PageQuery;
import top.continew.starter.extension.crud.model.query.SortQuery;
import top.continew.starter.extension.crud.model.resp.PageResp;
import top.continew.starter.log.annotation.Log;
/**
* 系统日志 API
*
* @author Charles7c
* @since 2023/1/18 23:55
*/
@Tag(name = "系统日志 API")
@RestController
@RequiredArgsConstructor
@RequestMapping("/system/log")
public class LogController {
private final LogService baseService;
@Log(ignore = true)
@Operation(summary = "分页查询列表", description = "分页查询列表")
@SaCheckPermission("monitor:log:list")
@GetMapping
public PageResp<LogResp> page(LogQuery query, @Validated PageQuery pageQuery) {
return baseService.page(query, pageQuery);
}
@Log(ignore = true)
@Operation(summary = "查询详情", description = "查询详情")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("monitor:log:get")
@GetMapping("/{id}")
public LogDetailResp get(@PathVariable Long id) {
return baseService.get(id);
}
@ExcludeFromGracefulResponse
@Operation(summary = "导出登录日志", description = "导出登录日志")
@SaCheckPermission("monitor:log:export")
@GetMapping("/export/login")
public void exportLoginLog(LogQuery query, SortQuery sortQuery, HttpServletResponse response) {
baseService.exportLoginLog(query, sortQuery, response);
}
@ExcludeFromGracefulResponse
@Operation(summary = "导出操作日志", description = "导出操作日志")
@SaCheckPermission("monitor:log:export")
@GetMapping("/export/operation")
public void exportOperationLog(LogQuery query, SortQuery sortQuery, HttpServletResponse response) {
baseService.exportOperationLog(query, sortQuery, response);
}
}

View File

@@ -1,80 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.system;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.RestController;
import top.continew.admin.common.constant.CacheConstants;
import top.continew.admin.common.controller.BaseController;
import top.continew.admin.system.model.query.MenuQuery;
import top.continew.admin.system.model.req.MenuReq;
import top.continew.admin.system.model.resp.MenuResp;
import top.continew.admin.system.service.MenuService;
import top.continew.starter.cache.redisson.util.RedisUtils;
import top.continew.starter.core.constant.StringConstants;
import top.continew.starter.core.util.URLUtils;
import top.continew.starter.core.validation.ValidationUtils;
import top.continew.starter.extension.crud.annotation.CrudApi;
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
import top.continew.starter.extension.crud.enums.Api;
import java.lang.reflect.Method;
/**
* 菜单管理 API
*
* @author Charles7c
* @since 2023/2/15 20:35
*/
@Tag(name = "菜单管理 API")
@RestController
@CrudRequestMapping(value = "/system/menu", api = {Api.TREE, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE})
public class MenuController extends BaseController<MenuService, MenuResp, MenuResp, MenuQuery, MenuReq> {
@Operation(summary = "清除缓存", description = "清除缓存")
@SaCheckPermission("system:menu:clearCache")
@DeleteMapping("/cache")
public void clearCache() {
RedisUtils.deleteByPattern(CacheConstants.ROLE_MENU_KEY_PREFIX + StringConstants.ASTERISK);
}
@Override
public void preHandle(CrudApi crudApi, Object[] args, Method targetMethod, Class<?> targetClass) throws Exception {
super.preHandle(crudApi, args, targetMethod, targetClass);
Api api = crudApi.value();
if (!(Api.CREATE.equals(api) || Api.UPDATE.equals(api))) {
return;
}
MenuReq req = (MenuReq)args[0];
Boolean isExternal = ObjectUtil.defaultIfNull(req.getIsExternal(), false);
String path = req.getPath();
ValidationUtils.throwIf(Boolean.TRUE.equals(isExternal) && !URLUtils
.isHttpUrl(path), "路由地址格式不正确,请以 http:// 或 https:// 开头");
// 非外链菜单参数修正
if (Boolean.FALSE.equals(isExternal)) {
ValidationUtils.throwIf(URLUtils.isHttpUrl(path), "路由地址格式不正确");
req.setPath(StrUtil.isBlank(path) ? path : StrUtil.prependIfMissing(path, StringConstants.SLASH));
req.setName(StrUtil.removePrefix(req.getName(), StringConstants.SLASH));
req.setComponent(StrUtil.removePrefix(req.getComponent(), StringConstants.SLASH));
}
}
}

View File

@@ -1,72 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.system;
import cn.hutool.core.collection.CollUtil;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.RestController;
import top.continew.admin.common.controller.BaseController;
import top.continew.admin.system.enums.NoticeMethodEnum;
import top.continew.admin.system.enums.NoticeScopeEnum;
import top.continew.admin.system.model.query.NoticeQuery;
import top.continew.admin.system.model.req.NoticeReq;
import top.continew.admin.system.model.resp.notice.NoticeDetailResp;
import top.continew.admin.system.model.resp.notice.NoticeResp;
import top.continew.admin.system.service.NoticeService;
import top.continew.starter.core.validation.ValidationUtils;
import top.continew.starter.extension.crud.annotation.CrudApi;
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
import top.continew.starter.extension.crud.enums.Api;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
/**
* 公告管理 API
*
* @author Charles7c
* @since 2023/8/20 10:55
*/
@Tag(name = "公告管理 API")
@RestController
@CrudRequestMapping(value = "/system/notice", api = {Api.PAGE, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE})
public class NoticeController extends BaseController<NoticeService, NoticeResp, NoticeDetailResp, NoticeQuery, NoticeReq> {
@Override
public void preHandle(CrudApi crudApi, Object[] args, Method targetMethod, Class<?> targetClass) throws Exception {
super.preHandle(crudApi, args, targetMethod, targetClass);
Api api = crudApi.value();
if (!(Api.CREATE.equals(api) || Api.UPDATE.equals(api))) {
return;
}
NoticeReq req = (NoticeReq)args[0];
// 校验通知范围
if (NoticeScopeEnum.USER.equals(req.getNoticeScope())) {
ValidationUtils.throwIfEmpty(req.getNoticeUsers(), "通知用户不能为空");
}
// 校验通知方式
List<Integer> noticeMethods = req.getNoticeMethods();
if (CollUtil.isNotEmpty(noticeMethods)) {
List<Integer> validMethods = Arrays.stream(NoticeMethodEnum.values())
.map(NoticeMethodEnum::getValue)
.toList();
noticeMethods.forEach(method -> ValidationUtils.throwIf(!validMethods
.contains(method), "通知方式 [{}] 不正确", method));
}
}
}

View File

@@ -1,73 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.system;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaMode;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import top.continew.admin.system.model.query.OptionQuery;
import top.continew.admin.system.model.req.OptionReq;
import top.continew.admin.system.model.req.OptionResetValueReq;
import top.continew.admin.system.model.resp.OptionResp;
import top.continew.admin.system.service.OptionService;
import java.util.List;
/**
* 参数管理 API
*
* @author Bull-BCLS
* @since 2023/8/26 19:38
*/
@Tag(name = "参数管理 API")
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("/system/option")
public class OptionController {
private final OptionService baseService;
@Operation(summary = "查询参数列表", description = "查询参数列表")
@SaCheckPermission(value = {"system:siteConfig:get", "system:securityConfig:get", "system:loginConfig:get",
"system:mailConfig:get"}, mode = SaMode.OR)
@GetMapping
public List<OptionResp> list(@Validated OptionQuery query) {
return baseService.list(query);
}
@Operation(summary = "修改参数", description = "修改参数")
@SaCheckPermission(value = {"system:siteConfig:update", "system:securityConfig:update", "system:loginConfig:update",
"system:mailConfig:update"}, mode = SaMode.OR)
@PutMapping
public void update(@Valid @RequestBody List<OptionReq> options) {
baseService.update(options);
}
@Operation(summary = "重置参数", description = "重置参数")
@SaCheckPermission(value = {"system:siteConfig:update", "system:securityConfig:update", "system:loginConfig:update",
"system:mailConfig:update"}, mode = SaMode.OR)
@PatchMapping("/value")
public void resetValue(@Validated @RequestBody OptionResetValueReq req) {
baseService.resetValue(req);
}
}

View File

@@ -1,100 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.system;
import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotEmpty;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import top.continew.admin.common.controller.BaseController;
import top.continew.admin.system.model.query.RoleQuery;
import top.continew.admin.system.model.query.RoleUserQuery;
import top.continew.admin.system.model.req.RoleReq;
import top.continew.admin.system.model.req.RoleUpdatePermissionReq;
import top.continew.admin.system.model.resp.role.RoleDetailResp;
import top.continew.admin.system.model.resp.role.RoleResp;
import top.continew.admin.system.model.resp.role.RoleUserResp;
import top.continew.admin.system.service.RoleService;
import top.continew.admin.system.service.UserRoleService;
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
import top.continew.starter.extension.crud.enums.Api;
import top.continew.starter.extension.crud.model.query.PageQuery;
import top.continew.starter.extension.crud.model.resp.PageResp;
import java.util.List;
/**
* 角色管理 API
*
* @author Charles7c
* @since 2023/2/8 23:11
*/
@Tag(name = "角色管理 API")
@Validated
@RestController
@RequiredArgsConstructor
@CrudRequestMapping(value = "/system/role", api = {Api.LIST, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE})
public class RoleController extends BaseController<RoleService, RoleResp, RoleDetailResp, RoleQuery, RoleReq> {
private final UserRoleService userRoleService;
@Operation(summary = "修改权限", description = "修改角色的功能权限")
@SaCheckPermission("system:role:updatePermission")
@PutMapping("/{id}/permission")
public void updatePermission(@PathVariable("id") Long id, @Validated @RequestBody RoleUpdatePermissionReq req) {
baseService.updatePermission(id, req);
}
@Operation(summary = "分页查询关联用户", description = "分页查询角色关联的用户列表")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("system:role:list")
@GetMapping("/{id}/user")
public PageResp<RoleUserResp> pageUser(@PathVariable("id") Long id,
@Validated RoleUserQuery query,
@Validated PageQuery pageQuery) {
query.setRoleId(id);
return userRoleService.pageUser(query, pageQuery);
}
@Operation(summary = "分配用户", description = "批量分配角色给用户")
@SaCheckPermission("system:role:assign")
@PostMapping("/{id}/user")
public void assignToUsers(@PathVariable("id") Long id,
@Validated @NotEmpty(message = "用户ID列表不能为空") @RequestBody List<Long> userIds) {
baseService.assignToUsers(id, userIds);
}
@Operation(summary = "取消分配用户", description = "批量取消分配角色给用户")
@SaCheckPermission("system:role:unassign")
@DeleteMapping("/user")
public void unassignFromUsers(@Validated @NotEmpty(message = "用户列表不能为空") @RequestBody List<Long> userRoleIds) {
userRoleService.deleteByIds(userRoleIds);
}
@Operation(summary = "查询关联用户ID", description = "查询角色关联的用户ID列表")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("system:role:list")
@GetMapping("/{id}/user/id")
public List<Long> listUserId(@PathVariable("id") Long id) {
return userRoleService.listUserIdByRoleId(id);
}
}

View File

@@ -1,56 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.system;
import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RestController;
import top.continew.admin.common.controller.BaseController;
import top.continew.admin.system.model.query.SmsConfigQuery;
import top.continew.admin.system.model.req.SmsConfigReq;
import top.continew.admin.system.model.resp.SmsConfigResp;
import top.continew.admin.system.service.SmsConfigService;
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
import top.continew.starter.extension.crud.enums.Api;
/**
* 短信配置管理 API
*
* @author luoqiz
* @author Charles7c
* @since 2025/03/15 18:41
*/
@Tag(name = "短信配置管理 API")
@Validated
@RestController
@CrudRequestMapping(value = "/system/smsConfig", api = {Api.PAGE, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE})
public class SmsConfigController extends BaseController<SmsConfigService, SmsConfigResp, SmsConfigResp, SmsConfigQuery, SmsConfigReq> {
@Operation(summary = "设为默认配置", description = "设为默认配置")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("system:smsConfig:setDefault")
@PutMapping({"/{id}/default"})
public void setDefault(@PathVariable("id") Long id) {
baseService.setDefaultConfig(id);
}
}

View File

@@ -1,42 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.system;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import top.continew.admin.common.controller.BaseController;
import top.continew.admin.system.model.query.SmsLogQuery;
import top.continew.admin.system.model.req.SmsLogReq;
import top.continew.admin.system.model.resp.SmsLogResp;
import top.continew.admin.system.service.SmsLogService;
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
import top.continew.starter.extension.crud.enums.Api;
/**
* 短信日志管理 API
*
* @author luoqiz
* @author Charles7c
* @since 2025/03/15 22:15
*/
@Tag(name = "短信日志管理 API")
@Validated
@RestController
@CrudRequestMapping(value = "/system/smsLog", api = {Api.PAGE, Api.GET, Api.DELETE, Api.EXPORT})
public class SmsLogController extends BaseController<SmsLogService, SmsLogResp, SmsLogResp, SmsLogQuery, SmsLogReq> {
}

View File

@@ -1,65 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.system;
import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import top.continew.admin.common.controller.BaseController;
import top.continew.admin.common.model.req.CommonStatusUpdateReq;
import top.continew.admin.system.model.query.StorageQuery;
import top.continew.admin.system.model.req.StorageReq;
import top.continew.admin.system.model.resp.StorageResp;
import top.continew.admin.system.service.StorageService;
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
import top.continew.starter.extension.crud.enums.Api;
/**
* 存储管理 API
*
* @author Charles7c
* @since 2023/12/26 22:09
*/
@Tag(name = "存储管理 API")
@Validated
@RestController
@CrudRequestMapping(value = "/system/storage", api = {Api.LIST, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE})
public class StorageController extends BaseController<StorageService, StorageResp, StorageResp, StorageQuery, StorageReq> {
@Operation(summary = "修改状态", description = "修改状态")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("system:storage:updateStatus")
@PutMapping({"/{id}/status"})
public void updateStatus(@Validated @RequestBody CommonStatusUpdateReq req, @PathVariable("id") Long id) {
baseService.updateStatus(req, id);
}
@Operation(summary = "设为默认存储", description = "设为默认存储")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("system:storage:setDefault")
@PutMapping({"/{id}/default"})
public void setDefault(@PathVariable("id") Long id) {
baseService.setDefaultStorage(id);
}
}

View File

@@ -1,121 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.system;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.ReUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import top.continew.admin.common.constant.RegexConstants;
import top.continew.admin.common.controller.BaseController;
import top.continew.admin.common.util.SecureUtils;
import top.continew.admin.system.model.query.UserQuery;
import top.continew.admin.system.model.req.user.UserImportReq;
import top.continew.admin.system.model.req.user.UserPasswordResetReq;
import top.continew.admin.system.model.req.user.UserReq;
import top.continew.admin.system.model.req.user.UserRoleUpdateReq;
import top.continew.admin.system.model.resp.user.UserDetailResp;
import top.continew.admin.system.model.resp.user.UserImportParseResp;
import top.continew.admin.system.model.resp.user.UserImportResp;
import top.continew.admin.system.model.resp.user.UserResp;
import top.continew.admin.system.service.UserService;
import top.continew.starter.core.util.ExceptionUtils;
import top.continew.starter.core.validation.ValidationUtils;
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
import top.continew.starter.extension.crud.enums.Api;
import top.continew.starter.extension.crud.model.resp.IdResp;
import top.continew.starter.extension.crud.validation.CrudValidationGroup;
import java.io.IOException;
/**
* 用户管理 API
*
* @author Charles7c
* @since 2023/2/20 21:00
*/
@Tag(name = "用户管理 API")
@Validated
@RestController
@RequiredArgsConstructor
@CrudRequestMapping(value = "/system/user", api = {Api.PAGE, Api.LIST, Api.GET, Api.CREATE, Api.UPDATE, Api.DELETE,
Api.EXPORT})
public class UserController extends BaseController<UserService, UserResp, UserDetailResp, UserQuery, UserReq> {
@Override
@Operation(summary = "新增数据", description = "新增数据")
public IdResp<Long> create(@Validated(CrudValidationGroup.Create.class) @RequestBody UserReq req) {
String rawPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(req.getPassword()));
ValidationUtils.throwIfNull(rawPassword, "密码解密失败");
ValidationUtils.throwIf(!ReUtil
.isMatch(RegexConstants.PASSWORD, rawPassword), "密码长度为 8-32 个字符,支持大小写字母、数字、特殊字符,至少包含字母和数字");
req.setPassword(rawPassword);
return super.create(req);
}
@Operation(summary = "下载导入模板", description = "下载导入模板")
@SaCheckPermission("system:user:import")
@GetMapping(value = "/import/template", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void downloadImportTemplate(HttpServletResponse response) throws IOException {
baseService.downloadImportTemplate(response);
}
@Operation(summary = "解析导入数据", description = "解析导入数据")
@SaCheckPermission("system:user:import")
@PostMapping("/import/parse")
public UserImportParseResp parseImport(@NotNull(message = "文件不能为空") @RequestPart MultipartFile file) {
ValidationUtils.throwIf(file::isEmpty, "文件不能为空");
return baseService.parseImport(file);
}
@Operation(summary = "导入数据", description = "导入数据")
@SaCheckPermission("system:user:import")
@PostMapping(value = "/import")
public UserImportResp importUser(@Validated @RequestBody UserImportReq req) {
return baseService.importUser(req);
}
@Operation(summary = "重置密码", description = "重置用户登录密码")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("system:user:resetPwd")
@PatchMapping("/{id}/password")
public void resetPassword(@Validated @RequestBody UserPasswordResetReq req, @PathVariable Long id) {
String rawNewPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(req.getNewPassword()));
ValidationUtils.throwIfNull(rawNewPassword, "新密码解密失败");
ValidationUtils.throwIf(!ReUtil
.isMatch(RegexConstants.PASSWORD, rawNewPassword), "密码长度为 8-32 个字符,支持大小写字母、数字、特殊字符,至少包含字母和数字");
req.setNewPassword(rawNewPassword);
baseService.resetPassword(req, id);
}
@Operation(summary = "分配角色", description = "为用户新增或移除角色")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("system:user:updateRole")
@PatchMapping("/{id}/role")
public void updateRole(@Validated @RequestBody UserRoleUpdateReq updateReq, @PathVariable Long id) {
baseService.updateRole(updateReq, id);
}
}

View File

@@ -1,144 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.system;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import top.continew.admin.common.context.UserContextHolder;
import top.continew.admin.system.enums.NoticeMethodEnum;
import top.continew.admin.system.enums.NoticeScopeEnum;
import top.continew.admin.system.model.query.MessageQuery;
import top.continew.admin.system.model.query.NoticeQuery;
import top.continew.admin.system.model.resp.message.MessageDetailResp;
import top.continew.admin.system.model.resp.message.MessageResp;
import top.continew.admin.system.model.resp.message.MessageUnreadResp;
import top.continew.admin.system.model.resp.notice.NoticeDetailResp;
import top.continew.admin.system.model.resp.notice.NoticeResp;
import top.continew.admin.system.model.resp.notice.NoticeUnreadCountResp;
import top.continew.admin.system.service.MessageService;
import top.continew.admin.system.service.NoticeService;
import top.continew.starter.core.validation.CheckUtils;
import top.continew.starter.extension.crud.model.query.PageQuery;
import top.continew.starter.extension.crud.model.req.IdsReq;
import top.continew.starter.extension.crud.model.resp.BasePageResp;
import top.continew.starter.extension.crud.model.resp.PageResp;
import top.continew.starter.log.annotation.Log;
import java.util.Collections;
import java.util.List;
/**
* 个人消息 API
*
* @author Charles7c
* @since 2025/4/5 21:30
*/
@Tag(name = "个人消息 API")
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("/user/message")
public class UserMessageController {
private final NoticeService noticeService;
private final MessageService messageService;
@Log(ignore = true)
@Operation(summary = "查询未读消息数量", description = "查询当前用户的未读消息数量")
@Parameter(name = "isDetail", description = "是否查询详情", example = "true", in = ParameterIn.QUERY)
@GetMapping("/unread")
public MessageUnreadResp countUnreadMessage(@RequestParam(required = false) Boolean detail) {
return messageService.countUnreadByUserId(UserContextHolder.getUserId(), detail);
}
@Operation(summary = "分页查询消息列表", description = "分页查询消息列表")
@GetMapping
public PageResp<MessageResp> page(MessageQuery query, @Validated PageQuery pageQuery) {
query.setUserId(UserContextHolder.getUserId());
return messageService.page(query, pageQuery);
}
@Operation(summary = "查询消息", description = "查询消息详情")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@GetMapping("/{id}")
public MessageDetailResp getMessage(@PathVariable Long id) {
MessageDetailResp detail = messageService.get(id);
CheckUtils.throwIf(detail == null || (NoticeScopeEnum.USER.equals(detail.getScope()) && !detail.getUsers()
.contains(UserContextHolder.getUserId().toString())), "消息不存在或无权限访问");
messageService.readMessage(Collections.singletonList(id), UserContextHolder.getUserId());
detail.setIsRead(true);
return detail;
}
@Operation(summary = "删除消息", description = "删除消息")
@DeleteMapping
public void delete(@Validated @RequestBody IdsReq req) {
messageService.delete(req.getIds());
}
@Operation(summary = "消息标记为已读", description = "将消息标记为已读状态")
@PatchMapping("/read")
public void read(@Validated @RequestBody IdsReq req) {
messageService.readMessage(req.getIds(), UserContextHolder.getUserId());
}
@Operation(summary = "消息全部已读", description = "将所有消息标记为已读状态")
@PatchMapping("/readAll")
public void readAll() {
messageService.readMessage(null, UserContextHolder.getUserId());
}
@Log(ignore = true)
@Operation(summary = "查询未读公告数量", description = "查询当前用户的未读公告数量")
@GetMapping("/notice/unread")
public NoticeUnreadCountResp countUnreadNotice() {
List<Long> list = noticeService.listUnreadIdsByUserId(null, UserContextHolder.getUserId());
return new NoticeUnreadCountResp(list.size());
}
@Log(ignore = true)
@Operation(summary = "查询未读公告", description = "查询当前用户的未读公告")
@Parameter(name = "method", description = "通知方式", example = "LOGIN_POPUP", in = ParameterIn.PATH)
@GetMapping("/notice/unread/{method}")
public List<Long> listUnreadNotice(@PathVariable String method) {
return noticeService.listUnreadIdsByUserId(NoticeMethodEnum.valueOf(method), UserContextHolder.getUserId());
}
@Operation(summary = "分页查询公告列表", description = "分页查询公告列表")
@GetMapping("/notice")
public BasePageResp<NoticeResp> pageNotice(@Validated NoticeQuery query, @Validated PageQuery pageQuery) {
query.setUserId(UserContextHolder.getUserId());
return noticeService.page(query, pageQuery);
}
@Operation(summary = "查询公告", description = "查询公告详情")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@GetMapping("/notice/{id}")
public NoticeDetailResp getNotice(@PathVariable Long id) {
NoticeDetailResp detail = noticeService.get(id);
CheckUtils.throwIf(detail == null || (NoticeScopeEnum.USER.equals(detail.getNoticeScope()) && !detail
.getNoticeUsers()
.contains(UserContextHolder.getUserId().toString())), "公告不存在或无权限访问");
noticeService.readNotice(id, UserContextHolder.getUserId());
return detail;
}
}

View File

@@ -1,169 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.controller.system;
import com.xkcoding.justauth.autoconfigure.JustAuthProperties;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import me.zhyd.oauth.AuthRequestBuilder;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import top.continew.admin.common.constant.CacheConstants;
import top.continew.admin.common.context.UserContextHolder;
import top.continew.admin.common.util.SecureUtils;
import top.continew.admin.system.enums.SocialSourceEnum;
import top.continew.admin.system.model.entity.user.UserSocialDO;
import top.continew.admin.system.model.req.user.UserBasicInfoUpdateReq;
import top.continew.admin.system.model.req.user.UserEmailUpdateReq;
import top.continew.admin.system.model.req.user.UserPasswordUpdateReq;
import top.continew.admin.system.model.req.user.UserPhoneUpdateReq;
import top.continew.admin.system.model.resp.AvatarResp;
import top.continew.admin.system.model.resp.user.UserSocialBindResp;
import top.continew.admin.system.service.UserService;
import top.continew.admin.system.service.UserSocialService;
import top.continew.starter.cache.redisson.util.RedisUtils;
import top.continew.starter.core.exception.BadRequestException;
import top.continew.starter.core.util.ExceptionUtils;
import top.continew.starter.core.validation.ValidationUtils;
import java.io.IOException;
import java.util.List;
/**
* 个人信息 API
*
* @author Charles7c
* @since 2023/1/2 11:41
*/
@Tag(name = "个人信息 API")
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("/user/profile")
public class UserProfileController {
private static final String DECRYPT_FAILED = "当前密码解密失败";
private static final String CAPTCHA_EXPIRED = "验证码已失效";
private final UserService userService;
private final UserSocialService userSocialService;
private final JustAuthProperties authProperties;
@Operation(summary = "修改头像", description = "用户修改个人头像")
@PatchMapping("/avatar")
public AvatarResp updateAvatar(@NotNull(message = "头像不能为空") MultipartFile avatarFile) throws IOException {
ValidationUtils.throwIf(avatarFile::isEmpty, "头像不能为空");
String newAvatar = userService.updateAvatar(avatarFile, UserContextHolder.getUserId());
return AvatarResp.builder().avatar(newAvatar).build();
}
@Operation(summary = "修改基础信息", description = "修改用户基础信息")
@PatchMapping("/basic/info")
public void updateBasicInfo(@Validated @RequestBody UserBasicInfoUpdateReq req) {
userService.updateBasicInfo(req, UserContextHolder.getUserId());
}
@Operation(summary = "修改密码", description = "修改用户登录密码")
@PatchMapping("/password")
public void updatePassword(@Validated @RequestBody UserPasswordUpdateReq updateReq) {
String rawOldPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updateReq
.getOldPassword()));
ValidationUtils.throwIfNull(rawOldPassword, DECRYPT_FAILED);
String rawNewPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updateReq
.getNewPassword()));
ValidationUtils.throwIfNull(rawNewPassword, "新密码解密失败");
userService.updatePassword(rawOldPassword, rawNewPassword, UserContextHolder.getUserId());
}
@Operation(summary = "修改手机号", description = "修改手机号")
@PatchMapping("/phone")
public void updatePhone(@Validated @RequestBody UserPhoneUpdateReq updateReq) {
String rawOldPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updateReq
.getOldPassword()));
ValidationUtils.throwIfBlank(rawOldPassword, DECRYPT_FAILED);
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + updateReq.getPhone();
String captcha = RedisUtils.get(captchaKey);
ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
ValidationUtils.throwIfNotEqualIgnoreCase(updateReq.getCaptcha(), captcha, "验证码不正确");
RedisUtils.delete(captchaKey);
userService.updatePhone(updateReq.getPhone(), rawOldPassword, UserContextHolder.getUserId());
}
@Operation(summary = "修改邮箱", description = "修改用户邮箱")
@PatchMapping("/email")
public void updateEmail(@Valid @RequestBody UserEmailUpdateReq updateReq) {
String rawOldPassword = ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updateReq
.getOldPassword()));
ValidationUtils.throwIfBlank(rawOldPassword, DECRYPT_FAILED);
String captchaKey = CacheConstants.CAPTCHA_KEY_PREFIX + updateReq.getEmail();
String captcha = RedisUtils.get(captchaKey);
ValidationUtils.throwIfBlank(captcha, CAPTCHA_EXPIRED);
ValidationUtils.throwIfNotEqualIgnoreCase(updateReq.getCaptcha(), captcha, "验证码不正确");
RedisUtils.delete(captchaKey);
userService.updateEmail(updateReq.getEmail(), rawOldPassword, UserContextHolder.getUserId());
}
@Operation(summary = "查询绑定的三方账号", description = "查询绑定的三方账号")
@GetMapping("/social")
public List<UserSocialBindResp> listSocialBind() {
List<UserSocialDO> userSocialList = userSocialService.listByUserId(UserContextHolder.getUserId());
return userSocialList.stream().map(userSocial -> {
String source = userSocial.getSource();
UserSocialBindResp userSocialBind = new UserSocialBindResp();
userSocialBind.setSource(source);
userSocialBind.setDescription(SocialSourceEnum.valueOf(source).getDescription());
return userSocialBind;
}).toList();
}
@Operation(summary = "绑定三方账号", description = "绑定三方账号")
@Parameter(name = "source", description = "来源", example = "gitee", in = ParameterIn.PATH)
@PostMapping("/social/{source}")
public void bindSocial(@PathVariable String source, @RequestBody AuthCallback callback) {
AuthRequest authRequest = this.getAuthRequest(source);
AuthResponse<AuthUser> response = authRequest.login(callback);
ValidationUtils.throwIf(!response.ok(), response.getMsg());
AuthUser authUser = response.getData();
userSocialService.bind(authUser, UserContextHolder.getUserId());
}
@Operation(summary = "解绑三方账号", description = "解绑三方账号")
@Parameter(name = "source", description = "来源", example = "gitee", in = ParameterIn.PATH)
@DeleteMapping("/social/{source}")
public void unbindSocial(@PathVariable String source) {
userSocialService.deleteBySourceAndUserId(source, UserContextHolder.getUserId());
}
private AuthRequest getAuthRequest(String source) {
try {
AuthConfig authConfig = authProperties.getType().get(source.toUpperCase());
return AuthRequestBuilder.builder().source(source).authConfig(authConfig).build();
} catch (Exception e) {
throw new BadRequestException("暂不支持 [%s] 平台账号登录".formatted(source));
}
}
}

View File

@@ -114,33 +114,6 @@ springdoc:
# 设置对象型参数的展示形式(设为 true 表示将对象型参数平展开,即对象内的属性直接作为参数展示而不是嵌套在对象内,默认 false
# 如果不添加该全局配置,可以在需要如此处理的对象参数类上使用 @ParameterObject
default-flat-param-object: true
# 分组配置
group-configs:
- group: all
paths-to-match: /**
paths-to-exclude:
- /error
- group: auth
display-name: 系统认证
packages-to-scan: ${project.base-package}.controller.auth
- group: common
display-name: 通用接口
packages-to-scan: ${project.base-package}.controller.common
- group: system
display-name: 系统管理
packages-to-scan: ${project.base-package}.controller.system
- group: monitor
display-name: 系统监控
packages-to-scan: ${project.base-package}.controller.monitor
- group: schedule
display-name: 任务调度
packages-to-scan: ${project.base-package}.controller.schedule
- group: open
display-name: 能力开放
packages-to-scan: ${project.base-package}.controller.open
- group: code
display-name: 代码生成
packages-to-scan: ${project.base-package}.controller.code
## 组件配置
components:
# 鉴权配置