mirror of
https://github.com/vran-dev/databasir.git
synced 2025-08-08 17:32:14 +08:00
Feature: add operation log (#16)
* feat: auto record operation log * feat: add list project operation log api * feat: update frontend resource
This commit is contained in:
@@ -5,6 +5,7 @@ import com.databasir.common.SystemException;
|
||||
import com.databasir.core.domain.document.data.DatabaseDocumentResponse;
|
||||
import com.databasir.core.domain.document.data.DatabaseDocumentVersionResponse;
|
||||
import com.databasir.core.domain.document.service.DocumentService;
|
||||
import com.databasir.core.domain.log.annotation.Operation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -33,6 +34,7 @@ public class DocumentController {
|
||||
private final DocumentService documentService;
|
||||
|
||||
@PostMapping(Routes.Document.SYNC_ONE)
|
||||
@Operation(module = Operation.Modules.PROJECT, name = "文档同步", involvedProjectId = "#projectId")
|
||||
public JsonData<Void> sync(@PathVariable Integer projectId) {
|
||||
documentService.syncByProjectId(projectId);
|
||||
return JsonData.ok();
|
||||
|
@@ -2,6 +2,7 @@ package com.databasir.api;
|
||||
|
||||
import com.databasir.api.config.security.DatabasirUserDetails;
|
||||
import com.databasir.common.JsonData;
|
||||
import com.databasir.core.domain.log.annotation.Operation;
|
||||
import com.databasir.core.domain.remark.data.RemarkCreateRequest;
|
||||
import com.databasir.core.domain.remark.data.RemarkListCondition;
|
||||
import com.databasir.core.domain.remark.data.RemarkResponse;
|
||||
@@ -38,6 +39,9 @@ public class DocumentRemarkController {
|
||||
|
||||
@DeleteMapping(Routes.DocumentRemark.DELETE)
|
||||
@PreAuthorize("hasAnyAuthority('SYS_OWNER', 'GROUP_OWNER?groupId='+#groupId)")
|
||||
@Operation(module = Operation.Modules.PROJECT,
|
||||
name = "删除批注",
|
||||
involvedProjectId = "#projectId")
|
||||
public JsonData<Void> delete(@PathVariable Integer groupId,
|
||||
@PathVariable Integer projectId,
|
||||
@PathVariable Integer remarkId) {
|
||||
@@ -47,6 +51,9 @@ public class DocumentRemarkController {
|
||||
|
||||
@PostMapping(Routes.DocumentRemark.CREATE)
|
||||
@PreAuthorize("hasAnyAuthority('SYS_OWNER', 'GROUP_OWNER?groupId='+#groupId, 'GROUP_MEMBER?groupId='+#groupId)")
|
||||
@Operation(module = Operation.Modules.PROJECT,
|
||||
name = "新增批注",
|
||||
involvedProjectId = "#projectId")
|
||||
public JsonData<Void> create(@PathVariable Integer groupId,
|
||||
@PathVariable Integer projectId,
|
||||
@RequestBody @Valid RemarkCreateRequest request) {
|
||||
|
@@ -4,6 +4,7 @@ import com.databasir.api.validator.UserOperationValidator;
|
||||
import com.databasir.common.JsonData;
|
||||
import com.databasir.core.domain.group.data.*;
|
||||
import com.databasir.core.domain.group.service.GroupService;
|
||||
import com.databasir.core.domain.log.annotation.Operation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -28,6 +29,7 @@ public class GroupController {
|
||||
|
||||
@PostMapping(Routes.Group.CREATE)
|
||||
@PreAuthorize("hasAnyAuthority('SYS_OWNER')")
|
||||
@Operation(module = Operation.Modules.GROUP, name = "创建分组")
|
||||
public JsonData<Void> create(@RequestBody @Valid GroupCreateRequest request) {
|
||||
groupService.create(request);
|
||||
return JsonData.ok();
|
||||
@@ -35,6 +37,9 @@ public class GroupController {
|
||||
|
||||
@PatchMapping(Routes.Group.UPDATE)
|
||||
@PreAuthorize("hasAnyAuthority('SYS_OWNER', 'GROUP_OWNER'.concat('?groupId='.concat(#request.id)))")
|
||||
@Operation(module = Operation.Modules.GROUP,
|
||||
name = "更新分组",
|
||||
involvedGroupId = "#request.id")
|
||||
public JsonData<Void> update(@RequestBody @Valid GroupUpdateRequest request) {
|
||||
groupService.update(request);
|
||||
return JsonData.ok();
|
||||
@@ -49,6 +54,9 @@ public class GroupController {
|
||||
|
||||
@DeleteMapping(Routes.Group.DELETE)
|
||||
@PreAuthorize("hasAnyAuthority('SYS_OWNER', 'GROUP_OWNER'.concat('?groupId='.concat(#groupId)))")
|
||||
@Operation(module = Operation.Modules.GROUP,
|
||||
name = "删除分组",
|
||||
involvedGroupId = "#groupId")
|
||||
public JsonData<Void> deleteById(@PathVariable Integer groupId) {
|
||||
groupService.delete(groupId);
|
||||
return JsonData.ok();
|
||||
@@ -69,6 +77,10 @@ public class GroupController {
|
||||
|
||||
@PostMapping(Routes.Group.ADD_MEMBER)
|
||||
@PreAuthorize("hasAnyAuthority('SYS_OWNER', 'GROUP_OWNER'.concat('?groupId='.concat(#groupId)))")
|
||||
@Operation(module = Operation.Modules.GROUP,
|
||||
name = "添加组员",
|
||||
involvedGroupId = "#groupId",
|
||||
involvedUserId = "#request.userId")
|
||||
public JsonData<Void> addGroupMember(@PathVariable Integer groupId,
|
||||
@RequestBody @Valid GroupMemberCreateRequest request) {
|
||||
userOperationValidator.forbiddenIfUpdateSelfRole(request.getUserId());
|
||||
@@ -82,6 +94,10 @@ public class GroupController {
|
||||
|
||||
@DeleteMapping(Routes.Group.DELETE_MEMBER)
|
||||
@PreAuthorize("hasAnyAuthority('SYS_OWNER', 'GROUP_OWNER'.concat('?groupId='.concat(#groupId)))")
|
||||
@Operation(module = Operation.Modules.GROUP,
|
||||
name = "移除组员",
|
||||
involvedGroupId = "#groupId",
|
||||
involvedUserId = "#userId")
|
||||
public JsonData<Void> removeGroupMember(@PathVariable Integer groupId,
|
||||
@PathVariable Integer userId) {
|
||||
userOperationValidator.forbiddenIfUpdateSelfRole(userId);
|
||||
@@ -91,6 +107,10 @@ public class GroupController {
|
||||
|
||||
@PatchMapping(Routes.Group.UPDATE_MEMBER)
|
||||
@PreAuthorize("hasAnyAuthority('SYS_OWNER', 'GROUP_OWNER'.concat('?groupId='.concat(#groupId)))")
|
||||
@Operation(module = Operation.Modules.GROUP,
|
||||
name = "更新组员角色",
|
||||
involvedGroupId = "#groupId",
|
||||
involvedUserId = "#userId")
|
||||
public JsonData<Void> updateGroupMemberRole(@PathVariable Integer groupId,
|
||||
@PathVariable Integer userId,
|
||||
@RequestBody GroupMemberRoleUpdateRequest request) {
|
||||
|
@@ -4,6 +4,7 @@ import com.databasir.common.DatabasirException;
|
||||
import com.databasir.common.JsonData;
|
||||
import com.databasir.common.exception.InvalidTokenException;
|
||||
import com.databasir.core.domain.DomainErrors;
|
||||
import com.databasir.core.domain.log.annotation.Operation;
|
||||
import com.databasir.core.domain.login.data.AccessTokenRefreshRequest;
|
||||
import com.databasir.core.domain.login.data.AccessTokenRefreshResponse;
|
||||
import com.databasir.core.domain.login.service.LoginService;
|
||||
@@ -32,6 +33,7 @@ public class LoginController {
|
||||
private final LoginService loginService;
|
||||
|
||||
@GetMapping(Routes.Login.LOGOUT)
|
||||
@Operation(module = Operation.Modules.USER, name = "注销登录")
|
||||
public JsonData<Void> logout() {
|
||||
SecurityContextHolder.clearContext();
|
||||
return JsonData.ok();
|
||||
|
@@ -0,0 +1,30 @@
|
||||
package com.databasir.api;
|
||||
|
||||
import com.databasir.common.JsonData;
|
||||
import com.databasir.core.domain.log.data.OperationLogPageCondition;
|
||||
import com.databasir.core.domain.log.data.OperationLogPageResponse;
|
||||
import com.databasir.core.domain.log.service.OperationLogService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.web.PageableDefault;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@Validated
|
||||
public class OperationLogController {
|
||||
|
||||
private final OperationLogService operationLogService;
|
||||
|
||||
@GetMapping(Routes.OperationLog.LIST)
|
||||
public JsonData<Page<OperationLogPageResponse>> list(@PageableDefault(sort = "id", direction = Sort.Direction.DESC)
|
||||
Pageable page,
|
||||
OperationLogPageCondition condition) {
|
||||
Page<OperationLogPageResponse> pageData = operationLogService.list(page, condition);
|
||||
return JsonData.ok(pageData);
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@ package com.databasir.api;
|
||||
|
||||
import com.databasir.api.validator.CronExpressionValidator;
|
||||
import com.databasir.common.JsonData;
|
||||
import com.databasir.core.domain.log.annotation.Operation;
|
||||
import com.databasir.core.domain.project.data.*;
|
||||
import com.databasir.core.domain.project.service.ProjectService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -26,6 +27,9 @@ public class ProjectController {
|
||||
|
||||
@PostMapping(Routes.GroupProject.CREATE)
|
||||
@PreAuthorize("hasAnyAuthority('SYS_OWNER', 'GROUP_OWNER?groupId='+#request.groupId, 'GROUP_MEMBER?groupId='+#request.groupId)")
|
||||
@Operation(module = Operation.Modules.PROJECT,
|
||||
name = "创建项目",
|
||||
involvedGroupId = "#request.groupId")
|
||||
public JsonData<Void> create(@RequestBody @Valid ProjectCreateRequest request) {
|
||||
cronExpressionValidator.isValidCron(request);
|
||||
projectService.create(request);
|
||||
@@ -34,6 +38,10 @@ public class ProjectController {
|
||||
|
||||
@PatchMapping(Routes.GroupProject.UPDATE)
|
||||
@PreAuthorize("hasAnyAuthority('SYS_OWNER', 'GROUP_OWNER?groupId='+#groupId, 'GROUP_MEMBER?groupId='+#groupId)")
|
||||
@Operation(module = Operation.Modules.PROJECT,
|
||||
name = "更新项目",
|
||||
involvedGroupId = "#groupId",
|
||||
involvedProjectId = "#request.id")
|
||||
public JsonData<Void> update(@RequestBody @Valid ProjectUpdateRequest request,
|
||||
@PathVariable Integer groupId) {
|
||||
cronExpressionValidator.isValidCron(request);
|
||||
@@ -43,6 +51,10 @@ public class ProjectController {
|
||||
|
||||
@DeleteMapping(Routes.GroupProject.DELETE)
|
||||
@PreAuthorize("hasAnyAuthority('SYS_OWNER', 'GROUP_OWNER?groupId='+#groupId, 'GROUP_MEMBER?groupId='+#groupId)")
|
||||
@Operation(module = Operation.Modules.PROJECT,
|
||||
name = "删除项目",
|
||||
involvedGroupId = "#groupId",
|
||||
involvedProjectId = "#projectId")
|
||||
public JsonData<Void> delete(@PathVariable Integer groupId,
|
||||
@PathVariable Integer projectId) {
|
||||
projectService.delete(projectId);
|
||||
|
@@ -94,4 +94,8 @@ public interface Routes {
|
||||
|
||||
String REFRESH_ACCESS_TOKEN = "/access_tokens";
|
||||
}
|
||||
|
||||
interface OperationLog {
|
||||
String LIST = BASE + "/operation_logs";
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package com.databasir.api;
|
||||
|
||||
|
||||
import com.databasir.common.JsonData;
|
||||
import com.databasir.core.domain.log.annotation.Operation;
|
||||
import com.databasir.core.domain.system.data.SystemEmailResponse;
|
||||
import com.databasir.core.domain.system.data.SystemEmailUpdateRequest;
|
||||
import com.databasir.core.domain.system.service.SystemService;
|
||||
@@ -28,6 +29,7 @@ public class SettingController {
|
||||
}
|
||||
|
||||
@PostMapping(Routes.Setting.UPDATE_SYS_EMAIL)
|
||||
@Operation(module = Operation.Modules.PROJECT, name = "更新邮件配置")
|
||||
public JsonData<Void> updateSystemEmailSetting(@RequestBody @Valid SystemEmailUpdateRequest request) {
|
||||
systemService.updateEmailSetting(request);
|
||||
return JsonData.ok();
|
||||
|
@@ -3,6 +3,7 @@ package com.databasir.api;
|
||||
import com.databasir.api.validator.UserOperationValidator;
|
||||
import com.databasir.common.JsonData;
|
||||
import com.databasir.common.exception.Forbidden;
|
||||
import com.databasir.core.domain.log.annotation.Operation;
|
||||
import com.databasir.core.domain.user.data.*;
|
||||
import com.databasir.core.domain.user.service.UserService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -34,6 +35,7 @@ public class UserController {
|
||||
|
||||
@PostMapping(Routes.User.DISABLE)
|
||||
@PreAuthorize("hasAnyAuthority('SYS_OWNER')")
|
||||
@Operation(module = Operation.Modules.USER, name = "禁用用户", involvedUserId = "#userId")
|
||||
public JsonData<Void> disableUser(@PathVariable Integer userId) {
|
||||
userService.switchEnableStatus(userId, false);
|
||||
return JsonData.ok();
|
||||
@@ -41,6 +43,7 @@ public class UserController {
|
||||
|
||||
@PostMapping(Routes.User.ENABLE)
|
||||
@PreAuthorize("hasAnyAuthority('SYS_OWNER')")
|
||||
@Operation(module = Operation.Modules.USER, name = "启用用户", involvedUserId = "#userId")
|
||||
public JsonData<Void> enableUser(@PathVariable Integer userId) {
|
||||
userService.switchEnableStatus(userId, true);
|
||||
return JsonData.ok();
|
||||
@@ -48,6 +51,7 @@ public class UserController {
|
||||
|
||||
@PostMapping(Routes.User.CREATE)
|
||||
@PreAuthorize("hasAnyAuthority('SYS_OWNER')")
|
||||
@Operation(module = Operation.Modules.USER, name = "创建用户")
|
||||
public JsonData<Void> create(@RequestBody @Valid UserCreateRequest request) {
|
||||
userService.create(request);
|
||||
return JsonData.ok();
|
||||
@@ -60,6 +64,7 @@ public class UserController {
|
||||
|
||||
@PostMapping(Routes.User.RENEW_PASSWORD)
|
||||
@PreAuthorize("hasAnyAuthority('SYS_OWNER')")
|
||||
@Operation(module = Operation.Modules.USER, name = "重置用户密码", involvedUserId = "#userId")
|
||||
public JsonData<Void> renewPassword(@PathVariable Integer userId) {
|
||||
userService.renewPassword(userId);
|
||||
return JsonData.ok();
|
||||
@@ -67,6 +72,7 @@ public class UserController {
|
||||
|
||||
@PostMapping(Routes.User.ADD_OR_REMOVE_SYS_OWNER)
|
||||
@PreAuthorize("hasAnyAuthority('SYS_OWNER')")
|
||||
@Operation(module = Operation.Modules.USER, name = "添加系统管理员", involvedUserId = "#userId")
|
||||
public JsonData<Void> addSysOwner(@PathVariable Integer userId) {
|
||||
userOperationValidator.forbiddenIfUpdateSelfRole(userId);
|
||||
userService.addSysOwnerTo(userId);
|
||||
@@ -75,6 +81,7 @@ public class UserController {
|
||||
|
||||
@DeleteMapping(Routes.User.ADD_OR_REMOVE_SYS_OWNER)
|
||||
@PreAuthorize("hasAnyAuthority('SYS_OWNER')")
|
||||
@Operation(module = Operation.Modules.USER, name = "移除系统管理员", involvedUserId = "#userId")
|
||||
public JsonData<Void> removeSysOwner(@PathVariable Integer userId) {
|
||||
userOperationValidator.forbiddenIfUpdateSelfRole(userId);
|
||||
userService.removeSysOwnerFrom(userId);
|
||||
@@ -82,6 +89,7 @@ public class UserController {
|
||||
}
|
||||
|
||||
@PostMapping(Routes.User.UPDATE_PASSWORD)
|
||||
@Operation(module = Operation.Modules.USER, name = "更新密码", involvedUserId = "#userId")
|
||||
public JsonData<Void> updatePassword(@PathVariable Integer userId,
|
||||
@RequestBody @Valid UserPasswordUpdateRequest request) {
|
||||
if (userOperationValidator.isMyself(userId)) {
|
||||
@@ -93,6 +101,7 @@ public class UserController {
|
||||
}
|
||||
|
||||
@PostMapping(Routes.User.UPDATE_NICKNAME)
|
||||
@Operation(module = Operation.Modules.USER, name = "更新昵称", involvedUserId = "#userId")
|
||||
public JsonData<Void> updateNickname(@PathVariable Integer userId,
|
||||
@RequestBody @Valid UserNicknameUpdateRequest request) {
|
||||
if (userOperationValidator.isMyself(userId)) {
|
||||
|
@@ -0,0 +1,117 @@
|
||||
package com.databasir.api.advice;
|
||||
|
||||
import com.databasir.api.config.security.DatabasirUserDetails;
|
||||
import com.databasir.common.JsonData;
|
||||
import com.databasir.core.domain.log.annotation.Operation;
|
||||
import com.databasir.core.domain.log.data.OperationLogRequest;
|
||||
import com.databasir.core.domain.log.service.OperationLogService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.AfterReturning;
|
||||
import org.aspectj.lang.annotation.AfterThrowing;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Aspect
|
||||
@Slf4j
|
||||
public class OperationLogAspect {
|
||||
|
||||
private final OperationLogService operationLogService;
|
||||
|
||||
private SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
|
||||
|
||||
private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||
|
||||
@AfterReturning(value = "@annotation(operation)", returning = "returnValue")
|
||||
public void log(JoinPoint joinPoint, Object returnValue, Operation operation) {
|
||||
saveLog(operation, joinPoint, (JsonData<Object>) returnValue);
|
||||
}
|
||||
|
||||
@AfterThrowing(value = "@annotation(operation)", throwing = "ex")
|
||||
public void log(JoinPoint joinPoint, RuntimeException ex, Operation operation) {
|
||||
saveLog(operation, joinPoint, JsonData.error("-1", ex.getMessage()));
|
||||
throw ex;
|
||||
}
|
||||
|
||||
private void saveLog(Operation operation, JoinPoint joinPoint, JsonData<Object> result) {
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
Object[] arguments = joinPoint.getArgs();
|
||||
|
||||
DatabasirUserDetails principal = (DatabasirUserDetails) SecurityContextHolder.getContext()
|
||||
.getAuthentication()
|
||||
.getPrincipal();
|
||||
Integer involvedProjectId = getValueBySPEL(method, arguments, operation.involvedProjectId(), Integer.class)
|
||||
.orElse(null);
|
||||
Integer involvedGroupId = getValueBySPEL(method, arguments, operation.involvedGroupId(), Integer.class)
|
||||
.orElse(null);
|
||||
Integer involvedUserId = getValueBySPEL(method, arguments, operation.involvedUserId(), Integer.class)
|
||||
.orElse(null);
|
||||
int userId = userId();
|
||||
String username = principal.getUserPojo().getUsername();
|
||||
String nickname = principal.getUserPojo().getNickname();
|
||||
if (userId == Operation.Types.SYSTEM_USER_ID) {
|
||||
username = "system";
|
||||
nickname = "system";
|
||||
}
|
||||
OperationLogRequest request = OperationLogRequest.builder()
|
||||
.operatorUserId(userId)
|
||||
.operatorUsername(username)
|
||||
.operatorNickname(nickname)
|
||||
.operationModule(operation.module())
|
||||
.operationCode(method.getName())
|
||||
.operationName(operation.name())
|
||||
.operationResponse(result)
|
||||
.isSuccess(result.getErrCode() == null)
|
||||
.involvedProjectId(involvedProjectId)
|
||||
.involvedGroupId(involvedGroupId)
|
||||
.involvedUserId(involvedUserId)
|
||||
.build();
|
||||
operationLogService.save(request);
|
||||
}
|
||||
|
||||
private int userId() {
|
||||
DatabasirUserDetails principal = (DatabasirUserDetails) SecurityContextHolder.getContext()
|
||||
.getAuthentication()
|
||||
.getPrincipal();
|
||||
return principal.getUserPojo().getId();
|
||||
}
|
||||
|
||||
private <T> Optional<T> getValueBySPEL(Method method,
|
||||
Object[] arguments,
|
||||
String expression,
|
||||
Class<T> valueType) {
|
||||
if (expression == null || "N/A".equals(expression)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
String[] parameterNames =
|
||||
Objects.requireNonNullElse(parameterNameDiscoverer.getParameterNames(method), new String[0]);
|
||||
EvaluationContext context = new StandardEvaluationContext();
|
||||
for (int len = 0; len < parameterNames.length; len++) {
|
||||
context.setVariable(parameterNames[len], arguments[len]);
|
||||
}
|
||||
try {
|
||||
Expression expr = spelExpressionParser.parseExpression(expression);
|
||||
return Optional.ofNullable(expr.getValue(context, valueType));
|
||||
} catch (Exception e) {
|
||||
log.warn("parse expression error: " + expression, e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,6 +1,9 @@
|
||||
package com.databasir.job;
|
||||
|
||||
import com.databasir.common.JsonData;
|
||||
import com.databasir.core.domain.document.service.DocumentService;
|
||||
import com.databasir.core.domain.log.data.OperationLogRequest;
|
||||
import com.databasir.core.domain.log.service.OperationLogService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.quartz.Job;
|
||||
@@ -12,14 +15,47 @@ import org.quartz.JobExecutionException;
|
||||
@Slf4j
|
||||
public class ProjectDocumentAutoSyncJob implements Job {
|
||||
|
||||
private final OperationLogService operationLogService;
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException {
|
||||
JobDataMap dataMap = context.getMergedJobDataMap();
|
||||
log.info("start sync project document: " + dataMap.toString());
|
||||
DocumentService documentService = (DocumentService) dataMap.get("documentService");
|
||||
Integer projectId = dataMap.getInt("projectId");
|
||||
documentService.syncByProjectId(projectId);
|
||||
log.info("sync project document {} over....", projectId);
|
||||
|
||||
try {
|
||||
documentService.syncByProjectId(projectId);
|
||||
OperationLogRequest request = OperationLogRequest.builder()
|
||||
.isSuccess(true)
|
||||
.operatorNickname("system")
|
||||
.operatorUsername("system")
|
||||
.operatorUserId(-1)
|
||||
.operationName("文档自动同步")
|
||||
.operationCode("autoSyncDocumentation")
|
||||
.operationModule("project")
|
||||
.operationResponse(JsonData.ok())
|
||||
.isSuccess(true)
|
||||
.involvedProjectId(projectId)
|
||||
.build();
|
||||
operationLogService.save(request);
|
||||
log.info("sync project document {} over....", projectId);
|
||||
} catch (Exception e) {
|
||||
OperationLogRequest request = OperationLogRequest.builder()
|
||||
.isSuccess(true)
|
||||
.operatorNickname("system")
|
||||
.operatorUsername("system")
|
||||
.operatorUserId(-1)
|
||||
.operationName("文档自动同步")
|
||||
.operationCode("autoSyncDocumentation")
|
||||
.operationModule("project")
|
||||
.operationResponse(JsonData.error("-1", e.getMessage()))
|
||||
.isSuccess(false)
|
||||
.involvedProjectId(projectId)
|
||||
.build();
|
||||
operationLogService.save(request);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
BIN
api/src/main/resources/static/.DS_Store
vendored
BIN
api/src/main/resources/static/.DS_Store
vendored
Binary file not shown.
@@ -1 +1 @@
|
||||
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>databasir-frontend</title><link href="/css/chunk-04ac1c26.a5cbc9e6.css" rel="prefetch"><link href="/css/chunk-4fd080e4.a5b9f9ad.css" rel="prefetch"><link href="/css/chunk-7e394785.ab54ac4c.css" rel="prefetch"><link href="/css/chunk-7fa689fe.a79c1787.css" rel="prefetch"><link href="/js/chunk-04ac1c26.b03a6105.js" rel="prefetch"><link href="/js/chunk-2d0cc811.feb081c8.js" rel="prefetch"><link href="/js/chunk-48cebeac.b43a95b4.js" rel="prefetch"><link href="/js/chunk-4fd080e4.d40c8d0d.js" rel="prefetch"><link href="/js/chunk-7e394785.b93f6d8c.js" rel="prefetch"><link href="/js/chunk-7fa689fe.e971bfe1.js" rel="prefetch"><link href="/js/chunk-abb10c56.4c323350.js" rel="prefetch"><link href="/js/chunk-fffb1b64.df1e960f.js" rel="prefetch"><link href="/css/app.df19208c.css" rel="preload" as="style"><link href="/css/chunk-vendors.d4aa889d.css" rel="preload" as="style"><link href="/js/app.943c1753.js" rel="preload" as="script"><link href="/js/chunk-vendors.8b5336af.js" rel="preload" as="script"><link href="/css/chunk-vendors.d4aa889d.css" rel="stylesheet"><link href="/css/app.df19208c.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but databasir-frontend doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="/js/chunk-vendors.8b5336af.js"></script><script src="/js/app.943c1753.js"></script></body></html>
|
||||
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>databasir-frontend</title><link href="/css/chunk-04ac1c26.00ac37b1.css" rel="prefetch"><link href="/css/chunk-7e394785.e51aa148.css" rel="prefetch"><link href="/css/chunk-7fa689fe.80a92238.css" rel="prefetch"><link href="/css/chunk-c2109158.06814884.css" rel="prefetch"><link href="/js/chunk-04ac1c26.b5c879b8.js" rel="prefetch"><link href="/js/chunk-2d0cc811.c5d1ef9e.js" rel="prefetch"><link href="/js/chunk-48cebeac.162363c9.js" rel="prefetch"><link href="/js/chunk-7e394785.e090ef46.js" rel="prefetch"><link href="/js/chunk-7fa689fe.337b34fc.js" rel="prefetch"><link href="/js/chunk-abb10c56.bd8d31bf.js" rel="prefetch"><link href="/js/chunk-c2109158.94b6c554.js" rel="prefetch"><link href="/js/chunk-fffb1b64.1ffb9f27.js" rel="prefetch"><link href="/css/app.36ecf611.css" rel="preload" as="style"><link href="/css/chunk-vendors.d4aa889d.css" rel="preload" as="style"><link href="/js/app.7a0ffda3.js" rel="preload" as="script"><link href="/js/chunk-vendors.8b5336af.js" rel="preload" as="script"><link href="/css/chunk-vendors.d4aa889d.css" rel="stylesheet"><link href="/css/app.36ecf611.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but databasir-frontend doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="/js/chunk-vendors.8b5336af.js"></script><script src="/js/app.7a0ffda3.js"></script></body></html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +1,2 @@
|
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0cc811"],{"4de0":function(e,t,r){"use strict";r.r(t);var n=r("7a23"),o=Object(n["createTextVNode"])(" : "),u=Object(n["createTextVNode"])("保存");function l(e,t,r,l,a,c){var s=Object(n["resolveComponent"])("el-input"),i=Object(n["resolveComponent"])("el-form-item"),d=Object(n["resolveComponent"])("el-col"),m=Object(n["resolveComponent"])("el-button"),f=Object(n["resolveComponent"])("el-form"),p=Object(n["resolveComponent"])("el-card"),b=Object(n["resolveComponent"])("el-main"),j=Object(n["resolveComponent"])("el-container");return Object(n["openBlock"])(),Object(n["createBlock"])(j,null,{default:Object(n["withCtx"])((function(){return[Object(n["createVNode"])(b,null,{default:Object(n["withCtx"])((function(){return[Object(n["createVNode"])(p,null,{default:Object(n["withCtx"])((function(){return[Object(n["createVNode"])(f,{model:a.form,"label-position":"top",rules:a.formRule,ref:"formRef",style:{"max-width":"900px"}},{default:Object(n["withCtx"])((function(){return[Object(n["createVNode"])(i,{label:"邮箱账号",prop:"username"},{default:Object(n["withCtx"])((function(){return[Object(n["createVNode"])(s,{modelValue:a.form.username,"onUpdate:modelValue":t[0]||(t[0]=function(e){return a.form.username=e})},null,8,["modelValue"])]})),_:1}),Object(n["createVNode"])(i,{label:"邮箱密码",prop:"password"},{default:Object(n["withCtx"])((function(){return[Object(n["createVNode"])(s,{modelValue:a.form.password,"onUpdate:modelValue":t[1]||(t[1]=function(e){return a.form.password=e}),type:"password",placeholder:"请输入密码","show-password":""},null,8,["modelValue"])]})),_:1}),Object(n["createVNode"])(i,{label:"SMTP",prop:"smtpHost"},{default:Object(n["withCtx"])((function(){return[Object(n["createVNode"])(d,{span:12},{default:Object(n["withCtx"])((function(){return[Object(n["createVNode"])(s,{modelValue:a.form.smtpHost,"onUpdate:modelValue":t[2]||(t[2]=function(e){return a.form.smtpHost=e}),placeholder:"SMTP Host"},null,8,["modelValue"])]})),_:1}),Object(n["createVNode"])(d,{span:1,style:{"text-align":"center"}},{default:Object(n["withCtx"])((function(){return[o]})),_:1}),Object(n["createVNode"])(d,{span:6},{default:Object(n["withCtx"])((function(){return[Object(n["createVNode"])(s,{modelValue:a.form.smtpPort,"onUpdate:modelValue":t[3]||(t[3]=function(e){return a.form.smtpPort=e}),placeholder:"SMTP Port"},null,8,["modelValue"])]})),_:1})]})),_:1}),Object(n["createVNode"])(i,{style:{"margin-top":"38px"}},{default:Object(n["withCtx"])((function(){return[Object(n["createVNode"])(m,{type:"primary",onClick:t[4]||(t[4]=function(e){return c.onSubmit("formRef")})},{default:Object(n["withCtx"])((function(){return[u]})),_:1})]})),_:1})]})),_:1},8,["model","rules"])]})),_:1})]})),_:1})]})),_:1})}var a=r("1da1"),c=(r("96cf"),r("1c1e")),s="/api/v1.0/settings",i=function(){return c["a"].get(s+"/sys_email")},d=function(e){return c["a"].post(s+"/sys_email",e)},m={data:function(){return{form:{smtpHost:null,smtpPort:null,username:null,password:null},formRule:{username:[this.requiredInputValidRule("请输入邮箱账号"),{type:"email",message:"邮箱格式不正确",trigger:"blur"}],password:[this.requiredInputValidRule("请输入邮箱密码")],smtpHost:[this.requiredInputValidRule("请输入 SMTP 地址")],smtpPort:[this.requiredInputValidRule("请输入 SMTP 端口"),{min:1,max:65535,message:"端口有效值为 1~65535",trigger:"blur"}]}}},mounted:function(){this.fetchSysMail()},methods:{requiredInputValidRule:function(e){return{required:!0,message:e,trigger:"blur"}},fetchSysMail:function(){var e=this;return Object(a["a"])(regeneratorRuntime.mark((function t(){var r;return regeneratorRuntime.wrap((function(t){while(1)switch(t.prev=t.next){case 0:return t.next=2,i().then((function(e){return e.data}));case 2:r=t.sent,r&&(e.form=r);case 4:case"end":return t.stop()}}),t)})))()},onSubmit:function(){var e=this;this.$refs.formRef.validate((function(t){return t?(d(e.form).then((function(t){t.errCode||e.$message.success("更新成功")})),!0):(e.$message.error("请完善表单相关信息!"),!1)}))}}},f=r("6b0d"),p=r.n(f);const b=p()(m,[["render",l]]);t["default"]=b}}]);
|
||||
//# sourceMappingURL=chunk-2d0cc811.feb081c8.js.map
|
||||
//# sourceMappingURL=chunk-2d0cc811.c5d1ef9e.js.map
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +1,2 @@
|
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-7e394785"],{a55b:function(e,t,n){"use strict";n.r(t);var o=n("7a23"),r={class:"login-card"},c=Object(o["createElementVNode"])("h1",null,"Databasir",-1),a=Object(o["createTextVNode"])(" 登录 "),u=Object(o["createTextVNode"])(" 忘记密码? ");function l(e,t,n,l,i,d){var s=Object(o["resolveComponent"])("el-header"),b=Object(o["resolveComponent"])("el-link"),f=Object(o["resolveComponent"])("el-divider"),m=Object(o["resolveComponent"])("el-form-item"),j=Object(o["resolveComponent"])("el-button"),p=Object(o["resolveComponent"])("el-tooltip"),O=Object(o["resolveComponent"])("el-space"),h=Object(o["resolveComponent"])("el-form"),w=Object(o["resolveComponent"])("el-main"),C=Object(o["resolveComponent"])("el-footer"),v=Object(o["resolveComponent"])("el-container");return Object(o["openBlock"])(),Object(o["createBlock"])(v,null,{default:Object(o["withCtx"])((function(){return[Object(o["createVNode"])(s),Object(o["createVNode"])(w,{class:"login-main"},{default:Object(o["withCtx"])((function(){return[Object(o["createElementVNode"])("div",r,[Object(o["createVNode"])(h,{ref:"formRef",rules:i.formRule,model:i.form,style:{border:"none"}},{default:Object(o["withCtx"])((function(){return[Object(o["createVNode"])(m,null,{default:Object(o["withCtx"])((function(){return[Object(o["createVNode"])(f,{"content-position":"left"},{default:Object(o["withCtx"])((function(){return[Object(o["createVNode"])(b,{href:"https://github.com/vran-dev/databasir",target:"_blank",underline:!1,type:"info"},{default:Object(o["withCtx"])((function(){return[c]})),_:1})]})),_:1})]})),_:1}),Object(o["createVNode"])(m,{prop:"username"},{default:Object(o["withCtx"])((function(){return[Object(o["withDirectives"])(Object(o["createElementVNode"])("input",{type:"text",class:"login-input",placeholder:"用户名或邮箱","onUpdate:modelValue":t[0]||(t[0]=function(e){return i.form.username=e})},null,512),[[o["vModelText"],i.form.username]])]})),_:1}),Object(o["createVNode"])(m,{prop:"password"},{default:Object(o["withCtx"])((function(){return[Object(o["withDirectives"])(Object(o["createElementVNode"])("input",{type:"password",class:"login-input",placeholder:"密码","onUpdate:modelValue":t[1]||(t[1]=function(e){return i.form.password=e})},null,512),[[o["vModelText"],i.form.password]])]})),_:1}),Object(o["createVNode"])(m,null,{default:Object(o["withCtx"])((function(){return[Object(o["createVNode"])(O,{size:32},{default:Object(o["withCtx"])((function(){return[Object(o["createVNode"])(j,{style:{width:"120px","margin-top":"10px"},color:"#000",onClick:t[2]||(t[2]=function(e){return d.onLogin("formRef")}),plain:"",round:""},{default:Object(o["withCtx"])((function(){return[a]})),_:1}),Object(o["createVNode"])(p,{content:"请联系管理员为您重置密码"},{default:Object(o["withCtx"])((function(){return[Object(o["createVNode"])(b,{target:"_blank",underline:!1,type:"info"},{default:Object(o["withCtx"])((function(){return[u]})),_:1})]})),_:1})]})),_:1})]})),_:1})]})),_:1},8,["rules","model"])])]})),_:1}),Object(o["createVNode"])(C,null,{default:Object(o["withCtx"])((function(){return[Object(o["createVNode"])(O)]})),_:1})]})),_:1})}var i=n("b0af"),d=n("5f87"),s={data:function(){return{form:{username:null,password:null},formRule:{username:[{required:!0,message:"请输入用户名或邮箱",trigger:"blur"}],password:[{required:!0,message:"请输入密码",trigger:"blur"}]}}},methods:{toIndexPage:function(){this.$router.push({path:"/groups"})},onLogin:function(){var e=this;this.$refs.formRef.validate((function(t){t&&Object(i["a"])(e.form).then((function(t){t.errCode||(d["b"].saveUserLoginData(t.data),e.$store.commit("userUpdate",{nickname:t.data.nickname,username:t.data.username,email:t.data.email}),e.toIndexPage())}))}))}}},b=(n("d30d"),n("6b0d")),f=n.n(b);const m=f()(s,[["render",l]]);t["default"]=m},d30d:function(e,t,n){"use strict";n("edba")},edba:function(e,t,n){}}]);
|
||||
//# sourceMappingURL=chunk-7e394785.b93f6d8c.js.map
|
||||
//# sourceMappingURL=chunk-7e394785.e090ef46.js.map
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user