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
21 changes: 21 additions & 0 deletions src/docs/asciidoc/api/support/business/business-delete.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
=== 비지니스 문의 삭제 ===

용자는 등록한 문의글을 삭제할 수 있습니다.

물리적으로 삭제되는 것이 아닌 논리 삭제가 수행되며 status 컬럼이 DELETED로 변경됩니.

PathVariable로 문의글의 id를 전달합니다.

존재하지 않는 문의글 id로 요청을 보낸 경우 HELP_NOT_FOUND 예외가 발생합니다.

로그인 한 유저만 요청이 가능하며, 문의글의 작성자가 아닌 경우 HELP_NOT_AUTHORIZED 예외가 발생합니다.

[source]
----
DELETE /api/v1/business-support/{id}
----

[discrete]
==== 응답 파라미터 ====
include::{snippets}/support/business/delete/response-fields.adoc[]
include::{snippets}/support/business/delete/response-body.adoc[]
26 changes: 26 additions & 0 deletions src/docs/asciidoc/api/support/business/business-modify.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
=== 비지니스 문의 수정 ===

사용자는 등록한 비지니스 문의글을 수정할 수 있습니다.

수정하고자 하는 문의글 `제목`, `내용`, `타입` 은 null일 수 없습니다

PathVariable로 문의글의 id를 전달합니다.

존재하지 않는 문의글 id로 요청을 보낸 경우 HELP_NOT_FOUND 예외가 발생합니다.

로그인 한 유저만 요청이 가능하며, 문의글의 작성자가 아닌 경우 HELP_NOT_AUTHORIZED 예외가 발생합니다.

[source]
----
PATCH /api/v1/business-support/{id}
----

[discrete]
==== 요청 파라미터 ====
include::{snippets}/support/business/modify/request-fields.adoc[]
include::{snippets}/support/business/modify/request-body.adoc[]

[discrete]
==== 응답 파라미터 ====
include::{snippets}/support/business/modify/response-fields.adoc[]
include::{snippets}/support/business/modify/response-body.adoc[]
25 changes: 25 additions & 0 deletions src/docs/asciidoc/api/support/business/business-read-detail.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
=== 비지니스 문의 상세 조회 ===

사용자는 등록한 비지니스 문의글 상세조회 할 수 있습니다.

PathVariable로 문의글의 id를 전달합니다.

로그인 한 유저만 조회가 가능합니다.

존재하지 않는 문의글 id로 요청을 보낸 경우 HELP_NOT_FOUND 예외가 발생합니다.

[source]
----
GET /api/v1/business-support/{id}
----

[discrete]
==== 요청 파라미터 ====

- PathVariable id : 문의 아이디

[discrete]
==== 응답 파라미터 ====

include::{snippets}/support/business/read-detail/response-fields.adoc[]
include::{snippets}/support/business/read-detail/response-body.adoc[]
18 changes: 18 additions & 0 deletions src/docs/asciidoc/api/support/business/business-read-list.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
=== 비지니스 문의 목록 조회 ===

사용자는 등록한 비지니스 문의글의 목록을 조회할 수 있습니다.

로그인 한 유저만 조회가 가능합니다.

QueryParam으로 cursor와 pageSize를 전달하며, default 값은 cursor는 0, pageSize는 10입니다.

[source]
----
GET /api/v1/business-support
----

[discrete]
==== 응답 파라미터 ====

include::{snippets}/support/business/read-list/response-fields.adoc[]
include::{snippets}/support/business/read-list/response-body.adoc[]
20 changes: 20 additions & 0 deletions src/docs/asciidoc/api/support/business/business-register.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
=== 비지니스 문의 등록 ===

사용자는 비지니스 관련 문의를 등록할 수 있습니다.

[source]
----
POST /api/v1/business-support
----

[discrete]
==== 요청 파라미터 ====

include::{snippets}/support/business/register/request-fields.adoc[]
include::{snippets}/support/business/register/request-body.adoc[]

[discrete]
==== 응답 파라미터 ====

include::{snippets}/support/business/register/response-fields.adoc[]
include::{snippets}/support/business/register/response-body.adoc[]
10 changes: 10 additions & 0 deletions src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,16 @@ include::api/support/help/help-modify.adoc[]

include::api/support/help/help-delete.adoc[]

include::api/support/business/business-register.adoc[]

include::api/support/business/business-read-list.adoc[]

include::api/support/business/business-read-detail.adoc[]

include::api/support/business/business-modify.adoc[]

include::api/support/business/business-delete.adoc[]

== 팔로우 (follow) 관련 API

