Skip to content

Commit

Permalink
Merge branch 'dev/BE' into feat/626
Browse files Browse the repository at this point in the history
  • Loading branch information
shb03323 committed Oct 10, 2023
2 parents 0db6274 + 053be73 commit 9ccfe3a
Show file tree
Hide file tree
Showing 86 changed files with 2,758 additions and 74 deletions.
8 changes: 2 additions & 6 deletions .github/workflows/deploy-be-ci-cd-push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,9 @@ jobs:
- name: Pull Latest Docker Image
run: |
sudo docker login --username ${{ secrets.DOCKERHUB_DEPLOY_USERNAME }} --password ${{ secrets.DOCKERHUB_DEPLOY_TOKEN }}
if sudo docker inspect spring-baton &>/dev/null; then
sudo docker stop spring-baton
sudo docker rm -f spring-baton
sudo docker image prune -af
fi
sudo docker pull 2023batondeploy/2023-baton-deploy:latest
- name: Docker Compose
run: |
sudo docker run --name spring-baton -v /home/ubuntu/logs:/app/logs -p 8080:8080 -e TZ=Asia/Seoul 2023batondeploy/2023-baton-deploy:latest 1>> build.log 2>> error.log &
/home/ubuntu/zero-downtime-deploy.sh
sudo docker image prune -af
29 changes: 29 additions & 0 deletions backend/baton/src/docs/asciidoc/NotificationDeleteApi.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
ifndef::snippets[]
:snippets: ../../../build/generated-snippets
endif::[]
:doctype: book
:icons: font
:source-highlighter: highlight.js
:toc: left
:toclevels: 3
:sectlinks:
:operation-http-request-title: Example Request
:operation-http-response-title: Example Response

==== *์•Œ๋ฆผ ์‚ญ์ œ API*

===== *Http Request*

include::{snippets}/../../build/generated-snippets/notification-delete-api-test/delete-notification-by-notification-id/http-request.adoc[]

===== *Http Request Headers*

include::{snippets}/../../build/generated-snippets/notification-delete-api-test/delete-notification-by-notification-id/request-headers.adoc[]

===== *Http Request Path Parameters*

include::{snippets}/../../build/generated-snippets/notification-delete-api-test/delete-notification-by-notification-id/path-parameters.adoc[]

===== *Http Response*

include::{snippets}/../../build/generated-snippets/notification-delete-api-test/delete-notification-by-notification-id/http-response.adoc[]
29 changes: 29 additions & 0 deletions backend/baton/src/docs/asciidoc/NotificationLoginReadApi.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
ifndef::snippets[]
:snippets: ../../../build/generated-snippets
endif::[]
:doctype: book
:icons: font
:source-highlighter: highlight.js
:toc: left
:toclevels: 3
:sectlinks:
:operation-http-request-title: Example Request
:operation-http-response-title: Example Response

==== *๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž ์•Œ๋ฆผ ๋ชฉ๋ก ์กฐํšŒ API*

===== *Http Request*

include::{snippets}/../../build/generated-snippets/notification-read-with-logined-member-api-test/read-notifications-by-member-id/http-request.adoc[]

===== *Http Request Headers*

include::{snippets}/../../build/generated-snippets/notification-read-with-logined-member-api-test/read-notifications-by-member-id/request-headers.adoc[]

===== *Http Response*

include::{snippets}/../../build/generated-snippets/notification-read-with-logined-member-api-test/read-notifications-by-member-id/http-response.adoc[]

===== *Http Response Fields*

include::{snippets}/../../build/generated-snippets/notification-read-with-logined-member-api-test/read-notifications-by-member-id/response-fields.adoc[]
29 changes: 29 additions & 0 deletions backend/baton/src/docs/asciidoc/NotificationUpdateApi.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
ifndef::snippets[]
:snippets: ../../../build/generated-snippets
endif::[]
:doctype: book
:icons: font
:source-highlighter: highlight.js
:toc: left
:toclevels: 3
:sectlinks:
:operation-http-request-title: Example Request
:operation-http-response-title: Example Response

==== *์•Œ๋ฆผ ์ฝ์Œ ์—ฌ๋ถ€ ์—…๋ฐ์ดํŠธ API*

===== *Http Request*

