Projekt

Obecné

Profil

« Předchozí | Další » 

Revize e111342b

Přidáno uživatelem Jakub Šmíd před více než 2 roky(ů)

Added JWT and permissions, changed project structure
- filters when authenticating - sends JWT
- filters per request - controls JWT
- added permission to user (READ, WRITE, DELETE)
- created package-by-feature from package-by-layer
re #9204

Zobrazit rozdíly:

backend/pom.xml
66 66
            <artifactId>commons-csv</artifactId>
67 67
            <version>1.9.0</version>
68 68
        </dependency>
69

  
70
        <dependency>
71
            <groupId>com.auth0</groupId>
72
            <artifactId>java-jwt</artifactId>
73
            <version>3.19.0</version>
74
        </dependency>
75

  
76
        <dependency>
77
            <groupId>com.google.guava</groupId>
78
            <artifactId>guava</artifactId>
79
            <version>31.1-jre</version>
80
        </dependency>
81

  
82
        <dependency>
83
            <groupId>org.springframework.boot</groupId>
84
            <artifactId>spring-boot-configuration-processor</artifactId>
85
            <version>2.4.2</version>
86
            <optional>true</optional>
87
        </dependency>
69 88
    </dependencies>
70 89

  
71 90
    <build>
backend/src/main/java/cz/zcu/kiv/backendapi/alternativename/AlternativeNameEntity.java
1
package cz.zcu.kiv.backendapi.alternativename;
2

  
3
import cz.zcu.kiv.backendapi.catalog.CatalogEntity;
4
import lombok.AllArgsConstructor;
5
import lombok.Data;
6
import lombok.NoArgsConstructor;
7

  
8
import javax.persistence.*;
9
import java.io.Serializable;
10

  
11
/**
12
 * Alternative name entity representing alternative name of geographic entry
13
 */
14
@Data
15
@NoArgsConstructor
16
@AllArgsConstructor
17
@Entity
18
@Table(name = "alternative_names")
19
@IdClass(AlternativeNameEntity.class)
20
public class AlternativeNameEntity implements Serializable {
21
    /**
22
     * Name, serves as ID
23
     */
24
    @Id
25
    private String name;
26

  
27
    /**
28
     * Catalog entity
29
     */
30
    @ManyToOne
31
    @JoinColumn(name = "catalog_id")
32
    @Id
33
    private CatalogEntity catalog;
34
}
backend/src/main/java/cz/zcu/kiv/backendapi/alternativename/AlternativeNameRepository.java
1
package cz.zcu.kiv.backendapi.alternativename;
2

  
3
import org.springframework.data.jpa.repository.JpaRepository;
4
import org.springframework.stereotype.Repository;
5
import org.springframework.transaction.annotation.Transactional;
6

  
7
/**
8
 * Alternative name repository
9
 */
10
@Repository
11
@Transactional(readOnly = true)
12
public interface AlternativeNameRepository extends JpaRepository<AlternativeNameEntity, AlternativeNameEntity> {
13
}
backend/src/main/java/cz/zcu/kiv/backendapi/alternativename/AlternativeNameServiceImpl.java
1
package cz.zcu.kiv.backendapi.alternativename;
2

  
3
import lombok.RequiredArgsConstructor;
4
import org.springframework.stereotype.Service;
5
import org.springframework.transaction.annotation.Transactional;
6

  
7
/**
8
 * Alternative name service implementation
9
 */
10
@Service
11
@Transactional
12
@RequiredArgsConstructor
13
public class AlternativeNameServiceImpl implements IAlternativeNameService {
14

  
15
    /**
16
     * Alternative name repository
17
     */
18
    private final AlternativeNameRepository alternativeNameRepository;
19
}
backend/src/main/java/cz/zcu/kiv/backendapi/alternativename/IAlternativeNameService.java
1
package cz.zcu.kiv.backendapi.alternativename;
2

  
3
/**
4
 * Alternative name service interface
5
 */
6
public interface IAlternativeNameService {
7
}
backend/src/main/java/cz/zcu/kiv/backendapi/bibliography/BibliographyEntity.java
1
package cz.zcu.kiv.backendapi.bibliography;
2

  
3
import cz.zcu.kiv.backendapi.catalog.CatalogEntity;
4
import lombok.AllArgsConstructor;
5
import lombok.Data;
6
import lombok.NoArgsConstructor;
7

  
8
import javax.persistence.*;
9
import java.io.Serializable;
10

  
11
/**
12
 * Bibliography entity representing bibliography
13
 */
14
@Data
15
@NoArgsConstructor
16
@AllArgsConstructor
17
@Entity
18
@Table(name = "bibliography")
19
@IdClass(BibliographyEntity.class)
20
public class BibliographyEntity implements Serializable {
21
    /**
22
     * Source, serves as ID
23
     */
24
    @Id
25
    private String source;
26

  
27
    @ManyToOne
28
    @JoinColumn(name = "catalog_id")
29
    private CatalogEntity catalog;
30
}
backend/src/main/java/cz/zcu/kiv/backendapi/bibliography/BibliographyRepository.java
1
package cz.zcu.kiv.backendapi.bibliography;
2

  
3
import org.springframework.data.jpa.repository.JpaRepository;
4
import org.springframework.stereotype.Repository;
5
import org.springframework.transaction.annotation.Transactional;
6

  
7
/**
8
 * Bibliography repository
9
 */
10
@Repository
11
@Transactional(readOnly = true)
12
public interface BibliographyRepository extends JpaRepository<BibliographyEntity, BibliographyEntity> {
13
}
backend/src/main/java/cz/zcu/kiv/backendapi/bibliography/BibliographyServiceImpl.java
1
package cz.zcu.kiv.backendapi.bibliography;
2

  
3
import lombok.RequiredArgsConstructor;
4
import org.springframework.stereotype.Service;
5
import org.springframework.transaction.annotation.Transactional;
6

  
7
/**
8
 * Bibliography service implementation
9
 */
