commit 39c320ad7d7ed9122e508edc50ed948037cc9580
Author: Jakub Smid <jaksmid@seznam.cz>
Date:   Thu Mar 17 21:30:35 2022 +0100

    Added Catalog function
     - catalog DTO
     - catalog controller
     - adding, deleting, updating catalog entries
     - getting all catalog entries
    re #9164

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
new file mode 100644
index 0000000..e2fee67
--- /dev/null
+++ b/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogController.java
@@ -0,0 +1,59 @@
+package cz.zcu.kiv.backendapi.catalog;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * Controller for catalog
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/catalog")
+public class CatalogController {
+
+    /**
+     * Catalog service
+     */
+    private final ICatalogService catalogService;
+
+    @PostMapping("")
+    public void addCatalogEntry(@RequestBody CatalogDto catalogDto) {
+        catalogService.saveCatalogEntry(catalogDto);
+    }
+
+    /**
+     * Returns catalog
+     *
+     * @return catalog
+     */
+    @GetMapping("")
+    public ResponseEntity<List<CatalogDto>> getAllUsers() {
+        return new ResponseEntity<>(catalogService.getCatalog(), HttpStatus.OK);
+    }
+
+    /**
+     * Updates catalog entry with given ID
+     *
+     * @param id         ID
+     * @param catalogDto catalog DTO
+     */
+    @PutMapping("/{id}")
+    public void updateCatalogEntry(@PathVariable UUID id, @RequestBody CatalogDto catalogDto) {
+        catalogService.updateCatalogEntry(id, catalogDto);
+    }
+
+    /**
+     * Deletes catalog entry with given ID
+     *
+     * @param id ID
+     */
+    @DeleteMapping("/{id}")
+    public void deleteCatalogEntry(@PathVariable UUID id) {
+        catalogService.deleteCatalogEntry(id);
+    }
+}
diff --git a/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogDto.java b/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogDto.java
new file mode 100644
index 0000000..6ae5cba
--- /dev/null
+++ b/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogDto.java
@@ -0,0 +1,64 @@
+package cz.zcu.kiv.backendapi.catalog;
+
+import lombok.Data;
+
+import java.util.Collections;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * Class representing catalog DTO
+ */
+@Data
+public class CatalogDto {
+    /**
+     * Id
+     */
+    private UUID id;
+
+    /**
+     * Name of geographic entry
+     */
+    private String name;
+
+    /**
+     * Certainty
+     */
+    private int certainty;
+
+    /**
+     * Longitude
+     */
+    private double longitude;
+
+    /**
+     * Latitude
+     */
+    private double latitude;
+
+    /**
+     * Bibliography
+     */
+    private Set<String> bibliography = Collections.emptySet();
+
+    /**
+     * Countries
+     */
+    private Set<String> countries = Collections.emptySet();
+
+    /**
+     * Written forms
+     */
+    private Set<String> writtenForms = Collections.emptySet();
+
+    /**
+     * Alternative names
+     */
+    private Set<String> alternativeNames = Collections.emptySet();
+
+    /**
+     * Types
+     */
+    private Set<String> types = Collections.emptySet();
+
+}
diff --git a/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogEntity.java b/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogEntity.java
index fccf530..af609bd 100644
--- a/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogEntity.java
+++ b/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogEntity.java
@@ -79,7 +79,7 @@ public class CatalogEntity {
     private Set<WrittenFormEntity> writtenForms;
 
     /**
-     * Alternative name
+     * Alternative names
      */
     @OneToMany(mappedBy = "catalog", cascade = CascadeType.ALL)
     @LazyCollection(LazyCollectionOption.FALSE)
@@ -104,33 +104,23 @@ public class CatalogEntity {
 
         this.name = csvFields.get(1);
         List<String> stringList = processListField(csvFields.get(2));
-        this.alternativeNames = new HashSet<>(stringList.size());
-        for (String s : stringList) {
-            this.alternativeNames.add(new AlternativeNameEntity(s, this));
-        }
+        this.alternativeNames = stringList.stream().map(s->new AlternativeNameEntity(s, this)).collect(Collectors.toSet());
+
         this.certainty = processIntField(csvFields.get(3));
         this.latitude = processDoubleField(csvFields.get(4));
         this.longitude = processDoubleField(csvFields.get(5));
+
         stringList = processListField(csvFields.get(6));
-        this.writtenForms = new HashSet<>(stringList.size());
-        for (String s : stringList) {
-            this.writtenForms.add(new WrittenFormEntity(s, this));
-        }
+        this.writtenForms = stringList.stream().map(s->new WrittenFormEntity(s, this)).collect(Collectors.toSet());
+
         stringList = processListField(csvFields.get(7));
-        this.types = new HashSet<>(stringList.size());
-        for (String s : stringList) {
-            this.types.add(new TypeEntity(s));
-        }
+        this.types = stringList.stream().map(TypeEntity::new).collect(Collectors.toSet());
+
         stringList = processListField(csvFields.get(8));
-        this.countries = new HashSet<>(stringList.size());
-        for (String s : stringList) {
-            this.countries.add(new CountryEntity(s, this));
-        }
+        this.countries = stringList.stream().map(s->new CountryEntity(s, this)).collect(Collectors.toSet());
+
         stringList = processListField(csvFields.get(10));
-        this.bibliography = new HashSet<>(stringList.size());
-        for (String s : stringList) {
-            this.bibliography.add(new BibliographyEntity(s, this));
-        }
+        this.bibliography = stringList.stream().map(s->new BibliographyEntity(s, this)).collect(Collectors.toSet());
     }
 
     private int processIntField(String field) {
diff --git a/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogRepository.java b/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogRepository.java
index b886f76..5d88524 100644
--- a/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogRepository.java
+++ b/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogRepository.java
@@ -6,6 +6,7 @@ import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
+import java.util.Set;
 import java.util.UUID;
 
 /**
@@ -22,4 +23,8 @@ public interface CatalogRepository extends JpaRepository<CatalogEntity, UUID> {
      */
     @Query("SELECT DISTINCT c FROM CatalogEntity c LEFT JOIN AlternativeNameEntity a ON c = a.catalog WHERE (?1 = c.name OR ?1 = a.name)")
     List<CatalogEntity> getCatalogEntitiesByName(String name);
+
+//    @Query("SELECT DISTINCT c FROM CatalogEntity c LEFT JOIN AlternativeNameEntity a ON c = a.catalog WHERE (?1 IS NULL OR ?1 = c.name OR ?1 = a.name)" +
+//            "LEFT JOIN TypeEntity e on c = e.catalog WHERE (?2 IS NULL OR e.)")
+//    Set<CatalogEntity> filterCatalog(String name, String type, String country);
 }
diff --git a/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogServiceImpl.java b/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogServiceImpl.java
index 51d3912..ff5de87 100644
--- a/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogServiceImpl.java
+++ b/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogServiceImpl.java
@@ -1,12 +1,20 @@
 package cz.zcu.kiv.backendapi.catalog;
 
+import cz.zcu.kiv.backendapi.alternativename.AlternativeNameEntity;
+import cz.zcu.kiv.backendapi.bibliography.BibliographyEntity;
+import cz.zcu.kiv.backendapi.country.CountryEntity;
 import cz.zcu.kiv.backendapi.type.TypeEntity;
 import cz.zcu.kiv.backendapi.type.ITypeService;
+import cz.zcu.kiv.backendapi.writtenform.WrittenFormEntity;
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
 
 /**
  * Catalog service implementation
@@ -14,24 +22,125 @@ import java.util.List;
 @Service
 @Transactional
 @RequiredArgsConstructor
+@Slf4j
 public class CatalogServiceImpl implements ICatalogService {
+    /**
+     * Message for exception when catalog entry is not found by id
+     */
+    private static final String CATALOG_ENTRY_NOT_FOUND = "Catalog entry not found";
     /**
      * Catalog repository
      */
     private final CatalogRepository catalogRepository;
 
+    /**
+     * Type service
+     */
     private final ITypeService typeService;
 
     @Override
     public void saveCatalog(List<CatalogEntity> catalogEntities) {
-        for (CatalogEntity catalogEntity : catalogEntities) {
-            for (TypeEntity type: catalogEntity.getTypes()                 ) {
+        log.info("Saving catalog");
+        catalogEntities.forEach(this::saveCatalogEntity);
+    }
+
+    @Override
+    public void saveCatalogEntry(CatalogDto catalogDto) {
+        log.info("Saving catalog entry");
+        CatalogEntity catalogEntity = new CatalogEntity();
+        convertDtoToEntity(catalogDto, catalogEntity);
+        saveCatalogEntity(catalogEntity);
+    }
+
+    @Override
+    public void updateCatalogEntry(UUID id, CatalogDto catalogDto) {
+        CatalogEntity catalogEntity = catalogRepository.findById(id).orElseThrow(() -> {
+            log.error(CATALOG_ENTRY_NOT_FOUND);
+            throw new UsernameNotFoundException(CATALOG_ENTRY_NOT_FOUND);
+        });
+        convertDtoToEntity(catalogDto, catalogEntity);
+        catalogRepository.save(catalogEntity);
+        log.info("Catalog entry updated");
+    }
+
+    @Override
+    public void deleteCatalogEntry(UUID id) {
+        CatalogEntity catalogEntity = catalogRepository.findById(id).orElseThrow(() -> {
+            log.error(CATALOG_ENTRY_NOT_FOUND);
+            throw new UsernameNotFoundException(CATALOG_ENTRY_NOT_FOUND);
+        });
+        catalogRepository.delete(catalogEntity);
+        log.info("Catalog entry deleted");
+    }
 
-                if (typeService.getTypeByName(type.getType()).isEmpty()){
-                    typeService.saveType(type);
-                }
+    @Override
+    public List<CatalogDto> getCatalog() {
+        log.info("Retrieving catalog");
+        List<CatalogEntity> entities = catalogRepository.findAll();
+        return entities.stream().map(this::convertEntityToDto).collect(Collectors.toList());
+    }
+
+    /**
+     * Saves catalog entity to database
+     *
+     * @param catalogEntity catalog entity
+     */
+    private void saveCatalogEntity(CatalogEntity catalogEntity) {
+        for (TypeEntity type : catalogEntity.getTypes()) {
+            if (typeService.getTypeByName(type.getType()).isEmpty()) {
+                typeService.saveType(type);
             }
         }
-        catalogRepository.saveAll(catalogEntities);
+        catalogRepository.save(catalogEntity);
+    }
+
+    /**
+     * Converts catalog DTO to catalog entity
+     *
+     * @param catalogDto    catalog DTO
+     * @param catalogEntity catalog entity
+     */
+    private void convertDtoToEntity(CatalogDto catalogDto, CatalogEntity catalogEntity) {
+        catalogEntity.setName(catalogDto.getName());
+        catalogEntity.setCertainty(catalogDto.getCertainty());
+        catalogEntity.setLatitude(catalogDto.getLatitude());
+        catalogEntity.setLongitude(catalogDto.getLongitude());
+        catalogEntity.setBibliography(catalogDto.getBibliography()
+                .stream().map(s -> new BibliographyEntity(s, catalogEntity)).collect(Collectors.toSet()));
+        catalogEntity.setTypes(catalogDto.getTypes()
+                .stream().map(TypeEntity::new).collect(Collectors.toSet()));
+        catalogEntity.setCountries(catalogDto.getCountries()
+                .stream().map(s -> new CountryEntity(s, catalogEntity)).collect(Collectors.toSet()));
+        catalogEntity.setAlternativeNames(catalogDto.getAlternativeNames()
+                .stream().map(s -> new AlternativeNameEntity(s, catalogEntity)).collect(Collectors.toSet()));
+        catalogEntity.setWrittenForms(catalogDto.getWrittenForms()
+                .stream().map(s -> new WrittenFormEntity(s, catalogEntity)).collect(Collectors.toSet()));
     }
+
+    /**
+     * Converts catalog entity to catalog DTO
+     *
+     * @param entity catalog entity
+     * @return catalog DTO
+     */
+    private CatalogDto convertEntityToDto(CatalogEntity entity) {
+        CatalogDto catalogDto = new CatalogDto();
+        catalogDto.setId(entity.getId());
+        catalogDto.setName(entity.getName());
+        catalogDto.setLatitude(entity.getLatitude());
+        catalogDto.setLongitude(entity.getLongitude());
+        catalogDto.setCertainty(entity.getCertainty());
+        catalogDto.setBibliography(entity.getBibliography()
+                .stream().map(BibliographyEntity::getSource).collect(Collectors.toSet()));
+        catalogDto.setTypes(entity.getTypes()
+                .stream().map(TypeEntity::getType).collect(Collectors.toSet()));
+        catalogDto.setCountries(entity.getCountries()
+                .stream().map(CountryEntity::getName).collect(Collectors.toSet()));
+        catalogDto.setAlternativeNames(entity.getAlternativeNames()
+                .stream().map(AlternativeNameEntity::getName).collect(Collectors.toSet()));
+        catalogDto.setWrittenForms(entity.getWrittenForms()
+                .stream().map(WrittenFormEntity::getForm).collect(Collectors.toSet()));
+        return catalogDto;
+    }
+
 }
diff --git a/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/ICatalogService.java b/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/ICatalogService.java
index c34864b..c479467 100644
--- a/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/ICatalogService.java
+++ b/backend/src/main/java/cz/zcu/kiv/backendapi/catalog/ICatalogService.java
@@ -1,10 +1,46 @@
 package cz.zcu.kiv.backendapi.catalog;
 
 import java.util.List;
+import java.util.UUID;
 
 /**
  * Catalog service interface
  */
 public interface ICatalogService {
+    /**
+     * Saves list of catalog entries
+     *
+     * @param catalogEntities catalog entris
+     */
     void saveCatalog(List<CatalogEntity> catalogEntities);
+
+    /**
+     * Saves one catalog entry
+     *
+     * @param catalogDto catalog DTO
+     */
+    void saveCatalogEntry(CatalogDto catalogDto);
+
+    /**
+     * Updates catalog entry with given ID
+     *
+     * @param id         ID
+     * @param catalogDto catalog DTO
+     */
+    void updateCatalogEntry(UUID id, CatalogDto catalogDto);
+
+    /**
+     * Deletes catalog entry with given ID
+     *
+     * @param id ID
+     */
+    void deleteCatalogEntry(UUID id);
+
+    /**
+     * Returns whole catalog
+     *
+     * @return catalog (as list of catalog entries)
+     */
+    List<CatalogDto> getCatalog();
+
 }
diff --git a/backend/src/main/java/cz/zcu/kiv/backendapi/exception/ApiExceptionHandler.java b/backend/src/main/java/cz/zcu/kiv/backendapi/exception/ApiExceptionHandler.java
index c749504..81303e8 100644
--- a/backend/src/main/java/cz/zcu/kiv/backendapi/exception/ApiExceptionHandler.java
+++ b/backend/src/main/java/cz/zcu/kiv/backendapi/exception/ApiExceptionHandler.java
@@ -43,4 +43,15 @@ public class ApiExceptionHandler {
     public ResponseEntity<Object> handleApiRequestException(ApiRequestException exception) {
         return new ResponseEntity<>(exception.getMessage(), exception.getHttpStatus());
     }
+
+    /**
+     * Handles illegal argument exception
+     *
+     * @param exception illegal argument exception
+     * @return response entity with message and status
+     */
+    @ExceptionHandler(value = {IllegalArgumentException.class})
+    public ResponseEntity<Object> handleIllegalArgumentException(IllegalArgumentException exception) {
+        return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
+    }
 }
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 9928ea9..2b70185 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
@@ -74,11 +74,6 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
                 .addFilterAfter(new JwtTokenVerifier(jwtUtils, permittedUrls), JwtUsernameAndPasswordAuthenticationFilter.class);
 
     }
-//    @Override
-//    public void configure(WebSecurity web) throws Exception {
-//        web.ignoring().antMatchers("/swagger-ui/**", "/v3/api-docs","/v3/api-docs/swagger-config", "/swagger-ui.html", "/swagger-ui-custom.html");
-//    }
-
 
     /**
      * Sets authentication provider to authentication manager
diff --git a/backend/src/main/java/cz/zcu/kiv/backendapi/user/IUserService.java b/backend/src/main/java/cz/zcu/kiv/backendapi/user/IUserService.java
index 100bbb5..0c8f245 100644
--- a/backend/src/main/java/cz/zcu/kiv/backendapi/user/IUserService.java
+++ b/backend/src/main/java/cz/zcu/kiv/backendapi/user/IUserService.java
@@ -15,11 +15,21 @@ public interface IUserService {
      */
     UserEntity getUserByName(String username);
 
+    /**
+     * Registers new user
+     *
+     * @param userDto user DTO
+     */
     void registerNewUser(UserDto userDto);
 
-    void updateUser(UserDto userDto);
+    void updateUser(String username, UserDto userDto);
 
     void deleteUser(String username);
 
+    /**
+     * Returns list of all users
+     *
+     * @return list of all users
+     */
     List<UserDto> getAllUsers();
 }