include::{snippets}/../../build/generated-snippets/notification-update-api-test/update-notification-is-read-true-by-member/http-request.adoc[]

===== *Http Request Headers*

include::{snippets}/../../build/generated-snippets/notification-update-api-test/update-notification-is-read-true-by-member/request-headers.adoc[]

===== *Http Request Path Parameters*

include::{snippets}/../../build/generated-snippets/notification-update-api-test/update-notification-is-read-true-by-member/path-parameters.adoc[]

===== *Http Response*

include::{snippets}/../../build/generated-snippets/notification-update-api-test/update-notification-is-read-true-by-member/http-response.adoc[]
25 changes: 25 additions & 0 deletions backend/baton/src/docs/asciidoc/OauthLogoutApi.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
ifndef::snippets[]
:snippets: ../../../build/generated-snippets
endif::[]
:doctype: book
:icons: font
:source-highlighter: highlight.js
:toc: left
:toclevels: 3
:sectlinks:
:operation-http-request-title: Example Request
:operation-http-response-title: Example Response

==== *๋กœ๊ทธ์•„์›ƒ API*

===== *Http Request*

include::{snippets}/../../build/generated-snippets/oauth-logout-api-test/logout/http-request.adoc[]

===== *Http Request Headers*

include::{snippets}/../../build/generated-snippets/oauth-logout-api-test/logout/request-headers.adoc[]

===== *Http Response*

include::{snippets}/../../build/generated-snippets/oauth-logout-api-test/logout/http-response.adoc[]
15 changes: 15 additions & 0 deletions backend/baton/src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ include::GithubBranchCreateApi.adoc[]
== *[ ๋กœ๊ทธ์ธ ]*

include::GithubOauthApi.adoc[]
include::OauthLogoutApi.adoc[]
include::RefreshTokenApi.adoc[]

== *[ ํ”„๋กœํ•„ ]*
Expand Down Expand Up @@ -63,3 +64,17 @@ include::RunnerPostUpdateApplicantCancelationApi.adoc[]
=== *๋Ÿฌ๋„ˆ ๊ฒŒ์‹œ๊ธ€ ์‚ญ์ œ*

include::RunnerPostDeleteApi.adoc[]

== *[ ์•Œ๋ฆผ ]*

=== *์•Œ๋ฆผ ์กฐํšŒ*

include::NotificationLoginReadApi.adoc[]

=== *์•Œ๋ฆผ ์ˆ˜์ •*

include::NotificationUpdateApi.adoc[]

=== *์•Œ๋ฆผ ์‚ญ์ œ*