10
@Service
11
@Transactional
12
@RequiredArgsConstructor
13
public class BibliographyServiceImpl implements IBibliographyService {
14
    /**
15
     * Bibliography repository
16
     */
17
    private final BibliographyRepository bibliographyRepository;
18
}
backend/src/main/java/cz/zcu/kiv/backendapi/bibliography/IBibliographyService.java
1
package cz.zcu.kiv.backendapi.bibliography;
2

  
3
/**
4
 * Bibliography service interface
5
 */
6
public interface IBibliographyService {
7
}
backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogEntity.java
1
package cz.zcu.kiv.backendapi.catalog;
2

  
3
import cz.zcu.kiv.backendapi.alternativename.AlternativeNameEntity;
4
import cz.zcu.kiv.backendapi.bibliography.BibliographyEntity;
5
import cz.zcu.kiv.backendapi.country.CountryEntity;
6
import cz.zcu.kiv.backendapi.type.TypeEntity;
7
import cz.zcu.kiv.backendapi.writtenform.WrittenFormEntity;
8
import lombok.Getter;
9
import lombok.NoArgsConstructor;
10
import lombok.Setter;
11
import org.hibernate.annotations.LazyCollection;
12
import org.hibernate.annotations.LazyCollectionOption;
13

  
14
import javax.persistence.*;
15
import java.util.*;
16
import java.util.regex.Matcher;
17
import java.util.regex.Pattern;
18
import java.util.stream.Collectors;
19

  
20
/**
21
 * Catalog entity representing catalog
22
 */
23
//@Data
24
@Getter
25
@Setter
26
@NoArgsConstructor
27
@Entity
28
@Table(name = "catalog")
29
public class CatalogEntity {
30
    private static final String INTEGER_PATTERN = "\\d+";
31
    private static final String DOUBLE_PATTERN = "(\\d+[.]\\d+)|(\\d+)";
32
    private static final String EMPTY_ENTRY = "–";
33
    /**
34
     * Catalog entry id
35
     */
36
    @Id
37
    @GeneratedValue
38
    private UUID id;
39

  
40
    /**
41
     * Name of geographic entry
42
     */
43
    private String name;
44

  
45
    /**
46
     * Certainty
47
     */
48
    private int certainty;
49

  
50
    /**
51
     * Longitude
52
     */
53
    private double longitude;
54

  
55
    /**
56
     * Latitude
57
     */
58
    private double latitude;
59

  
60
    /**
61
     * Bibliography
62
     */
63
    @OneToMany(mappedBy = "catalog", cascade = CascadeType.ALL)
64
    @LazyCollection(LazyCollectionOption.FALSE)
65
    private Set<BibliographyEntity> bibliography;
66

  
67
    /**
68
     * Countries
69
     */
70
    @OneToMany(mappedBy = "catalog", cascade = CascadeType.ALL)
71
    @LazyCollection(LazyCollectionOption.FALSE)
72
    private Set<CountryEntity> countries;
73

  
74
    /**
75
     * Written forms
76
     */
77
    @OneToMany(mappedBy = "catalog", cascade = CascadeType.ALL)
78
    @LazyCollection(LazyCollectionOption.FALSE)
79
    private Set<WrittenFormEntity> writtenForms;
80

  
81
    /**
82
     * Alternative name
83
     */
84
    @OneToMany(mappedBy = "catalog", cascade = CascadeType.ALL)
85
    @LazyCollection(LazyCollectionOption.FALSE)
86
    private Set<AlternativeNameEntity> alternativeNames;
87

  
88
    /**
89
     * Set of user roles - many-to-many relationship
90
     */
91
    @ManyToMany(fetch = FetchType.EAGER)
92
    @JoinTable(
93
            name = "catalog_type",
94
            joinColumns = {
95
                    @JoinColumn(name = "catalog_id", referencedColumnName = "id")
96
            },
97
            inverseJoinColumns = {
98
                    @JoinColumn(name = "type", referencedColumnName = "type")
99
            }
100
    )
101
    private Set<TypeEntity> types = Collections.emptySet();
102

  
103
    public CatalogEntity(final List<String> csvFields) {
104

  
105
        this.name = csvFields.get(1);
106
        List<String> stringList = processListField(csvFields.get(2));
107
        this.alternativeNames = new HashSet<>(stringList.size());
108
        for (String s : stringList) {
109
            this.alternativeNames.add(new AlternativeNameEntity(s, this));
110
        }
111
        this.certainty = processIntField(csvFields.get(3));
112
        this.latitude = processDoubleField(csvFields.get(4));
113
        this.longitude = processDoubleField(csvFields.get(5));
114
        stringList = processListField(csvFields.get(6));
115
        this.writtenForms = new HashSet<>(stringList.size());
116
        for (String s : stringList) {
117
            this.writtenForms.add(new WrittenFormEntity(s, this));
118
        }
119
        stringList = processListField(csvFields.get(7));
120
        this.types = new HashSet<>(stringList.size());
121
        for (String s : stringList) {
122
            this.types.add(new TypeEntity(s));
123
        }
124
        stringList = processListField(csvFields.get(8));
125
        this.countries = new HashSet<>(stringList.size());
126
        for (String s : stringList) {
127
            this.countries.add(new CountryEntity(s, this));
128
        }
129
        stringList = processListField(csvFields.get(10));
130
        this.bibliography = new HashSet<>(stringList.size());
131
        for (String s : stringList) {
132
            this.bibliography.add(new BibliographyEntity(s, this));
133
        }
134
    }
135

  
136
    private int processIntField(String field) {
137
        Matcher matcher = Pattern.compile(INTEGER_PATTERN).matcher(field);
138
        if (matcher.find()) {
139
            return Integer.parseInt(matcher.group());
140
        } else {
141
            return 0;
142
        }
143
    }
144

  
145
    private double processDoubleField(String field) {
146
        Matcher matcher = Pattern.compile(DOUBLE_PATTERN).matcher(field);
147
        if (matcher.find()) {
148
            return Double.parseDouble(matcher.group());
149
        } else {
150
            return 0.0;
151
        }
152
    }
153

  
154
    private List<String> processListField(String field) {
155
        if (field.isEmpty() || field.equals(EMPTY_ENTRY)) {
156
            return new ArrayList<>();
157
        }
158
        return Arrays.stream(field.split(",")).map(String::trim).filter(item -> !item.isEmpty()).collect(Collectors.toList());
159
    }
160
}
backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogRepository.java
1
package cz.zcu.kiv.backendapi.catalog;
2

  
3
import org.springframework.data.jpa.repository.JpaRepository;
4
import org.springframework.data.jpa.repository.Query;
5
import org.springframework.stereotype.Repository;
6
import org.springframework.transaction.annotation.Transactional;
7

  
8
import java.util.List;
9
import java.util.UUID;
10

  
11
/**
12
 * Catalog repository
13
 */
