commit 0598e57df5a106ff0b6bce4f66d5d1af8f88e201
Author: Jakub Smid <jaksmid@seznam.cz>
Date:   Tue May 17 13:16:04 2022 +0200

    Added batch endpoint for saving multiple catalog items, POST and PUT endpoint for catalog items merged
    
    re #9753

diff --git a/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogController.java b/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogController.java
index 23ebb96..c8a6bba 100644
--- a/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogController.java
+++ b/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogController.java
@@ -23,16 +23,27 @@ public class CatalogController {
     private final ICatalogItemService catalogService;
 
     /**
-     * Saves new catalog item
+     * Creates new or updates catalog item
      *
      * @param catalogItemDto catalog item DTO
      */
     @PostMapping("")
-    @Operation(summary = "creates new catalog item")
-    public void addCatalogItem(@RequestBody CatalogItemDto catalogItemDto) {
+    @Operation(summary = "creates new or updates catalog item")
+    public void saveCatalogItem(@RequestBody CatalogItemDto catalogItemDto) {
         catalogService.saveCatalogItem(catalogItemDto);
     }
 
+    /**
+     * Saves list of catalog items
+     *
+     * @param catalogItemDtoList list of catalog items DTO
+     */
+    @PostMapping("/batch")
+    @Operation(summary = "saves list of catalog items")
+    public void saveCatalogItems(@RequestBody List<CatalogItemDto> catalogItemDtoList) {
+        catalogService.saveCatalogItems(catalogItemDtoList);
+    }
+
     /**
      * Returns catalog items satisfying given filter
      *
@@ -47,17 +58,6 @@ public class CatalogController {
         return new ResponseEntity<>(catalogService.getCatalog(name, country, type, writtenForm), HttpStatus.OK);
     }
 
-    /**
-     * Updates catalog item with given ID
-     *
-     * @param id             ID
-     * @param catalogItemDto catalog item DTO
-     */
-    @PutMapping("/{id}")
-    @Operation(summary = "updates catalog item with given ID")
-    public void updateCatalogItem(@PathVariable UUID id, @RequestBody CatalogItemDto catalogItemDto) {
-        catalogService.updateCatalogItem(id, catalogItemDto);
-    }
 
     /**
      * Deletes catalog item with given ID
diff --git a/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogItemDto.java b/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogItemDto.java
index 153b86a..18fe4a2 100644
--- a/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogItemDto.java
+++ b/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogItemDto.java
@@ -1,6 +1,5 @@
 package cz.zcu.kiv.backendapi.catalog;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
@@ -18,7 +17,6 @@ public class CatalogItemDto {
     /**
      * Id
      */
-    @JsonProperty(access = JsonProperty.Access.READ_ONLY)
     private UUID id;
 
     /**
diff --git a/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogItemServiceImpl.java b/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogItemServiceImpl.java
index 772b4d4..24b126a 100644
--- a/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogItemServiceImpl.java
+++ b/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogItemServiceImpl.java
@@ -87,28 +87,25 @@ public class CatalogItemServiceImpl implements ICatalogItemService {
     private final ITypeService typeService;
 
     @Override
-    public void saveCatalog(List<CatalogItem> catalogItems) {
+    public void saveCatalogItems(List<CatalogItemDto> catalogItemDtoList) {
         log.info("Saving catalog");
-        catalogItems.forEach(this::saveCatalogEntity);
+        catalogItemDtoList.forEach(this::saveCatalogItem);
+        log.info("Catalog saved");
     }
 
     @Override
     public void saveCatalogItem(CatalogItemDto catalogItemDto) {
         log.info("Saving catalog item");
-        CatalogItem catalogItem = new CatalogItem();
-        convertDtoToEntity(catalogItemDto, catalogItem);
-        saveCatalogEntity(catalogItem);
-    }
-
-    @Override
-    public void updateCatalogItem(UUID id, CatalogItemDto catalogItemDto) {
-        CatalogItem catalogItem = catalogItemRepository.findById(id).orElseThrow(() -> {
-            log.error(CATALOG_ITEM_NOT_FOUND);
-            throw new ApiRequestException(CATALOG_ITEM_NOT_FOUND, HttpStatus.NOT_FOUND);
-        });
+        CatalogItem catalogItem;
+        Optional<CatalogItem> optionalCatalogItem;
+        if (catalogItemDto.getId() != null && (optionalCatalogItem = catalogItemRepository.findById(catalogItemDto.getId())).isPresent()) {
+            catalogItem = optionalCatalogItem.get();
+        } else {
+            catalogItem = new CatalogItem();
+        }
         convertDtoToEntity(catalogItemDto, catalogItem);
         saveCatalogEntity(catalogItem);
-        log.info("Catalog item updated");
+        log.info("Catalog item saved");
     }
 
     @Override
@@ -133,6 +130,7 @@ public class CatalogItemServiceImpl implements ICatalogItemService {
 
     @Override
     public PathDto getPath(String text) {
+        log.info("Searching path");
         PathDto pathDto = new PathDto();
         StringBuilder highlightedText = new StringBuilder();
         List<List<CatalogItemDto>> foundCatalogItems = new ArrayList<>();
@@ -186,6 +184,7 @@ public class CatalogItemServiceImpl implements ICatalogItemService {
 
         pathDto.setText(highlightedText.toString());
         pathDto.setFoundCatalogItems(foundCatalogItems);
+        log.info("Path searched");
         return pathDto;
     }
 
diff --git a/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/ICatalogItemService.java b/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/ICatalogItemService.java
index 428bbd5..a6f69de 100644
--- a/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/ICatalogItemService.java
+++ b/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/ICatalogItemService.java
@@ -10,27 +10,19 @@ import java.util.UUID;
  */
 public interface ICatalogItemService {
     /**
-     * Saves list of catalog items
+     * Saves list of catalog items DTO
      *
-     * @param catalogItems catalog items
+     * @param catalogItemDtoList list of catalog items DTO
      */
-    void saveCatalog(List<CatalogItem> catalogItems);
+    void saveCatalogItems(List<CatalogItemDto> catalogItemDtoList);
 
     /**
-     * Saves one catalog item
+     * Saves one catalog item (creates new if ID is null or does not exist, updates catalog item otherwise)
      *
      * @param catalogItemDto catalog item DTO
      */
     void saveCatalogItem(CatalogItemDto catalogItemDto);
 
-    /**
-     * Updates catalog item with given ID
-     *
-     * @param id             ID
-     * @param catalogItemDto catalog item DTO
-     */
-    void updateCatalogItem(UUID id, CatalogItemDto catalogItemDto);
-
     /**
      * Deletes catalog item with given ID
      *
diff --git a/backend/src/main/java/cz/zcu/kiv/backendapi/config/CorsConfig.java b/backend/src/main/java/cz/zcu/kiv/backendapi/config/CorsConfig.java
index 5358bf0..352a3f6 100644
--- a/backend/src/main/java/cz/zcu/kiv/backendapi/config/CorsConfig.java
+++ b/backend/src/main/java/cz/zcu/kiv/backendapi/config/CorsConfig.java
@@ -1,7 +1,6 @@
 package cz.zcu.kiv.backendapi.config;
 
 import org.springframework.context.annotation.Configuration;
-import org.springframework.http.HttpMethod;
 import org.springframework.web.servlet.config.annotation.CorsRegistry;
 import org.springframework.web.servlet.config.annotation.EnableWebMvc;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
diff --git a/backend/src/main/java/cz/zcu/kiv/backendapi/security/SecurityConfig.java b/backend/src/main/java/cz/zcu/kiv/backendapi/security/SecurityConfig.java
index 1520500..e7c3b00 100644
--- a/backend/src/main/java/cz/zcu/kiv/backendapi/security/SecurityConfig.java
+++ b/backend/src/main/java/cz/zcu/kiv/backendapi/security/SecurityConfig.java
@@ -21,11 +21,11 @@ import org.springframework.web.cors.CorsConfiguration;
 import org.springframework.web.cors.CorsConfigurationSource;
 import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
 
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
+
 /**
  * Security config class
  */
@@ -65,6 +65,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
         PERMITTED_ENDPOINTS.put("/catalog-items", HttpMethod.GET);
         PERMITTED_ENDPOINTS.put("/catalog-items/**", HttpMethod.GET);
         PERMITTED_ENDPOINTS.put("/title-page", HttpMethod.GET);
+        PERMITTED_ENDPOINTS.put("/sources", HttpMethod.GET);
     }
 
     /**
@@ -73,7 +74,6 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
      * @param http http security
      * @throws Exception exception
      */
-    // TODO configure and check rights
     @Override
     protected void configure(HttpSecurity http) throws Exception {
         http.csrf().disable()
@@ -86,15 +86,14 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
                 .authorizeRequests()
                 .antMatchers(HttpMethod.GET, PERMITTED_ENDPOINTS.keySet().stream().filter(k -> PERMITTED_ENDPOINTS.get(k).equals(HttpMethod.GET)).toArray(String[]::new)).permitAll()
                 .antMatchers(HttpMethod.POST, "/login").permitAll()
-                .antMatchers("/external-catalog-items").hasRole(Role.ADMIN.name())
+                .antMatchers(HttpMethod.POST, "/users", "/external-catalog-items").hasRole(Role.ADMIN.name())
                 .antMatchers(HttpMethod.PATCH, "/users/*/permissions", "/users/*/password").hasRole(Role.ADMIN.name())
                 .antMatchers(HttpMethod.DELETE, "/users/**").hasRole(Role.ADMIN.name())
                 .antMatchers(HttpMethod.GET, "/users").hasRole(Role.ADMIN.name())
-                .antMatchers(HttpMethod.GET, "/path").hasAuthority(Permission.READ.name())
-                .antMatchers(HttpMethod.POST, "/catalog-items").hasAuthority(Permission.WRITE.name())
-                .antMatchers(HttpMethod.PUT, "/catalog-items/*").hasAuthority(Permission.WRITE.name())
+                .antMatchers(HttpMethod.GET, "/path", "/external-catalog-items").hasAuthority(Permission.READ.name())
+                .antMatchers(HttpMethod.POST, "/catalog-items", "/catalog-items/batch").hasAuthority(Permission.WRITE.name())
                 .antMatchers(HttpMethod.DELETE, "/catalog-items/*").hasAuthority(Permission.DELETE.name())
-                .antMatchers(HttpMethod.POST, "/title-page").hasRole(Role.ADMIN.name())
+                .antMatchers(HttpMethod.POST, "/title-page", "/sources").hasRole(Role.ADMIN.name())
                 .anyRequest()
                 .authenticated();
     }
@@ -117,7 +116,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
      */
     @Bean
     public DaoAuthenticationProvider authenticationProvider() {
-        final DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
         provider.setUserDetailsService(userDetailsService);
         provider.setPasswordEncoder(bCryptPasswordEncoder);
         return provider;
@@ -125,9 +124,10 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
     @Bean
     CorsConfigurationSource corsConfigurationSource() {
-        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
         CorsConfiguration corsConfiguration = new CorsConfiguration().applyPermitDefaultValues();
-        corsConfiguration.setAllowedMethods(java.util.List.of(HttpMethod.GET.name(), HttpMethod.HEAD.name(), HttpMethod.POST.name(), HttpMethod.DELETE.name(), HttpMethod.PATCH.name(), HttpMethod.PUT.name()));
+        corsConfiguration.setAllowedMethods(List.of(HttpMethod.GET.name(), HttpMethod.HEAD.name(), HttpMethod.POST.name(),
+                HttpMethod.DELETE.name(), HttpMethod.PATCH.name(), HttpMethod.PUT.name()));
         source.registerCorsConfiguration("/**", corsConfiguration);
         return source;
     }
diff --git a/backend/src/main/java/cz/zcu/kiv/backendapi/user/UserServiceImpl.java b/backend/src/main/java/cz/zcu/kiv/backendapi/user/UserServiceImpl.java
index 006ef8f..f55ea43 100644
--- a/backend/src/main/java/cz/zcu/kiv/backendapi/user/UserServiceImpl.java
+++ b/backend/src/main/java/cz/zcu/kiv/backendapi/user/UserServiceImpl.java
@@ -66,6 +66,7 @@ public class UserServiceImpl implements IUserService, UserDetailsService {
 
     @Override
     public void registerNewUser(UserDto userDto) {
+        log.info("Registering new user");
         if (userRepository.findByEmail(userDto.getEmail()).isPresent()) {
             log.error("Trying to register new user with username that is already taken: " + userDto.getEmail());
             throw new ApiRequestException(String.format("User with username %s already exists", userDto.getEmail()), HttpStatus.CONFLICT);
@@ -73,10 +74,12 @@ public class UserServiceImpl implements IUserService, UserDetailsService {
         UserEntity userEntity = new UserEntity();
         convertDtoToEntity(userDto, userEntity);
         userRepository.save(userEntity);
+        log.info("New user registered");
     }
 
     @Override
     public void updatePermissions(String username, PermissionDto permissionDto) {
+        log.info("Updating permissions to user: " + username);
         UserEntity userEntity = userRepository.findByEmail(username).orElseThrow(() -> {
             log.error(String.format(USER_NOT_FOUND, username));
             throw new UsernameNotFoundException(String.format(USER_NOT_FOUND, username));
@@ -87,10 +90,12 @@ public class UserServiceImpl implements IUserService, UserDetailsService {
         }
         userEntity.setPermissions(getPermissionsFromDto(permissionDto));
         userRepository.save(userEntity);
+        log.info("Permissions to user " + username + " updated");
     }
 
     @Override
     public void resetPassword(String username, String newPassword) {
+        log.info("Resetting password to user " + username);
         if (username.equals(SUPER_ADMIN_NAME)) {
             log.error("Password for SUPER ADMIN can not be changed");
             throw new ApiRequestException("Password for SUPER ADMIN can not be changed", HttpStatus.BAD_REQUEST);
@@ -101,10 +106,12 @@ public class UserServiceImpl implements IUserService, UserDetailsService {
         });
         userEntity.setPassword(bCryptPasswordEncoder.encode(newPassword));
         userRepository.save(userEntity);
+        log.info("Password to user " + username + " reset");
     }
 
     @Override
     public void deleteUser(String username) {
+        log.info("Deleting user " + username);
         UserEntity userEntity = userRepository.findByEmail(username).orElseThrow(() -> {
             log.error(String.format(USER_NOT_FOUND, username));
             throw new UsernameNotFoundException(String.format(USER_NOT_FOUND, username));
@@ -114,6 +121,7 @@ public class UserServiceImpl implements IUserService, UserDetailsService {
             throw new ApiRequestException("User with ADMIN rights can not be deleted", HttpStatus.BAD_REQUEST);
         }
         userRepository.delete(userEntity);
+        log.info("User " + username + " deleted");
     }
 
     @Override
@@ -123,6 +131,7 @@ public class UserServiceImpl implements IUserService, UserDetailsService {
 
     @Override
     public void changePassword(String oldPassword, String newPassword) {
+        log.info("Changing password to logged user");
         UserEntity loggedUser = getUserByName((String) SecurityContextHolder.getContext().getAuthentication().getPrincipal());
         if (loggedUser.getEmail().equals(SUPER_ADMIN_NAME)) {
             throw new ApiRequestException("Can not change password for SUPER ADMIN", HttpStatus.BAD_REQUEST);
@@ -132,6 +141,7 @@ public class UserServiceImpl implements IUserService, UserDetailsService {
         }
         loggedUser.setPassword(bCryptPasswordEncoder.encode(newPassword));
         userRepository.save(loggedUser);
+        log.info("Password to logged user changed");
     }
 
 
diff --git a/backend/src/test/java/cz/zcu/kiv/backendapi/catalog/CatalogItemServiceImplTest.java b/backend/src/test/java/cz/zcu/kiv/backendapi/catalog/CatalogItemServiceImplTest.java
index 5802958..b26f655 100644
--- a/backend/src/test/java/cz/zcu/kiv/backendapi/catalog/CatalogItemServiceImplTest.java
+++ b/backend/src/test/java/cz/zcu/kiv/backendapi/catalog/CatalogItemServiceImplTest.java
@@ -59,6 +59,18 @@ class CatalogItemServiceImplTest {
         catalogItem.setLatitude(0.1);
         catalogItem.setLongitude(0.2);
 
+        CatalogItemDto catalogItemDto = new CatalogItemDto();
+        catalogItemDto.setId(catalogItem.getId());
+        catalogItemDto.setName("aaacbbbbbbbaa");
+        catalogItemDto.setBibliography(Stream.of("bibl").collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItemDto.setTypes(Stream.of(type.getType()).collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItemDto.setAllNames(Stream.of("altName").collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItemDto.setCountries(Stream.of("aaaabbaa").collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItemDto.setWrittenForms(Stream.of("written").collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItemDto.setCertainty(0);
+        catalogItemDto.setLatitude(0.1);
+        catalogItemDto.setLongitude(0.2);
+
         CatalogItem catalogItem2 = new CatalogItem();
         catalogItem2.setName("name");
         catalogItem2.setBibliography(Stream.of(new Bibliography("bibl", catalogItem2, 1)).collect(Collectors.toCollection(LinkedHashSet::new)));
@@ -70,12 +82,26 @@ class CatalogItemServiceImplTest {
         catalogItem2.setLatitude(1.1);
         catalogItem2.setLongitude(1.2);
 
-        List<CatalogItem> catalog = List.of(catalogItem, catalogItem2);
+        CatalogItemDto catalogItemDto2 = new CatalogItemDto();
+        catalogItemDto2.setId(catalogItem2.getId());
+        catalogItemDto2.setName("name");
+        catalogItemDto2.setBibliography(Stream.of("bibl").collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItemDto2.setTypes(Stream.of(type.getType()).collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItemDto2.setAllNames(Stream.of("aaaabbbbbbaa").collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItemDto2.setCountries(Stream.of("aaaabbcccefaa").collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItemDto2.setWrittenForms(Stream.of("written").collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItemDto2.setCertainty(1);
+        catalogItemDto2.setLatitude(1.1);
+        catalogItemDto2.setLongitude(1.2);
+
+        List<CatalogItemDto> catalog = List.of(catalogItemDto, catalogItemDto2);
 
         given(typeService.getTypeByName(anyString())).willReturn(Optional.of(type));
+        given(catalogItemRepository.findById(catalogItemDto.getId())).willReturn(Optional.of(catalogItem));
+        given(catalogItemRepository.findById(catalogItemDto2.getId())).willReturn(Optional.of(catalogItem2));
 
         // when
-        underTest.saveCatalog(catalog);
+        underTest.saveCatalogItems(catalog);
 
         // then
         verify(typeService, never()).saveType(type);
@@ -125,6 +151,7 @@ class CatalogItemServiceImplTest {
 
         CatalogItem capturedItem = argumentCaptor.getValue();
 
+        assertThat(capturedItem.getId()).isNotEqualTo(catalogItemDto.getId());
         assertThat(capturedItem.getName()).isEqualTo(catalogItem.getName());
         assertThat(capturedItem.getLongitude()).isEqualTo(catalogItem.getLongitude());
         assertThat(capturedItem.getLatitude()).isEqualTo(catalogItem.getLatitude());
@@ -139,43 +166,70 @@ class CatalogItemServiceImplTest {
     }
 
     @Test
-    void testCanGetCatalogItem() {
+    void testSaveCatalogItemIdNotPresent() {
         // given
-        UUID id = UUID.randomUUID();
-        CatalogItem catalogItem = new CatalogItem();
-        catalogItem.setId(id);
         CatalogItemDto catalogItemDto = new CatalogItemDto();
-        catalogItemDto.setId(id);
-        given(catalogItemRepository.findById(id)).willReturn(Optional.of(catalogItem));
+        catalogItemDto.setId(UUID.randomUUID());
+        catalogItemDto.setName("name");
+        catalogItemDto.setBibliography(Stream.of("bibl").collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItemDto.setTypes(Stream.of("type").collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItemDto.setAllNames(Stream.of("altName").collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItemDto.setCountries(Stream.of("country").collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItemDto.setWrittenForms(Stream.of("written").collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItemDto.setCertainty(0);
+        catalogItemDto.setLatitude(0.1);
+        catalogItemDto.setLongitude(0.2);
+        catalogItemDto.setDescription("description");
 
-        // when
-        CatalogItemDto retrievedItemDto = underTest.getCatalogItem(id);
+        Type type = new Type("type");
 
-        // then
-        verify(catalogItemRepository).findById(id);
-        assertThat(retrievedItemDto).isEqualTo(catalogItemDto);
-    }
+        CatalogItem catalogItem = new CatalogItem();
+        catalogItem.setName("name");
+        catalogItem.setBibliography(Stream.of(new Bibliography("bibl", catalogItem, 1)).collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItem.setTypes(Stream.of(type).collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItem.setAllNames(Stream.of(new CatalogItemName("altName", catalogItem, 1), new CatalogItemName("name", catalogItem, 2)).collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItem.setCountries(Stream.of(new Country("country", catalogItem, 1)).collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItem.setWrittenForms(Stream.of(new WrittenForm("written", catalogItem, 1)).collect(Collectors.toCollection(LinkedHashSet::new)));
+        catalogItem.setCertainty(0);
+        catalogItem.setLatitude(0.1);
+        catalogItem.setLongitude(0.2);
+        catalogItem.setDescription("description");
 
-    @Test
-    void testCanNotGetCatalogItem() {
-        // given
-        UUID id = UUID.randomUUID();
+        given(typeService.getTypeByName(anyString())).willReturn(Optional.of(type));
+        given(catalogItemRepository.findById(catalogItemDto.getId())).willReturn(Optional.empty());
 
         // when
+        underTest.saveCatalogItem(catalogItemDto);
+
         // then
-        assertThatThrownBy(() -> underTest.getCatalogItem(id))
-                .isInstanceOf(ApiRequestException.class)
-                .hasMessageContaining("Catalog item not found");
+        ArgumentCaptor<CatalogItem> argumentCaptor = ArgumentCaptor.forClass(CatalogItem.class);
+
+        verify(catalogItemRepository).save(argumentCaptor.capture());
+        verify(typeService, never()).saveType(type);
+
+        CatalogItem capturedItem = argumentCaptor.getValue();
+
+        assertThat(capturedItem.getId()).isNotEqualTo(catalogItemDto.getId());
+        assertThat(capturedItem.getName()).isEqualTo(catalogItem.getName());
+        assertThat(capturedItem.getLongitude()).isEqualTo(catalogItem.getLongitude());
+        assertThat(capturedItem.getLatitude()).isEqualTo(catalogItem.getLatitude());
+        assertThat(capturedItem.getCertainty()).isEqualTo(catalogItem.getCertainty());
+        assertThat(capturedItem.getAllNames().size()).isEqualTo(catalogItem.getAllNames().size());
+        assertThat(capturedItem.getBibliography().size()).isEqualTo(catalogItem.getBibliography().size());
+        assertThat(capturedItem.getCountries().size()).isEqualTo(catalogItem.getCountries().size());
+        assertThat(capturedItem.getWrittenForms().size()).isEqualTo(catalogItem.getWrittenForms().size());
+        assertThat(capturedItem.getTypes().size()).isEqualTo(catalogItem.getTypes().size());
+        assertThat(capturedItem.getDescription()).isEqualTo(catalogItem.getDescription());
 
-        verify(catalogItemRepository).findById(id);
     }
 
     @Test
-    void testCanUpdateCatalogItem() {
+    void testSaveCatalogItemIdPresent() {
         // given
         UUID id = UUID.randomUUID();
 
         CatalogItemDto catalogItemDto = new CatalogItemDto();
+        catalogItemDto.setId(id);
         catalogItemDto.setName("name");
         catalogItemDto.setBibliography(Stream.of("bibl").collect(Collectors.toCollection(LinkedHashSet::new)));
         catalogItemDto.setTypes(Stream.of("type").collect(Collectors.toCollection(LinkedHashSet::new)));
@@ -220,7 +274,7 @@ class CatalogItemServiceImplTest {
 
         // when
 
-        underTest.updateCatalogItem(id, catalogItemDto);
+        underTest.saveCatalogItem(catalogItemDto);
 
         // then
         verify(typeService).saveType(type);
@@ -245,30 +299,38 @@ class CatalogItemServiceImplTest {
         assertThat(capturedCatalogItem.getWrittenForms().stream().map(WrittenForm::getForm).collect(Collectors.toSet())).isEqualTo(catalogItem.getWrittenForms().stream().map(WrittenForm::getForm).collect(Collectors.toCollection(LinkedHashSet::new)));
     }
 
+
+
     @Test
-    void testCanNotUpdateCatalogItem() {
+    void testCanGetCatalogItem() {
         // given
         UUID id = UUID.randomUUID();
-
+        CatalogItem catalogItem = new CatalogItem();
+        catalogItem.setId(id);
         CatalogItemDto catalogItemDto = new CatalogItemDto();
-        catalogItemDto.setName("name");
-        catalogItemDto.setBibliography(Stream.of("bibl").collect(Collectors.toCollection(LinkedHashSet::new)));
-        catalogItemDto.setTypes(Stream.of("type").collect(Collectors.toCollection(LinkedHashSet::new)));
-        catalogItemDto.setAllNames(Stream.of("altName").collect(Collectors.toCollection(LinkedHashSet::new)));
-        catalogItemDto.setCountries(Stream.of("country").collect(Collectors.toCollection(LinkedHashSet::new)));
-        catalogItemDto.setWrittenForms(Stream.of("written").collect(Collectors.toCollection(LinkedHashSet::new)));
-        catalogItemDto.setCertainty(0);
-        catalogItemDto.setLatitude(0.1);
-        catalogItemDto.setLongitude(0.2);
+        catalogItemDto.setId(id);
+        given(catalogItemRepository.findById(id)).willReturn(Optional.of(catalogItem));
+
+        // when
+        CatalogItemDto retrievedItemDto = underTest.getCatalogItem(id);
+
+        // then
+        verify(catalogItemRepository).findById(id);
+        assertThat(retrievedItemDto).isEqualTo(catalogItemDto);
+    }
+
+    @Test
+    void testCanNotGetCatalogItem() {
+        // given
+        UUID id = UUID.randomUUID();
 
         // when
         // then
-        assertThatThrownBy(() -> underTest.updateCatalogItem(id, catalogItemDto))
+        assertThatThrownBy(() -> underTest.getCatalogItem(id))
                 .isInstanceOf(ApiRequestException.class)
                 .hasMessageContaining("Catalog item not found");
 
-        verify(catalogItemRepository, never()).save(any());
-        verify(typeService, never()).saveType(any());
+        verify(catalogItemRepository).findById(id);
     }
 
     @Test
