diff --git a/backend/codiki-domain/src/main/java/org/codiki/domain/publication/model/Publication.java b/backend/codiki-domain/src/main/java/org/codiki/domain/publication/model/Publication.java index 3ae4d45..0594cb8 100644 --- a/backend/codiki-domain/src/main/java/org/codiki/domain/publication/model/Publication.java +++ b/backend/codiki-domain/src/main/java/org/codiki/domain/publication/model/Publication.java @@ -8,6 +8,7 @@ public record Publication( String key, String title, String text, + String parsedText, String description, ZonedDateTime creationDate, UUID illustrationId, diff --git a/backend/codiki-domain/src/main/java/org/codiki/domain/publication/model/builder/PublicationBuilder.java b/backend/codiki-domain/src/main/java/org/codiki/domain/publication/model/builder/PublicationBuilder.java index e8a1181..3901b1e 100644 --- a/backend/codiki-domain/src/main/java/org/codiki/domain/publication/model/builder/PublicationBuilder.java +++ b/backend/codiki-domain/src/main/java/org/codiki/domain/publication/model/builder/PublicationBuilder.java @@ -1,17 +1,17 @@ package org.codiki.domain.publication.model.builder; +import org.codiki.domain.publication.model.Author; +import org.codiki.domain.publication.model.Publication; + import java.time.ZonedDateTime; import java.util.UUID; -import org.codiki.domain.category.model.Category; -import org.codiki.domain.publication.model.Author; -import org.codiki.domain.publication.model.Publication; - public class PublicationBuilder { private UUID id; private String key; private String title; private String text; + private String parsedText; private String description; private ZonedDateTime creationDate; private UUID illustrationId; @@ -30,6 +30,7 @@ public class PublicationBuilder { .withKey(publication.key()) .withTitle(publication.title()) .withText(publication.text()) + .withParsedText(publication.parsedText()) .withDescription(publication.description()) .withCreationDate(publication.creationDate()) .withIllustrationId(publication.illustrationId()) @@ -57,6 +58,11 @@ public class PublicationBuilder { return this; } + public PublicationBuilder withParsedText(String parsedText) { + this.parsedText = parsedText; + return this; + } + public PublicationBuilder withDescription(String description) { this.description = description; return this; @@ -88,6 +94,7 @@ public class PublicationBuilder { key, title, text, + parsedText, description, creationDate, illustrationId, diff --git a/backend/codiki-exposition/src/main/java/org/codiki/exposition/publication/model/PublicationDto.java b/backend/codiki-exposition/src/main/java/org/codiki/exposition/publication/model/PublicationDto.java index 9a5a99b..08a0499 100644 --- a/backend/codiki-exposition/src/main/java/org/codiki/exposition/publication/model/PublicationDto.java +++ b/backend/codiki-exposition/src/main/java/org/codiki/exposition/publication/model/PublicationDto.java @@ -1,16 +1,16 @@ package org.codiki.exposition.publication.model; +import org.codiki.domain.publication.model.Publication; + import java.time.ZonedDateTime; import java.util.UUID; -import org.codiki.domain.publication.model.Publication; -import org.codiki.exposition.category.model.CategoryDto; - public record PublicationDto( UUID id, String key, String title, String text, + String parsedText, String description, ZonedDateTime creationDate, UUID illustrationId, @@ -23,6 +23,7 @@ public record PublicationDto( publication.key(), publication.title(), publication.text(), + publication.parsedText(), publication.description(), publication.creationDate(), publication.illustrationId(), diff --git a/backend/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/ParserService.java b/backend/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/ParserService.java new file mode 100755 index 0000000..507e07b --- /dev/null +++ b/backend/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/ParserService.java @@ -0,0 +1,143 @@ +package org.codiki.infrastructure.publication; + +import org.springframework.stereotype.Service; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.apache.commons.lang3.StringEscapeUtils.escapeHtml4; + +@Service +public class ParserService { + private static final String REG_CODE = "\\[code lg="([a-z]+)"\\](.*)\\[\\/code\\]\\n"; + private static final String REG_IMAGES = "\\[img src="([^\"| ]+)"( alt="([^\"| ]+)")? \\/\\]"; + private static final String REG_LINKS = "\\[link href="([^\"| ]+)" txt="([^\"| ]+)" \\/\\]"; + + private static final Pattern PATTERN_CODE; + private static final Pattern PATTERN_IMAGES; + private static final Pattern PATTERN_LINKS; + + static { + PATTERN_CODE = Pattern.compile(REG_CODE); + PATTERN_IMAGES = Pattern.compile(REG_IMAGES); + PATTERN_LINKS = Pattern.compile(REG_LINKS); + } + + public String parse(String pSource) { + return unParseDolars(parseCode(parseHeaders(parseImages(parseLinks(parseBackSpaces(escapeHtml4(parseDolars(pSource)))))))); + } + + private String parseDolars(final String pSource) { + return pSource.replace("$", "£ø"); + } + + private String unParseDolars(final String pSource) { + return pSource.replace("£ø", "$"); + } + + String parseHeaders(final String pSource) { + String result = pSource; + for(int i = 1 ; i <= 3 ; i++) { + result = parseHeadersHX(result, i); + } + return result; + } + + String parseHeadersHX(final String pSource, final int pNumHeader) { + String result = pSource; + + // (.*)(\[hX\](.*)\[\/hX\])+(.*) + final String regex = concat("(.*)(\\[h", pNumHeader, "\\](.*)\\[\\/h", pNumHeader, "\\])+(.*)"); + + final Pattern pattern = Pattern.compile(regex); + + Matcher matcher = pattern.matcher(result); + + while(matcher.find()) { + // \1\3\4 + result = matcher.replaceFirst(concat(matcher.group(1), + "", matcher.group(3), "", matcher.group(4))); + matcher = pattern.matcher(result); + } + + return result; + } + + String parseBackSpaces(final String pSource) { + return pSource.replaceAll("\r?\n", "
").replaceAll("\\[\\/code\\]", "[/code]\n"); + } + + String parseImages(final String pSource) { + String result = pSource; + + Matcher matcher = PATTERN_IMAGES.matcher(result); + + while(matcher.find()) { + String altStr = matcher.group(3); + + if(altStr == null) { + altStr = ""; + } + + result = matcher.replaceFirst(concat("\"",")); + matcher = PATTERN_IMAGES.matcher(result); + } + + return result; + } + + String parseLinks(final String pSource) { + String result = pSource; + + Matcher matcher = PATTERN_LINKS.matcher(result); + + while(matcher.find()) { + result = matcher.replaceFirst(concat("", matcher.group(2), "")); + matcher = PATTERN_LINKS.matcher(result); + } + + return result; + } + + protected String parseCode(final String pSource) { + String result = pSource; + + Matcher matcher = PATTERN_CODE.matcher(result); + + while(matcher.find()) { + // replace the '
' in group by '\n' + String codeContent = matcher.group(2).replaceAll("", "\n"); + if(codeContent.startsWith("\n")) { + codeContent = codeContent.substring(1); + } + + result = matcher.replaceFirst( + concat( + "
",
+							codeContent,
+							"
" + ) + ); + matcher = PATTERN_CODE.matcher(result); + } + + return result; + } + + /** + * Concatenate the parameters to form just one single string. + * + * @param pArgs + * The strings to concatenate. + * @return The parameters concatenated. + */ + private static String concat(final Object... pArgs) { + final StringBuilder result = new StringBuilder(); + for (final Object arg : pArgs) { + result.append(arg); + } + return result.toString(); + } +} diff --git a/backend/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/PublicationJpaAdapter.java b/backend/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/PublicationJpaAdapter.java index 8f1d075..fec58b8 100644 --- a/backend/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/PublicationJpaAdapter.java +++ b/backend/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/PublicationJpaAdapter.java @@ -1,11 +1,5 @@ package org.codiki.infrastructure.publication; -import static java.util.Collections.reverseOrder; -import static java.util.Comparator.comparingInt; -import java.util.List; -import java.util.Optional; -import java.util.UUID; - import org.codiki.domain.publication.model.Publication; import org.codiki.domain.publication.model.search.PublicationSearchCriterion; import org.codiki.domain.publication.port.PublicationPort; @@ -14,17 +8,29 @@ import org.codiki.infrastructure.publication.model.PublicationSearchResult; import org.codiki.infrastructure.publication.repository.PublicationRepository; import org.springframework.stereotype.Component; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import static java.util.Collections.reverseOrder; +import static java.util.Comparator.comparingInt; +import static org.codiki.domain.publication.model.builder.PublicationBuilder.aPublication; +import static org.springframework.util.ObjectUtils.isEmpty; + @Component public class PublicationJpaAdapter implements PublicationPort { private final PublicationRepository repository; private final PublicationSearchCriteriaJpaAdapter publicationSearchCriteriaJpaAdapter; + private final ParserService parserService; public PublicationJpaAdapter( - PublicationRepository repository, - PublicationSearchCriteriaJpaAdapter publicationSearchCriteriaJpaAdapter + PublicationRepository repository, + PublicationSearchCriteriaJpaAdapter publicationSearchCriteriaJpaAdapter, + ParserService parserService ) { this.repository = repository; this.publicationSearchCriteriaJpaAdapter = publicationSearchCriteriaJpaAdapter; + this.parserService = parserService; } @Override @@ -35,8 +41,24 @@ public class PublicationJpaAdapter implements PublicationPort { @Override public Optional findById(UUID publicationId) { - return repository.findById(publicationId) - .map(PublicationEntity::toDomain); + Optional result = repository.findById(publicationId) + .map(PublicationEntity::toDomain); + + if (result.isPresent()) { + Publication publication = result.get(); + if (isEmpty(publication.parsedText())) { + Publication editedPublication = aPublication() + .basedOn(publication) + .withParsedText(parserService.parse(publication.text())) + .build(); + PublicationEntity editedPublicationEntity = new PublicationEntity(editedPublication); + repository.save(editedPublicationEntity); + + result = Optional.of(editedPublication); + } + } + + return result; } @Override diff --git a/backend/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/model/PublicationEntity.java b/backend/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/model/PublicationEntity.java index d09f20f..df07d50 100644 --- a/backend/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/model/PublicationEntity.java +++ b/backend/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/model/PublicationEntity.java @@ -1,22 +1,16 @@ package org.codiki.infrastructure.publication.model; -import java.time.ZonedDateTime; -import java.util.UUID; - -import org.codiki.domain.publication.model.Publication; -import org.codiki.infrastructure.category.model.CategoryEntity; - -import static jakarta.persistence.FetchType.LAZY; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.Table; +import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import org.codiki.domain.publication.model.Publication; + +import java.time.ZonedDateTime; +import java.util.UUID; + +import static jakarta.persistence.FetchType.LAZY; @Entity @Table(name = "publication") @@ -34,6 +28,8 @@ public class PublicationEntity { @Column(nullable = false) private String text; @Column(nullable = false) + private String parsedText; + @Column(nullable = false) private String description; @Column(nullable = false) private ZonedDateTime creationDate; @@ -51,6 +47,7 @@ public class PublicationEntity { publication.key(), publication.title(), publication.text(), + publication.parsedText(), publication.description(), publication.creationDate(), publication.illustrationId(), @@ -65,6 +62,7 @@ public class PublicationEntity { key, title, text, + parsedText, description, creationDate, illustrationId, diff --git a/backend/codiki-infrastructure/src/main/resources/sql/001-initial-script-tables-creation.sql b/backend/codiki-infrastructure/src/main/resources/sql/001-initial-script-tables-creation.sql index be99f7a..2e742fa 100644 --- a/backend/codiki-infrastructure/src/main/resources/sql/001-initial-script-tables-creation.sql +++ b/backend/codiki-infrastructure/src/main/resources/sql/001-initial-script-tables-creation.sql @@ -49,6 +49,7 @@ CREATE TABLE IF NOT EXISTS publication ( key VARCHAR(14) NOT NULL, title VARCHAR NOT NULL, text VARCHAR NOT NULL, + parsed_text VARCHAR, description VARCHAR NOT NULL, creation_date TIMESTAMP NOT NULL, illustration_id UUID NOT NULL,