include::NotificationDeleteApi.adoc[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package touch.baton.domain.common;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

public abstract class TruncatedBaseEntity extends BaseEntity {

@Override
public LocalDateTime getCreatedAt() {
return super.getCreatedAt().truncatedTo(ChronoUnit.MINUTES);
}

@Override
public LocalDateTime getDeletedAt() {
return super.getDeletedAt().truncatedTo(ChronoUnit.MINUTES);
}

@Override
public LocalDateTime getUpdatedAt() {
return super.getUpdatedAt().truncatedTo(ChronoUnit.MINUTES);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package touch.baton.domain.notification.command;

import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.Enumerated;
import jakarta.persistence.ForeignKey;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;
import touch.baton.domain.common.TruncatedBaseEntity;
import touch.baton.domain.member.command.Member;
import touch.baton.domain.notification.command.vo.IsRead;
import touch.baton.domain.notification.command.vo.NotificationMessage;
import touch.baton.domain.notification.command.vo.NotificationReferencedId;
import touch.baton.domain.notification.command.vo.NotificationTitle;
import touch.baton.domain.notification.command.vo.NotificationType;
import touch.baton.domain.notification.exception.NotificationDomainException;

import java.util.Objects;

import static jakarta.persistence.EnumType.STRING;
import static jakarta.persistence.FetchType.LAZY;
import static jakarta.persistence.GenerationType.IDENTITY;
import static lombok.AccessLevel.PROTECTED;

@Getter
@NoArgsConstructor(access = PROTECTED)
@Where(clause = "deleted_at IS NULL")
@SQLDelete(sql = "UPDATE notification SET deleted_at = now() WHERE id = ?")
@Entity
public class Notification extends TruncatedBaseEntity {

@Id
@GeneratedValue(strategy = IDENTITY)
private Long id;

@Embedded
private NotificationTitle notificationTitle;

@Embedded
private NotificationMessage notificationMessage;

@Enumerated(STRING)
@Column(nullable = false)
private NotificationType notificationType;

@Embedded
private NotificationReferencedId notificationReferencedId;

@Embedded
private IsRead isRead;

@ManyToOne(fetch = LAZY)
@JoinColumn(name = "member_id",
nullable = false,
foreignKey = @ForeignKey(name = "fk_notification_to_member"))
private Member member;

@Builder
private Notification(final NotificationTitle notificationTitle,
final NotificationMessage notificationMessage,
final NotificationType notificationType,
final NotificationReferencedId notificationReferencedId,
final IsRead isRead,
final Member member
) {
this(null, notificationTitle, notificationMessage, notificationType, notificationReferencedId, isRead, member);
}

private Notification(final Long id,
final NotificationTitle notificationTitle,
final NotificationMessage notificationMessage,
final NotificationType notificationType,
final NotificationReferencedId notificationReferencedId,
final IsRead isRead,
final Member member
) {
validateNotNull(notificationTitle, notificationMessage, notificationType, notificationReferencedId, isRead, member);
this.id = id;
this.notificationTitle = notificationTitle;
this.notificationMessage = notificationMessage;
this.notificationType = notificationType;
this.notificationReferencedId = notificationReferencedId;
this.isRead = isRead;
this.member = member;
}

private void validateNotNull(final NotificationTitle notificationTitle,
final NotificationMessage notificationMessage,
final NotificationType notificationType,
final NotificationReferencedId notificationReferencedId,
final IsRead isRead,
final Member member
) {
if (notificationTitle == null) {
throw new NotificationDomainException("NotificationTitle ์˜ notificationTitle ์€ null ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
}
if (notificationMessage == null) {
throw new NotificationDomainException("NotificationMessage ์˜ notificationMessage ๋Š” null ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
}
if (notificationType == null) {
throw new NotificationDomainException("NotificationType ์˜ notificationType ๋Š” null ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
}
if (notificationReferencedId == null) {
throw new NotificationDomainException("NotificationReferencedId ์˜ notificationReferencedId ์€ null ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
}
if (isRead == null) {
throw new NotificationDomainException("IsRead ์˜ isRead ๋Š” null ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
}
if (member == null) {
throw new NotificationDomainException("Member ์˜ member ๋Š” null ์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
}
}

public void markAsRead(final Member currentMember) {
if (!this.member.equals(currentMember)) {
throw new NotificationDomainException("Notification ์˜ ์ฃผ์ธ(์‚ฌ์šฉ์ž)๊ฐ€ ์•„๋‹ˆ๋ฏ€๋กœ ์•Œ๋ฆผ์˜ ์ฝ์€ ์—ฌ๋ถ€๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
}

this.isRead = IsRead.asRead();
}

public boolean isNotOwner(final Member currentMember) {
return !this.member.equals(currentMember);
}

@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final Notification notification = (Notification) o;
return Objects.equals(id, notification.id);
}

@Override
public int hashCode() {
return Objects.hash(id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package touch.baton.domain.notification.command.controller;

import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import touch.baton.domain.notification.command.service.NotificationCommandService;
import touch.baton.domain.member.command.Member;
import touch.baton.domain.oauth.query.controller.resolver.AuthMemberPrincipal;

@RequiredArgsConstructor
@RequestMapping("/api/v1/notifications")
@RestController
public class NotificationCommandController {

private final NotificationCommandService notificationCommandService;

@PatchMapping("/{notificationId}")
public ResponseEntity<Void> updateNotificationIsReadTrueByNotificationId(@AuthMemberPrincipal final Member member,
@PathVariable final Long notificationId
) {
notificationCommandService.updateNotificationIsReadTrueByMember(member, notificationId);

return ResponseEntity.noContent().build();
}

@DeleteMapping("/{notificationId}")
public ResponseEntity<Void> deleteNotificationByNotificationId(@AuthMemberPrincipal final Member member,
@PathVariable final Long notificationId
) {
notificationCommandService.deleteNotificationByMember(member, notificationId);

return ResponseEntity.noContent().build();
}
}
Loading

0 comments on commit 9ccfe3a

Please sign in to comment.