Skip to content

Commit

Permalink
feat: #105 악기 매물 설명(description)에 링크(URL)가 포함되어 있는 경우 예외가 발생하도록 검증 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
Wo-ogie committed Apr 15, 2024
1 parent 34da23e commit 878dcf9
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 8 deletions.
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);
}
}

0 comments on commit 878dcf9

Please sign in to comment.