14
@Repository
15
@Transactional(readOnly = true)
16
public interface CatalogRepository extends JpaRepository<CatalogEntity, UUID> {
17

  
18
    /**
19
     * Selects all catalog entries with given name or where given name appears in alternative names
20
     * @param name name
21
     * @return list of catalog entries with given name / alternative name
22
     */
23
    @Query("SELECT DISTINCT c FROM CatalogEntity c LEFT JOIN AlternativeNameEntity a ON c = a.catalog WHERE (?1 = c.name OR ?1 = a.name)")
24
    List<CatalogEntity> getCatalogEntitiesByName(String name);
25
}
backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogServiceImpl.java
1
package cz.zcu.kiv.backendapi.catalog;
2

  
3
import cz.zcu.kiv.backendapi.type.TypeEntity;
4
import cz.zcu.kiv.backendapi.type.ITypeService;
5
import lombok.RequiredArgsConstructor;
6
import org.springframework.stereotype.Service;
7
import org.springframework.transaction.annotation.Transactional;
8

  
9
import java.util.List;
10

  
11
/**
12
 * Catalog service implementation
13
 */
14
@Service
15
@Transactional
16
@RequiredArgsConstructor
17
public class CatalogServiceImpl implements ICatalogService {
18
    /**
19
     * Catalog repository
20
     */
21
    private final CatalogRepository catalogRepository;
22

  
23
    private final ITypeService typeService;
24

  
25
    @Override
26
    public void saveCatalog(List<CatalogEntity> catalogEntities) {
27
        for (CatalogEntity catalogEntity : catalogEntities) {
28
            for (TypeEntity type: catalogEntity.getTypes()                 ) {
29

  
30
                if (typeService.getTypeByName(type.getType()).isEmpty()){
31
                    typeService.saveType(type);
32
                }
33
            }
34
        }
35
        catalogRepository.saveAll(catalogEntities);
36
    }
37
}
backend/src/main/java/cz/zcu/kiv/backendapi/catalog/ICatalogService.java
1
package cz.zcu.kiv.backendapi.catalog;
2

  
3
import java.util.List;
4

  
5
/**
6
 * Catalog service interface
7
 */
8
public interface ICatalogService {
9
    void saveCatalog(List<CatalogEntity> catalogEntities);
10
}
backend/src/main/java/cz/zcu/kiv/backendapi/config/DataInitiator.java
1 1
package cz.zcu.kiv.backendapi.config;
2 2

  
3
import cz.zcu.kiv.backendapi.model.CatalogEntity;
4
import cz.zcu.kiv.backendapi.service.catalog.ICatalogService;
3
import cz.zcu.kiv.backendapi.catalog.CatalogEntity;
4
import cz.zcu.kiv.backendapi.type.TypeEntity;
5
import cz.zcu.kiv.backendapi.catalog.CatalogRepository;
6
import cz.zcu.kiv.backendapi.catalog.ICatalogService;
7
import cz.zcu.kiv.backendapi.type.ITypeService;
8
import cz.zcu.kiv.backendapi.user.UserEntity;
9
import cz.zcu.kiv.backendapi.user.UserRepository;
5 10
import lombok.RequiredArgsConstructor;
6 11
import org.apache.commons.csv.CSVFormat;
7 12
import org.apache.commons.csv.CSVParser;
8 13
import org.apache.commons.csv.CSVRecord;
9 14
import org.springframework.context.ApplicationListener;
10 15
import org.springframework.context.event.ContextRefreshedEvent;
16
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
11 17
import org.springframework.stereotype.Component;
12 18
import org.springframework.transaction.annotation.Transactional;
13 19

  
14 20
import java.io.File;
15 21
import java.io.IOException;
22
import java.nio.charset.Charset;
16 23
import java.nio.charset.StandardCharsets;
17 24
import java.util.ArrayList;
18 25
import java.util.List;
......
24 31

  
25 32
    private final ICatalogService catalogService;
26 33

  
34
    private final ITypeService typeService;
35

  
36
    private final CatalogRepository catalogRepository;
37

  
38
    private final UserRepository userRepository;
39

  
40
    private final BCryptPasswordEncoder encoder;
41

  
27 42
    @Override
28 43
    @Transactional
