Skip to content

Commit

Permalink
✨ feat: 최근 조회한 공고 기능 구현 (#152)
Browse files Browse the repository at this point in the history
* ♻️ refactor : request dto 및 엔티티에 null 허용

* ♻️ refactor : 미삭제된 location 변수도 삭제

* ♻️ refactor : redis에 저장되는 refresh token의 key값 구체화

* style: 코드 포맷팅

* style: redis에 함수명 수정

* ✨ feat: 최근 조회한 공고 기능 구현

* style: 코드 포맷팅
  • Loading branch information
oxdjww authored Feb 10, 2024
1 parent 7cda365 commit 69b1ee1
Show file tree
Hide file tree
Showing 17 changed files with 94 additions and 38 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 Long announcementId) {
return ApiResponse.onSuccess(announcementService.getAnnouncement(announcementId));
public ApiResponse<AnnouncementDetailResponse> getAnnouncement(
@PathVariable Long announcementId,
@AuthOrganization Organization authOrganization
) {
return ApiResponse.onSuccess(announcementService.getAnnouncement(authOrganization, announcementId));
}

@GetMapping("/status")
Expand Down Expand Up @@ -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 @@ -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 @@ -6,6 +6,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 All @@ -32,6 +33,7 @@ public class AnnouncementService {

private final AnnouncementRepository announcementRepository;
private final S3Service s3Service;
private final RedisUtil redisUtil;

public AnnouncementCreateResponse createAnnouncement(
Organization authOrganization,
Expand All @@ -43,10 +45,14 @@ public AnnouncementCreateResponse createAnnouncement(
return AnnouncementCreateResponse.from(announcementRepository.save(announcement));
}

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

redisUtil.appendToRecentlyViewedAnnouncement(organization.getEmail() + "_recently_viewed_list",
String.valueOf(announcementId));

return AnnouncementDetailResponse.from(announcement);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,13 @@ public class Bookmark extends BaseEntity {
@JoinColumn(name = "announcement_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
private Announcement announcement;

public void increaseSaveCount() { this.saveCount++; }
public void increaseSaveCount() {
this.saveCount++;
}

public void decreaseSaveCount() {
if (this.saveCount > 0) {
this.saveCount--;
} }
this.saveCount--;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,4 @@ public interface BookmarkRepository extends JpaRepository<Bookmark, Long> {
List<Bookmark> findByOrganizationOrderByCreatedAtDesc(Organization organization);
List<Bookmark> findByOrganizationOrderBySaveCountDesc(Organization organization);

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,4 @@ public List<BookmarkGetResponse> getSavedBookmark(Organization organization) {
.map(bookmark -> BookmarkGetResponse.from(bookmark.getAnnouncement(), bookmark))
.collect(Collectors.toList());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.sponus.sponusbe.domain.organizationLink.dto.request.OrganizationLinkUpdateRequest;
import com.sponus.sponusbe.domain.organizationLink.dto.response.OrganizationLinkGetResponse;

import org.springframework.web.bind.annotation.*;

import com.sponus.sponusbe.auth.annotation.AuthOrganization;
Expand Down Expand Up @@ -30,13 +31,14 @@ public ApiResponse<OrganizationLinkCreateResponse> createOrganizationLink(
}

@GetMapping("/{organizationLinkId}")
public ApiResponse<OrganizationLinkGetResponse> getOrganizationLink(@PathVariable("organizationLinkId") Long organizationLinkId) {
public ApiResponse<OrganizationLinkGetResponse> getOrganizationLink(
@PathVariable("organizationLinkId") Long organizationLinkId) {
return ApiResponse.onSuccess(organizationLinkQueryService.getOrganizationLink(organizationLinkId));
}

@PatchMapping("/{organizationLinkId}")
public ApiResponse<Void> updateOrganizationLink(@PathVariable("organizationLinkId") Long organizationLinkId,
@RequestBody OrganizationLinkUpdateRequest request) {
@RequestBody OrganizationLinkUpdateRequest request) {
organizationLinkService.updateOrganizationLink(organizationLinkId, request);
return ApiResponse.onSuccess(null);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.sponus.sponusbe.domain.organizationLink.dto.request;

public record OrganizationLinkUpdateRequest(
String name,
String url
String name,
String url
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.sponus.sponusbe.domain.organization.entity.Organization;

import com.sponus.sponusbe.domain.organizationLink.dto.request.OrganizationLinkUpdateRequest;

import jakarta.persistence.Column;
import jakarta.persistence.ConstraintMode;
import jakarta.persistence.Entity;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.sponus.sponusbe.domain.organizationLink.dto.response.OrganizationLinkGetResponse;
import com.sponus.sponusbe.domain.organizationLink.entity.OrganizationLink;
import com.sponus.sponusbe.domain.organizationLink.repository.OrganizationLinkRepository;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -15,12 +16,13 @@
@Transactional(readOnly = true)
@Service
public class OrganizationLinkQueryService {
private final OrganizationLinkRepository organizationLinkRepository;
public OrganizationLinkGetResponse getOrganizationLink(Long organizationLinkId) {
OrganizationLink organizationLink = organizationLinkRepository.findById(organizationLinkId)
.orElseThrow(() -> new OrganizationException(ORGANIZATION_LINK_NOT_FOUND));
private final OrganizationLinkRepository organizationLinkRepository;

public OrganizationLinkGetResponse getOrganizationLink(Long organizationLinkId) {
OrganizationLink organizationLink = organizationLinkRepository.findById(organizationLinkId)
.orElseThrow(() -> new OrganizationException(ORGANIZATION_LINK_NOT_FOUND));

return OrganizationLinkGetResponse.from(organizationLink);
return OrganizationLinkGetResponse.from(organizationLink);

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,11 @@ public ApiResponse<ReportUpdateResponse> updateReport(
@RequestPart(value = "attachments") List<MultipartFile> attachments) {
return ApiResponse.onSuccess(
reportService.updateReport(
authOrganization,
reportId,
request,
images,
attachments));
authOrganization,
reportId,
request,
images,
attachments));
}

@GetMapping("/{reportId}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ public ReportUpdateResponse updateReport(
if (!isOrganizationsReport(authOrganization.getId(), report))
throw new ReportException(ReportErrorCode.INVALID_ORGANIZATION);


report.update(request.title(), request.content());
setReportImages(images, report);
setReportAttachments(attachments, report);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,21 @@ public ApiResponse<TagCreateResponse> createTag(@AuthOrganization Organization o
return ApiResponse.onSuccess(tagService.createTag(organization.getId(), request));
}

@DeleteMapping("/{tagId}")
@DeleteMapping("/{tagId}")
public ApiResponse<Void> deleteTag(@PathVariable Long tagId) {
tagService.deleteTag(tagId);
return ApiResponse.onSuccess(null);
}

@PatchMapping("/{tagId}")
@PatchMapping("/{tagId}")
public ApiResponse<Void> updateTag(@PathVariable Long tagId, @RequestBody TagUpdateRequest request) {
tagService.updateTag(tagId, request);
return ApiResponse.onSuccess(null);
}
@GetMapping("/{tagId}")

@GetMapping("/{tagId}")
public ApiResponse<TagGetResponse> getTag(@PathVariable Long tagId) {
return ApiResponse.onSuccess(tagQueryService.getTag(tagId));
}

}

0 comments on commit 69b1ee1

Please sign in to comment.