diff --git a/build.gradle.kts b/build.gradle.kts index 1d5b58c..06730cd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,6 +5,7 @@ plugins { `java-library` `maven-publish` + kotlin("jvm") } repositories { @@ -12,6 +13,7 @@ repositories { maven { url = uri("https://repo.maven.apache.org/maven2/") } + mavenCentral() } dependencies { @@ -31,11 +33,11 @@ dependencies { annotationProcessor("org.projectlombok:lombok:1.18.38") testCompileOnly("org.projectlombok:lombok:1.18.38") testAnnotationProcessor("org.projectlombok:lombok:1.18.38") + implementation(kotlin("stdlib-jdk8")) } group = "kr.re.etri" version = "0.0.1-SNAPSHOT" description = "spring-security-refresh-token" -java.sourceCompatibility = JavaVersion.VERSION_21 publishing { publications.create("maven") { @@ -45,8 +47,12 @@ publishing { tasks.withType() { options.encoding = "UTF-8" + options.compilerArgs.add("-parameters") } tasks.withType() { options.encoding = "UTF-8" +} +kotlin { + jvmToolchain(21) } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index d2cb500..294daa0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,3 +1,11 @@ +pluginManagement { + plugins { + kotlin("jvm") version "2.2.0" + } +} +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" +} /* * This file was generated by the Gradle 'init' task. */ diff --git a/src/main/java/kr/re/etri/autoflow/controllers/ProjectController.java b/src/main/java/kr/re/etri/autoflow/controllers/ProjectController.java index 3017322..6bc5295 100644 --- a/src/main/java/kr/re/etri/autoflow/controllers/ProjectController.java +++ b/src/main/java/kr/re/etri/autoflow/controllers/ProjectController.java @@ -83,17 +83,4 @@ public class ProjectController { } return ResponseEntity.notFound().build(); } - - @Operation(summary = "프로젝트에 사용자 권한 추가") - @PostMapping("/{projectId}/users") - public ResponseEntity addUserPermission( - @Parameter(description = "프로젝트 ID", required = true, in = ParameterIn.PATH) - @PathVariable("projectId") Long projectId, - - @Parameter(description = "사용자 권한 요청 정보", required = true) - @RequestBody UserPermissionRequest request) { - - projectService.addUserPermission(projectId, request.getUserId(), request.getPermissions()); - return ResponseEntity.ok().build(); - } } diff --git a/src/main/java/kr/re/etri/autoflow/controllers/ProjectPermissionController.java b/src/main/java/kr/re/etri/autoflow/controllers/ProjectPermissionController.java new file mode 100644 index 0000000..f77b93e --- /dev/null +++ b/src/main/java/kr/re/etri/autoflow/controllers/ProjectPermissionController.java @@ -0,0 +1,69 @@ +package kr.re.etri.autoflow.controllers; + +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 kr.re.etri.autoflow.entity.ProjectPermission; +import kr.re.etri.autoflow.payload.request.UserPermissionRequest; +import kr.re.etri.autoflow.service.ProjectPermissionService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.Set; + +@RestController +@RequestMapping("/api/projects") +@Tag(name = "Project Permissions", description = "프로젝트 사용자 권한 관리 API") +@RequiredArgsConstructor +public class ProjectPermissionController { + + private final ProjectPermissionService projectPermissionService; + //private final AuthService authService; + + @Operation(summary = "프로젝트에 사용자 권한 추가") + @PostMapping("/{projectId}/users") + public ResponseEntity addUserPermission( + @Parameter(description = "프로젝트 ID", required = true, in = ParameterIn.PATH) + @PathVariable Long projectId, + @RequestBody UserPermissionRequest request) { + + projectPermissionService.addUserPermission(projectId, request.getUserId(), request.getPermissions()); + return ResponseEntity.ok().build(); + } + + @Operation(summary = "사용자 권한 조회") + @GetMapping("/{projectId}/users/{userId}/permissions") + public ResponseEntity> getUserPermissions( + @Parameter(name = "projectId", description = "프로젝트 ID", example = "1", required = true) + @PathVariable("projectId") Long projectId, + + @Parameter(name = "userId", description = "사용자 ID", example = "100", required = true) + @PathVariable("userId") Long userId) { + + Set permissions = projectPermissionService.getUserPermissions(projectId, userId); + return ResponseEntity.ok(permissions); + } + + @Operation(summary = "사용자 권한 수정") + @PutMapping("/{projectId}/users/{userId}/permissions") + public ResponseEntity updateUserPermissions( + @PathVariable Long projectId, + @PathVariable Long userId, + @RequestBody Set newPermissions) { + + projectPermissionService.updateUserPermissions(projectId, userId, newPermissions); + return ResponseEntity.ok().build(); + } + + @Operation(summary = "사용자 권한 삭제") + @DeleteMapping("/{projectId}/users/{userId}/permissions") + public ResponseEntity deleteUserPermissions( + @PathVariable Long projectId, + @PathVariable Long userId) { + + projectPermissionService.deleteUserPermissions(projectId, userId); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/kr/re/etri/autoflow/payload/request/SignupRequest.java b/src/main/java/kr/re/etri/autoflow/payload/request/SignupRequest.java index e1f1a2f..c158668 100644 --- a/src/main/java/kr/re/etri/autoflow/payload/request/SignupRequest.java +++ b/src/main/java/kr/re/etri/autoflow/payload/request/SignupRequest.java @@ -6,6 +6,8 @@ import lombok.Setter; import lombok.NoArgsConstructor; import lombok.AllArgsConstructor; +import io.swagger.v3.oas.annotations.media.Schema; + import java.util.Set; @Getter @@ -16,16 +18,20 @@ public class SignupRequest { @NotBlank @Size(min = 3, max = 20) + @Schema(description = "사용자 이름", example = "testuser", defaultValue = "testuser") private String username; @NotBlank @Size(max = 50) @Email + @Schema(description = "이메일 주소", example = "test@example.com", defaultValue = "test@example.com") private String email; + @Schema(description = "요청된 역할 목록 (예: ROLE_USER, ROLE_ADMIN)", example = "[\"ROLE_USER\"]", defaultValue = "[\"ROLE_USER\"]") private Set role; @NotBlank @Size(min = 6, max = 40) + @Schema(description = "비밀번호", example = "password123", defaultValue = "password123") private String password; } diff --git a/src/main/java/kr/re/etri/autoflow/security/services/UserDetailsImpl.java b/src/main/java/kr/re/etri/autoflow/security/services/UserDetailsImpl.java index b0a036d..953ebb4 100644 --- a/src/main/java/kr/re/etri/autoflow/security/services/UserDetailsImpl.java +++ b/src/main/java/kr/re/etri/autoflow/security/services/UserDetailsImpl.java @@ -10,6 +10,7 @@ import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; +import java.io.Serial; import java.util.Collection; import java.util.List; import java.util.Objects; @@ -18,6 +19,7 @@ import java.util.stream.Collectors; @Getter @Builder public class UserDetailsImpl implements UserDetails { + @Serial private static final long serialVersionUID = 1L; private final Long id; diff --git a/src/main/java/kr/re/etri/autoflow/service/ProjectPermissionService.java b/src/main/java/kr/re/etri/autoflow/service/ProjectPermissionService.java new file mode 100644 index 0000000..e875762 --- /dev/null +++ b/src/main/java/kr/re/etri/autoflow/service/ProjectPermissionService.java @@ -0,0 +1,80 @@ +package kr.re.etri.autoflow.service; + +import kr.re.etri.autoflow.entity.ProjectEntity; +import kr.re.etri.autoflow.entity.ProjectPermission; +import kr.re.etri.autoflow.entity.UserProjectMapEntity; +import kr.re.etri.autoflow.models.User; +import kr.re.etri.autoflow.repository.ProjectRepository; +import kr.re.etri.autoflow.repository.UserProjectMapRepository; +import kr.re.etri.autoflow.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collections; +import java.util.Set; + +@Service +@RequiredArgsConstructor +@Transactional +public class ProjectPermissionService { + + private final ProjectRepository projectRepository; + private final UserRepository userRepository; + private final UserProjectMapRepository userProjectMapRepository; + + public void addUserPermission(Long projectId, Long userId, Set permissions) { + ProjectEntity project = getProject(projectId); + User user = getUser(userId); + + UserProjectMapEntity mapping = userProjectMapRepository.findByProjectAndUser(project, user) + .orElseGet(() -> { + UserProjectMapEntity newMap = new UserProjectMapEntity(); + newMap.setProject(project); + newMap.setUser(user); + return newMap; + }); + + mapping.setPermissions(permissions); + userProjectMapRepository.save(mapping); + } + + @Transactional(readOnly = true) + public Set getUserPermissions(Long projectId, Long userId) { + ProjectEntity project = getProject(projectId); + User user = getUser(userId); + + return userProjectMapRepository.findByProjectAndUser(project, user) + .map(UserProjectMapEntity::getPermissions) + .orElse(Collections.emptySet()); + } + + public void updateUserPermissions(Long projectId, Long userId, Set newPermissions) { + ProjectEntity project = getProject(projectId); + User user = getUser(userId); + + UserProjectMapEntity mapping = userProjectMapRepository.findByProjectAndUser(project, user) + .orElseThrow(() -> new IllegalArgumentException("권한 정보가 존재하지 않습니다.")); + + mapping.setPermissions(newPermissions); + userProjectMapRepository.save(mapping); + } + + public void deleteUserPermissions(Long projectId, Long userId) { + ProjectEntity project = getProject(projectId); + User user = getUser(userId); + + userProjectMapRepository.findByProjectAndUser(project, user) + .ifPresent(userProjectMapRepository::delete); + } + + private ProjectEntity getProject(Long projectId) { + return projectRepository.findById(projectId) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 프로젝트입니다.")); + } + + private User getUser(Long userId) { + return userRepository.findById(userId) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 사용자입니다.")); + } +} diff --git a/src/main/java/kr/re/etri/autoflow/service/ProjectService.java b/src/main/java/kr/re/etri/autoflow/service/ProjectService.java index 0d44804..c4c0d13 100644 --- a/src/main/java/kr/re/etri/autoflow/service/ProjectService.java +++ b/src/main/java/kr/re/etri/autoflow/service/ProjectService.java @@ -102,24 +102,4 @@ public class ProjectService { projectRepository.deleteById(id); return true; } - - @Transactional - public void addUserPermission(Long projectId, Long userId, Set permissions) { - ProjectEntity project = projectRepository.findById(projectId) - .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 프로젝트입니다.")); - - User user = userRepository.findById(userId) - .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 사용자입니다.")); - - UserProjectMapEntity mapping = userProjectMapRepository.findByProjectAndUser(project, user) - .orElseGet(() -> { - UserProjectMapEntity newMap = new UserProjectMapEntity(); - newMap.setProject(project); - newMap.setUser(user); - return newMap; - }); - - mapping.setPermissions(permissions); - userProjectMapRepository.save(mapping); - } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 32b492c..b50b2fb 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -3,7 +3,7 @@ spring.datasource.username=cuuva spring.datasource.password=cuuva spring.jpa.database-platform=org.hibernate.dialect.MariaDBDialect -spring.jpa.hibernate.ddl-auto=create-drop +spring.jpa.hibernate.ddl-auto=create-only spring.sql.init.mode=always @@ -33,3 +33,8 @@ logging.level.org.hibernate.type.descriptor.sql=TRACE logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE + +spring.datasource.hikari.connection-timeout=3000 +spring.datasource.hikari.idle-timeout=0 +spring.datasource.hikari.max-lifetime=170000 + diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 895cc04..e62aefd 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -1,6 +1,6 @@ -- src/main/resources/data.sql - -INSERT INTO tb_role (id, name) VALUES (1, 'ROLE_USER'); -INSERT INTO tb_role (id, name) VALUES (2, 'ROLE_MODERATOR'); -INSERT INTO tb_role (id, name) VALUES (3, 'ROLE_ADMIN'); - +# +# INSERT INTO tb_role (id, name) VALUES (1, 'ROLE_USER'); +# INSERT INTO tb_role (id, name) VALUES (2, 'ROLE_MODERATOR'); +# INSERT INTO tb_role (id, name) VALUES (3, 'ROLE_ADMIN'); +#