-
Notifications
You must be signed in to change notification settings - Fork 4
Feature/user created at #498
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -3,6 +3,7 @@ package upbrella.be.user.entity | |||||
| import upbrella.be.user.dto.request.JoinRequest | ||||||
| import upbrella.be.user.dto.response.KakaoLoginResponse | ||||||
| import upbrella.be.util.AesEncryptor | ||||||
| import upbrella.be.util.BaseTimeEntity | ||||||
| import javax.persistence.Entity | ||||||
| import javax.persistence.GeneratedValue | ||||||
| import javax.persistence.GenerationType | ||||||
|
|
@@ -20,7 +21,7 @@ class User( | |||||
| @Id | ||||||
| @GeneratedValue(strategy = GenerationType.IDENTITY) | ||||||
| val id: Long? = null, | ||||||
| ) { | ||||||
| ) : BaseTimeEntity() { | ||||||
|
|
||||||
| companion object { | ||||||
| fun createNewUser( | ||||||
|
|
@@ -64,17 +65,9 @@ class User( | |||||
| this.accountNumber = null | ||||||
| } | ||||||
|
|
||||||
| fun decryptData(aesEncryptor: AesEncryptor): User { | ||||||
| return User( | ||||||
| socialId = socialId, | ||||||
| name = name, | ||||||
| phoneNumber = phoneNumber, | ||||||
| email = email, | ||||||
| adminStatus = adminStatus, | ||||||
| bank = aesEncryptor.decrypt(bank), | ||||||
| accountNumber = aesEncryptor.decrypt(accountNumber), | ||||||
| id = id | ||||||
| ) | ||||||
| fun decryptData(aesEncryptor: AesEncryptor) { | ||||||
|
||||||
| fun decryptData(aesEncryptor: AesEncryptor) { | |
| fun decryptDataInPlace(aesEncryptor: AesEncryptor) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Breaking change: decryptData method now mutates instance in-place.
The decryptData method has been changed from returning a new User instance to mutating the current instance in-place. This is a breaking change that affects the method's API contract.
Verify that all usages of decryptData in the codebase have been updated to handle the new in-place mutation behavior:
🏁 Script executed:
#!/bin/bash
# Description: Find all usages of decryptData to ensure they handle in-place mutation
# Search for all calls to decryptData method
rg -A 5 -B 2 'decryptData'
# Look for any assignments that might expect a return value
rg -A 3 -B 1 '\.decryptData\s*\('Length of output: 8585
Ensure tests accommodate decryptData’s in-place mutation
The decryptData method now returns Unit and mutates the User instance directly. Existing tests still treat it as a factory (expecting a returned User), causing compile/runtime errors. Update the following:
-
src/test/kotlin/upbrella/be/user/service/UserServiceTest.kt
Replace.map { user -> user.decryptData(aesEncryptor) } .map { decrypted -> SingleUserInfoResponse.fromUser(decrypted) }With either:
// Option A: apply mutation, then map .onEach { it.decryptData(aesEncryptor) } .map { SingleUserInfoResponse.fromUser(it) }
Or:
.map { user -> user.apply { decryptData(aesEncryptor) } } .map { SingleUserInfoResponse.fromUser(it) } -
src/test/kotlin/upbrella/be/user/controller/UserControllerTest.kt
Update its.map { user -> user.decryptData(aesEncryptor) }in the same way as above so that you’re mappingUserobjects, notUnit. -
src/test/kotlin/upbrella/be/user/entity/UserTest.kt
Changeval decryptedUser = user.decryptData(aesEncryptor)
To:
user.decryptData(aesEncryptor) val decryptedUser = user
After these adjustments, tests will correctly reflect the new in-place behavior of decryptData.
🤖 Prompt for AI Agents
In src/main/kotlin/upbrella/be/user/entity/User.kt around lines 68 to 71, the
decryptData method was changed to mutate the User instance in-place and return
Unit instead of a new User. To fix related issues, update all usages of
decryptData to no longer expect a returned User. In test files like
UserServiceTest.kt and UserControllerTest.kt, replace map calls that invoke
decryptData with onEach or map using apply to perform mutation and then map the
User objects. In UserTest.kt, call decryptData on the user instance without
assignment, then use the original user variable as the decrypted user. This
ensures all code and tests handle the new in-place mutation correctly.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,7 +31,7 @@ class UserService( | |
| ) { | ||
|
|
||
| fun login(socialId: Long): SessionUser { | ||
| val foundUser = userReader.findBySocialId(socialId) | ||
| val foundUser = userReader.findBySocialId(socialId.hashCode().toLong()) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainVerify consistent hashing implementation across the codebase. The socialId is being hashed before querying. Ensure this hashing approach is consistent with how socialId is stored and used throughout the application, particularly in the join method and other query operations. 🏁 Script executed: #!/bin/bash
# Description: Verify consistent usage of socialId hashing across the codebase
# Expected: All socialId operations should use consistent hashing
# Search for socialId usage patterns
rg -A 3 -B 3 "socialId.*hashCode|findBySocialId|existsBySocialId" --type kotlinLength of output: 12146 Align socialId hashing consistently across the codebase The • In src/main/kotlin/upbrella/be/user/service/UserService.kt (line 34), change: val foundUser = userReader.findBySocialId(socialId.hashCode().toLong())to: val foundUser = userReader.findBySocialId(socialId)• In your tests (src/test/kotlin/upbrella/be/user/service/UserServiceTest.kt), make sure you’re stubbing and verifying • Confirm that FixtureBuilderFactory (src/main/kotlin/upbrella/be/config/FixtureBuilderFactory.kt) generates This will ensure all 🤖 Prompt for AI Agents |
||
|
|
||
| return SessionUser.fromUser(foundUser) | ||
| } | ||
|
|
@@ -56,7 +56,7 @@ class UserService( | |
|
|
||
| fun findUsers(): AllUsersInfoResponse { | ||
| val users = userReader.findAll() | ||
| .map { it.decryptData(aesEncryptor) } | ||
| users.forEach { it.decryptData(aesEncryptor) } | ||
|
|
||
| return AllUsersInfoResponse.fromUsers(users) | ||
| } | ||
|
|
@@ -100,16 +100,20 @@ class UserService( | |
| fun findDecryptedUserById(sessionUser: SessionUser): User { | ||
| val id = sessionUser.id | ||
|
|
||
| return userRepository.findById(id) | ||
| val user = userRepository.findById(id) | ||
| .orElseThrow { NonExistingMemberException("[ERROR] 존재하지 않는 회원입니다.") } | ||
| .decryptData(aesEncryptor) | ||
|
|
||
| user.decryptData(aesEncryptor) | ||
|
|
||
| return user | ||
| } | ||
|
|
||
| @Transactional | ||
| fun deleteUserBankAccount(id: Long) { | ||
| val foundUser = userReader.findUserById(id) | ||
| foundUser.deleteBankAccount() | ||
| } | ||
|
|
||
| @Transactional | ||
| fun updateAdminStatus(id: Long) { | ||
| val foundUser = userReader.findUserById(id) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| package upbrella.be.util | ||
|
|
||
| import org.springframework.data.annotation.CreatedDate | ||
| import org.springframework.data.annotation.LastModifiedDate | ||
| import org.springframework.data.jpa.domain.support.AuditingEntityListener | ||
| import java.time.LocalDateTime | ||
| import javax.persistence.Column | ||
| import javax.persistence.EntityListeners | ||
| import javax.persistence.MappedSuperclass | ||
|
|
||
| @MappedSuperclass | ||
| @EntityListeners(AuditingEntityListener::class) | ||
| abstract class BaseTimeEntity { | ||
| @CreatedDate | ||
| @Column(updatable = false) | ||
| var createdAt: LocalDateTime? = null | ||
|
|
||
| @LastModifiedDate | ||
| var updatedAt: LocalDateTime? = null | ||
|
|
||
| var deletedAt: LocalDateTime? = null | ||
|
|
||
| fun softDelete() { | ||
| deletedAt = LocalDateTime.now() | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| ALTER TABLE user | ||
| ADD COLUMN created_at DATETIME NOT NULL DEFAULT NOW() COMMENT '생성일', | ||
| ADD COLUMN updated_at DATETIME NOT NULL DEFAULT NOW() ON UPDATE NOW() COMMENT '수정일', | ||
| ADD COLUMN deleted_at DATETIME NULL COMMENT '삭제일'; |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -78,10 +78,10 @@ class UserControllerTest ( | |||||||||||||
| val user = FixtureBuilderFactory.builderUser(aesEncryptor).sample() | ||||||||||||||
|
|
||||||||||||||
| session.setAttribute("user", sessionUser) | ||||||||||||||
| val decryptedUser = user.decryptData(aesEncryptor) | ||||||||||||||
| user.decryptData(aesEncryptor) | ||||||||||||||
|
|
||||||||||||||
| given(userService.findDecryptedUserById(sessionUser)) | ||||||||||||||
| .willReturn(decryptedUser) | ||||||||||||||
| .willReturn(user) | ||||||||||||||
|
|
||||||||||||||
| // when & then | ||||||||||||||
| mockMvc.perform( | ||||||||||||||
|
|
@@ -461,9 +461,12 @@ class UserControllerTest ( | |||||||||||||
| users.add(FixtureBuilderFactory.builderUser(aesEncryptor).sample()) | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| users.forEach { user -> user.createdAt = LocalDateTime.now()} | ||||||||||||||
| users.forEach { user -> user.decryptData(aesEncryptor) | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| val allUsersInfoResponse = AllUsersInfoResponse( | ||||||||||||||
| users = users.stream() | ||||||||||||||
| .map { user -> user.decryptData(aesEncryptor) } | ||||||||||||||
| .map { SingleUserInfoResponse.fromUser(it) } | ||||||||||||||
| .toList() | ||||||||||||||
| ) | ||||||||||||||
|
|
@@ -499,7 +502,10 @@ class UserControllerTest ( | |||||||||||||
| .optional() | ||||||||||||||
| .description("사용자 계좌 번호"), | ||||||||||||||
| fieldWithPath("users[].adminStatus").type(JsonFieldType.BOOLEAN) | ||||||||||||||
| .description("관리자 여부") | ||||||||||||||
| .description("관리자 여부"), | ||||||||||||||
| fieldWithPath("users[].createdAt").type(JsonFieldType.ARRAY) | ||||||||||||||
| .description("사용자 생성일") | ||||||||||||||
|
Comment on lines
+505
to
+507
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainVerify the field type in API documentation. The 🏁 Script executed: #!/bin/bash
# Description: Check how createdAt is defined in the User entity and DTOs to verify correct field type
# Expected: createdAt should be a timestamp/datetime field, not an array
# Check User entity definition
echo "=== User entity definition ==="
rg -A 5 -B 5 "createdAt" --type kotlin
# Check DTO definitions
echo "=== DTO definitions ==="
ast-grep --pattern 'class $_ {
$$$
createdAt: $TYPE
$$$
}'
# Check if there are any LocalDateTime imports or usages
echo "=== LocalDateTime usage ==="
rg "LocalDateTime" --type kotlin -A 2 -B 2Length of output: 70329 Change The • File: src/test/kotlin/upbrella/be/user/controller/UserControllerTest.kt - fieldWithPath("users[].createdAt").type(JsonFieldType.ARRAY)
+ fieldWithPath("users[].createdAt").type(JsonFieldType.STRING)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
|
|
||||||||||||||
| ) | ||||||||||||||
| ) | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify BaseTimeEntity implementation and ensure auditing fields are properly configured.
The inheritance from
BaseTimeEntityis a good approach for adding auditing capabilities. However, I need to verify the implementation details.Also applies to: 24-24
🏁 Script executed:
Length of output: 819
Audit fields verified – BaseTimeEntity is properly implemented
The
BaseTimeEntitysuperclass is correctly defined with@MappedSuperclass,@EntityListeners(AuditingEntityListener::class), and JPA auditing annotations (@CreatedDate,@LastModifiedDate). No further changes needed for auditing.Breaking change:
decryptDatanow mutates the instanceThe switch from returning a new
Userto in-place mutation is a breaking API change. Please:decryptDatato ensure callers expect the method to modify the current instance.decryptDatareturns a freshUserrather than mutating it.🤖 Prompt for AI Agents