29 44
    public void onApplicationEvent(ContextRefreshedEvent event) {
45
        List<TypeEntity> types = loadTypes();
46
        typeService.saveTypes(types);
30 47
        List<CatalogEntity> catalog = loadCatalog();
31 48
        catalogService.saveCatalog(catalog);
32 49

  
50
        UserEntity user1 = new UserEntity("admin", "admin", encoder.encode("password"), (byte) 7, true);
51
        userRepository.save(user1);
52

  
53
        UserEntity user2 = new UserEntity("normal", "normal", encoder.encode("password"), (byte) 1, false);
54
        userRepository.save(user2);
55

  
33 56
    }
34 57

  
35 58
    private List<CatalogEntity> loadCatalog() {
......
50 73
        return catalogEntities;
51 74

  
52 75
    }
76

  
77
    private List<TypeEntity> loadTypes() {
78
        List<TypeEntity> types = new ArrayList<>();
79
        CSVParser parser;
80
        File csvData = new File("AssyrianProject-All.csv");
81
        try {
82
            parser = CSVParser.parse(csvData, Charset.defaultCharset(), CSVFormat.DEFAULT.builder().setSkipHeaderRecord(true).build());
83
            for (CSVRecord csvRecord : parser) {
84
                if (csvRecord.get(0).equals("10000")) {
85
                    types.add(new TypeEntity(csvRecord.get(2)));
86
                }
87
            }
88
        } catch (IOException e) {
89
            e.printStackTrace();
90
        }
91
        return types;
92
    }
53 93
}
backend/src/main/java/cz/zcu/kiv/backendapi/country/CountryEntity.java
1
package cz.zcu.kiv.backendapi.country;
2

  
3
import cz.zcu.kiv.backendapi.catalog.CatalogEntity;
4
import lombok.AllArgsConstructor;
5
import lombok.Data;
6
import lombok.NoArgsConstructor;
7

  
8
import javax.persistence.*;
9
import java.io.Serializable;
10

  
11
/**
12
 * Country entity representing country of geographic entry
13
 */
14
@Data
15
@NoArgsConstructor
16
@AllArgsConstructor
17
@Entity
18
@Table(name = "countries")
19
@IdClass(CountryEntity.class)
20
public class CountryEntity implements Serializable {
21
    /**
22
     * Name of country, serves as ID
23
     */
24
    @Id
25
    private String name;
26

  
27
    @ManyToOne
28
    @JoinColumn(name = "catalog_id")
29
    @Id
30
    private CatalogEntity catalog;
31
}
backend/src/main/java/cz/zcu/kiv/backendapi/country/CountryRepository.java
1
package cz.zcu.kiv.backendapi.country;
2

  
3
import org.springframework.data.jpa.repository.JpaRepository;
4
import org.springframework.stereotype.Repository;
5
import org.springframework.transaction.annotation.Transactional;
6

  
7
/**
8
 * Country repository
9
 */
10
@Repository
11
@Transactional(readOnly = true)
12
public interface CountryRepository extends JpaRepository<CountryEntity, CountryEntity> {
13
}
backend/src/main/java/cz/zcu/kiv/backendapi/country/CountryServiceImpl.java
1
package cz.zcu.kiv.backendapi.country;
2

  
3
import lombok.RequiredArgsConstructor;
4
import org.springframework.stereotype.Service;
5
import org.springframework.transaction.annotation.Transactional;
6

  
7
/**
8
 * Country service implementation
9
 */
10
@Service
11
@Transactional
12
@RequiredArgsConstructor
13
public class CountryServiceImpl implements ICountryService {
14

  
15
    /**
16
     * Country repository
17
     */
18
    private final CountryRepository countryRepository;
19
}
backend/src/main/java/cz/zcu/kiv/backendapi/country/ICountryService.java
1
package cz.zcu.kiv.backendapi.country;
2

  
3
/**
4
 * Country service interface
5
 */
6
public interface ICountryService {
7
}
backend/src/main/java/cz/zcu/kiv/backendapi/exception/ApiExceptionHandler.java
1
package cz.zcu.kiv.backendapi.exception;
2

  
3

  
4
import org.springframework.http.ResponseEntity;
5
import org.springframework.web.bind.annotation.ControllerAdvice;
6
import org.springframework.web.bind.annotation.ExceptionHandler;
7

  
8
@ControllerAdvice
9
public class ApiExceptionHandler {
10

  
11
    @ExceptionHandler(value = {ApiRequestException.class})
12
    public ResponseEntity<Object> handleApiRequestException(ApiRequestException exception) {
13
        return new ResponseEntity<>(exception, exception.getHttpStatus());
14
    }
15
}
backend/src/main/java/cz/zcu/kiv/backendapi/exception/ApiRequestException.java
1
package cz.zcu.kiv.backendapi.exception;
2

  
3
import lombok.Getter;
4
import org.springframework.http.HttpStatus;
5

  
6
@Getter
7
public class ApiRequestException extends RuntimeException {
8
    private final HttpStatus httpStatus;
9

  
10
    public ApiRequestException(String message, HttpStatus httpStatus) {
11
        super(message);
12
        this.httpStatus = httpStatus;
13
    }
14

  
15
    public ApiRequestException(String message, Throwable cause, HttpStatus httpStatus) {
16
        super(message, cause);
17
        this.httpStatus = httpStatus;
18
    }
19
}
backend/src/main/java/cz/zcu/kiv/backendapi/model/AlternativeNameEntity.java
1
package cz.zcu.kiv.backendapi.model;
2

  
3
import lombok.AllArgsConstructor;
4
import lombok.Data;
5
import lombok.NoArgsConstructor;
6

  
7
import javax.persistence.*;
8
import java.io.Serializable;
9
import java.util.UUID;
10

  
11
/**
12
 * Alternative name entity representing alternative name of geographic entry
13
 */
