From 01234c51326f8a255014f71fe7c6a3d8b1e22daa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20K=C5=99emen?= Date: Thu, 8 Apr 2021 21:42:25 +0200 Subject: [PATCH 1/7] [R-#1572] changing file mime type detection logic to Apache Tika (#62) --- pom.xml | 8 +++ .../document/DefaultDocumentManager.java | 24 ++++---- .../document/DefaultDocumentManagerTest.java | 56 ++++++++++++------- 3 files changed, 56 insertions(+), 32 deletions(-) diff --git a/pom.xml b/pom.xml index 253cfa809..02d41f06d 100644 --- a/pom.xml +++ b/pom.xml @@ -38,6 +38,7 @@ DEV jar + 1.26 @@ -78,6 +79,13 @@ 1.11 + + + org.apache.tika + tika-core + ${org.apache.tika.tika-core.version} + + cz.cvut.kbss.jopa diff --git a/src/main/java/cz/cvut/kbss/termit/service/document/DefaultDocumentManager.java b/src/main/java/cz/cvut/kbss/termit/service/document/DefaultDocumentManager.java index aab5d4d53..5daa0bcdc 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/document/DefaultDocumentManager.java +++ b/src/main/java/cz/cvut/kbss/termit/service/document/DefaultDocumentManager.java @@ -26,6 +26,7 @@ import cz.cvut.kbss.termit.util.ConfigParam; import cz.cvut.kbss.termit.util.Configuration; import cz.cvut.kbss.termit.util.TypeAwareResource; +import org.apache.tika.Tika; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -91,15 +92,6 @@ public TypeAwareResource getAsResource(File file) { return new TypeAwareFileSystemResource(resolveFile(file, true), getMediaType(file)); } - private String getMediaType(File file) { - final java.io.File content = resolveFile(file, true); - try { - return Files.probeContentType(content.toPath()); - } catch (IOException e) { - throw new DocumentManagerException("Unable to determine file content type.", e); - } - } - @Override public void saveFileContent(File file, InputStream content) { try { @@ -143,15 +135,23 @@ public boolean exists(File file) { @Override public Optional getContentType(File file) { - final java.io.File physicalFile = resolveFile(file, true); try { - return Optional.ofNullable(Files.probeContentType(physicalFile.toPath())); - } catch (IOException e) { + return Optional.ofNullable(getMediaType(file)); + } catch (DocumentManagerException e) { LOG.error("Exception caught when determining content type of file {}.", file, e); return Optional.empty(); } } + private String getMediaType(File file) { + final java.io.File content = resolveFile(file, true); + try { + return new Tika().detect(content); + } catch (IOException e) { + throw new DocumentManagerException("Unable to determine file content type.", e); + } + } + @Override public void remove(Resource resource) { Objects.requireNonNull(resource); diff --git a/src/test/java/cz/cvut/kbss/termit/service/document/DefaultDocumentManagerTest.java b/src/test/java/cz/cvut/kbss/termit/service/document/DefaultDocumentManagerTest.java index 0cc7ff5cc..fabd1d7db 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/document/DefaultDocumentManagerTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/document/DefaultDocumentManagerTest.java @@ -11,6 +11,17 @@ */ package cz.cvut.kbss.termit.service.document; +import static cz.cvut.kbss.termit.environment.Environment.loadFile; +import static cz.cvut.kbss.termit.util.ConfigParam.FILE_STORAGE; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.startsWith; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import cz.cvut.kbss.termit.environment.Generator; import cz.cvut.kbss.termit.environment.PropertyMockingApplicationContextInitializer; import cz.cvut.kbss.termit.event.FileRenameEvent; @@ -22,6 +33,13 @@ import cz.cvut.kbss.termit.service.IdentifierResolver; import cz.cvut.kbss.termit.util.ConfigParam; import cz.cvut.kbss.termit.util.TypeAwareResource; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -31,21 +49,6 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.util.MimeTypeUtils; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; - -import static cz.cvut.kbss.termit.environment.Environment.loadFile; -import static cz.cvut.kbss.termit.util.ConfigParam.FILE_STORAGE; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.startsWith; -import static org.junit.jupiter.api.Assertions.*; - @ContextConfiguration(initializers = {PropertyMockingApplicationContextInitializer.class}) class DefaultDocumentManagerTest extends BaseServiceTestRunner { @@ -68,6 +71,10 @@ void setUp() { } private java.io.File generateFile() throws Exception { + return generateFile("test", ".html", CONTENT); + } + + private java.io.File generateFile(String filePrefix, String fileSuffix, String fileContent) throws Exception { final java.io.File dir = Files.createTempDirectory("termit").toFile(); dir.deleteOnExit(); ((MockEnvironment) environment).setProperty(ConfigParam.FILE_STORAGE.toString(), dir.getAbsolutePath()); @@ -75,9 +82,9 @@ private java.io.File generateFile() throws Exception { document.getDirectoryName()); docDir.mkdir(); docDir.deleteOnExit(); - final java.io.File content = Files.createTempFile(docDir.toPath(), "test", ".html").toFile(); + final java.io.File content = Files.createTempFile(docDir.toPath(), filePrefix, fileSuffix).toFile(); content.deleteOnExit(); - Files.write(content.toPath(), Collections.singletonList(CONTENT)); + Files.write(content.toPath(), Collections.singletonList(fileContent)); return content; } @@ -243,15 +250,24 @@ void existsReturnsFalseForNonExistentFile() { } @Test - void getContentTypeResolvesContentTypeOfSpecifiedFileFromDisk() throws Exception { + void getContentTypeResolvesHtmlContentTypeFromFileNameFromDisk() throws Exception { + testContentType("test", ".html", CONTENT, MimeTypeUtils.TEXT_HTML_VALUE); + } + + @Test + void getContentTypeResolvesHtmlContentTypeFromContentFromDisk() throws Exception { + testContentType("test", "", CONTENT, MimeTypeUtils.TEXT_HTML_VALUE); + } + + void testContentType(final String prefix, String suffix, String content, String mimeType) throws Exception { final File file = new File(); - final java.io.File physicalFile = generateFile(); + final java.io.File physicalFile = generateFile(prefix, suffix, content); file.setLabel(physicalFile.getName()); document.addFile(file); file.setDocument(document); final Optional result = sut.getContentType(file); assertTrue(result.isPresent()); - assertEquals(MimeTypeUtils.TEXT_HTML_VALUE, result.get()); + assertEquals(mimeType, result.get()); } @Test From 13f7ff337e6ac48c11600ba3d927fca35bceb660 Mon Sep 17 00:00:00 2001 From: Michal Med Date: Mon, 12 Apr 2021 18:50:05 +0200 Subject: [PATCH 2/7] je-draft rdfs:range xsd:boolean --- ontology/termit-model.ttl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ontology/termit-model.ttl b/ontology/termit-model.ttl index b97bf1c0d..9c83fe7b2 100644 --- a/ontology/termit-model.ttl +++ b/ontology/termit-model.ttl @@ -52,14 +52,14 @@ termit-pojem:uživatel-termitu termit-pojem:má-zdroj-definice-termu a owl:ObjectProperty , ; rdfs:domain ; - rdfs:range xsd:boolean ; - rdfs:subPropertyOf . + rdfs:range termit-pojem:zdroj-definice-termu ; + rdfs:subPropertyOf . termit-pojem:je-draft a owl:DatatypeProperty , ; rdfs:domain ; - rdfs:range termit-pojem:zdroj-definice-termu ; - rdfs:subPropertyOf . + rdfs:range xsd:boolean ; + rdfs:subPropertyOf . a owl:Class . @@ -252,4 +252,4 @@ termit-pojem:konfigurace termit-pojem:je-tématem a owl:ObjectProperty; - owl:inverseOf sioc:topic . \ No newline at end of file + owl:inverseOf sioc:topic . From dffb5a5dd376938e9cfe89dc3a96a20d8e10c5cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20K=C5=99emen?= Date: Tue, 13 Apr 2021 11:38:19 +0200 Subject: [PATCH 3/7] [R-#1575] document label change notification (#64) --- .../termit/event/DocumentRenameEvent.java | 34 +++++++++++++++++++ .../service/business/ResourceService.java | 33 ++++++++++++------ .../document/DefaultDocumentManager.java | 28 +++++++++++++++ .../service/business/ResourceServiceTest.java | 29 +++++++++++++--- .../document/DefaultDocumentManagerTest.java | 27 +++++++++++++-- 5 files changed, 134 insertions(+), 17 deletions(-) create mode 100644 src/main/java/cz/cvut/kbss/termit/event/DocumentRenameEvent.java diff --git a/src/main/java/cz/cvut/kbss/termit/event/DocumentRenameEvent.java b/src/main/java/cz/cvut/kbss/termit/event/DocumentRenameEvent.java new file mode 100644 index 000000000..0728ccbef --- /dev/null +++ b/src/main/java/cz/cvut/kbss/termit/event/DocumentRenameEvent.java @@ -0,0 +1,34 @@ +package cz.cvut.kbss.termit.event; + +import cz.cvut.kbss.termit.model.resource.Document; +import java.util.Objects; +import org.springframework.context.ApplicationEvent; + +/** + * Indicates that a {@link Document} asset has changed its label. + */ +public class DocumentRenameEvent extends ApplicationEvent { + + private final String originalName; + + private final String newName; + + public DocumentRenameEvent(Document source, String originalName, String newName) { + super(source); + this.originalName = Objects.requireNonNull(originalName); + this.newName = Objects.requireNonNull(newName); + } + + public String getOriginalName() { + return originalName; + } + + public String getNewName() { + return newName; + } + + @Override + public Document getSource() { + return (Document) super.getSource(); + } +} diff --git a/src/main/java/cz/cvut/kbss/termit/service/business/ResourceService.java b/src/main/java/cz/cvut/kbss/termit/service/business/ResourceService.java index ef7861050..b7078af21 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/business/ResourceService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/business/ResourceService.java @@ -16,6 +16,7 @@ import cz.cvut.kbss.termit.asset.provenance.SupportsLastModification; import cz.cvut.kbss.termit.dto.assignment.ResourceTermAssignments; +import cz.cvut.kbss.termit.event.DocumentRenameEvent; import cz.cvut.kbss.termit.event.FileRenameEvent; import cz.cvut.kbss.termit.exception.InvalidParameterException; import cz.cvut.kbss.termit.exception.NotFoundException; @@ -238,7 +239,11 @@ public void addFileToDocument(Resource document, File file) { } else { persist(file); } - update(doc); + if ( !getReference(document.getUri()).isPresent() ) { + persist(document); + } else { + update(doc); + } } /** @@ -255,7 +260,9 @@ public void removeFile(File file) { throw new InvalidParameterException("File was not attached to a document."); } else { doc.removeFile(file); - update(doc); + if ( repositoryService.getReference(doc.getUri()).isPresent() ) { + update(doc); + } } documentManager.remove(file); repositoryService.remove(file); @@ -351,7 +358,7 @@ public void persist(Resource instance) { @Transactional @Override public Resource update(Resource instance) { - final Optional evt = createFileLabelUpdateNotification(instance); + final Optional evt = createFileOrDocumentLabelUpdateNotification(instance); final Resource result = repositoryService.update(instance); // Notify only after update in repository to ensure that the change has succeeded // Note that since this is happening in the same transaction, we are relying on the hypothetical exception @@ -361,13 +368,19 @@ public Resource update(Resource instance) { return result; } - private Optional createFileLabelUpdateNotification(Resource instance) { - if (!(instance instanceof File)) { - return Optional.empty(); - } - final Resource original = findRequired(instance.getUri()); - if (!Objects.equals(original.getLabel(), instance.getLabel())) { - return Optional.of(new FileRenameEvent((File) instance, original.getLabel(), instance.getLabel())); + private Optional createFileOrDocumentLabelUpdateNotification(Resource instance) { + if (instance instanceof File) { + final Resource original = findRequired(instance.getUri()); + if (!Objects.equals(original.getLabel(), instance.getLabel())) { + return Optional.of(new FileRenameEvent((File) instance, original.getLabel(), + instance.getLabel())); + } + } else if (instance instanceof Document ) { + final Resource original = findRequired(instance.getUri()); + if (!Objects.equals(original.getLabel(), instance.getLabel())) { + return Optional.of(new DocumentRenameEvent((Document) instance, original.getLabel(), + instance.getLabel())); + } } return Optional.empty(); } diff --git a/src/main/java/cz/cvut/kbss/termit/service/document/DefaultDocumentManager.java b/src/main/java/cz/cvut/kbss/termit/service/document/DefaultDocumentManager.java index 5daa0bcdc..ce11664c6 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/document/DefaultDocumentManager.java +++ b/src/main/java/cz/cvut/kbss/termit/service/document/DefaultDocumentManager.java @@ -14,6 +14,7 @@ */ package cz.cvut.kbss.termit.service.document; +import cz.cvut.kbss.termit.event.DocumentRenameEvent; import cz.cvut.kbss.termit.event.FileRenameEvent; import cz.cvut.kbss.termit.exception.DocumentManagerException; import cz.cvut.kbss.termit.exception.NotFoundException; @@ -75,6 +76,13 @@ private java.io.File resolveFile(File file, boolean verifyExists) { return result; } + private java.io.File resolveDocumentDirectory(Document document) { + Objects.requireNonNull(document); + final String path = + config.get(ConfigParam.FILE_STORAGE) + java.io.File.separator + document.getDirectoryName(); + return new java.io.File(path); + } + @Override public String loadFileContent(File file) { try { @@ -236,6 +244,26 @@ public void onFileRename(FileRenameEvent event) { } } + @EventListener + public void onDocumentRename(DocumentRenameEvent event) { + final Document tempOriginal = new Document(); + tempOriginal.setUri(event.getSource().getUri()); + tempOriginal.setLabel(event.getOriginalName()); + + final java.io.File originalDirectory = resolveDocumentDirectory(tempOriginal); + + final Document tempNewDocument = new Document(); + tempNewDocument.setUri(event.getSource().getUri()); + tempNewDocument.setLabel(event.getNewName()); + final java.io.File newDirectory = resolveDocumentDirectory(tempNewDocument); + + try { + Files.move(originalDirectory.toPath(), newDirectory.toPath()); + } catch (IOException e) { + throw new DocumentManagerException("Cannot rename the directory on document label change.", e); + } + } + /** * If a file does not belong to any document, its content is stored in a folder whose name is derived from the file * name. diff --git a/src/test/java/cz/cvut/kbss/termit/service/business/ResourceServiceTest.java b/src/test/java/cz/cvut/kbss/termit/service/business/ResourceServiceTest.java index 36e3b57d9..0c3beecf4 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/business/ResourceServiceTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/business/ResourceServiceTest.java @@ -13,6 +13,7 @@ import cz.cvut.kbss.termit.dto.assignment.ResourceTermAssignments; import cz.cvut.kbss.termit.environment.Generator; +import cz.cvut.kbss.termit.event.DocumentRenameEvent; import cz.cvut.kbss.termit.event.FileRenameEvent; import cz.cvut.kbss.termit.exception.NotFoundException; import cz.cvut.kbss.termit.exception.TermItException; @@ -351,12 +352,12 @@ void getFilesThrowsUnsupportedAssetOperationExceptionWhenSpecifiedResourceIsNotD } @Test - void addFileToDocumentPersistsFileAndUpdatesDocumentWithAddedFile() { + void addFileToDocumentPersistsFileAndPersistsDocumentWithAddedFile() { final Document doc = Generator.generateDocumentWithId(); final File fOne = Generator.generateFileWithId("test.html"); sut.addFileToDocument(doc, fOne); verify(resourceRepositoryService).persist(fOne); - verify(resourceRepositoryService).update(doc); + verify(resourceRepositoryService).persist(doc); } @Test @@ -388,12 +389,12 @@ void addFileToDocumentUpdatesDocumentInVocabularyContextForDocumentWithVocabular when(vocabularyService.getRequiredReference(vocabulary.getUri())).thenReturn(vocabulary); sut.addFileToDocument(doc, fOne); - verify(resourceRepositoryService).update(doc); + verify(resourceRepositoryService).persist(doc); verify(vocabularyService).getRequiredReference(vocabulary.getUri()); } @Test - void removeFileRemovesFileUpdatesDocumentAndRemovesContent() { + void removeFileRemovesFileAndRemovesContent() { final Vocabulary vocabulary = Generator.generateVocabularyWithId(); final Document doc = Generator.generateDocumentWithId(); doc.setVocabulary(vocabulary.getUri()); @@ -402,7 +403,6 @@ void removeFileRemovesFileUpdatesDocumentAndRemovesContent() { sut.removeFile(fOne); - verify(resourceRepositoryService).update(doc); verify(resourceRepositoryService).remove(fOne); verify(documentManager).remove(fOne); } @@ -498,6 +498,25 @@ void updatePublishesEventOnFileLabelChange() { assertEquals(file.getLabel(), event.getNewName()); } + @Test + void updatePublishesEventOnDocumentLabelChange() { + final Document document = Generator.generateDocumentWithId(); + document.setLabel("newTest"); + + final Document originalDocument = new Document(); + originalDocument.setUri(document.getUri()); + originalDocument.setLabel("originalTest"); + + when(resourceRepositoryService.findRequired(document.getUri())).thenReturn(originalDocument); + sut.update(document); + final ArgumentCaptor captor = ArgumentCaptor.forClass(DocumentRenameEvent.class); + verify(eventPublisher).publishEvent(captor.capture()); + final DocumentRenameEvent event = captor.getValue(); + assertEquals(document, event.getSource()); + assertEquals(originalDocument.getLabel(), event.getOriginalName()); + assertEquals(document.getLabel(), event.getNewName()); + } + @Test void updateDoesNotPublishFileRenameEventWhenRepositoryServiceThrowsException() { final File file = Generator.generateFileWithId("newTest.html"); diff --git a/src/test/java/cz/cvut/kbss/termit/service/document/DefaultDocumentManagerTest.java b/src/test/java/cz/cvut/kbss/termit/service/document/DefaultDocumentManagerTest.java index fabd1d7db..3f9dddf9d 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/document/DefaultDocumentManagerTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/document/DefaultDocumentManagerTest.java @@ -24,6 +24,7 @@ import cz.cvut.kbss.termit.environment.Generator; import cz.cvut.kbss.termit.environment.PropertyMockingApplicationContextInitializer; +import cz.cvut.kbss.termit.event.DocumentRenameEvent; import cz.cvut.kbss.termit.event.FileRenameEvent; import cz.cvut.kbss.termit.exception.NotFoundException; import cz.cvut.kbss.termit.model.resource.Document; @@ -74,14 +75,19 @@ private java.io.File generateFile() throws Exception { return generateFile("test", ".html", CONTENT); } - private java.io.File generateFile(String filePrefix, String fileSuffix, String fileContent) throws Exception { + private java.io.File generateDirectory() throws Exception { final java.io.File dir = Files.createTempDirectory("termit").toFile(); dir.deleteOnExit(); ((MockEnvironment) environment).setProperty(ConfigParam.FILE_STORAGE.toString(), dir.getAbsolutePath()); final java.io.File docDir = new java.io.File(dir.getAbsolutePath() + java.io.File.separator + - document.getDirectoryName()); + document.getDirectoryName()); docDir.mkdir(); docDir.deleteOnExit(); + return docDir; + } + + private java.io.File generateFile(String filePrefix, String fileSuffix, String fileContent) throws Exception { + final java.io.File docDir = generateDirectory(); final java.io.File content = Files.createTempFile(docDir.toPath(), filePrefix, fileSuffix).toFile(); content.deleteOnExit(); Files.write(content.toPath(), Collections.singletonList(fileContent)); @@ -547,4 +553,21 @@ void onFileRenameMovesWholeDirectoryWhenFileHasNoDocument() throws Exception { assertFalse(physicalOriginal.getParentFile().exists()); assertFalse(physicalOriginal.exists()); } + + @Test + void onDocumentRenameMovesWholeDirectory() throws Exception { + final String oldDirLabel = document.getLabel(); + final java.io.File oldDirectory = generateDirectory(); + + final String newDirLabel = "mpp"; + document.setLabel(newDirLabel); + sut.onDocumentRename(new DocumentRenameEvent(document, oldDirLabel, document.getLabel())); + + final java.io.File newDirectory = new java.io.File( + environment.getProperty(FILE_STORAGE.toString()) + java.io.File.separator + document.getDirectoryName()); + + assertTrue(newDirectory.exists()); + newDirectory.deleteOnExit(); + assertFalse(oldDirectory.exists()); + } } From c54610496db9956c37ba5522d04311bbb9d2c189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20K=C5=99emen?= Date: Fri, 16 Apr 2021 13:43:58 +0200 Subject: [PATCH 4/7] [R-#1579] adjusting the dashboard of last reactions to my comments (#65) * [R-#1579] adjusting the dashboard of last reactions to my comments * [R-#1579] PR feedback * [R-#1579] PR feedback + fixing tests --- "ontology/termit-glos\303\241\305\231.ttl" | 11 ++- ontology/termit-model.ttl | 3 + .../termit/dto/RecentlyCommentedAsset.java | 33 ++++++++- .../kbss/termit/persistence/dao/AssetDao.java | 72 ++++++------------- .../kbss/termit/rest/AssetController.java | 6 -- .../termit/service/business/AssetService.java | 13 ---- .../BaseAssetRepositoryService.java | 12 ---- .../kbss/termit/rest/AssetControllerTest.java | 21 +----- .../service/business/AssetServiceTest.java | 14 +--- .../BaseAssetRepositoryServiceTest.java | 52 ++++---------- 10 files changed, 80 insertions(+), 157 deletions(-) diff --git "a/ontology/termit-glos\303\241\305\231.ttl" "b/ontology/termit-glos\303\241\305\231.ttl" index f2692b470..d3ad46c9e 100644 --- "a/ontology/termit-glos\303\241\305\231.ttl" +++ "b/ontology/termit-glos\303\241\305\231.ttl" @@ -450,4 +450,13 @@ termit-pojem:je-tématem termit:glosář ; - "Is topic of"@en , "Je tématem"@cs . \ No newline at end of file + "Is topic of"@en , "Je tématem"@cs . + +termit-pojem:má-můj-poslední-komentář + a ; + + , ; + + termit:glosář ; + + "Has my last comment"@en , "Má můj poslední komentář"@cs . \ No newline at end of file diff --git a/ontology/termit-model.ttl b/ontology/termit-model.ttl index 9c83fe7b2..35267d7f6 100644 --- a/ontology/termit-model.ttl +++ b/ontology/termit-model.ttl @@ -253,3 +253,6 @@ termit-pojem:konfigurace termit-pojem:je-tématem a owl:ObjectProperty; owl:inverseOf sioc:topic . + +termit-pojem:má-můj-poslední-komentář + a owl:ObjectProperty. diff --git a/src/main/java/cz/cvut/kbss/termit/dto/RecentlyCommentedAsset.java b/src/main/java/cz/cvut/kbss/termit/dto/RecentlyCommentedAsset.java index 98b6a429b..906e22790 100644 --- a/src/main/java/cz/cvut/kbss/termit/dto/RecentlyCommentedAsset.java +++ b/src/main/java/cz/cvut/kbss/termit/dto/RecentlyCommentedAsset.java @@ -21,6 +21,7 @@ variables = { @VariableResult(name = "entity", type = URI.class), @VariableResult(name = "lastCommentUri", type = URI.class), + @VariableResult(name = "myLastCommentUri", type = URI.class), @VariableResult(name = "type", type = String.class) })}) public class RecentlyCommentedAsset implements Serializable { @@ -34,15 +35,22 @@ public class RecentlyCommentedAsset implements Serializable { @OWLObjectProperty(iri = Vocabulary.s_p_je_tematem) private Comment lastComment; + @Transient + private URI myLastCommentUri; + + @OWLObjectProperty(iri = Vocabulary.s_p_ma_muj_posledni_komentar) + private Comment myLastComment; + @Types private Set types; public RecentlyCommentedAsset() { } - public RecentlyCommentedAsset(URI entity, URI lastCommentUri, String type) { + public RecentlyCommentedAsset(URI entity, URI lastCommentUri, URI myLastCommentUri, String type) { this.uri = entity; this.lastCommentUri = lastCommentUri; + this.myLastCommentUri = myLastCommentUri; this.types = new HashSet<>(Collections.singleton(type)); } @@ -79,11 +87,29 @@ public RecentlyCommentedAsset setLastComment(Comment lastComment) { return this; } + public URI getMyLastCommentUri() { + return myLastCommentUri; + } + + public void setMyLastCommentUri(URI myLastCommentUri) { + this.myLastCommentUri = myLastCommentUri; + } + + public Comment getMyLastComment() { + return myLastComment; + } + + public RecentlyCommentedAsset setMyLastComment(Comment myLastComment) { + this.myLastComment = myLastComment; + return this; + } + @Override public String toString() { return "RecentlyCommentedAsset{" + "uri=" + uri + - ", comment=" + lastComment.toString() + + ", comment=" + lastComment + + ", myLastComment=" + myLastComment + ", types=" + types + '}'; } @@ -99,11 +125,12 @@ public boolean equals(Object o) { RecentlyCommentedAsset that = (RecentlyCommentedAsset) o; return Objects.equals(uri, that.uri) && Objects.equals(lastComment, that.lastComment) && + Objects.equals(myLastComment, that.myLastComment) && Objects.equals(types, that.types); } @Override public int hashCode() { - return Objects.hash(uri, lastComment, types); + return Objects.hash(uri, lastComment, myLastComment, types); } } diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/dao/AssetDao.java b/src/main/java/cz/cvut/kbss/termit/persistence/dao/AssetDao.java index f2e701c51..6f9ee1694 100644 --- a/src/main/java/cz/cvut/kbss/termit/persistence/dao/AssetDao.java +++ b/src/main/java/cz/cvut/kbss/termit/persistence/dao/AssetDao.java @@ -184,7 +184,7 @@ List findUniqueLastModifiedEntitiesBy(User author, int limit) { public List findLastCommented(int limit) { try { return (List) em - .createNativeQuery("SELECT DISTINCT ?entity ?lastCommentUri ?type" + .createNativeQuery("SELECT DISTINCT ?entity ?lastCommentUri ?myLastCommentUri ?type" + " WHERE { ?lastCommentUri a ?commentType ;" + " ?hasEntity ?entity ." + " OPTIONAL { ?lastCommentUri ?hasModifiedTime ?modified . }" @@ -226,12 +226,24 @@ public List findLastCommented(int limit) { public List findLastCommentedInReaction(User author, int limit) { try { return (List) em - .createNativeQuery("SELECT DISTINCT ?entity ?lastCommentUri ?type" + .createNativeQuery("SELECT DISTINCT ?entity ?lastCommentUri ?myLastCommentUri ?type" + " WHERE { ?lastCommentUri a ?commentType ;" + " ?hasEntity ?entity ." - + " FILTER EXISTS { ?comment3 ?hasEntity ?entity ;" - + " ?hasAuthor ?author . " - + " FILTER(?comment3 != ?lastCommentUri)}" + + " ?myLastCommentUri ?hasEntity ?entity ;" + + " ?hasAuthor ?author . " + + " OPTIONAL { ?myLastCommentUri ?hasModifiedTime ?modifiedByMe . } " + + " OPTIONAL { ?myLastCommentUri ?hasCreatedByMe ?createdByMe . } " + + " BIND(COALESCE(?modifiedByMe,?createdByMe) AS ?lastCommentedByMe) " + + " { SELECT (MAX(?lastCommentedByMe2) AS ?maxByMe) {" + + " ?commentByMe ?hasEntity ?entity ; " + + " ?hasAuthor ?author . " + + " OPTIONAL { ?commentByMe ?hasModifiedTime ?modifiedByMe2 . } " + + " OPTIONAL { ?commentByMe ?hasCreatedTime ?createdByMe2 . } " + + " BIND(COALESCE(?modifiedByMe2,?createdByMe2) AS ?lastCommentedByMe2) " + + " } GROUP BY ?entity " + + " }" + + " FILTER (?lastCommentedByMe = ?maxByMe )" + + " FILTER(?myLastCommentUri != ?lastCommentUri)" + " OPTIONAL { ?lastCommentUri ?hasModifiedTime ?modified . }" + " OPTIONAL { ?lastCommentUri ?hasCreatedTime ?created . }" + " BIND(COALESCE(?modified,?created) AS ?lastCommented) " @@ -257,7 +269,8 @@ public List findLastCommentedInReaction(User author, int .setMaxResults(limit).getResultStream() .map(r -> { final RecentlyCommentedAsset a = (RecentlyCommentedAsset) r; - return a.setLastComment(em.find(Comment.class, a.getLastCommentUri())); + return a.setLastComment(em.find(Comment.class, a.getLastCommentUri())) + .setMyLastComment(em.find(Comment.class, a.getMyLastCommentUri())); } ).collect(Collectors.toList()); } catch (RuntimeException e) { @@ -273,7 +286,7 @@ public List findLastCommentedInReaction(User author, int public List findMyLastCommented(User author, int limit) { try { return (List) em - .createNativeQuery("SELECT DISTINCT ?entity ?lastCommentUri ?type" + .createNativeQuery("SELECT DISTINCT ?entity ?lastCommentUri ?myLastCommentUri ?type" + " WHERE { ?lastCommentUri a ?commentType ;" + " ?hasEntity ?entity ." + " FILTER EXISTS{ ?x ?hasModifiedEntity ?entity ;" @@ -312,51 +325,6 @@ public List findMyLastCommented(User author, int limit) } } - /** - * Finds unique assets last commented by me. - * @param limit max number of entities - * @return list - */ - public List findLastCommentedByMe(User author, int limit) { - try { - return (List) em - .createNativeQuery("SELECT DISTINCT ?entity ?lastCommentUri ?type" - + " WHERE { ?lastCommentUri a ?commentType ;" - + " ?hasEntity ?entity ;" - + " ?hasCreator ?author ." - + " OPTIONAL { ?lastCommentUri ?hasModifiedTime ?modified . }" - + " OPTIONAL { ?lastCommentUri ?hasCreatedTime ?created . }" - + " BIND(COALESCE(?modified,?created) AS ?lastCommented) " - + " BIND(?cls as ?type) " - + " { SELECT (MAX(?lastCommented2) AS ?max) {" - + " ?comment2 ?hasEntity ?entity ." - + " OPTIONAL { ?comment2 ?hasModifiedTime ?modified2 . }" - + " OPTIONAL { ?comment2 ?hasCreatedTime ?created2 . }" - + " BIND(COALESCE(?modified2,?created2) AS ?lastCommented2) " - + " } GROUP BY ?entity" - + " }" - + " FILTER (?lastCommented = ?max )" - + "} ORDER BY DESC(?lastCommented) ", "RecentlyCommentedAsset") - .setParameter("cls", typeUri) - .setParameter("commentType", URI.create(Vocabulary.s_c_Comment)) - .setParameter("hasEntity", URI.create(Vocabulary.s_p_topic)) - .setParameter("hasCreator", URI.create(Vocabulary.s_p_has_creator)) - .setParameter("author", author) - .setParameter("hasModifiedTime", - URI.create(Vocabulary.s_p_ma_datum_a_cas_posledni_modifikace)) - .setParameter("hasCreatedTime", - URI.create(Vocabulary.s_p_ma_datum_a_cas_vytvoreni)) - .setMaxResults(limit).getResultStream() - .map(r -> { - final RecentlyCommentedAsset a = (RecentlyCommentedAsset) r; - return a.setLastComment(em.find(Comment.class, a.getLastCommentUri())); - } - ).collect(Collectors.toList()); - } catch (RuntimeException e) { - throw new PersistenceException(e); - } - } - /** * Identifier of an RDF property representing this assets label. * diff --git a/src/main/java/cz/cvut/kbss/termit/rest/AssetController.java b/src/main/java/cz/cvut/kbss/termit/rest/AssetController.java index 26f8e31b0..d449964b9 100644 --- a/src/main/java/cz/cvut/kbss/termit/rest/AssetController.java +++ b/src/main/java/cz/cvut/kbss/termit/rest/AssetController.java @@ -66,10 +66,4 @@ public List getMyLastCommented( @RequestParam(name = "limit", required = false, defaultValue = DEFAULT_LIMIT) int limit) { return assetService.findMyLastCommented(limit); } - - @RequestMapping(value = "/last-commented-by-me", produces = {MediaType.APPLICATION_JSON_VALUE, JsonLd.MEDIA_TYPE}) - public List getLastCommentedByMe( - @RequestParam(name = "limit", required = false, defaultValue = DEFAULT_LIMIT) int limit) { - return assetService.findLastCommentedByMe(limit); - } } diff --git a/src/main/java/cz/cvut/kbss/termit/service/business/AssetService.java b/src/main/java/cz/cvut/kbss/termit/service/business/AssetService.java index c5538c3c9..b2797eede 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/business/AssetService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/business/AssetService.java @@ -150,19 +150,6 @@ public List findMyLastCommented(int limit) { return result.subList(0, Math.min(result.size(), limit)); } - /** - * Finds the specified number of assets most recently commented by me. - * - * @param limit Maximum number of assets to retrieve - * @return List of recently commented assets - */ - public List findLastCommentedByMe(int limit) { - ensureValidLimitForLastCommented(limit); - final User me = securityUtils.getCurrentUser().toUser(); - final List result = termRepositoryService.findLastCommentedByMe(me, limit); - return result.subList(0, Math.min(result.size(), limit)); - } - private void ensureValidLimitForLastCommented(int limit) { if (limit < 0) { throw new IllegalArgumentException("Maximum for recently commented assets must not be less than 0."); diff --git a/src/main/java/cz/cvut/kbss/termit/service/repository/BaseAssetRepositoryService.java b/src/main/java/cz/cvut/kbss/termit/service/repository/BaseAssetRepositoryService.java index e65599c46..e3a9e71b0 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/repository/BaseAssetRepositoryService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/repository/BaseAssetRepositoryService.java @@ -105,16 +105,4 @@ public List findLastCommentedInReaction(User me, int lim public List findMyLastCommented(User me, int limit) { return getPrimaryDao().findMyLastCommented(me, limit); } - - /** - * Gets the specified number of assets last commented by me. - *

- * The returned assets are sorted by commented date in descending order. - * - * @param limit Maximum number of assets returned - * @return List of most recently commented assets - */ - public List findLastCommentedByMe(User me, int limit) { - return getPrimaryDao().findLastCommentedByMe(me, limit); - } } diff --git a/src/test/java/cz/cvut/kbss/termit/rest/AssetControllerTest.java b/src/test/java/cz/cvut/kbss/termit/rest/AssetControllerTest.java index 3eb2d17d0..7fe49d1ba 100644 --- a/src/test/java/cz/cvut/kbss/termit/rest/AssetControllerTest.java +++ b/src/test/java/cz/cvut/kbss/termit/rest/AssetControllerTest.java @@ -96,7 +96,7 @@ void getLastEditedRetrievesCurrentUsersLastEditedWhenMineParameterIsSpecified() private static List generateRecentlyCommentedAssetRecords() { return IntStream.range(0, 5).mapToObj(i -> - new RecentlyCommentedAsset( Generator.generateUri(), Generator.generateUri(), SKOS.CONCEPT )) + new RecentlyCommentedAsset( Generator.generateUri(), Generator.generateUri(), null, SKOS.CONCEPT )) .collect(Collectors.toList()); } @@ -156,23 +156,4 @@ void getLastCommentedInReactionToMineRetrievesLastCommentedInReactionToMineWithC .andExpect(status().isOk()); verify(assetService).findLastCommentedInReactionToMine(limit); } - - @Test - void getLastCommentedByMeRetrievesLastCommentedByMeWithDefaultLimit() throws Exception { - final List assets = generateRecentlyCommentedAssetRecords(); - when(assetService.findLastCommentedByMe(anyInt())).thenReturn(assets); - mockMvc.perform(get(PATH + "/last-commented-by-me")).andExpect(status().isOk()); - verify(assetService).findLastCommentedByMe(Integer.parseInt(AssetController.DEFAULT_LIMIT)); - } - - @Test - void getLastCommentedByMeRetrievesLastCommentedByMeWithCustomLimit() throws Exception { - final int limit = Math.abs(Generator.randomInt()); - final List assets = generateRecentlyCommentedAssetRecords(); - when(assetService.findLastCommentedByMe(anyInt())).thenReturn(assets); - mockMvc.perform(get(PATH + "/last-commented-by-me") - .param("limit", "" + limit)) - .andExpect(status().isOk()); - verify(assetService).findLastCommentedByMe(limit); - } } diff --git a/src/test/java/cz/cvut/kbss/termit/service/business/AssetServiceTest.java b/src/test/java/cz/cvut/kbss/termit/service/business/AssetServiceTest.java index a52d396c1..4c89725b8 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/business/AssetServiceTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/business/AssetServiceTest.java @@ -164,7 +164,7 @@ private List generateRecentlyCommentedAssets(int count) for (int i = 0; i < count; i++) { final Term term = Generator.generateTermWithId(); Comment comment = Generator.generateComment(author, term); - RecentlyCommentedAsset rca = new RecentlyCommentedAsset(term.getUri(), comment.getUri(), SKOS.CONCEPT); + RecentlyCommentedAsset rca = new RecentlyCommentedAsset(term.getUri(), comment.getUri(), null, SKOS.CONCEPT); comment.setCreated(new Date(System.currentTimeMillis() - i * 1000)); comment.setAuthor(author); comment.setAsset(term.getUri()); @@ -174,7 +174,6 @@ private List generateRecentlyCommentedAssets(int count) when(termService.findLastCommented(anyInt())).thenReturn(assets); when(termService.findMyLastCommented(any(User.class), anyInt())).thenReturn(assets); when(termService.findLastCommentedInReaction(any(User.class), anyInt())).thenReturn(assets); - when(termService.findLastCommentedByMe(any(User.class), anyInt())).thenReturn(assets); return assets; } @@ -207,15 +206,4 @@ void findLastCommentedInReactionToMineReturnsAssetsSortedByDateCommentCreatedDes final List result = sut.findLastCommentedInReactionToMine(10); assertEquals(allExpected, result); } - - @Test - void findLastCommentedByMeReturnsAssetsSortedByDateCommentCreatedDescending() { - final UserAccount currentUser = Generator.generateUserAccount(); - when(securityUtils.getCurrentUser()).thenReturn(currentUser); - - final List allExpected = generateRecentlyCommentedAssets(6); - allExpected.sort(Comparator.comparing((RecentlyCommentedAsset a) -> a.getLastComment().getCreated()).reversed()); - final List result = sut.findLastCommentedByMe(10); - assertEquals(allExpected, result); - } } diff --git a/src/test/java/cz/cvut/kbss/termit/service/repository/BaseAssetRepositoryServiceTest.java b/src/test/java/cz/cvut/kbss/termit/service/repository/BaseAssetRepositoryServiceTest.java index e52ce2266..a60f23c1b 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/repository/BaseAssetRepositoryServiceTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/repository/BaseAssetRepositoryServiceTest.java @@ -11,6 +11,11 @@ */ package cz.cvut.kbss.termit.service.repository; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + + import cz.cvut.kbss.jopa.model.EntityManager; import cz.cvut.kbss.jopa.model.MultilingualString; import cz.cvut.kbss.termit.dto.RecentlyCommentedAsset; @@ -27,7 +32,14 @@ import cz.cvut.kbss.termit.persistence.dao.VocabularyDao; import cz.cvut.kbss.termit.service.BaseServiceTestRunner; import cz.cvut.kbss.termit.service.security.SecurityUtils; +import java.net.URI; +import java.time.Instant; +import java.util.Comparator; +import java.util.List; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import javax.validation.Validator; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -36,17 +48,6 @@ import org.springframework.test.annotation.DirtiesContext; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; -import javax.validation.Validator; -import java.net.URI; -import java.time.Instant; -import java.util.Comparator; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) class BaseAssetRepositoryServiceTest extends BaseServiceTestRunner { @@ -206,32 +207,9 @@ void findLastCommentedInReactionLoadsLastCommentedItems() { final int count = 2; final List result = sut.findLastCommentedInReaction(author, count); assertEquals(count, result.size()); - } - - @Test - void findLastCommentedByMeLoadsLastCommentedByMe() { - enableRdfsInference(em); - final List terms = IntStream.range(0, 5).mapToObj(i -> Generator.generateTermWithId()) - .collect(Collectors.toList()); - AtomicInteger i = new AtomicInteger(0); - terms.forEach( t -> t.setLabel(MultilingualString.create("Term " + i.incrementAndGet(),"cs"))); - transactional(() -> terms.forEach(em::persist)); - - final List persistRecords = terms.stream().map(Generator::generatePersistChange) - .collect( - Collectors.toList()); - setCreated(persistRecords); - transactional(() -> persistRecords.forEach(em::persist)); - - final List comments = terms.stream().map(t -> Generator.generateComment(author,t)).collect( - Collectors.toList()); - transactional(() -> comments.forEach(em::persist)); - - em.getEntityManagerFactory().getCache().evictAll(); - - final int count = 2; - final List result = sut.findLastCommentedByMe(author, count); - assertEquals(count, result.size()); + result.stream().forEach(a -> + assertNotNull(a.getMyLastComment()) + ); } @Test From 2814b346e3e19023c794eb59666d3205a15b72f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20K=C5=99emen?= Date: Thu, 22 Apr 2021 22:20:26 +0200 Subject: [PATCH 5/7] Update README.md --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 03845c14c..222dd8f19 100644 --- a/README.md +++ b/README.md @@ -126,11 +126,13 @@ Build configuration and deployment is described in [setup.md](doc/setup.md). ## Dockerization The docker image of TermIt backend can be built by -`docker build -t kbss-cvut:termit .` -An optional argument is `REPOSITORY_URL` pointing to the RDF4J/GraphDB repository. +`docker build -t termit-server .` Then, TermIt can be run and exposed at the port 8080 as -`sudo docker run -p 8080:8080 kbss-cvut:termit` +`sudo docker run -e REPOSITORY_URL= -p 8080:8080 termit-server` + +An optional argument is `` pointing to the RDF4J/GraphDB repository. + ## License From 4042ecc70a2ed6f134fdb71fb4e00d73b2077589 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Mon, 26 Apr 2021 08:26:05 +0200 Subject: [PATCH 6/7] Include null values into JSON produced by the REST API. --- .../java/cz/cvut/kbss/termit/config/WebAppConfig.java | 6 +++++- .../kbss/termit/util/json/ManageableIgnoreMixin.java | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 src/main/java/cz/cvut/kbss/termit/util/json/ManageableIgnoreMixin.java diff --git a/src/main/java/cz/cvut/kbss/termit/config/WebAppConfig.java b/src/main/java/cz/cvut/kbss/termit/config/WebAppConfig.java index 64523b445..c83f93ef9 100644 --- a/src/main/java/cz/cvut/kbss/termit/config/WebAppConfig.java +++ b/src/main/java/cz/cvut/kbss/termit/config/WebAppConfig.java @@ -20,12 +20,14 @@ import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import cz.cvut.kbss.jopa.model.MultilingualString; +import cz.cvut.kbss.jopa.sessions.UnitOfWorkImpl; import cz.cvut.kbss.jsonld.JsonLd; import cz.cvut.kbss.jsonld.jackson.JsonLdModule; import cz.cvut.kbss.termit.rest.servlet.DiagnosticsContextFilter; import cz.cvut.kbss.termit.util.AdjustedUriTemplateProxyServlet; import cz.cvut.kbss.termit.util.ConfigParam; import cz.cvut.kbss.termit.util.Constants; +import cz.cvut.kbss.termit.util.json.ManageableIgnoreMixin; import cz.cvut.kbss.termit.util.json.MultilingualStringDeserializer; import cz.cvut.kbss.termit.util.json.MultilingualStringSerializer; import org.springframework.boot.web.servlet.FilterRegistrationBean; @@ -79,12 +81,14 @@ public ObjectMapper objectMapper() { */ public static ObjectMapper createJsonObjectMapper() { final ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final SimpleModule multilingualStringModule = new SimpleModule(); multilingualStringModule.addSerializer(MultilingualString.class, new MultilingualStringSerializer()); multilingualStringModule.addDeserializer(MultilingualString.class, new MultilingualStringDeserializer()); objectMapper.registerModule(multilingualStringModule); + // Ignore UoW references injected into entities + objectMapper.addMixIn(UnitOfWorkImpl.class, ManageableIgnoreMixin.class); // JSR 310 (Java 8 DateTime API) objectMapper.registerModule(new JavaTimeModule()); return objectMapper; diff --git a/src/main/java/cz/cvut/kbss/termit/util/json/ManageableIgnoreMixin.java b/src/main/java/cz/cvut/kbss/termit/util/json/ManageableIgnoreMixin.java new file mode 100644 index 000000000..8de2080c0 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/termit/util/json/ManageableIgnoreMixin.java @@ -0,0 +1,10 @@ +package cz.cvut.kbss.termit.util.json; + +import com.fasterxml.jackson.annotation.JsonIgnoreType; + +/** + * Mixin declared to allow ignoring JOPA's Manageable reference to the current UnitOfWork + */ +@JsonIgnoreType +public class ManageableIgnoreMixin { +} From 079ce0fe021bb25247ecaf671b8d73a1ad590b9f Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Tue, 27 Apr 2021 07:35:22 +0200 Subject: [PATCH 7/7] [2.4.1] Bump version. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 02d41f06d..639491c4e 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ termit - 2.4.0 + 2.4.1 TermIt Terminology manager based on Semantic Web technologies. ${packaging}