Skip to content

Commit

Permalink
Merge branch 'develop' into feature/#119
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/main/java/com/sponus/sponusbe/domain/announcement/controller/AnnouncementController.java
#	src/main/java/com/sponus/sponusbe/domain/announcement/entity/Announcement.java
#	src/main/java/com/sponus/sponusbe/domain/announcement/service/AnnouncementService.java
  • Loading branch information
dbwp031 committed Feb 11, 2024
2 parents ea93125 + 69b1ee1 commit 4bdc749
Show file tree
Hide file tree
Showing 37 changed files with 310 additions and 182 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public Authentication attemptAuthentication(
String password = (String)requestBody.get("password");
String fcmToken = (String)requestBody.get("fcmToken");

redisUtil.save(
redisUtil.saveAsValue(
email + "_fcm_token",
fcmToken,
999999999L,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public void logout(HttpServletRequest request, HttpServletResponse response, Aut

String accessToken = jwtUtil.resolveAccessToken(request);

redisUtil.save(
redisUtil.saveAsValue(
accessToken,
"logout",
jwtUtil.getExpTime(accessToken),
Expand All @@ -40,7 +40,7 @@ public void logout(HttpServletRequest request, HttpServletResponse response, Aut
String email = jwtUtil.getEmail(accessToken);

redisUtil.delete(
email
email + "_refresh_token"
);

redisUtil.delete(
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/com/sponus/sponusbe/auth/jwt/util/JwtUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ public String createJwtRefreshToken(CustomUserDetails customUserDetails) {
.signWith(secretKey)
.compact();

redisUtil.save(
customUserDetails.getEmail(),
redisUtil.saveAsValue(
customUserDetails.getEmail() + "_refresh_token",
refreshToken,
refreshExpMs,
TimeUnit.MILLISECONDS
Expand All @@ -94,7 +94,7 @@ public String createJwtRefreshToken(CustomUserDetails customUserDetails) {
}

public JwtPair reissueToken(String refreshToken) {
// TODO: 임시메서드(작동안함). Repository에 대한 의존성을 가져야해서 Service로 빼야함

CustomUserDetails tempCustomUserDetails = new CustomUserDetails(
getId(refreshToken),
getEmail(refreshToken),
Expand Down Expand Up @@ -125,7 +125,7 @@ public void validateRefreshToken(String refreshToken) {
String email = getEmail(refreshToken);

//redis에 refreshToken 있는지 검증
if (!redisUtil.hasKey(email)) {
if (!redisUtil.hasKey(email + "_refresh_token")) {
log.warn("[*] case : Invalid refreshToken");
throw new SecurityCustomException(SecurityErrorCode.INVALID_TOKEN);
}
Expand Down
27 changes: 26 additions & 1 deletion src/main/java/com/sponus/sponusbe/auth/jwt/util/RedisUtil.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,43 @@
package com.sponus.sponusbe.auth.jwt.util;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
@RequiredArgsConstructor
public class RedisUtil {

private final RedisTemplate<String, Object> redisTemplate;

public void save(String key, Object val, Long time, TimeUnit timeUnit) {
public void saveAsValue(String key, Object val, Long time, TimeUnit timeUnit) {
redisTemplate.opsForValue().set(key, val, time, timeUnit);
}

public void appendToRecentlyViewedAnnouncement(String key, String newValue) {
long RECENT_VIEWED_ANNOUNCEMENT_LIMIT = 20;

log.info("[*] Newly Viewed Announcement: " + newValue);
Object mostRecentlyViewedValue = redisTemplate.opsForList().index(key, 0);
if (Objects.equals(mostRecentlyViewedValue, newValue)) {
log.info("[*] Skip saving viewed history...");
return;
}
if (Objects.equals(redisTemplate.opsForList().size(key), RECENT_VIEWED_ANNOUNCEMENT_LIMIT)) {
log.info("[*] Recent Announcement Deque Full Capacity..");
log.info("[*] Del Top()");
redisTemplate.opsForList().rightPop(key);
}
redisTemplate.opsForList().leftPush(key, newValue);
}

public boolean hasKey(String key) {
return Boolean.TRUE.equals(redisTemplate.hasKey(key));
}
Expand All @@ -25,6 +46,10 @@ public Object get(String key) {
return redisTemplate.opsForValue().get(key);
}

public List<Object> getList(String key) {
return redisTemplate.opsForList().range(key, 0, -1);
}

public boolean delete(String key) {
return Boolean.TRUE.equals(redisTemplate.delete(key));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,11 @@ public ApiResponse<Void> getAnnouncement() {
}

@GetMapping("/{announcementId}")
public ApiResponse<AnnouncementDetailResponse> getAnnouncement(@PathVariable("announcementId") Long announcementId, @AuthOrganization Organization organization) {
return ApiResponse.onSuccess(announcementService.getAnnouncement(organization.getId(), announcementId));
public ApiResponse<AnnouncementDetailResponse> getAnnouncement(
@PathVariable Long announcementId,
@AuthOrganization Organization authOrganization
) {
return ApiResponse.onSuccess(announcementService.getAnnouncement(authOrganization, announcementId));
}

@GetMapping("/status")
Expand All @@ -70,7 +73,7 @@ public ApiResponse<List<AnnouncementSummaryResponse>> searchAnnouncement(@Reques
@PostMapping(consumes = "multipart/form-data")
public ApiResponse<AnnouncementCreateResponse> createAnnouncement(
@AuthOrganization Organization authOrganization,
@RequestPart("request") @Valid AnnouncementCreateRequest request,
@Valid @RequestPart("request") AnnouncementCreateRequest request,
@RequestPart(value = "images") List<MultipartFile> images
) {
return ApiResponse.onSuccess(
Expand All @@ -95,7 +98,7 @@ public ApiResponse<AnnouncementUpdateResponse> updateAnnouncement(
@AuthOrganization Organization authOrganization,
@PathVariable Long announcementId,
@RequestPart("request") @Valid AnnouncementUpdateRequest request,
@RequestPart(value = "images", required = false) List<MultipartFile> images
@RequestPart(value = "images") @Valid List<MultipartFile> images
) {
return ApiResponse.onSuccess(announcementService.updateAnnouncement(
authOrganization,
Expand All @@ -114,4 +117,13 @@ public ApiResponse<List<AnnouncementSummaryResponse>> getAnnouncementByCategory(
return ApiResponse.onSuccess(
announcementQueryService.getAnnouncementByCategory(category, type));
}

@GetMapping("/recently_viewed_announcements")
public ApiResponse<List<Object>> getRecentAnnouncement(
@AuthOrganization Organization authOrganization
) {
return ApiResponse.onSuccess(
announcementQueryService.getRecentlyViewedAnnouncement(authOrganization)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,21 @@

import com.sponus.sponusbe.domain.announcement.entity.Announcement;
import com.sponus.sponusbe.domain.announcement.entity.enums.AnnouncementCategory;
import com.sponus.sponusbe.domain.announcement.entity.enums.AnnouncementStatus;
import com.sponus.sponusbe.domain.announcement.entity.enums.AnnouncementType;
import com.sponus.sponusbe.domain.organization.entity.Organization;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

public record AnnouncementCreateRequest(
@NotNull(message = "[ERROR] 타이틀 입력은 필수 입니다.")
@NotBlank(message = "[ERROR] 타이틀 입력은 필수 입니다.")
String title,
@NotNull(message = "[ERROR] 유형 입력은 필수 입니다.")
AnnouncementType type,
@NotNull(message = "[ERROR] 카테코리 입력은 필수 입니다.")
AnnouncementCategory category,
@NotNull(message = "[ERROR] 내용 입력은 필수 입니다.")
String content,
AnnouncementStatus status
@NotBlank(message = "[ERROR] 내용 입력은 필수 입니다.")
String content
) {

public Announcement toEntity(Organization writer) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
public record AnnouncementSummaryResponse(
Long id,
Long writerId,
String writerName,
String title,
AnnouncementType type,
AnnouncementCategory category,
Expand All @@ -27,6 +28,7 @@ public static AnnouncementSummaryResponse from(Announcement announcement) {
return AnnouncementSummaryResponse.builder()
.id(announcement.getId())
.writerId(announcement.getWriter().getId())
.writerName(announcement.getWriter().getName())
.title(announcement.getTitle())
.type(announcement.getType())
.category(announcement.getCategory())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.sponus.sponusbe.domain.announcement.entity.enums.AnnouncementCategory;
import com.sponus.sponusbe.domain.announcement.entity.enums.AnnouncementStatus;
import com.sponus.sponusbe.domain.announcement.entity.enums.AnnouncementType;
import com.sponus.sponusbe.domain.bookmark.entity.Bookmark;
import com.sponus.sponusbe.domain.organization.entity.Organization;
import com.sponus.sponusbe.global.common.BaseEntity;

Expand Down Expand Up @@ -72,6 +73,9 @@ public class Announcement extends BaseEntity {
@OneToMany(mappedBy = "announcement", cascade = CascadeType.ALL, orphanRemoval = true)
private List<AnnouncementImage> announcementImages = new ArrayList<>();

@OneToMany(mappedBy = "announcement", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Bookmark> bookmarks = new ArrayList<>();

public void increaseViewCount() {
this.viewCount++;
}
Expand All @@ -85,13 +89,6 @@ public void updateInfo(String title, AnnouncementType type, AnnouncementCategory
this.status = (status != null) ? status : this.status;
}

public void updateImages(List<AnnouncementImage> images) {
if (images != null) {
this.announcementImages.clear();
this.announcementImages.addAll(images);
}
}

public void updateViewCount(long viewCount) {
this.viewCount = viewCount;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.sponus.sponusbe.auth.jwt.util.RedisUtil;
import com.sponus.sponusbe.domain.announcement.dto.response.AnnouncementSummaryResponse;
import com.sponus.sponusbe.domain.announcement.entity.enums.AnnouncementCategory;
import com.sponus.sponusbe.domain.announcement.entity.enums.AnnouncementType;
import com.sponus.sponusbe.domain.announcement.repository.AnnouncementRepository;
import com.sponus.sponusbe.domain.organization.entity.Organization;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -20,6 +22,7 @@
public class AnnouncementQueryService {

private final AnnouncementRepository announcementRepository;
private final RedisUtil redisUtil;

public List<AnnouncementSummaryResponse> searchAnnouncement(String keyword) {
log.info("search announcement by keyword: {}", keyword);
Expand Down Expand Up @@ -57,4 +60,8 @@ else if (type != null) {
return announcementRepository.findAll().stream().map(AnnouncementSummaryResponse::from).toList();
}
}

public List<Object> getRecentlyViewedAnnouncement(Organization authOrganization) {
return redisUtil.getList(authOrganization.getEmail() + "_recently_viewed_list");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.sponus.sponusbe.auth.jwt.util.RedisUtil;
import com.sponus.sponusbe.domain.announcement.dto.request.AnnouncementCreateRequest;
import com.sponus.sponusbe.domain.announcement.dto.request.AnnouncementUpdateRequest;
import com.sponus.sponusbe.domain.announcement.dto.response.AnnouncementCreateResponse;
Expand Down Expand Up @@ -36,30 +37,34 @@ public class AnnouncementService {
private final AnnouncementRepository announcementRepository;
private final AnnouncementViewRepository announcementViewRepository;
private final S3Service s3Service;
private final RedisUtil redisUtil;

public AnnouncementCreateResponse createAnnouncement(
Organization authOrganization,
AnnouncementCreateRequest request,
List<MultipartFile> images
) {
final Announcement announcement = request.toEntity(authOrganization);
setAnnouncementImages(images, announcement);
updateAnnouncementImages(announcement, images);
return AnnouncementCreateResponse.from(announcementRepository.save(announcement));
}

public AnnouncementDetailResponse getAnnouncement(Long organizationId, Long announcementId) {
public AnnouncementDetailResponse getAnnouncement(Organization organization, Long announcementId) {
Announcement announcement = announcementRepository.findById(announcementId)
.orElseThrow(() -> new AnnouncementException(AnnouncementErrorCode.ANNOUNCEMENT_NOT_FOUND));

AnnouncementView announcementView = announcementViewRepository.findById(announcementId.toString())
.orElseGet(() -> AnnouncementView.builder().announcementId(announcementId.toString()).build());
.orElseGet(() -> AnnouncementView.builder().announcementId(announcementId.toString()).build());

if (!announcementView.getOrganizationIds().contains(organizationId.toString())) {
announcementView.getOrganizationIds().add(organizationId.toString());
announcementViewRepository.save(announcementView);
}

return AnnouncementDetailResponse.from(announcement);
redisUtil.appendToRecentlyViewedAnnouncement(organization.getEmail() + "_recently_viewed_list",
String.valueOf(announcementId));

return AnnouncementDetailResponse.from(announcement);
}

public List<AnnouncementSummaryResponse> getListAnnouncement(AnnouncementStatus status) {
Expand Down Expand Up @@ -92,9 +97,14 @@ public AnnouncementUpdateResponse updateAnnouncement(
if (!isOrganizationsAnnouncement(authOrganization.getId(), announcement))
throw new AnnouncementException(AnnouncementErrorCode.INVALID_ORGANIZATION);

announcement.updateInfo(request.title(), request.type(), request.category(), request.content(),
request.status());
setAnnouncementImages(images, announcement);
announcement.updateInfo(
request.title(),
request.type(),
request.category(),
request.content(),
request.status()
);
updateAnnouncementImages(announcement, images);
announcementRepository.save(announcement);
return AnnouncementUpdateResponse.from(announcement);
}
Expand All @@ -119,7 +129,8 @@ private boolean isOrganizationsAnnouncement(Long organizationId, Announcement an
return announcement.getWriter().getId().equals(organizationId);
}

private void setAnnouncementImages(List<MultipartFile> images, Announcement announcement) {
private void updateAnnouncementImages(Announcement announcement, List<MultipartFile> images) {
// 공고의 이미지는 반드시 존재해야함
announcement.getAnnouncementImages().clear();
images.forEach(image -> {
final String url = s3Service.uploadFile(image);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public ApiResponse<BookmarkToggleResponse> bookmarkToggle(
}

@GetMapping("/bookmarked")
public ApiResponse<List<BookmarkGetResponse>> getRecentBookmark(
public ApiResponse<List<BookmarkGetResponse>> getBookmark(
@AuthOrganization Organization authOrganization,
@RequestParam(name = "sort") BookmarkStatus sortStatus
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,40 @@

import java.time.LocalDateTime;

import com.sponus.sponusbe.domain.announcement.dto.response.AnnouncementImageResponse;
import com.sponus.sponusbe.domain.announcement.entity.Announcement;
import com.sponus.sponusbe.domain.announcement.entity.AnnouncementImage;
import com.sponus.sponusbe.domain.announcement.entity.enums.AnnouncementCategory;
import com.sponus.sponusbe.domain.announcement.entity.enums.AnnouncementType;
import com.sponus.sponusbe.domain.bookmark.entity.Bookmark;

import lombok.Builder;

// TODO: 이미지 등 추가
@Builder
public record BookmarkGetResponse(
Long id,
Long announcementId,
String announcementTitle,
Long writerId,
String title,
AnnouncementType type,
AnnouncementCategory category,
AnnouncementImageResponse mainImage,
LocalDateTime createdAt,
Long saveCount
) {

public static BookmarkGetResponse from(Bookmark bookmark) {
public static BookmarkGetResponse from(Announcement announcement, Bookmark bookmark) {
AnnouncementImage mainImage = announcement.getAnnouncementImages()
.stream()
.findFirst()
.orElseThrow();

return BookmarkGetResponse.builder()
.id(bookmark.getId())
.announcementId(bookmark.getAnnouncement().getId())
.announcementTitle(bookmark.getAnnouncement().getTitle())
.id(announcement.getId())
.writerId(announcement.getWriter().getId())
.title(announcement.getTitle())
.type(announcement.getType())
.category(announcement.getCategory())
.mainImage(AnnouncementImageResponse.from(mainImage))
.createdAt(bookmark.getCreatedAt())
.saveCount(bookmark.getSaveCount())
.build();
Expand Down
Loading

0 comments on commit 4bdc749

Please sign in to comment.