14
@Data
15
@NoArgsConstructor
16
@AllArgsConstructor
17
@Entity
18
@Table(name = "alternative_names")
19
@IdClass(AlternativeNameEntity.class)
20
public class AlternativeNameEntity implements Serializable {
21
    /**
22
     * Name, serves as ID
23
     */
24
    @Id
25
    private String name;
26

  
27
    /**
28
     * Catalog entity
29
     */
30
    @ManyToOne
31
    @JoinColumn(name = "catalog_id")
32
    @Id
33
    private CatalogEntity catalog;
34
}
backend/src/main/java/cz/zcu/kiv/backendapi/model/BibliographyEntity.java
1
package cz.zcu.kiv.backendapi.model;
2

  
3
import lombok.AllArgsConstructor;
4
import lombok.Data;
5
import lombok.NoArgsConstructor;
6

  
7
import javax.persistence.*;
8
import java.io.Serializable;
9

  
10
/**
11
 * Bibliography entity representing bibliography
12
 */
13
@Data
14
@NoArgsConstructor
15
@AllArgsConstructor
16
@Entity
17
@Table(name = "bibliography")
18
@IdClass(BibliographyEntity.class)
19
public class BibliographyEntity implements Serializable {
20
    /**
21
     * Source, serves as ID
22
     */
23
    @Id
24
    private String source;
25

  
26
    @ManyToOne
27
    @JoinColumn(name = "catalog_id")
28
    private CatalogEntity catalog;
29
}
backend/src/main/java/cz/zcu/kiv/backendapi/model/CatalogEntity.java
1
package cz.zcu.kiv.backendapi.model;
2

  
3
import lombok.Data;
4
import lombok.Getter;
5
import lombok.NoArgsConstructor;
6
import lombok.Setter;
7
import org.hibernate.annotations.LazyCollection;
8
import org.hibernate.annotations.LazyCollectionOption;
9

  
10
import javax.persistence.*;
11
import java.util.*;
12
import java.util.regex.Matcher;
13
import java.util.regex.Pattern;
14
import java.util.stream.Collectors;
15

  
16
/**
17
 * Catalog entity representing catalog
18
 */
19
//@Data
20
@Getter
21
@Setter
22
@NoArgsConstructor
23
@Entity
24
@Table(name = "catalog")
25
public class CatalogEntity {
26
    private static final String INTEGER_PATTERN = "\\d+";
27
    private static final String DOUBLE_PATTERN = "(\\d+[.]\\d+)|(\\d+)";
28
    private static final String EMPTY_ENTRY = "–";
29
    /**
30
     * Catalog entry id
31
     */
32
    @Id
33
    @GeneratedValue
34
    private UUID id;
35

  
36
    /**
37
     * Name of geographic entry
38
     */
39
    private String name;
40

  
41
    /**
42
     * Certainty
43
     */
44
    private int certainty;
45

  
46
    /**
47
     * Longitude
48
     */
49
    private double longitude;
50

  
51
    /**
52
     * Latitude
53
     */
54
    private double latitude;
55

  
56
    /**
57
     * Bibliography
58
     */
59
    @OneToMany(mappedBy = "catalog", cascade = CascadeType.ALL)
60
    @LazyCollection(LazyCollectionOption.FALSE)
61
    private Set<BibliographyEntity> bibliography;
62

  
63
    /**
64
     * Countries
65
     */
66
    @OneToMany(mappedBy = "catalog", cascade = CascadeType.ALL)
67
    @LazyCollection(LazyCollectionOption.FALSE)
68
    private Set<CountryEntity> countries;
69

  
70
    /**
71
     * Written forms
72
     */
73
    @OneToMany(mappedBy = "catalog", cascade = CascadeType.ALL)
74
    @LazyCollection(LazyCollectionOption.FALSE)
75
    private Set<WrittenFormEntity> writtenForms;
76

  
77
    /**
78
     * Alternative name
79
     */
80
    @OneToMany(mappedBy = "catalog", cascade = CascadeType.ALL)
81
    @LazyCollection(LazyCollectionOption.FALSE)
82
    private Set<AlternativeNameEntity> alternativeNames;
83

  
84
    /**
85
     * Set of user roles - many-to-many relationship
86
     */
87
    @ManyToMany(fetch = FetchType.EAGER)
88
    @JoinTable(
89
            name = "catalog_type",
90
            joinColumns = {
91
                    @JoinColumn(name = "catalog_id", referencedColumnName = "id")
92
            },
93
            inverseJoinColumns = {
94
                    @JoinColumn(name = "type", referencedColumnName = "type")
95
            }
96
    )
97
    private Set<TypeEntity> types = Collections.emptySet();
98

  
99
    public CatalogEntity(final List<String> csvFields) {
100

  
101
        this.name = csvFields.get(1);
102
        List<String> stringList = processListField(csvFields.get(2));
103
        this.alternativeNames = new HashSet<>(stringList.size());
104
        for (String s : stringList) {
105
            this.alternativeNames.add(new AlternativeNameEntity(s, this));
106
        }
107
        this.certainty = processIntField(csvFields.get(3));
108
        this.latitude = processDoubleField(csvFields.get(4));
109
        this.longitude = processDoubleField(csvFields.get(5));
110
        stringList = processListField(csvFields.get(6));
111
        this.writtenForms = new HashSet<>(stringList.size());
112
        for (String s : stringList) {
113
            this.writtenForms.add(new WrittenFormEntity(s, this));
114
        }
115
        stringList = processListField(csvFields.get(7));
116
        this.types = new HashSet<>(stringList.size());
117
        for (String s : stringList) {
118
            this.types.add(new TypeEntity(s));
119
        }
120
        stringList = processListField(csvFields.get(8));
121
        this.countries = new HashSet<>(stringList.size());
122
        for (String s : stringList) {
123
            this.countries.add(new CountryEntity(s, this));
124
        }
125
        stringList = processListField(csvFields.get(10));
126
        this.bibliography = new HashSet<>(stringList.size());
127
        for (String s : stringList) {
128
            this.bibliography.add(new BibliographyEntity(s, this));
129
        }
130
    }
131

  
132
    private int processIntField(String field) {
133
        Matcher matcher = Pattern.compile(INTEGER_PATTERN).matcher(field);
134
        if (matcher.find()) {
135
            return Integer.parseInt(matcher.group());
136
        } else {
137
            return 0;
138
        }
139
    }
140

  
141
    private double processDoubleField(String field) {
142
        Matcher matcher = Pattern.compile(DOUBLE_PATTERN).matcher(field);
143
        if (matcher.find()) {
144
            return Double.parseDouble(matcher.group());
145
        } else {
146
            return 0.0;
147
        }
148
    }
149

  
150
    private List<String> processListField(String field) {
151
        if (field.isEmpty() || field.equals(EMPTY_ENTRY)) {
152
            return new ArrayList<>();
153
        }
154
        return Arrays.stream(field.split(",")).map(String::trim).collect(Collectors.toList());
155
    }
156
}
backend/src/main/java/cz/zcu/kiv/backendapi/model/CountryEntity.java
1
package cz.zcu.kiv.backendapi.model;
2

  
3
import lombok.AllArgsConstructor;
4
import lombok.Data;
5
import lombok.NoArgsConstructor;
6

  
7
import javax.persistence.*;
8
import java.io.Serializable;
9

  
10
/**
11
 * Country entity representing country of geographic entry
12
 */