include::api/follow/follow-update.adoc[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ public String getFilteredText(String text) {
return response.filtered();
}

@Override
public String filter(String content) {
if (content == null || content.isBlank()) {
return "";
}
return getFilteredText(content);
}

@Override
public void validateProfanity(String text) {
log.info("[validateProfanity] 검증 요청 대상: {}", text);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ public interface ProfanityClient {
*/
String getFilteredText(String text);

/**
* 텍스트가 null이거나 비어있는지 확인하고, 필터링 된 텍스트를 반환한다.
*
* @param content 필터링 대상 텍스트
* @return 필터링 된 텍스트, 텍스트가 null이거나 비어있으면 빈 문자열 반환
*/
String filter(String content);

/**
* 욕설이 포함되어 있는지 확인한다.
* 만약 욕설이 포함되어 있다면, 예외를 발생시킨다.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ public CursorPageable(Long currentCursor, Long cursor, Long pageSize, Boolean ha
public static <T> CursorPageable of(List<T> items, Long currentCursor, Long pageSize) {
boolean hasNext = items.size() > pageSize;

// 다음 페이지가 있는 경우 추가 항목 제거
if (hasNext) {
items.remove(items.size() - 1);
}
// 결과 리스트 생성 (원본 리스트를 수정하지 않음)
List<T> result = hasNext
? items.subList(0, items.size() - 1)
: items;

return CursorPageable.builder()
.currentCursor(currentCursor)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package app.bottlenote.support.business.constant;

import lombok.Getter;

@Getter
public enum BusinessResultMessage {
REGISTER_SUCCESS("비지니스 문의가 등록되었습니다"),
MODIFY_SUCCESS("비지니스 문의가 수정되었습니다"),
DELETE_SUCCESS("비지니스 문의가 삭제되었습니다");

private final String description;

BusinessResultMessage(String description) {
this.description = description;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package app.bottlenote.support.business.constant;

import lombok.Getter;

@Getter
public enum ContactType {
EMAIL, PHONE, ETC;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package app.bottlenote.support.business.controller;

import app.bottlenote.global.data.response.CollectionResponse;
import app.bottlenote.global.data.response.GlobalResponse;
import app.bottlenote.global.security.SecurityContextUtil;
import app.bottlenote.support.business.dto.request.BusinessSupportPageableRequest;
import app.bottlenote.support.business.dto.request.BusinessSupportUpsertRequest;
import app.bottlenote.support.business.dto.response.BusinessInfoResponse;
import app.bottlenote.support.business.dto.response.BusinessSupportDetailItem;
import app.bottlenote.support.business.service.BusinessSupportService;
import app.bottlenote.user.exception.UserException;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import static app.bottlenote.user.exception.UserExceptionCode.REQUIRED_USER_ID;

@RestController
@RequestMapping("/api/v1/business-support")
@RequiredArgsConstructor
public class BusinessSupportController {

private final BusinessSupportService service;

@PostMapping
public ResponseEntity<?> register(@Valid @RequestBody BusinessSupportUpsertRequest req) {
Long userId = SecurityContextUtil.getUserIdByContext().orElseThrow(() -> new UserException(REQUIRED_USER_ID));
return GlobalResponse.ok(service.register(req, userId));
}

@GetMapping
public ResponseEntity<?> getAllList(@ModelAttribute BusinessSupportPageableRequest req) {
Long userId = SecurityContextUtil.getUserIdByContext().orElseThrow(() -> new UserException(REQUIRED_USER_ID));
CollectionResponse<BusinessInfoResponse> collection = service.getList(req, userId);
return GlobalResponse.ok(collection);
}

@GetMapping("/{id}")
public ResponseEntity<?> getDetail(@PathVariable Long id) {
Long userId = SecurityContextUtil.getUserIdByContext().orElseThrow(() -> new UserException(REQUIRED_USER_ID));
BusinessSupportDetailItem item = service.getDetail(id, userId);
return GlobalResponse.ok(item);
}

@PatchMapping("/{id}")
public ResponseEntity<?> modify(@PathVariable Long id, @Valid @RequestBody BusinessSupportUpsertRequest req) {
Long userId = SecurityContextUtil.getUserIdByContext().orElseThrow(() -> new UserException(REQUIRED_USER_ID));
return GlobalResponse.ok(service.modify(id, req, userId));
}

@DeleteMapping("/{id}")
public ResponseEntity<?> delete(@PathVariable Long id) {
Long userId = SecurityContextUtil.getUserIdByContext().orElseThrow(() -> new UserException(REQUIRED_USER_ID));
return GlobalResponse.ok(service.delete(id, userId));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package app.bottlenote.support.business.domain;

import app.bottlenote.common.domain.BaseEntity;
import app.bottlenote.support.business.constant.ContactType;
import app.bottlenote.support.constant.StatusType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.Comment;

@Getter
@Entity(name = "business_support")
@Table(name = "business_supports")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class BusinessSupport extends BaseEntity {

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

@Comment("문의자")
@Column(name = "user_id", nullable = false)
private Long userId;

@Comment("문의 내용")
@Column(name = "content", nullable = false)
private String content;

@Comment("연락 방식")
@Column(name = "contact_way")
@Enumerated(EnumType.STRING)
private ContactType contactWay;

@Enumerated(EnumType.STRING)
@Column(name = "status")
@Comment("문의 타입")
private StatusType status = StatusType.WAITING;

@Column(name = "admin_id")
@Comment("어드민 ID")
private Long adminId;

@Column(name = "response_content")
@Comment("문의 답변 내용")
private String responseContent;

@Builder
private BusinessSupport(Long id, Long userId, String content, ContactType contactWay, Long adminId, String responseContent) {
this.id = id;
this.userId = userId;
this.content = content;
this.contactWay = contactWay;
this.adminId = adminId;
this.responseContent = responseContent;
}

public static BusinessSupport create(Long userId, String content, ContactType contactWay) {
return BusinessSupport.builder()
.userId(userId)
.content(content)
.contactWay(contactWay)
.build();
}

public void update(String content, ContactType contactWay) {
this.content = content;
this.contactWay = contactWay;
}

public void delete() {
this.status = StatusType.DELETED;
}

public boolean isMyPost(Long userId) {
return this.userId.equals(userId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package app.bottlenote.support.business.dto.request;

import lombok.Builder;

public record BusinessSupportPageableRequest(Long cursor, Long pageSize) {
@Builder
public BusinessSupportPageableRequest {
Comment thread
chadongmin marked this conversation as resolved.
cursor = cursor != null ? cursor : 0L;
pageSize = pageSize != null ? pageSize : 10L;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package app.bottlenote.support.business.dto.request;

import app.bottlenote.support.business.constant.ContactType;
import jakarta.validation.constraints.Size;
import lombok.Builder;

@Builder
public record BusinessSupportUpsertRequest(
@Size(max = 500)
String content,

ContactType contactWay
) {
}

Loading
Loading