Add parsed text to publication entities.

This commit is contained in:
Florian THIERRY
2024-04-22 14:13:17 +02:00
parent c54e1c57d7
commit db492b6316
7 changed files with 203 additions and 30 deletions

View File

@@ -8,6 +8,7 @@ public record Publication(
String key, String key,
String title, String title,
String text, String text,
String parsedText,
String description, String description,
ZonedDateTime creationDate, ZonedDateTime creationDate,
UUID illustrationId, UUID illustrationId,

View File

@@ -1,17 +1,17 @@
package org.codiki.domain.publication.model.builder; 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.time.ZonedDateTime;
import java.util.UUID; 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 { public class PublicationBuilder {
private UUID id; private UUID id;
private String key; private String key;
private String title; private String title;
private String text; private String text;
private String parsedText;
private String description; private String description;
private ZonedDateTime creationDate; private ZonedDateTime creationDate;
private UUID illustrationId; private UUID illustrationId;
@@ -30,6 +30,7 @@ public class PublicationBuilder {
.withKey(publication.key()) .withKey(publication.key())
.withTitle(publication.title()) .withTitle(publication.title())
.withText(publication.text()) .withText(publication.text())
.withParsedText(publication.parsedText())
.withDescription(publication.description()) .withDescription(publication.description())
.withCreationDate(publication.creationDate()) .withCreationDate(publication.creationDate())
.withIllustrationId(publication.illustrationId()) .withIllustrationId(publication.illustrationId())
@@ -57,6 +58,11 @@ public class PublicationBuilder {
return this; return this;
} }
public PublicationBuilder withParsedText(String parsedText) {
this.parsedText = parsedText;
return this;
}
public PublicationBuilder withDescription(String description) { public PublicationBuilder withDescription(String description) {
this.description = description; this.description = description;
return this; return this;
@@ -88,6 +94,7 @@ public class PublicationBuilder {
key, key,
title, title,
text, text,
parsedText,
description, description,
creationDate, creationDate,
illustrationId, illustrationId,

View File

@@ -1,16 +1,16 @@
package org.codiki.exposition.publication.model; package org.codiki.exposition.publication.model;
import org.codiki.domain.publication.model.Publication;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.util.UUID; import java.util.UUID;
import org.codiki.domain.publication.model.Publication;
import org.codiki.exposition.category.model.CategoryDto;
public record PublicationDto( public record PublicationDto(
UUID id, UUID id,
String key, String key,
String title, String title,
String text, String text,
String parsedText,
String description, String description,
ZonedDateTime creationDate, ZonedDateTime creationDate,
UUID illustrationId, UUID illustrationId,
@@ -23,6 +23,7 @@ public record PublicationDto(
publication.key(), publication.key(),
publication.title(), publication.title(),
publication.text(), publication.text(),
publication.parsedText(),
publication.description(), publication.description(),
publication.creationDate(), publication.creationDate(),
publication.illustrationId(), publication.illustrationId(),

View File

@@ -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<hX>\3</hX>\4
result = matcher.replaceFirst(concat(matcher.group(1),
"<h", pNumHeader, ">", matcher.group(3), "</h", pNumHeader, ">", matcher.group(4)));
matcher = pattern.matcher(result);
}
return result;
}
String parseBackSpaces(final String pSource) {
return pSource.replaceAll("\r?\n", "<br/>").replaceAll("\\[\\/code\\]<br\\/><br\\/>", "[/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("<img src=\"", matcher.group(1), "\" alt=\"", altStr, "\" />"));
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("<a href=\"", matcher.group(1), "\">", matcher.group(2), "</a>"));
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 '<br/>' in group by '\n'
String codeContent = matcher.group(2).replaceAll("<br\\/>", "\n");
if(codeContent.startsWith("\n")) {
codeContent = codeContent.substring(1);
}
result = matcher.replaceFirst(
concat(
"<pre class=\"line-numbers\"><code class=\"language-",
matcher.group(1),
"\">",
codeContent,
"</code></pre>"
)
);
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();
}
}

View File

@@ -1,11 +1,5 @@
package org.codiki.infrastructure.publication; 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.Publication;
import org.codiki.domain.publication.model.search.PublicationSearchCriterion; import org.codiki.domain.publication.model.search.PublicationSearchCriterion;
import org.codiki.domain.publication.port.PublicationPort; 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.codiki.infrastructure.publication.repository.PublicationRepository;
import org.springframework.stereotype.Component; 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 @Component
public class PublicationJpaAdapter implements PublicationPort { public class PublicationJpaAdapter implements PublicationPort {
private final PublicationRepository repository; private final PublicationRepository repository;
private final PublicationSearchCriteriaJpaAdapter publicationSearchCriteriaJpaAdapter; private final PublicationSearchCriteriaJpaAdapter publicationSearchCriteriaJpaAdapter;
private final ParserService parserService;
public PublicationJpaAdapter( public PublicationJpaAdapter(
PublicationRepository repository, PublicationRepository repository,
PublicationSearchCriteriaJpaAdapter publicationSearchCriteriaJpaAdapter PublicationSearchCriteriaJpaAdapter publicationSearchCriteriaJpaAdapter,
ParserService parserService
) { ) {
this.repository = repository; this.repository = repository;
this.publicationSearchCriteriaJpaAdapter = publicationSearchCriteriaJpaAdapter; this.publicationSearchCriteriaJpaAdapter = publicationSearchCriteriaJpaAdapter;
this.parserService = parserService;
} }
@Override @Override
@@ -35,8 +41,24 @@ public class PublicationJpaAdapter implements PublicationPort {
@Override @Override
public Optional<Publication> findById(UUID publicationId) { public Optional<Publication> findById(UUID publicationId) {
return repository.findById(publicationId) Optional<Publication> result = repository.findById(publicationId)
.map(PublicationEntity::toDomain); .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 @Override

View File

@@ -1,22 +1,16 @@
package org.codiki.infrastructure.publication.model; package org.codiki.infrastructure.publication.model;
import java.time.ZonedDateTime; import jakarta.persistence.*;
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 lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; 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 @Entity
@Table(name = "publication") @Table(name = "publication")
@@ -34,6 +28,8 @@ public class PublicationEntity {
@Column(nullable = false) @Column(nullable = false)
private String text; private String text;
@Column(nullable = false) @Column(nullable = false)
private String parsedText;
@Column(nullable = false)
private String description; private String description;
@Column(nullable = false) @Column(nullable = false)
private ZonedDateTime creationDate; private ZonedDateTime creationDate;
@@ -51,6 +47,7 @@ public class PublicationEntity {
publication.key(), publication.key(),
publication.title(), publication.title(),
publication.text(), publication.text(),
publication.parsedText(),
publication.description(), publication.description(),
publication.creationDate(), publication.creationDate(),
publication.illustrationId(), publication.illustrationId(),
@@ -65,6 +62,7 @@ public class PublicationEntity {
key, key,
title, title,
text, text,
parsedText,
description, description,
creationDate, creationDate,
illustrationId, illustrationId,

View File

@@ -49,6 +49,7 @@ CREATE TABLE IF NOT EXISTS publication (
key VARCHAR(14) NOT NULL, key VARCHAR(14) NOT NULL,
title VARCHAR NOT NULL, title VARCHAR NOT NULL,
text VARCHAR NOT NULL, text VARCHAR NOT NULL,
parsed_text VARCHAR,
description VARCHAR NOT NULL, description VARCHAR NOT NULL,
creation_date TIMESTAMP NOT NULL, creation_date TIMESTAMP NOT NULL,
illustration_id UUID NOT NULL, illustration_id UUID NOT NULL,