13
@Data
14
@NoArgsConstructor
15
@AllArgsConstructor
16
@Entity
17
@Table(name = "countries")
18
@IdClass(CountryEntity.class)
19
public class CountryEntity implements Serializable {
20
    /**
21
     * Name of country, serves as ID
22
     */
23
    @Id
24
    private String name;
25

  
26
    @ManyToOne
27
    @JoinColumn(name = "catalog_id")
28
    @Id
29
    private CatalogEntity catalog;
30
}
backend/src/main/java/cz/zcu/kiv/backendapi/model/Role.java
1
package cz.zcu.kiv.backendapi.model;
2

  
3
import lombok.Getter;
4

  
5
/**
6
 * Enum for user roles
7
 */
8
@Getter
9
public enum Role {
10
    ADMIN("ROLE_ADMIN"),
11
    USER("ROLE_USER");
12

  
13
    /**
14
     * Role
15
     */
16
    private final String role;
17

  
18
    /**
19
     * Creates role
20
     *
21
     * @param role role
22
     */
23
    Role(final String role) {
24
        this.role = role;
25
    }
26
}
backend/src/main/java/cz/zcu/kiv/backendapi/model/TypeEntity.java
1
package cz.zcu.kiv.backendapi.model;
2

  
3
import lombok.AllArgsConstructor;
4
import lombok.Data;
5
import lombok.NoArgsConstructor;
6

  
7
import javax.persistence.Entity;
8
import javax.persistence.Id;
9
import javax.persistence.Table;
10

  
11
/**
12
 * Type entity representing type of geographic entry
13
 */
14
@Data
15
@NoArgsConstructor
16
@AllArgsConstructor
17
@Entity
18
@Table(name = "types")
19
public class TypeEntity {
20
    /**
21
     * Type (e.g. river), serves as ID
22
     */
23
    @Id
24
    private String type;
25
}
backend/src/main/java/cz/zcu/kiv/backendapi/model/UserEntity.java
1
package cz.zcu.kiv.backendapi.model;
2

  
3
import lombok.Data;
4
import lombok.NoArgsConstructor;
5
import org.hibernate.annotations.Type;
6
import org.springframework.security.core.GrantedAuthority;
7
import org.springframework.security.core.authority.SimpleGrantedAuthority;
8
import org.springframework.security.core.userdetails.UserDetails;
9

  
10
import javax.persistence.*;
11
import java.util.ArrayList;
12
import java.util.Collection;
13
import java.util.List;
14
import java.util.UUID;
15

  
16
/**
17
 * User entity representing application user
18
 */
19
@Data
20
@NoArgsConstructor
21
@Entity
22
@Table(name = "users")
23
public class UserEntity implements UserDetails {
24
    /**
25
     * Name
26
     */
27
    private String name;
28

  
29
    /**
30
     * Email - serves as username and must be unique - serves as Id
31
     */
32
    @Id
33
    private String email;
34

  
35
    /**
36
     * Password
37
     */
38
    private String password;
39

  
40
    /**
41
     * Whether the user is admin or not
42
     */
43
    @Column(name = "is_admin")
44
    @Type(type = "numeric_boolean")
45
    private boolean isAdmin;
46

  
47
    @Override
48
    public Collection<? extends GrantedAuthority> getAuthorities() {
49
        final List<GrantedAuthority> authorities = new ArrayList<>();
50
        if (isAdmin) {
51
            authorities.add(new SimpleGrantedAuthority(Role.ADMIN.getRole()));
52
        } else {
53
            authorities.add(new SimpleGrantedAuthority(Role.USER.getRole()));
54
        }
55

  
56
        return authorities;
57
    }
58

  
59
    public String getPassword() {
60
        return password;
61
    }
62

  
63
    @Override
64
    public String getUsername() {
65
        return email;
66
    }
67

  
68
    @Override
69
    public boolean isAccountNonExpired() {
70
        return true;
71
    }
72

  
73
    @Override
74
    public boolean isAccountNonLocked() {
75
        return true;
76
    }
77

  
78
    @Override
79
    public boolean isCredentialsNonExpired() {
80
        return true;
81
    }
82

  
83
    @Override
84
    public boolean isEnabled() {
85
        return true;
86
    }
87
}
backend/src/main/java/cz/zcu/kiv/backendapi/model/WrittenFormEntity.java
1
package cz.zcu.kiv.backendapi.model;
2

  
3
import lombok.AllArgsConstructor;
4
import lombok.Data;
5
import lombok.NoArgsConstructor;
6

  
7
import javax.persistence.*;
8
import java.io.Serializable;
9

  
10
/**
11
 * Written form entity representing written form of geographic entry
12
 */
