Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions techeerzip/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ repositories {
}

dependencies {
// test H2
testImplementation 'com.h2database:h2:2.2.224'

implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
Expand Down Expand Up @@ -70,13 +67,19 @@ dependencies {
implementation 'net.logstash.logback:logstash-logback-encoder:7.4'
implementation 'org.projectlombok:lombok:1.18.30'

testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'

compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.postgresql:postgresql'
annotationProcessor 'org.projectlombok:lombok'

// test
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
testImplementation 'com.h2database:h2:2.2.224'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'org.springframework.boot:spring-boot-testcontainers' // Spring Boot 3.1+ 부터 제공하는 편리한 기능
testImplementation 'org.testcontainers:junit-jupiter'
testImplementation 'org.testcontainers:postgresql'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

// SpringDoc OpenAPI (테스트 용도)
Expand All @@ -102,10 +105,10 @@ dependencies {

// Pyroscope
implementation 'io.pyroscope:agent:2.1.2'

// GraphQL 클라이언트 (WebFlux)
implementation 'org.springframework.boot:spring-boot-starter-webflux'

// macOS DNS resolver for Netty
runtimeOnly 'io.netty:netty-resolver-dns-native-macos:4.1.114.Final:osx-aarch_64'
}
Expand Down Expand Up @@ -226,4 +229,4 @@ spotlessJava.dependsOn compileJava
tasks.test {
useJUnitPlatform()
finalizedBy tasks.jacocoTestReport
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,22 @@ public ResponseEntity<FeedbackCursorResponse> getReceivedFeedbackRequests(
if (status != null && !status.trim().isEmpty()) {
feedbacks =
feedbackService.getReceivedFeedbacksByStatus(
currentUser.getUserId(), status, startDateTime, endDateTime, cursor, limit, currentUser);
currentUser.getUserId(),
status,
startDateTime,
endDateTime,
cursor,
limit,
currentUser);
} else {
feedbacks =
feedbackService.getAllReceivedFeedbacks(
currentUser.getUserId(), startDateTime, endDateTime, cursor, limit, currentUser);
currentUser.getUserId(),
startDateTime,
endDateTime,
cursor,
limit,
currentUser);
}

FeedbackCursorResponse response = FeedbackCursorResponse.from(feedbacks, limit);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ Optional<Feedback> findByRequesterIdAndRecipientIdAndIsDeletedFalse(
Optional<Feedback> findByIdWithUsers(Long feedbackId);

List<Feedback> findReceivedFeedbacks(
Long recipientId, String status, LocalDateTime startDateTime, LocalDateTime endDateTime, Long cursor, int limit);
Long recipientId,
String status,
LocalDateTime startDateTime,
LocalDateTime endDateTime,
Long cursor,
int limit);

List<Feedback> findReceivedFeedbacksByStatus(
Long recipientId, String status, Long cursor, int limit);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,12 @@ public Optional<Feedback> findByIdWithUsers(Long feedbackId) {

@Override
public List<Feedback> findReceivedFeedbacks(
Long recipientId, String status, LocalDateTime startDateTime, LocalDateTime endDateTime, Long cursor, int limit) {
Long recipientId,
String status,
LocalDateTime startDateTime,
LocalDateTime endDateTime,
Long cursor,
int limit) {
var query =
queryFactory
.selectFrom(feedback)
Expand All @@ -179,7 +184,9 @@ public List<Feedback> findReceivedFeedbacks(
.leftJoin(feedback.recipient)
.fetchJoin()
.where(
feedback.recipient.id.eq(recipientId)
feedback.recipient
.id
.eq(recipientId)
.and(feedback.isDeleted.eq(false)));

if (status != null) {
Expand All @@ -200,4 +207,4 @@ public List<Feedback> findReceivedFeedbacks(

return query.orderBy(feedback.createdAt.desc()).limit(limit + 1).fetch();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,13 @@ public List<Feedback> getReceivedFeedbackRequests(Long userId) {

@Transactional(readOnly = true)
public List<Feedback> getReceivedFeedbacksByStatus(
Long mentorId, String status, LocalDateTime startDateTime, LocalDateTime endDateTime, Long cursor, int limit, CustomUserPrincipal currentUser) {
Long mentorId,
String status,
LocalDateTime startDateTime,
LocalDateTime endDateTime,
Long cursor,
int limit,
CustomUserPrincipal currentUser) {
logger.debug(
"멘토 상태별 피드백 조회 시작 - mentorId: {}, status: {}, startDateTime: {}, endDateTime: {} | context: {}",
mentorId,
Expand All @@ -171,10 +177,18 @@ public List<Feedback> getReceivedFeedbacksByStatus(
throw new FeedbackForbiddenException();
}

LocalDateTime effectiveStartDateTime = startDateTime != null ? startDateTime : LocalDateTime.now().minusMonths(1);
LocalDateTime effectiveStartDateTime =
startDateTime != null ? startDateTime : LocalDateTime.now().minusMonths(1);
LocalDateTime effectiveEndDateTime = endDateTime;

List<Feedback> feedbacks = feedbackRepository.findReceivedFeedbacks(mentorId, status, effectiveStartDateTime, effectiveEndDateTime, cursor, limit);
List<Feedback> feedbacks =
feedbackRepository.findReceivedFeedbacks(
mentorId,
status,
effectiveStartDateTime,
effectiveEndDateTime,
cursor,
limit);

logger.debug(
"멘토 상태별 피드백 조회 완료 - mentorId: {}, status: {}, count: {} | context: {}",
Expand All @@ -188,18 +202,36 @@ public List<Feedback> getReceivedFeedbacksByStatus(

@Transactional(readOnly = true)
public List<Feedback> getAllReceivedFeedbacks(
Long mentorId, LocalDateTime startDateTime, LocalDateTime endDateTime, Long cursor, int limit, CustomUserPrincipal currentUser) {
logger.debug("멘토 전체 피드백 조회 시작 - mentorId: {}, startDateTime: {}, endDateTime: {} | context: {}", mentorId, startDateTime, endDateTime, CONTEXT);
Long mentorId,
LocalDateTime startDateTime,
LocalDateTime endDateTime,
Long cursor,
int limit,
CustomUserPrincipal currentUser) {
logger.debug(
"멘토 전체 피드백 조회 시작 - mentorId: {}, startDateTime: {}, endDateTime: {} | context: {}",
mentorId,
startDateTime,
endDateTime,
CONTEXT);

validateMentorRole(currentUser);
if (!currentUser.getUserId().equals(mentorId) && !currentUser.isAdmin()) {
throw new FeedbackForbiddenException();
}

LocalDateTime effectiveStartDateTime = startDateTime != null ? startDateTime : LocalDateTime.now().minusMonths(1);
LocalDateTime effectiveStartDateTime =
startDateTime != null ? startDateTime : LocalDateTime.now().minusMonths(1);
LocalDateTime effectiveEndDateTime = endDateTime;

List<Feedback> feedbacks = feedbackRepository.findReceivedFeedbacks(mentorId, null, effectiveStartDateTime, effectiveEndDateTime, cursor, limit);
List<Feedback> feedbacks =
feedbackRepository.findReceivedFeedbacks(
mentorId,
null,
effectiveStartDateTime,
effectiveEndDateTime,
cursor,
limit);

logger.debug(
"멘토 전체 피드백 조회 완료 - mentorId: {}, count: {} | context: {}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
indexes = {
@Index(
name = "idx_WeeklyGitContributions_user_year_month_week",
columnList = "userId year month week"),
columnList = "userId,year,month,week"),
@Index(
name = "idx_WeeklyGitContributions_user_weekStart",
columnList = "userId weekStart")
columnList = "userId,weekStart")
})
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ public void todayCsPublishScheduler() {
String.format(
"[ERROR] CS 문제 발행 중 오류 발생!\n> 원인: %s\n> 시간: %s",
e.getMessage(), java.time.LocalDateTime.now());
eventPublisher.publishEvent(
new SlackEvent.Channel(errorMessage, SlackChannelType.EA));
eventPublisher.publishEvent(new SlackEvent.Channel(errorMessage, SlackChannelType.EA));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public ResponseEntity<Void> signupExternal(
}

@DeleteMapping(value = "")
@PreAuthorize("hasPermission(#userId, 'User', 'DELETE')")
@Override
public ResponseEntity<Void> deleteUser(
@Valid @Parameter(hidden = true) @CurrentUser Long userId,
Expand Down Expand Up @@ -187,6 +188,7 @@ public ResponseEntity<GetUserResponse> getProfile(@PathVariable Long userId) {
}

@PatchMapping("")
@PreAuthorize("hasPermission(#userId, 'User', 'UPDATE')")
@Override
public ResponseEntity<Void> updateProfile(
@Valid @Parameter(hidden = true) @CurrentUser Long userId,
Expand All @@ -198,6 +200,7 @@ public ResponseEntity<Void> updateProfile(
}

@DeleteMapping("/experience/{experienceId}")
@PreAuthorize("hasPermission(#experienceId, 'UserExperience', 'DELETE')")
@Override
public ResponseEntity<Void> deleteExperience(@PathVariable Long experienceId) {
logger.info("경력 삭제 요청 처리 중 - experienceId: {}", experienceId, CONTEXT);
Expand All @@ -207,6 +210,7 @@ public ResponseEntity<Void> deleteExperience(@PathVariable Long experienceId) {
}

@PatchMapping("/nickname")
@PreAuthorize("hasPermission(#userId, 'User', 'UPDATE_NICKNAME')")
@Override
public ResponseEntity<Void> updateNickname(
@Valid @Parameter(hidden = true) @CurrentUser Long userId,
Expand Down Expand Up @@ -261,6 +265,7 @@ public ResponseEntity<BootcampMemberListResponse> getBootcampMemberProfiles(
}

@PatchMapping(value = "/techeer", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@PreAuthorize("hasPermission(#userId, 'User', 'CHANGE_TECHEER')")
@Override
public ResponseEntity<Void> changeTecheer(
@RequestPart("file") MultipartFile file,
Expand All @@ -272,6 +277,7 @@ public ResponseEntity<Void> changeTecheer(
}

@PostMapping("/github/username")
@PreAuthorize("hasPermission(#userId, 'User', 'UPDATE_GITHUB')")
@Override
public ResponseEntity<Void> syncGithubData(
@CurrentUser Long userId, @Valid @RequestBody UpdateGithubUrlRequest request) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;

import backend.techeerzip.domain.user.entity.PermissionRequest;
import backend.techeerzip.global.entity.StatusCategory;

@Transactional
public interface PermissionRequestRepository extends JpaRepository<PermissionRequest, Long> {
@Transactional(readOnly = true)
List<PermissionRequest> findByStatus(StatusCategory status);

@Modifying
@Modifying(clearAutomatically = true, flushAutomatically = true)
@Query(
"UPDATE PermissionRequest p SET p.status = :status WHERE p.user.id = :userId AND p.status = backend.techeerzip.global.entity.StatusCategory.PENDING")
int updateStatusByUserId(@Param("userId") Long userId, @Param("status") StatusCategory status);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@

@Repository
public interface UserRepository extends JpaRepository<User, Long>, UserRepositoryCustom {
Optional<User> findByEmail(String email);
@Query("SELECT u FROM User u WHERE u.email = :email AND u.isDeleted = false")
Optional<User> findByEmail(@Param("email") String email);

boolean existsByEmail(String email);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@
import backend.techeerzip.domain.user.exception.UserNotFoundException;
import backend.techeerzip.domain.user.exception.UserNotResumeException;
import backend.techeerzip.domain.user.exception.UserProfileImgFailException;
import backend.techeerzip.domain.user.exception.UserUnauthorizedAdminException;
import backend.techeerzip.domain.user.mapper.TechStackMapper;
import backend.techeerzip.domain.user.mapper.UserMapper;
import backend.techeerzip.domain.user.repository.PermissionRequestRepository;
Expand Down Expand Up @@ -238,10 +237,17 @@ public void signUp(
TaskType.SIGNUP_BLOG_FETCH, savedUser.getId(), blogUrls);
}

userRepository.flush();

User managedUser =
userRepository
.findById(savedUser.getId())
.orElseThrow(() -> new UserNotFoundException());

CreateResumeRequest resumeRequest = createUserWithResumeRequest.getCreateResumeRequest();
// 이력서 저장
resumeService.createResumeByUser(
savedUser,
managedUser,
resumeFile,
resumeRequest.getTitle(),
resumeRequest.getPosition(),
Expand Down Expand Up @@ -689,13 +695,6 @@ public void deleteExperience(Long experienceId) {
@Transactional
public void updateNickname(Long userId, String nickname) {
User user = userRepository.findById(userId).orElseThrow(UserNotFoundException::new);

Long roleId = user.getRole().getId();
if (roleId == 3) {
logger.warn("권한 없음 - userId: {}", userId);
throw new UserUnauthorizedAdminException();
}

user.setNickname(nickname);
userRepository.save(user);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;

import backend.techeerzip.domain.userExperience.entity.UserExperience;

@Transactional
public interface UserExperienceRepository extends JpaRepository<UserExperience, Long> {
@Modifying
@Query("UPDATE UserExperience ue SET ue.isDeleted = true WHERE ue.user.id = :userId")
@Modifying(clearAutomatically = true, flushAutomatically = true)
@Query("UPDATE UserExperience ue SET ue.isDeleted = true WHERE ue.userId = :userId")
void updateIsDeletedByUserId(@Param("userId") Long userId);
}
Loading