diff --git a/backend/src/main/java/cz/zcu/kiv/backendapi/user/UserController.java b/backend/src/main/java/cz/zcu/kiv/backendapi/user/UserController.java
index 1b3f69c..dd32942 100644
--- a/backend/src/main/java/cz/zcu/kiv/backendapi/user/UserController.java
+++ b/backend/src/main/java/cz/zcu/kiv/backendapi/user/UserController.java
@@ -66,14 +66,12 @@ public class UserController {
 
     //TODO check if need, if needed probably change new dto without email, comment otherwise
     @PutMapping("/user/{username}")
-    @ResponseStatus(value = HttpStatus.OK)
     public void updateUser(@PathVariable String username, @RequestBody @Valid UserDto userDto) {
-        userService.updateUser(userDto);
+        userService.updateUser(username, userDto);
     }
 
     //TODO check if needed, comment otherwise
     @DeleteMapping("/user/{username}")
-    @ResponseStatus(value = HttpStatus.OK)
     public void deleteUser(@PathVariable String username) {
         userService.deleteUser(username);
     }
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 9c864e2..64a075c 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
@@ -62,16 +62,17 @@ public class UserServiceImpl implements IUserService, UserDetailsService {
     }
 
     @Override
-    public void updateUser(UserDto userDto) {
-        UserEntity userEntity = userRepository.findByEmail(userDto.getEmail()).orElseThrow(() ->{
-            log.error(String.format(USER_NOT_FOUND, userDto.getEmail()));
-            throw new UsernameNotFoundException(String.format(USER_NOT_FOUND, userDto.getEmail()));
+    public void updateUser(String username, UserDto userDto) {
+        UserEntity userEntity = userRepository.findByEmail(username).orElseThrow(() ->{
+            log.error(String.format(USER_NOT_FOUND, username));
+            throw new UsernameNotFoundException(String.format(USER_NOT_FOUND, username));
         });
         convertDtoToEntity(userDto, userEntity);
+        userEntity.setEmail(username);
         userRepository.save(userEntity);
     }
 
-    //TODO maybe chceck if user is not deleting himself - or it might be ok
+    //TODO maybe check if user is not deleting himself - or it might be ok
     @Override
     public void deleteUser(String username) {
         UserEntity userEntity = userRepository.findByEmail(username).orElseThrow(() ->{