13
@Data
14
@NoArgsConstructor
15
@AllArgsConstructor
16
@Entity
17
@Table(name = "written_forms")
18
@IdClass(WrittenFormEntity.class)
19
public class WrittenFormEntity implements Serializable {
20
    /**
21
     * Written form, serves as ID
22
     */
23
    @Id
24
    private String form;
25

  
26
    @ManyToOne
27
    @JoinColumn(name = "catalog_id")
28
    @Id
29
    private CatalogEntity catalog;
30
}
backend/src/main/java/cz/zcu/kiv/backendapi/repo/AlternativeNameRepository.java
1
package cz.zcu.kiv.backendapi.repo;
2

  
3
import cz.zcu.kiv.backendapi.model.AlternativeNameEntity;
4
import org.springframework.data.jpa.repository.JpaRepository;
5
import org.springframework.stereotype.Repository;
6
import org.springframework.transaction.annotation.Transactional;
7

  
8
/**
9
 * Alternative name repository
10
 */
11
@Repository
12
@Transactional(readOnly = true)
13
public interface AlternativeNameRepository extends JpaRepository<AlternativeNameEntity, AlternativeNameEntity> {
14
}
backend/src/main/java/cz/zcu/kiv/backendapi/repo/BibliographyRepository.java
1
package cz.zcu.kiv.backendapi.repo;
2

  
3
import cz.zcu.kiv.backendapi.model.BibliographyEntity;
4
import org.springframework.data.jpa.repository.JpaRepository;
5
import org.springframework.stereotype.Repository;
6
import org.springframework.transaction.annotation.Transactional;
7

  
8
/**
9
 * Bibliography repository
10
 */
11
@Repository
12
@Transactional(readOnly = true)
13
public interface BibliographyRepository extends JpaRepository<BibliographyEntity, BibliographyEntity> {
14
}
backend/src/main/java/cz/zcu/kiv/backendapi/repo/CatalogRepository.java
1
package cz.zcu.kiv.backendapi.repo;
2

  
3
import cz.zcu.kiv.backendapi.model.CatalogEntity;
4
import org.springframework.data.jpa.repository.JpaRepository;
5
import org.springframework.stereotype.Repository;
6
import org.springframework.transaction.annotation.Transactional;
7

  
8
import java.util.UUID;
9

  
10
/**
11
 * Catalog repository
12
 */
13
@Repository
14
@Transactional(readOnly = true)
15
public interface CatalogRepository extends JpaRepository<CatalogEntity, UUID> {
16
}
backend/src/main/java/cz/zcu/kiv/backendapi/repo/CountryRepository.java
1
package cz.zcu.kiv.backendapi.repo;
2

  
3
import cz.zcu.kiv.backendapi.model.CountryEntity;
4
import org.springframework.data.jpa.repository.JpaRepository;
5
import org.springframework.stereotype.Repository;
6
import org.springframework.transaction.annotation.Transactional;
7

  
8
/**
9
 * Country repository
10
 */
11
@Repository
12
@Transactional(readOnly = true)
13
public interface CountryRepository extends JpaRepository<CountryEntity, CountryEntity> {
14
}
backend/src/main/java/cz/zcu/kiv/backendapi/repo/TypeRepository.java
1
package cz.zcu.kiv.backendapi.repo;
2

  
3
import cz.zcu.kiv.backendapi.model.TypeEntity;
4
import org.springframework.data.jpa.repository.JpaRepository;
5
import org.springframework.stereotype.Repository;
6
import org.springframework.transaction.annotation.Transactional;
7

  
8

  
9
/**
10
 * Type repository
11
 */
12
@Repository
13
@Transactional(readOnly = true)
14
public interface TypeRepository extends JpaRepository<TypeEntity, String> {
15
}
backend/src/main/java/cz/zcu/kiv/backendapi/repo/UserRepository.java
1
package cz.zcu.kiv.backendapi.repo;
2

  
3
import cz.zcu.kiv.backendapi.model.UserEntity;
4
import org.springframework.data.jpa.repository.JpaRepository;
5
import org.springframework.stereotype.Repository;
6
import org.springframework.transaction.annotation.Transactional;
7

  
8

  
9
/**
10
 * User repository
11
 */
12
@Repository
13
@Transactional(readOnly = true)
14
public interface UserRepository extends JpaRepository<UserEntity, String> {
15
}
backend/src/main/java/cz/zcu/kiv/backendapi/repo/WrittenFormRepository.java
1
package cz.zcu.kiv.backendapi.repo;
2

  
3
import cz.zcu.kiv.backendapi.model.WrittenFormEntity;
4
import org.springframework.data.jpa.repository.JpaRepository;
5
import org.springframework.stereotype.Repository;
6
import org.springframework.transaction.annotation.Transactional;
7

  
8
/**
9
 * Written form repository
10
 */
11
@Repository
12
@Transactional(readOnly = true)
13
public interface WrittenFormRepository extends JpaRepository<WrittenFormEntity, WrittenFormEntity> {
14
}
backend/src/main/java/cz/zcu/kiv/backendapi/security/PasswordEncoder.java
1
package cz.zcu.kiv.backendapi.security;
2

  
3
import org.springframework.context.annotation.Bean;
4
import org.springframework.context.annotation.Configuration;
5
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
6

  
7
/**
8
 * Class representing password encoder
9
 */
