Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import java.util.List;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Slice;
import org.springframework.scheduling.annotation.Scheduled;

Expand Down Expand Up @@ -47,14 +46,11 @@ public void scheduleCleanupDeactivatedUsers() {

LocalDateTime dueDate = LocalDateTime.now().minusDays(30);

boolean hasNext;
do {
Page<User> userPage = userReader.findUsersDeletedBefore(
while (true) {
List<User> withdrawnUsers = userReader.findCleanupTargets(
dueDate,
pageableFactory.create(0, StaticValue.BATCH_USER_LIST_SIZE));

List<User> withdrawnUsers = userPage.getContent();

if (withdrawnUsers.isEmpty()) {
break;
}
Expand All @@ -66,10 +62,9 @@ public void scheduleCleanupDeactivatedUsers() {
admissionWriter.deleteAdmissionByUsers(withdrawnUsers);
userWriter.cleanupWithdrawnUsers(withdrawnUsers);

hasNext = userPage.hasNext();
log.info("[μœ μ € 정리 배치] {}λͺ… 처리 μ™„λ£Œ", withdrawnUsers.size());
}

} while (hasNext);
log.info("[μœ μ € 정리 배치] νƒˆν‡΄ μœ μ € ν›„μ²˜λ¦¬ μ™„λ£Œ");
} catch (Exception e) {
log.error("μœ μ € 정리 배치 μ‹€νŒ¨: {}", e.getMessage(), e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

import javax.crypto.SecretKey;
Expand Down Expand Up @@ -65,6 +66,8 @@ public String createRefreshToken() {
Date now = new Date();

return Jwts.builder()
.id(UUID.randomUUID().toString())
.issuedAt(now)
.expiration(new Date(now.getTime() + StaticValue.JWT_REFRESH_TOKEN_VALID_TIME))
.signWith(secretKey, Jwts.SIG.HS256)
.compact();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ public class CrawledToPostTransferService {
@Transactional
public void transferToPosts() {
Board board = getBoard();
User adminUser = getAdminUser();
User systemUser = getSystemUser();
List<CrawledNotice> updatedNotices = getUpdatedNotices();

int savedCount = 0;
for (CrawledNotice notice : updatedNotices) {
if (processUpdatedNotice(notice, board, adminUser)) {
if (processUpdatedNotice(notice, board, systemUser)) {
notice.setIsUpdated(false);
crawledNoticeRepository.save(notice);
savedCount++;
Expand All @@ -67,8 +67,8 @@ private Board getBoard() {
}

//κ΄€λ¦¬μž 쑰회
private User getAdminUser() {
return userRepository.findByStudentId(StaticValue.ADMIN_STUDENT_ID)
private User getSystemUser() {
return userRepository.findByEmail(StaticValue.SYSTEM_CRAWLER_ACCOUNT)
.orElseThrow(() -> new BadRequestException(
ErrorCode.ROW_DOES_NOT_EXIST, MessageUtil.USER_NOT_FOUND));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@
import net.causw.app.main.domain.user.account.api.v2.dto.request.UserInfoListRequest;
import net.causw.app.main.domain.user.account.api.v2.dto.request.UserInfoUpdateRequest;
import net.causw.app.main.domain.user.account.api.v2.dto.response.UserInfoDetailResponse;
import net.causw.app.main.domain.user.account.api.v2.dto.response.UserInfoDirectoryResponse;
import net.causw.app.main.domain.user.account.api.v2.dto.response.UserInfoSummaryResponse;
import net.causw.app.main.domain.user.account.api.v2.mapper.UserInfoDtoMapper;
import net.causw.app.main.domain.user.account.service.UserInfoService;
import net.causw.app.main.domain.user.account.service.dto.request.UserInfoListCondition;
import net.causw.app.main.domain.user.account.service.dto.result.UserInfoDetailResult;
import net.causw.app.main.domain.user.account.service.dto.result.UserInfoDirectoryResult;
import net.causw.app.main.domain.user.account.service.dto.result.UserInfoSummaryResult;
import net.causw.app.main.domain.user.auth.userdetails.CustomUserDetails;
import net.causw.app.main.shared.dto.ApiResponse;
Expand Down Expand Up @@ -100,9 +103,34 @@ public ApiResponse<PageResponse<UserInfoSummaryResponse>> getUserInfoPage(
@ModelAttribute @Valid UserInfoListRequest request,
@RequestParam(name = "pageNum", required = false, defaultValue = "0") Integer pageNum,
@AuthenticationPrincipal CustomUserDetails userDetails) {
Page<UserInfoSummaryResult> result = userInfoService.getUserInfoPage(userInfoDtoMapper.toListCondition(request),
pageNum, userDetails.getUserId());

UserInfoListCondition listCondition = userInfoDtoMapper.toListCondition(request);
Page<UserInfoSummaryResult> result = userInfoService.getUserInfoPage(listCondition, pageNum,
userDetails.getUserId());
Page<UserInfoSummaryResponse> response = result.map(userInfoDtoMapper::toSummaryResponse);

return ApiResponse.success(PageResponse.from(response));
}

/**
* 동문 수첩 ν”„λ‘œν•„ 리슀트 쑰회 및 검색
* @param request 동문 수첩 ν”„λ‘œν•„ 리슀트 쑰회 μš”μ²­ DTO
* @param pageNum νŽ˜μ΄μ§•
* @return 쑰회된 동문 수첩 ν”„λ‘œν•„ 리슀트
*/
@GetMapping(value = "/list")
@ResponseStatus(HttpStatus.OK)
@Operation(summary = "동문 수첩 ν”„λ‘œν•„ 리슀트 쑰회 및 검색 (μ»€μ„œκΈ°λ°˜)", description = "검색어 λ˜λŠ” ν•„ν„°λ₯Ό 포함해 동문 수첩 ν”„λ‘œν•„ 리슀트λ₯Ό μ‘°νšŒν•©λ‹ˆλ‹€.(본인 ν”„λ‘œν•„ 포함)")
public ApiResponse<UserInfoDirectoryResponse> getUserInfoList(
@ModelAttribute @Valid UserInfoListRequest request,
@AuthenticationPrincipal CustomUserDetails userDetails) {

UserInfoListCondition listCondition = userInfoDtoMapper.toListCondition(request);
UserInfoDirectoryResult result = userInfoService.getUserInfoByCursor(
listCondition,
userDetails.getUserId(),
request.cursor());

return ApiResponse.success(userInfoDtoMapper.toDirectoryResponse(result));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ public record UserInfoListRequest(

@Schema(description = "학적 μƒνƒœ", example = "[\"ENROLLED\", \"GRADUATED\"]") List<String> academicStatus,

@Schema(description = "μ •λ ¬ κΈ°μ€€", example = "UPDATED_AT_DESC") String sortType) {
@Schema(description = "μ •λ ¬ κΈ°μ€€", example = "UPDATED_AT_DESC") String sortType,

@Schema(description = "μš”μ²­ μ»€μ„œ(μ—†μœΌλ©΄ null)", example = "{랜덀 ν•΄μ‹œκ°’}") String cursor) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package net.causw.app.main.domain.user.account.api.v2.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;

public record DepartmentResponse(
@Schema(description = "ν•™κ³Ό μ½”λ“œ", example = "SCHOOL_OF_SW") String code,
@Schema(description = "ν•™κ³Ό 이름", example = "μ†Œν”„νŠΈμ›¨μ–΄ν•™λΆ€") String name) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public record UserInfoDetailResponse(

@Schema(description = "μ‚¬μš©μž ν•™λ²ˆ", example = "18ν•™λ²ˆ") String admissionYear,

@Schema(description = "μ‚¬μš©μž ν•™κ³Ό", example = "μ†Œν”„νŠΈμ›¨μ–΄ν•™λΆ€/λ―ΈκΈ°μž…") String departmentDescription,

@Schema(description = "μ‚¬μš©μž 학적 μƒνƒœ", example = "쑸업생") String academicStatus,

@Schema(description = "동문 수첩 ν”„λ‘œν•„ μ†Œκ°œκΈ€", example = "동문 수첩 ν”„λ‘œν•„ μ†Œκ°œκΈ€μž…λ‹ˆλ‹€.") String description,
Expand All @@ -35,5 +37,9 @@ public record UserInfoDetailResponse(

@Schema(description = "μ‚¬μš©μž 관심 기술", example = "[\"Tech0\", \"Tech1\"]") List<String> userInterestTech,

@Schema(description = "μ‚¬μš©μž 관심 도메인", example = "[\"Domain0\", \"Domain1\"]") List<String> userInterestDomain) {
@Schema(description = "μ‚¬μš©μž 관심 도메인", example = "[\"Domain0\", \"Domain1\"]") List<String> userInterestDomain,

@Schema(description = "컀피챗 κ°€λŠ₯ μ—¬λΆ€", example = "false") boolean isCoffeeChatAvailable

) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package net.causw.app.main.domain.user.account.api.v2.dto.response;

import java.util.List;

public record UserInfoDirectoryResponse(
UserInfoSummaryResponse myProfile,
List<UserInfoSectionResponse> sections,
String nextCursor) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package net.causw.app.main.domain.user.account.api.v2.dto.response;

import java.util.List;

import net.causw.app.main.domain.user.account.enums.userinfo.UserInfoSectionType;

public record UserInfoSectionResponse(
UserInfoSectionType type,
List<UserInfoSummaryResponse> items,
boolean hasNext) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,9 @@ public record UserInfoSummaryResponse(

@Schema(description = "μ‚¬μš©μž 학적 μƒνƒœ", example = "쑸업생") String academicStatus,

@Schema(description = "동문 수첩 ν”„λ‘œν•„ μ„€λͺ…", example = "동문 수첩 ν”„λ‘œν•„ μ„€λͺ…μž…λ‹ˆλ‹€.") String description) {
@Schema(description = "μ‚¬μš©μž ν•™κ³Ό") DepartmentResponse department,

@Schema(description = "동문 수첩 ν”„λ‘œν•„ μ„€λͺ…", example = "동문 수첩 ν”„λ‘œν•„ μ„€λͺ…μž…λ‹ˆλ‹€.") String description,

@Schema(description = "컀피챗 κ°€λŠ₯ μ—¬λΆ€", example = "false") boolean isCoffeeChatAvailable) {
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,58 @@
package net.causw.app.main.domain.user.account.api.v2.mapper;

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

import net.causw.app.main.domain.user.account.api.v2.dto.request.UserInfoListRequest;
import net.causw.app.main.domain.user.account.api.v2.dto.request.UserInfoUpdateRequest;
import net.causw.app.main.domain.user.account.api.v2.dto.response.DepartmentResponse;
import net.causw.app.main.domain.user.account.api.v2.dto.response.UserInfoDetailResponse;
import net.causw.app.main.domain.user.account.api.v2.dto.response.UserInfoDirectoryResponse;
import net.causw.app.main.domain.user.account.api.v2.dto.response.UserInfoSectionResponse;
import net.causw.app.main.domain.user.account.api.v2.dto.response.UserInfoSummaryResponse;
import net.causw.app.main.domain.user.account.enums.user.Department;
import net.causw.app.main.domain.user.account.service.dto.request.UserInfoListCondition;
import net.causw.app.main.domain.user.account.service.dto.request.UserInfoUpdateCommand;
import net.causw.app.main.domain.user.account.service.dto.result.UserInfoDetailResult;
import net.causw.app.main.domain.user.account.service.dto.result.UserInfoDirectoryResult;
import net.causw.app.main.domain.user.account.service.dto.result.UserInfoSectionResult;
import net.causw.app.main.domain.user.account.service.dto.result.UserInfoSummaryResult;

@Mapper(componentModel = "spring")
public interface UserInfoDtoMapper {

@Mapping(target = "departmentDescription", source = "result.department.name", defaultValue = "ν•™κ³Ό λ―ΈκΈ°μž…")
UserInfoDetailResponse toDetailResponse(UserInfoDetailResult result);

UserInfoSummaryResponse toSummaryResponse(UserInfoSummaryResult result);

/**
* ν•™κ³Ό enum을 API 응닡 객체둜 λ³€ν™˜ν•œλ‹€.
* @param department ν•™κ³Ό enum
* @return ν•™κ³Ό μ½”λ“œμ™€ 이름을 ν¬ν•¨ν•œ 응닡, ν•™κ³Όκ°€ μ—†μœΌλ©΄ {@code null}
*/
default DepartmentResponse toDepartmentResponse(Department department) {
if (department == null) {
return null;
}
return new DepartmentResponse(department.name(), department.getName());
}

/**
* 동문 μ„Ήμ…˜ 쑰회 κ²°κ³Όλ₯Ό API μ‘λ‹΅μœΌλ‘œ λ³€ν™˜ν•œλ‹€.
* @param result 동문 μ„Ήμ…˜ 쑰회 κ²°κ³Ό
* @return 동문 μ„Ήμ…˜ 응닡
*/
UserInfoSectionResponse toSectionResponse(UserInfoSectionResult result);

/**
* 동문 λͺ©λ‘ 쑰회 κ²°κ³Όλ₯Ό API μ‘λ‹΅μœΌλ‘œ λ³€ν™˜ν•œλ‹€.
* @param result 동문 λͺ©λ‘ 쑰회 κ²°κ³Ό
* @return 동문 λͺ©λ‘ 응닡
*/
UserInfoDirectoryResponse toDirectoryResponse(UserInfoDirectoryResult result);

UserInfoUpdateCommand toUpdateCommand(UserInfoUpdateRequest request);

UserInfoListCondition toListCondition(UserInfoListRequest request);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,6 @@ public class UserInfo extends BaseEntity {
@JoinColumn(name = "user_id", nullable = false)
private User user;

/**
* @deprecated v2 APIμ—μ„œλŠ” 직업(job) 정보가 μ†Œκ°œκΈ€(description)κ³Ό 역할이 겹쳐 더 이상 μ‚¬μš©ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
* v1 ν˜Έν™˜μ„ μœ„ν•΄ μ»¬λŸΌμ€ μœ μ§€ν•©λ‹ˆλ‹€.
* TODO: v2 배포 μ™„λ£Œ ν›„ 제거
*/
@Deprecated(since = "v2")
@Column(name = "job", nullable = true)
private String job;

@Column(name = "description", nullable = true)
private String description;

Expand Down Expand Up @@ -93,24 +84,16 @@ public class UserInfo extends BaseEntity {
@Builder.Default
private Set<String> userInterestDomain = new HashSet<>();

@Column(name = "is_coffee_chat_available", nullable = false)
@Builder.Default
private boolean isCoffeeChatAvailable = false;

public static UserInfo of(User user) {
return UserInfo.builder()
.user(user)
.build();
}

/**
* v1 API용 μ—…λ°μ΄νŠΈ. description, job, socialLinks, isPhoneNumberVisible을 ν•œ λ²ˆμ— κ°±μ‹ ν•œλ‹€.
* v1은 API λ ˆμ΄μ–΄μ—μ„œ κ²€μ¦ν•˜λ―€λ‘œ μ—”ν‹°ν‹° 레벨 검증 없이 직접 λ°˜μ˜ν•œλ‹€.
*/
@Deprecated(since = "v2 APIμ—μ„œλŠ” description, socialLinks, isPhoneNumberVisible을 각각 μ—…λ°μ΄νŠΈν•˜λŠ” λ³„λ„μ˜ λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.")
public void updateV1(String description, String job, List<String> socialLinks, boolean isPhoneNumberVisible) {
this.description = description;
this.job = job;
this.socialLinks = socialLinks == null ? new ArrayList<>() : new ArrayList<>(socialLinks);
this.isPhoneNumberVisible = isPhoneNumberVisible;
}

public void update(
String description,
boolean isPhoneNumberVisible) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package net.causw.app.main.domain.user.account.enums.userinfo;

public enum UserInfoSectionType {
COFFEE_CHAT_AVAILABLE,
ALL_MEMBERS;

/**
* ν˜„μž¬ μ„Ήμ…˜ λ‹€μŒμ— μ‘°νšŒν•  μ„Ήμ…˜μ„ λ°˜ν™˜ν•œλ‹€.
* @return λ‹€μŒ μ„Ήμ…˜, λ§ˆμ§€λ§‰ μ„Ήμ…˜μΈ 경우 {@code null}
*/
public UserInfoSectionType next() {
return switch (this) {
case COFFEE_CHAT_AVAILABLE -> ALL_MEMBERS;
case ALL_MEMBERS -> null;
};

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,17 @@ List<User> findByRoleAndAcademicStatusAndState(@Param("role") Role role,

Long countByCreatedAtBetween(LocalDateTime start, LocalDateTime end);

Page<User> findAllByDeletedAtIsNotNullAndDeletedAtBefore(LocalDateTime deletedAt, Pageable pageable);
@Query("""
SELECT u
FROM User u
WHERE u.deletedAt IS NOT NULL
AND u.deletedAt < :deletedAt
AND u.email NOT LIKE 'deleted\\_%' ESCAPE '\\'
ORDER BY u.deletedAt ASC
""")
List<User> findCleanupTargets(
@Param("deletedAt") LocalDateTime deletedAt,
Pageable pageable);

Slice<User> findAllByStateAndUpdatedAtBeforeAndDeletedAtIsNull(UserState state, LocalDateTime updatedAt,
Pageable pageable);
Expand Down
Loading
Loading