Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

중고 악기 매물 등록 시 내용(content)에 링크 포함 여부 검증 로직 추가 #106

Merged
merged 1 commit into from
Apr 15, 2024
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 @@ -56,7 +56,8 @@ public enum CustomExceptionType {
*/
INSTRUMENT_NOT_FOUND_BY_ID(2600, "일치하는 매물 정보를 찾을 수 없습니다."),
INSTRUMENT_DELETE_PERMISSION_DENIED(2601, "악기 매물을 삭제할 권한이 없습니다. 매물은 판매자 본인만 삭제할 수 있습니다."),
INSTRUMENT_UPDATE_PERMISSION_DENIED(2602, "악기 매물 정보를 수정할 권한이 없습니다. 매물 정보는 판매자 본인만 수정할 수 있습니다");
INSTRUMENT_UPDATE_PERMISSION_DENIED(2602, "악기 매물 정보를 수정할 권한이 없습니다. 매물 정보는 판매자 본인만 수정할 수 있습니다."),
UNEXPECTED_LINK_IN_INSTRUMENT_DESCRIPTION(2603, "악기 설명에는 링크(URL)를 첨부할 수 없습니다. 링크 정보를 제거한 후 다시 시도하세요.");

private final Integer code;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,10 @@ public Page<AudioEquipmentResponse> findAudioEquipmentsV1(
""",
security = @SecurityRequirement(name = "access-token")
)
@ApiResponses({
@ApiResponse(responseCode = "201"),
@ApiResponse(responseCode = "400", description = "[2603] 악기 설명에 링크(URL)이 첨부되어 있는 경우.", content = @Content)
})
@PostMapping(
value = "/electric-guitars",
headers = API_VERSION_HEADER_NAME + "=" + 1,
Expand All @@ -295,6 +299,10 @@ public ResponseEntity<ElectricGuitarResponse> createNewElectricGuitarV1(
""",
security = @SecurityRequirement(name = "access-token")
)
@ApiResponses({
@ApiResponse(responseCode = "201"),
@ApiResponse(responseCode = "400", description = "[2603] 악기 설명에 링크(URL)이 첨부되어 있는 경우.", content = @Content)
})
@PostMapping(
value = "/bass-guitars",
headers = API_VERSION_HEADER_NAME + "=" + 1,
Expand All @@ -321,6 +329,10 @@ public ResponseEntity<BassGuitarResponse> createNewBassGuitarV1(
""",
security = @SecurityRequirement(name = "access-token")
)
@ApiResponses({
@ApiResponse(responseCode = "201"),
@ApiResponse(responseCode = "400", description = "[2603] 악기 설명에 링크(URL)이 첨부되어 있는 경우.", content = @Content)
})
@PostMapping(
value = "/acoustic-and-classic-guitars",
headers = API_VERSION_HEADER_NAME + "=" + 1,
Expand Down Expand Up @@ -353,6 +365,10 @@ public ResponseEntity<AcousticAndClassicGuitarResponse> createNewAcousticAndClas
headers = API_VERSION_HEADER_NAME + "=" + 1,
consumes = MediaType.MULTIPART_FORM_DATA_VALUE
)
@ApiResponses({
@ApiResponse(responseCode = "201"),
@ApiResponse(responseCode = "400", description = "[2603] 악기 설명에 링크(URL)이 첨부되어 있는 경우.", content = @Content)
})
public ResponseEntity<EffectorResponse> createNewEffectorV1(
@AuthenticationPrincipal UserPrincipal userPrincipal,
@ParameterObject @ModelAttribute @Valid CreateNewEffectorRequest createNewEffectorRequest
Expand All @@ -374,6 +390,10 @@ public ResponseEntity<EffectorResponse> createNewEffectorV1(
""",
security = @SecurityRequirement(name = "access-token")
)
@ApiResponses({
@ApiResponse(responseCode = "201"),
@ApiResponse(responseCode = "400", description = "[2603] 악기 설명에 링크(URL)이 첨부되어 있는 경우.", content = @Content)
})
@PostMapping(
value = "/amplifiers",
headers = API_VERSION_HEADER_NAME + "=" + 1,
Expand All @@ -400,6 +420,10 @@ public ResponseEntity<AmplifierResponse> createNewAmplifierV1(
""",
security = @SecurityRequirement(name = "access-token")
)
@ApiResponses({
@ApiResponse(responseCode = "201"),
@ApiResponse(responseCode = "400", description = "[2603] 악기 설명에 링크(URL)이 첨부되어 있는 경우.", content = @Content)
})
@PostMapping(
value = "/audio-equipments",
headers = API_VERSION_HEADER_NAME + "=" + 1,
Expand Down Expand Up @@ -427,6 +451,10 @@ public ResponseEntity<AudioEquipmentResponse> createNewAudioEquipmentV1(
""",
security = @SecurityRequirement(name = "access-token")
)
@ApiResponses({
@ApiResponse(responseCode = "200"),
@ApiResponse(responseCode = "400", description = "[2603] 악기 설명에 링크(URL)이 첨부되어 있는 경우.", content = @Content)
})
@PatchMapping("/electric-guitars/{electricGuitarId}")
public ElectricGuitarResponse updateElectricGuitarV1(
@AuthenticationPrincipal UserPrincipal userPrincipal,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
import java.util.Map;

import com.ajou.hertz.common.dto.AddressDto;
import com.ajou.hertz.domain.instrument.constant.InstrumentCategory;
import com.ajou.hertz.domain.instrument.constant.InstrumentProgressStatus;
import com.ajou.hertz.domain.instrument.acoustic_and_classic_guitar.entity.AcousticAndClassicGuitar;
import com.ajou.hertz.domain.instrument.amplifier.entity.Amplifier;
import com.ajou.hertz.domain.instrument.audio_equipment.entity.AudioEquipment;
import com.ajou.hertz.domain.instrument.bass_guitar.entity.BassGuitar;
import com.ajou.hertz.domain.instrument.constant.InstrumentCategory;
import com.ajou.hertz.domain.instrument.constant.InstrumentProgressStatus;
import com.ajou.hertz.domain.instrument.effector.entity.Effector;
import com.ajou.hertz.domain.instrument.electric_guitar.entity.ElectricGuitar;
import com.ajou.hertz.domain.instrument.entity.Instrument;
Expand Down Expand Up @@ -58,7 +58,7 @@ protected InstrumentDto(Instrument instrument) {
instrument.getQualityStatus(),
instrument.getPrice(),
instrument.getHasAnomaly(),
instrument.getDescription(),
instrument.getDescription().getDescription(),
instrument.getImages().toDtos(),
instrument.getHashtags().toStrings()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ public abstract class Instrument extends TimeTrackedBaseEntity {
@Column(nullable = false)
private Boolean hasAnomaly;

@Column(length = 1000, nullable = false)
private String description;
@Embedded
private InstrumentDescription description;

@Embedded
private InstrumentImages images = new InstrumentImages();
Expand All @@ -89,7 +89,7 @@ protected Instrument(
this.qualityStatus = qualityStatus;
this.price = price;
this.hasAnomaly = hasAnomaly;
this.description = description;
this.description = new InstrumentDescription(description);
}

public void update(InstrumentUpdateRequest updateRequest) {
Expand All @@ -109,7 +109,7 @@ public void update(InstrumentUpdateRequest updateRequest) {
this.hasAnomaly = updateRequest.getHasAnomaly();
}
if (updateRequest.getDescription() != null) {
this.description = updateRequest.getDescription();
this.description = new InstrumentDescription(updateRequest.getDescription());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.ajou.hertz.domain.instrument.entity;

import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.ajou.hertz.domain.instrument.exception.UnexpectedLinkInInstrumentDescriptionException;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Embeddable
public class InstrumentDescription {

@Column(length = 1000, nullable = false)
private String description;

public InstrumentDescription(String description) {
validateDescription(description);
this.description = description;
}

private void validateDescription(String description) {
Matcher descriptionUrlMatcher = Pattern.compile("http://|https://|www\\.").matcher(description);
if (descriptionUrlMatcher.find()) {
throw new UnexpectedLinkInInstrumentDescriptionException();
}
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof InstrumentDescription that)) {
return false;
}
return Objects.equals(this.getDescription(), that.getDescription());
}

@Override
public int hashCode() {
return Objects.hashCode(getDescription());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.ajou.hertz.domain.instrument.exception;

import com.ajou.hertz.common.exception.BadRequestException;
import com.ajou.hertz.common.exception.constant.CustomExceptionType;

public class UnexpectedLinkInInstrumentDescriptionException extends BadRequestException {

public UnexpectedLinkInInstrumentDescriptionException() {
super(CustomExceptionType.UNEXPECTED_LINK_IN_INSTRUMENT_DESCRIPTION);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.ajou.hertz.unit.domain.instrument.entity;

import static org.assertj.core.api.Assertions.*;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import com.ajou.hertz.domain.instrument.entity.InstrumentDescription;
import com.ajou.hertz.domain.instrument.exception.UnexpectedLinkInInstrumentDescriptionException;

class InstrumentDescriptionTest {

@ParameterizedTest
@ValueSource(strings = {
"The violin is a small-bodied string instrument with a long neck, known for its beautiful melodies.",
"A drum set consists of various percussion instruments and cymbals, providing powerful rhythms.",
"The flute is a lightweight woodwind made of metal, known for its smooth and clear sound.",
"An electronic keyboard incorporates various sounds and rhythms, allowing for versatile performances.",
"The harmonica is a small wind instrument that produces sound by blowing air through it, offering a unique musical experience."
})
void 악기_설명에_링크가_존재하지_않는다면_정상적으로_객체가_생성된다(String description) {
// given

// when
InstrumentDescription instrumentDescription = new InstrumentDescription(description);

// then
assertThat(instrumentDescription).isNotNull();
}

@ParameterizedTest
@ValueSource(strings = {
"Keyboard instrument striking strings with hammers. Learn more at Musician's Friend: https://www.musiciansfriend.com/keyboards-midi/pianos",
"Stringed instrument played with a bow, high-pitched. More info at Violinist: http://www.violinist.com/",
"Stringed instrument for various genres, strummed or plucked. Details at Guitar Center: www.guitarcenter.com/Acoustic-Guitars.gc",
"Woodwind instrument, sound by blowing air across the mouthpiece. Additional info at Flute World: https://fluteworld.com/",
"Percussion instruments struck by sticks or hands. Explore more at Drumming.com: http://drumming.com/"
})
void 악기_설명에_링크가_포함되었다면_예외가_발생한다(String description) {
// given

// when
Throwable ex = catchThrowable(() -> new InstrumentDescription(description));

// then
assertThat(ex).isInstanceOf(UnexpectedLinkInInstrumentDescriptionException.class);
}
}
Loading