10
@Configuration
11
public class PasswordEncoder {
12

  
13
    /**
14
     * Returns password encoder
15
     *
16
     * @return password encoder
17
     */
18
    @Bean
19
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
20
        return new BCryptPasswordEncoder();
21
    }
22

  
23
}
backend/src/main/java/cz/zcu/kiv/backendapi/security/SecurityConfig.java
1
package cz.zcu.kiv.backendapi.security;
2

  
3
import cz.zcu.kiv.backendapi.security.jwt.JwtUtils;
4
import cz.zcu.kiv.backendapi.security.jwt.JwtTokenVerifier;
5
import cz.zcu.kiv.backendapi.security.jwt.JwtUsernameAndPasswordAuthenticationFilter;
6
import cz.zcu.kiv.backendapi.user.Permission;
7
import cz.zcu.kiv.backendapi.user.Role;
8
import lombok.RequiredArgsConstructor;
9
import org.springframework.context.annotation.Bean;
10
import org.springframework.context.annotation.Configuration;
11
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
12
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
13
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
14
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
15
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
16
import org.springframework.security.config.http.SessionCreationPolicy;
17
import org.springframework.security.core.userdetails.UserDetailsService;
18
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
19

  
20
/**
21
 * Security config class
22
 */
23
@Configuration
24
@EnableWebSecurity
25
@RequiredArgsConstructor
26
public class SecurityConfig extends WebSecurityConfigurerAdapter {
27
    /**
28
     * User detail service
29
     */
30
    private final UserDetailsService userDetailsService;
31

  
32
    /**
33
     * Password encoder
34
     */
35
    private final BCryptPasswordEncoder bCryptPasswordEncoder;
36

  
37
    /**
38
     * JWT utils
39
     */
40
    private final JwtUtils jwtUtils;
41

  
42
    /**
43
     * List of permitted pages without login
44
     */
45
    private final String[] permittedUrls = new String[]{"/login", "/token/refresh"};
46

  
47
    /**
48
     * Security configuration
49
     *
50
     * @param http http security
51
     * @throws Exception exception
52
     */
53
    @Override
54
    protected void configure(HttpSecurity http) throws Exception {
55
        http.
56
                csrf().disable()
57
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
58
                .and()
59
                .authorizeRequests()
60
                .antMatchers("/login").permitAll()
61
                .antMatchers(permittedUrls).permitAll()
62
                .antMatchers("/admin/**").hasRole(Role.ADMIN.name())
63
                .antMatchers("/write/**").hasAuthority(Permission.WRITE.name())
64
                .antMatchers("/read/**").hasAuthority(Permission.READ.name())
65
                .antMatchers("/delete/**").hasAuthority(Permission.DELETE.name())
66
                .anyRequest()
67
                .authenticated()
68
                .and()
69
                .addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), jwtUtils))
70
                .addFilterAfter(new JwtTokenVerifier(jwtUtils, permittedUrls), JwtUsernameAndPasswordAuthenticationFilter.class);
71
    }
72

  
73
    /**
74
     * Sets authentication provider to authentication manager
75
     *
76
     * @param auth authentication manager builder
77
     */
78
    @Override
79
    protected void configure(final AuthenticationManagerBuilder auth) {
80
        auth.authenticationProvider(authenticationProvider());
81
    }
82

  
83

  
84
    /**
85
     * Returns authentication provider
86
     *
87
     * @return authentication provider
88
     */
89
    @Bean
90
    public DaoAuthenticationProvider authenticationProvider() {
91
        final DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
92
        provider.setUserDetailsService(userDetailsService);
93
        provider.setPasswordEncoder(bCryptPasswordEncoder);
94
        return provider;
95
    }
96

  
97
}
backend/src/main/java/cz/zcu/kiv/backendapi/security/jwt/JwtTokenVerifier.java
1
package cz.zcu.kiv.backendapi.security.jwt;
2

  
3
import com.auth0.jwt.JWT;
4
import com.auth0.jwt.JWTVerifier;
5
import com.auth0.jwt.algorithms.Algorithm;
6
import com.auth0.jwt.interfaces.DecodedJWT;
7
import com.google.common.base.Strings;
8
import lombok.RequiredArgsConstructor;
9
import lombok.extern.slf4j.Slf4j;
10
import org.springframework.http.HttpHeaders;
11
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
12
import org.springframework.security.core.authority.SimpleGrantedAuthority;
13
import org.springframework.security.core.context.SecurityContextHolder;
14
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
15
import org.springframework.web.filter.OncePerRequestFilter;
16

  
17
import javax.servlet.FilterChain;
18
import javax.servlet.ServletException;
19
import javax.servlet.http.HttpServletRequest;
20
import javax.servlet.http.HttpServletResponse;
21
import java.io.IOException;
22
import java.util.*;
23
import java.util.stream.Collectors;
24

  
25

  
26
/**
27
 * Class that verifies JWT per request
28
 */
29
@Slf4j
30
@RequiredArgsConstructor
31
public class JwtTokenVerifier extends OncePerRequestFilter {
32

  
33
    /**
34
     * JWT utils
35
     */
36
    private final JwtUtils jwtUtils;
37

  
38
    /**
39
     * Array or urls with this filter (JWT not needed for them)
40
     */
41
    private final String[] skipFilterUrls;
42

  
43
    /**
44
     * Filters request - checks for JWT token and validates it
45
     *
... Rozdílový soubor je zkrácen, protože jeho délka přesahuje max. limit.

Také k dispozici: Unified diff