Revize c7d2ced1
Přidáno uživatelem Václav Honzík před téměř 3 roky(ů)
.gitignore | ||
---|---|---|
1 |
.idea |
backend/src/main/java/cz/zcu/kiv/backendapi/BackendApiApplication.java | ||
---|---|---|
11 | 11 |
public static final Logger LOGGER = Logger.getLogger(BackendApiApplication.class.getName()); |
12 | 12 |
|
13 | 13 |
public static void main(String[] args) { |
14 |
LOGGER.info("Starting ..."); |
|
15 | 14 |
SpringApplication.run(BackendApiApplication.class, args); |
15 |
LOGGER.info("Swagger is running at: http://localhost:8080/swagger-ui.html"); |
|
16 | 16 |
} |
17 | 17 |
|
18 | 18 |
} |
backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogController.java | ||
---|---|---|
1 |
package cz.zcu.kiv.backendapi.catalog; |
|
2 |
|
|
3 |
import lombok.RequiredArgsConstructor; |
|
4 |
import org.springframework.http.HttpStatus; |
|
5 |
import org.springframework.http.ResponseEntity; |
|
6 |
import org.springframework.web.bind.annotation.*; |
|
7 |
|
|
8 |
import java.util.List; |
|
9 |
import java.util.UUID; |
|
10 |
|
|
11 |
/** |
|
12 |
* Controller for catalog |
|
13 |
*/ |
|
14 |
@RestController |
|
15 |
@RequiredArgsConstructor |
|
16 |
@RequestMapping("/catalog") |
|
17 |
public class CatalogController { |
|
18 |
|
|
19 |
/** |
|
20 |
* Catalog service |
|
21 |
*/ |
|
22 |
private final ICatalogService catalogService; |
|
23 |
|
|
24 |
@PostMapping("") |
|
25 |
public void addCatalogEntry(@RequestBody CatalogDto catalogDto) { |
|
26 |
catalogService.saveCatalogEntry(catalogDto); |
|
27 |
} |
|
28 |
|
|
29 |
/** |
|
30 |
* Returns catalog |
|
31 |
* |
|
32 |
* @return catalog |
|
33 |
*/ |
|
34 |
@GetMapping("") |
|
35 |
public ResponseEntity<List<CatalogDto>> getAllUsers() { |
|
36 |
return new ResponseEntity<>(catalogService.getCatalog(), HttpStatus.OK); |
|
37 |
} |
|
38 |
|
|
39 |
/** |
|
40 |
* Updates catalog entry with given ID |
|
41 |
* |
|
42 |
* @param id ID |
|
43 |
* @param catalogDto catalog DTO |
|
44 |
*/ |
|
45 |
@PutMapping("/{id}") |
|
46 |
public void updateCatalogEntry(@PathVariable UUID id, @RequestBody CatalogDto catalogDto) { |
|
47 |
catalogService.updateCatalogEntry(id, catalogDto); |
|
48 |
} |
|
49 |
|
|
50 |
/** |
|
51 |
* Deletes catalog entry with given ID |
|
52 |
* |
|
53 |
* @param id ID |
|
54 |
*/ |
|
55 |
@DeleteMapping("/{id}") |
|
56 |
public void deleteCatalogEntry(@PathVariable UUID id) { |
|
57 |
catalogService.deleteCatalogEntry(id); |
|
58 |
} |
|
59 |
} |
backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogDto.java | ||
---|---|---|
1 |
package cz.zcu.kiv.backendapi.catalog; |
|
2 |
|
|
3 |
import lombok.Data; |
|
4 |
|
|
5 |
import java.util.Collections; |
|
6 |
import java.util.Set; |
|
7 |
import java.util.UUID; |
|
8 |
|
|
9 |
/** |
|
10 |
* Class representing catalog DTO |
|
11 |
*/ |
|
12 |
@Data |
|
13 |
public class CatalogDto { |
|
14 |
/** |
|
15 |
* Id |
|
16 |
*/ |
|
17 |
private UUID id; |
|
18 |
|
|
19 |
/** |
|
20 |
* Name of geographic entry |
|
21 |
*/ |
|
22 |
private String name; |
|
23 |
|
|
24 |
/** |
|
25 |
* Certainty |
|
26 |
*/ |
|
27 |
private int certainty; |
|
28 |
|
|
29 |
/** |
|
30 |
* Longitude |
|
31 |
*/ |
|
32 |
private double longitude; |
|
33 |
|
|
34 |
/** |
|
35 |
* Latitude |
|
36 |
*/ |
|
37 |
private double latitude; |
|
38 |
|
|
39 |
/** |
|
40 |
* Bibliography |
|
41 |
*/ |
|
42 |
private Set<String> bibliography = Collections.emptySet(); |
|
43 |
|
|
44 |
/** |
|
45 |
* Countries |
|
46 |
*/ |
|
47 |
private Set<String> countries = Collections.emptySet(); |
|
48 |
|
|
49 |
/** |
|
50 |
* Written forms |
|
51 |
*/ |
|
52 |
private Set<String> writtenForms = Collections.emptySet(); |
|
53 |
|
|
54 |
/** |
|
55 |
* Alternative names |
|
56 |
*/ |
|
57 |
private Set<String> alternativeNames = Collections.emptySet(); |
|
58 |
|
|
59 |
/** |
|
60 |
* Types |
|
61 |
*/ |
|
62 |
private Set<String> types = Collections.emptySet(); |
|
63 |
|
|
64 |
} |
backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogEntity.java | ||
---|---|---|
79 | 79 |
private Set<WrittenFormEntity> writtenForms; |
80 | 80 |
|
81 | 81 |
/** |
82 |
* Alternative name |
|
82 |
* Alternative names
|
|
83 | 83 |
*/ |
84 | 84 |
@OneToMany(mappedBy = "catalog", cascade = CascadeType.ALL) |
85 | 85 |
@LazyCollection(LazyCollectionOption.FALSE) |
... | ... | |
104 | 104 |
|
105 | 105 |
this.name = csvFields.get(1); |
106 | 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 |
} |
|
107 |
this.alternativeNames = stringList.stream().map(s->new AlternativeNameEntity(s, this)).collect(Collectors.toSet()); |
|
108 |
|
|
111 | 109 |
this.certainty = processIntField(csvFields.get(3)); |
112 | 110 |
this.latitude = processDoubleField(csvFields.get(4)); |
113 | 111 |
this.longitude = processDoubleField(csvFields.get(5)); |
112 |
|
|
114 | 113 |
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 |
} |
|
114 |
this.writtenForms = stringList.stream().map(s->new WrittenFormEntity(s, this)).collect(Collectors.toSet()); |
|
115 |
|
|
119 | 116 |
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 |
} |
|
117 |
this.types = stringList.stream().map(TypeEntity::new).collect(Collectors.toSet()); |
|
118 |
|
|
124 | 119 |
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 |
} |
|
120 |
this.countries = stringList.stream().map(s->new CountryEntity(s, this)).collect(Collectors.toSet()); |
|
121 |
|
|
129 | 122 |
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 |
} |
|
123 |
this.bibliography = stringList.stream().map(s->new BibliographyEntity(s, this)).collect(Collectors.toSet()); |
|
134 | 124 |
} |
135 | 125 |
|
136 | 126 |
private int processIntField(String field) { |
backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogRepository.java | ||
---|---|---|
6 | 6 |
import org.springframework.transaction.annotation.Transactional; |
7 | 7 |
|
8 | 8 |
import java.util.List; |
9 |
import java.util.Set; |
|
9 | 10 |
import java.util.UUID; |
10 | 11 |
|
11 | 12 |
/** |
... | ... | |
22 | 23 |
*/ |
23 | 24 |
@Query("SELECT DISTINCT c FROM CatalogEntity c LEFT JOIN AlternativeNameEntity a ON c = a.catalog WHERE (?1 = c.name OR ?1 = a.name)") |
24 | 25 |
List<CatalogEntity> getCatalogEntitiesByName(String name); |
26 |
|
|
27 |
// @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)" + |
|
28 |
// "LEFT JOIN TypeEntity e on c = e.catalog WHERE (?2 IS NULL OR e.)") |
|
29 |
// Set<CatalogEntity> filterCatalog(String name, String type, String country); |
|
25 | 30 |
} |
backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogServiceImpl.java | ||
---|---|---|
1 | 1 |
package cz.zcu.kiv.backendapi.catalog; |
2 | 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; |
|
3 | 6 |
import cz.zcu.kiv.backendapi.type.TypeEntity; |
4 | 7 |
import cz.zcu.kiv.backendapi.type.ITypeService; |
8 |
import cz.zcu.kiv.backendapi.writtenform.WrittenFormEntity; |
|
5 | 9 |
import lombok.RequiredArgsConstructor; |
10 |
import lombok.extern.slf4j.Slf4j; |
|
11 |
import org.springframework.security.core.userdetails.UsernameNotFoundException; |
|
6 | 12 |
import org.springframework.stereotype.Service; |
7 | 13 |
import org.springframework.transaction.annotation.Transactional; |
8 | 14 |
|
9 | 15 |
import java.util.List; |
16 |
import java.util.UUID; |
|
17 |
import java.util.stream.Collectors; |
|
10 | 18 |
|
11 | 19 |
/** |
12 | 20 |
* Catalog service implementation |
... | ... | |
14 | 22 |
@Service |
15 | 23 |
@Transactional |
16 | 24 |
@RequiredArgsConstructor |
25 |
@Slf4j |
|
17 | 26 |
public class CatalogServiceImpl implements ICatalogService { |
27 |
/** |
|
28 |
* Message for exception when catalog entry is not found by id |
|
29 |
*/ |
|
30 |
private static final String CATALOG_ENTRY_NOT_FOUND = "Catalog entry not found"; |
|
18 | 31 |
/** |
19 | 32 |
* Catalog repository |
20 | 33 |
*/ |
21 | 34 |
private final CatalogRepository catalogRepository; |
22 | 35 |
|
36 |
/** |
|
37 |
* Type service |
|
38 |
*/ |
|
23 | 39 |
private final ITypeService typeService; |
24 | 40 |
|
25 | 41 |
@Override |
26 | 42 |
public void saveCatalog(List<CatalogEntity> catalogEntities) { |
27 |
for (CatalogEntity catalogEntity : catalogEntities) { |
|
28 |
for (TypeEntity type: catalogEntity.getTypes() ) { |
|
43 |
log.info("Saving catalog"); |
|
44 |
catalogEntities.forEach(this::saveCatalogEntity); |
|
45 |
} |
|
46 |
|
|
47 |
@Override |
|
48 |
public void saveCatalogEntry(CatalogDto catalogDto) { |
|
49 |
log.info("Saving catalog entry"); |
|
50 |
CatalogEntity catalogEntity = new CatalogEntity(); |
|
51 |
convertDtoToEntity(catalogDto, catalogEntity); |
|
52 |
saveCatalogEntity(catalogEntity); |
|
53 |
} |
|
54 |
|
|
55 |
@Override |
|
56 |
public void updateCatalogEntry(UUID id, CatalogDto catalogDto) { |
|
57 |
CatalogEntity catalogEntity = catalogRepository.findById(id).orElseThrow(() -> { |
|
58 |
log.error(CATALOG_ENTRY_NOT_FOUND); |
|
59 |
throw new UsernameNotFoundException(CATALOG_ENTRY_NOT_FOUND); |
|
60 |
}); |
|
61 |
convertDtoToEntity(catalogDto, catalogEntity); |
|
62 |
catalogRepository.save(catalogEntity); |
|
63 |
log.info("Catalog entry updated"); |
|
64 |
} |
|
65 |
|
|
66 |
@Override |
|
67 |
public void deleteCatalogEntry(UUID id) { |
|
68 |
CatalogEntity catalogEntity = catalogRepository.findById(id).orElseThrow(() -> { |
|
69 |
log.error(CATALOG_ENTRY_NOT_FOUND); |
|
70 |
throw new UsernameNotFoundException(CATALOG_ENTRY_NOT_FOUND); |
|
71 |
}); |
|
72 |
catalogRepository.delete(catalogEntity); |
|
73 |
log.info("Catalog entry deleted"); |
|
74 |
} |
|
29 | 75 |
|
30 |
if (typeService.getTypeByName(type.getType()).isEmpty()){ |
|
31 |
typeService.saveType(type); |
|
32 |
} |
|
76 |
@Override |
|
77 |
public List<CatalogDto> getCatalog() { |
|
78 |
log.info("Retrieving catalog"); |
|
79 |
List<CatalogEntity> entities = catalogRepository.findAll(); |
|
80 |
return entities.stream().map(this::convertEntityToDto).collect(Collectors.toList()); |
|
81 |
} |
|
82 |
|
|
83 |
/** |
|
84 |
* Saves catalog entity to database |
|
85 |
* |
|
86 |
* @param catalogEntity catalog entity |
|
87 |
*/ |
|
88 |
private void saveCatalogEntity(CatalogEntity catalogEntity) { |
|
89 |
for (TypeEntity type : catalogEntity.getTypes()) { |
|
90 |
if (typeService.getTypeByName(type.getType()).isEmpty()) { |
|
91 |
typeService.saveType(type); |
|
33 | 92 |
} |
34 | 93 |
} |
35 |
catalogRepository.saveAll(catalogEntities); |
|
94 |
catalogRepository.save(catalogEntity); |
|
95 |
} |
|
96 |
|
|
97 |
/** |
|
98 |
* Converts catalog DTO to catalog entity |
|
99 |
* |
|
100 |
* @param catalogDto catalog DTO |
|
101 |
* @param catalogEntity catalog entity |
|
102 |
*/ |
|
103 |
private void convertDtoToEntity(CatalogDto catalogDto, CatalogEntity catalogEntity) { |
|
104 |
catalogEntity.setName(catalogDto.getName()); |
|
105 |
catalogEntity.setCertainty(catalogDto.getCertainty()); |
|
106 |
catalogEntity.setLatitude(catalogDto.getLatitude()); |
|
107 |
catalogEntity.setLongitude(catalogDto.getLongitude()); |
|
108 |
catalogEntity.setBibliography(catalogDto.getBibliography() |
|
109 |
.stream().map(s -> new BibliographyEntity(s, catalogEntity)).collect(Collectors.toSet())); |
|
110 |
catalogEntity.setTypes(catalogDto.getTypes() |
|
111 |
.stream().map(TypeEntity::new).collect(Collectors.toSet())); |
|
112 |
catalogEntity.setCountries(catalogDto.getCountries() |
|
113 |
.stream().map(s -> new CountryEntity(s, catalogEntity)).collect(Collectors.toSet())); |
|
114 |
catalogEntity.setAlternativeNames(catalogDto.getAlternativeNames() |
|
115 |
.stream().map(s -> new AlternativeNameEntity(s, catalogEntity)).collect(Collectors.toSet())); |
|
116 |
catalogEntity.setWrittenForms(catalogDto.getWrittenForms() |
|
117 |
.stream().map(s -> new WrittenFormEntity(s, catalogEntity)).collect(Collectors.toSet())); |
|
36 | 118 |
} |
119 |
|
|
120 |
/** |
|
121 |
* Converts catalog entity to catalog DTO |
|
122 |
* |
|
123 |
* @param entity catalog entity |
|
124 |
* @return catalog DTO |
|
125 |
*/ |
|
126 |
private CatalogDto convertEntityToDto(CatalogEntity entity) { |
|
127 |
CatalogDto catalogDto = new CatalogDto(); |
|
128 |
catalogDto.setId(entity.getId()); |
|
129 |
catalogDto.setName(entity.getName()); |
|
130 |
catalogDto.setLatitude(entity.getLatitude()); |
|
131 |
catalogDto.setLongitude(entity.getLongitude()); |
|
132 |
catalogDto.setCertainty(entity.getCertainty()); |
|
133 |
catalogDto.setBibliography(entity.getBibliography() |
|
134 |
.stream().map(BibliographyEntity::getSource).collect(Collectors.toSet())); |
|
135 |
catalogDto.setTypes(entity.getTypes() |
|
136 |
.stream().map(TypeEntity::getType).collect(Collectors.toSet())); |
|
137 |
catalogDto.setCountries(entity.getCountries() |
|
138 |
.stream().map(CountryEntity::getName).collect(Collectors.toSet())); |
|
139 |
catalogDto.setAlternativeNames(entity.getAlternativeNames() |
|
140 |
.stream().map(AlternativeNameEntity::getName).collect(Collectors.toSet())); |
|
141 |
catalogDto.setWrittenForms(entity.getWrittenForms() |
|
142 |
.stream().map(WrittenFormEntity::getForm).collect(Collectors.toSet())); |
|
143 |
return catalogDto; |
|
144 |
} |
|
145 |
|
|
37 | 146 |
} |
backend/src/main/java/cz/zcu/kiv/backendapi/catalog/ICatalogService.java | ||
---|---|---|
1 | 1 |
package cz.zcu.kiv.backendapi.catalog; |
2 | 2 |
|
3 | 3 |
import java.util.List; |
4 |
import java.util.UUID; |
|
4 | 5 |
|
5 | 6 |
/** |
6 | 7 |
* Catalog service interface |
7 | 8 |
*/ |
8 | 9 |
public interface ICatalogService { |
10 |
/** |
|
11 |
* Saves list of catalog entries |
|
12 |
* |
|
13 |
* @param catalogEntities catalog entris |
|
14 |
*/ |
|
9 | 15 |
void saveCatalog(List<CatalogEntity> catalogEntities); |
16 |
|
|
17 |
/** |
|
18 |
* Saves one catalog entry |
|
19 |
* |
|
20 |
* @param catalogDto catalog DTO |
|
21 |
*/ |
|
22 |
void saveCatalogEntry(CatalogDto catalogDto); |
|
23 |
|
|
24 |
/** |
|
25 |
* Updates catalog entry with given ID |
|
26 |
* |
|
27 |
* @param id ID |
|
28 |
* @param catalogDto catalog DTO |
|
29 |
*/ |
|
30 |
void updateCatalogEntry(UUID id, CatalogDto catalogDto); |
|
31 |
|
|
32 |
/** |
|
33 |
* Deletes catalog entry with given ID |
|
34 |
* |
|
35 |
* @param id ID |
|
36 |
*/ |
|
37 |
void deleteCatalogEntry(UUID id); |
|
38 |
|
|
39 |
/** |
|
40 |
* Returns whole catalog |
|
41 |
* |
|
42 |
* @return catalog (as list of catalog entries) |
|
43 |
*/ |
|
44 |
List<CatalogDto> getCatalog(); |
|
45 |
|
|
10 | 46 |
} |
backend/src/main/java/cz/zcu/kiv/backendapi/exception/ApiExceptionHandler.java | ||
---|---|---|
43 | 43 |
public ResponseEntity<Object> handleApiRequestException(ApiRequestException exception) { |
44 | 44 |
return new ResponseEntity<>(exception.getMessage(), exception.getHttpStatus()); |
45 | 45 |
} |
46 |
|
|
47 |
/** |
|
48 |
* Handles illegal argument exception |
|
49 |
* |
|
50 |
* @param exception illegal argument exception |
|
51 |
* @return response entity with message and status |
|
52 |
*/ |
|
53 |
@ExceptionHandler(value = {IllegalArgumentException.class}) |
|
54 |
public ResponseEntity<Object> handleIllegalArgumentException(IllegalArgumentException exception) { |
|
55 |
return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST); |
|
56 |
} |
|
46 | 57 |
} |
backend/src/main/java/cz/zcu/kiv/backendapi/security/SecurityConfig.java | ||
---|---|---|
74 | 74 |
.addFilterAfter(new JwtTokenVerifier(jwtUtils, permittedUrls), JwtUsernameAndPasswordAuthenticationFilter.class); |
75 | 75 |
|
76 | 76 |
} |
77 |
// @Override |
|
78 |
// public void configure(WebSecurity web) throws Exception { |
|
79 |
// web.ignoring().antMatchers("/swagger-ui/**", "/v3/api-docs","/v3/api-docs/swagger-config", "/swagger-ui.html", "/swagger-ui-custom.html"); |
|
80 |
// } |
|
81 |
|
|
82 | 77 |
|
83 | 78 |
/** |
84 | 79 |
* Sets authentication provider to authentication manager |
backend/src/main/java/cz/zcu/kiv/backendapi/user/IUserService.java | ||
---|---|---|
15 | 15 |
*/ |
16 | 16 |
UserEntity getUserByName(String username); |
17 | 17 |
|
18 |
/** |
|
19 |
* Registers new user |
|
20 |
* |
|
21 |
* @param userDto user DTO |
|
22 |
*/ |
|
18 | 23 |
void registerNewUser(UserDto userDto); |
19 | 24 |
|
20 |
void updateUser(UserDto userDto); |
|
25 |
void updateUser(String username, UserDto userDto);
|
|
21 | 26 |
|
22 | 27 |
void deleteUser(String username); |
23 | 28 |
|
29 |
/** |
|
30 |
* Returns list of all users |
|
31 |
* |
|
32 |
* @return list of all users |
|
33 |
*/ |
|
24 | 34 |
List<UserDto> getAllUsers(); |
25 | 35 |
} |
backend/src/main/java/cz/zcu/kiv/backendapi/user/UserController.java | ||
---|---|---|
66 | 66 |
|
67 | 67 |
//TODO check if need, if needed probably change new dto without email, comment otherwise |
68 | 68 |
@PutMapping("/user/{username}") |
69 |
@ResponseStatus(value = HttpStatus.OK) |
|
70 | 69 |
public void updateUser(@PathVariable String username, @RequestBody @Valid UserDto userDto) { |
71 |
userService.updateUser(userDto); |
|
70 |
userService.updateUser(username, userDto);
|
|
72 | 71 |
} |
73 | 72 |
|
74 | 73 |
//TODO check if needed, comment otherwise |
75 | 74 |
@DeleteMapping("/user/{username}") |
76 |
@ResponseStatus(value = HttpStatus.OK) |
|
77 | 75 |
public void deleteUser(@PathVariable String username) { |
78 | 76 |
userService.deleteUser(username); |
79 | 77 |
} |
backend/src/main/java/cz/zcu/kiv/backendapi/user/UserServiceImpl.java | ||
---|---|---|
62 | 62 |
} |
63 | 63 |
|
64 | 64 |
@Override |
65 |
public void updateUser(UserDto userDto) { |
|
66 |
UserEntity userEntity = userRepository.findByEmail(userDto.getEmail()).orElseThrow(() ->{
|
|
67 |
log.error(String.format(USER_NOT_FOUND, userDto.getEmail()));
|
|
68 |
throw new UsernameNotFoundException(String.format(USER_NOT_FOUND, userDto.getEmail()));
|
|
65 |
public void updateUser(String username, UserDto userDto) {
|
|
66 |
UserEntity userEntity = userRepository.findByEmail(username).orElseThrow(() ->{
|
|
67 |
log.error(String.format(USER_NOT_FOUND, username));
|
|
68 |
throw new UsernameNotFoundException(String.format(USER_NOT_FOUND, username));
|
|
69 | 69 |
}); |
70 | 70 |
convertDtoToEntity(userDto, userEntity); |
71 |
userEntity.setEmail(username); |
|
71 | 72 |
userRepository.save(userEntity); |
72 | 73 |
} |
73 | 74 |
|
74 |
//TODO maybe chceck if user is not deleting himself - or it might be ok
|
|
75 |
//TODO maybe check if user is not deleting himself - or it might be ok |
|
75 | 76 |
@Override |
76 | 77 |
public void deleteUser(String username) { |
77 | 78 |
UserEntity userEntity = userRepository.findByEmail(username).orElseThrow(() ->{ |
frontend/package.json | ||
---|---|---|
1 | 1 |
{ |
2 | 2 |
"name": "frontend", |
3 |
"type": "module", |
|
3 | 4 |
"version": "0.1.0", |
4 | 5 |
"private": true, |
5 | 6 |
"dependencies": { |
7 |
"@emotion/react": "^11.8.2", |
|
8 |
"@emotion/styled": "^11.8.1", |
|
9 |
"@mui/material": "^5.5.1", |
|
6 | 10 |
"@testing-library/jest-dom": "^5.14.1", |
7 | 11 |
"@testing-library/react": "^12.0.0", |
8 | 12 |
"@testing-library/user-event": "^13.2.1", |
... | ... | |
12 | 16 |
"@types/react-dom": "^17.0.9", |
13 | 17 |
"axios": "^0.26.0", |
14 | 18 |
"dotenv": "^16.0.0", |
19 |
"formik": "^2.2.9", |
|
15 | 20 |
"react": "^17.0.2", |
16 | 21 |
"react-dom": "^17.0.2", |
22 |
"react-router-dom": "^6.2.2", |
|
17 | 23 |
"react-scripts": "5.0.0", |
24 |
"swagger-typescript-api": "^9.3.1", |
|
25 |
"ts-node": "^10.7.0", |
|
18 | 26 |
"typescript": "^4.4.2", |
19 | 27 |
"web-vitals": "^2.1.0" |
20 | 28 |
}, |
21 | 29 |
"scripts": { |
22 | 30 |
"start": "react-scripts start", |
23 |
"build": "react-scripts build", |
|
31 |
"build": "react-scripts build && yarn run gen:swagger",
|
|
24 | 32 |
"test": "react-scripts test", |
25 |
"eject": "react-scripts eject" |
|
33 |
"eject": "react-scripts eject", |
|
34 |
"gen:swagger": "swagger-typescript-api -p http://localhost:8080/v3/api-docs -o ./src/swagger --modular" |
|
26 | 35 |
}, |
27 | 36 |
"eslintConfig": { |
28 | 37 |
"extends": [ |
frontend/src/.env | ||
---|---|---|
1 |
REACT_APP_API_BASE_URL=http://localhost:8080 |
frontend/src/App.test.tsx | ||
---|---|---|
1 |
import React from 'react'; |
|
2 |
import { render, screen } from '@testing-library/react'; |
|
3 |
import App from './App'; |
|
4 |
|
|
5 |
test('renders learn react link', () => { |
|
6 |
render(<App />); |
|
7 |
const linkElement = screen.getByText(/learn react/i); |
|
8 |
expect(linkElement).toBeInTheDocument(); |
|
9 |
}); |
frontend/src/App.tsx | ||
---|---|---|
1 |
import React from 'react'; |
|
2 |
import './App.css'; |
|
3 |
import StubComponent from './components/StubComponent' |
|
1 |
import React from 'react' |
|
2 |
import './App.css' |
|
3 |
import { Routes, Route, Link } from 'react-router-dom' |
|
4 |
import Home from './features/Home/Home' |
|
5 |
import Catalog from './features/Catalog/Catalog' |
|
6 |
import NotFound from './features/NotFound/NotFound' |
|
4 | 7 |
|
5 |
function App() { |
|
6 |
return ( |
|
8 |
const App = () => ( |
|
7 | 9 |
<div className="App"> |
8 |
<StubComponent /> |
|
10 |
<nav> |
|
11 |
<Link to="/">Home</Link> |
|
12 |
<Link to="/catalog">Catalog</Link> |
|
13 |
</nav> |
|
14 |
<Routes> |
|
15 |
<Route path="/" element={ <Home /> } /> |
|
16 |
<Route path="/catalog" element={ <Catalog /> } /> |
|
17 |
<Route path="*" element={ <NotFound /> } /> |
|
18 |
</Routes> |
|
9 | 19 |
</div> |
10 |
); |
|
11 |
} |
|
20 |
) |
|
12 | 21 |
|
13 |
export default App; |
|
22 |
export default App |
frontend/src/api/axios.ts | ||
---|---|---|
1 |
import axios from 'axios' |
|
2 |
import Config from '../config/Config' |
|
3 |
|
|
4 |
export default axios.create({ |
|
5 |
baseURL: Config.baseUrl, |
|
6 |
|
|
7 |
}) |
|
8 |
|
frontend/src/api/axiosInstance.ts | ||
---|---|---|
1 |
import axios from 'axios' |
|
2 |
import { Store } from 'redux' |
|
3 |
import config from '../config/conf' |
|
4 |
import { AppStore } from '../features/redux/store' |
|
5 |
|
|
6 |
let store: AppStore // this will get injected later |
|
7 |
|
|
8 |
export const injectStore = (_store: Store) => { |
|
9 |
store = _store |
|
10 |
} |
|
11 |
|
|
12 |
const axiosInstance = axios.create({ |
|
13 |
baseURL: config.baseUrl, |
|
14 |
}) |
|
15 |
|
|
16 |
axiosInstance.interceptors.request.use(config => { |
|
17 |
config.headers = { |
|
18 |
...config.headers, |
|
19 |
Authorization: store.getState().auth.token |
|
20 |
} |
|
21 |
}) |
|
22 |
|
|
23 |
axiosInstance.interceptors.response.use(response => response, error => { |
|
24 |
|
|
25 |
if (error?.response?.status === 401) { |
|
26 |
const refreshToken = store.getState().auth.refreshToken |
|
27 |
// TODO send the refresh token correctly |
|
28 |
console.log('401 called they want their token refreshed'); |
|
29 |
} |
|
30 |
|
|
31 |
}) |
|
32 |
|
|
33 |
export default axiosInstance |
frontend/src/components/StubComponent.tsx | ||
---|---|---|
1 |
// Example component that connects to the backend API and fetches dummy data |
|
2 |
|
|
3 |
import { useState } from 'react' |
|
4 |
import AxiosClient from '../services/AxiosClient' |
|
5 |
|
|
6 |
const StubComponent = () => { |
|
7 |
|
|
8 |
const [text, setText] = useState<string>('') |
|
9 |
|
|
10 |
// Sends api request to the backend |
|
11 |
const fetchStub = async () => { |
|
12 |
try { |
|
13 |
const { data } = await AxiosClient.get('/stub') |
|
14 |
if (!!data && data.success) { |
|
15 |
setText(data.message as string) |
|
16 |
} |
|
17 |
} |
|
18 |
catch (err) { |
|
19 |
console.log(`An error has occurred: ${err}`) |
|
20 |
} |
|
21 |
} |
|
22 |
|
|
23 |
return ( |
|
24 |
<> |
|
25 |
<h1>Welcome to the internet</h1> |
|
26 |
<p>Click the button to fetch the message</p> |
|
27 |
<p>The message: {text}</p> |
|
28 |
<button onClick={fetchStub}>Fetch the message</button> |
|
29 |
</> |
|
30 |
) |
|
31 |
|
|
32 |
} |
|
33 |
|
|
34 |
export default StubComponent |
frontend/src/config/Config.ts | ||
---|---|---|
1 |
|
|
2 |
export default { |
|
1 |
const Config = { |
|
3 | 2 |
baseUrl: process.env.REACT_APP_API_BASE_URL || 'http://localhost:8080' |
4 |
} |
|
3 |
} |
|
4 |
|
|
5 |
export default Config |
frontend/src/config/conf.ts | ||
---|---|---|
1 |
export default { |
|
2 |
baseUrl: process.env.REACT_APP_API_BASE_URL || 'http://localhost:8080' |
|
3 |
} |
frontend/src/features/Auth/AuthService.ts | ||
---|---|---|
1 |
import axios from "../../api/axios" |
|
2 |
import { UserDto } from "../../swagger/data-contracts" |
|
3 |
import ApiCallError from "../../utils/ApiCallError" |
|
4 |
|
|
5 |
export const getAccessToken = () => localStorage.getItem('accessToken') as string | null |
|
6 |
export const getRefreshToken = () => localStorage.getItem('refreshToken') as string | null |
|
7 |
|
|
8 |
export const setAccessToken = (accessToken: string) => localStorage.setItem('accessToken', accessToken) |
|
9 |
export const setRefreshToken = (refreshToken: string) => localStorage.setItem('refreshToken', refreshToken) |
|
10 |
|
|
11 |
|
|
12 |
export const sendRegisterRequest = (userDto: UserDto) => { |
|
13 |
|
|
14 |
} |
|
15 |
|
|
16 |
export const sendLoginRequest = async (username: string, password: string, setLoggedInState: (loggedIn: boolean) => void) => { |
|
17 |
try { |
|
18 |
const { data } = await axios.post('/login', {username, password}) |
|
19 |
|
|
20 |
if (!data) { |
|
21 |
throw new ApiCallError("An authentication error has occurred. Please try again later") |
|
22 |
} |
|
23 |
|
|
24 |
// TODO - set state as logged in |
|
25 |
const { accessToken, refreshToken } = data |
|
26 |
setAccessToken(accessToken) |
|
27 |
setRefreshToken(refreshToken) |
|
28 |
setLoggedInState(true) |
|
29 |
} |
|
30 |
catch (err) { |
|
31 |
|
|
32 |
} |
|
33 |
} |
frontend/src/features/Auth/Login.tsx | ||
---|---|---|
1 |
|
|
2 |
const Login = () => { |
|
3 |
|
|
4 |
return ( |
|
5 |
<> |
|
6 |
|
|
7 |
</> |
|
8 |
) |
|
9 |
} |
|
10 |
|
|
11 |
export default Login |
frontend/src/features/Auth/authReducer.ts | ||
---|---|---|
1 |
import { AnyAction } from 'redux' |
|
2 |
import { persist, load } from '../../utils/statePersistence' |
|
3 |
|
|
4 |
export interface UserInfo { |
|
5 |
accessToken: string | undefined // to send api requests |
|
6 |
refreshToken: string | undefined // to refresh the api key |
|
7 |
username: string // to display the username |
|
8 |
roles: string[] |
|
9 |
} |
|
10 |
|
|
11 |
export interface AuthState extends UserInfo { |
|
12 |
isAuthenticated: boolean // if this is false all other values should be ignored |
|
13 |
} |
|
14 |
|
|
15 |
const statePersistName = 'auth' |
|
16 |
|
|
17 |
// Initial state when the user first starts the application |
|
18 |
const initialState: AuthState = (load(statePersistName) as AuthState) || { |
|
19 |
isAuthenticated: false, |
|
20 |
username: '', |
|
21 |
roles: [], |
|
22 |
} |
|
23 |
|
|
24 |
// All possible actions |
|
25 |
export enum AuthStateActions { |
|
26 |
LOG_IN = 'LOG_IN', |
|
27 |
LOG_OUT = 'LOG_OUT', |
|
28 |
UPDATE_ACCESS_TOKEN = 'REFRESH_ACCESS_TOKEN', |
|
29 |
UPDATE_REFRESH_TOKEN = 'UPDATE_REFRESH_TOKEN', |
|
30 |
UPDATE_TOKENS = 'UPDATE_TOKENS', |
|
31 |
} |
|
32 |
|
|
33 |
// Actions |
|
34 |
const authReducer = (state: AuthState = initialState, action: AnyAction) => { |
|
35 |
switch (action.type) { |
|
36 |
case AuthStateActions.LOG_IN: |
|
37 |
return persist(statePersistName, { |
|
38 |
...action.payload, |
|
39 |
isAuthenticated: true, |
|
40 |
}) |
|
41 |
|
|
42 |
case AuthStateActions.LOG_OUT: |
|
43 |
return persist(statePersistName, initialState) |
|
44 |
|
|
45 |
case AuthStateActions.UPDATE_ACCESS_TOKEN: |
|
46 |
return persist(statePersistName, { |
|
47 |
...state, |
|
48 |
accessToken: action.payload, |
|
49 |
}) |
|
50 |
|
|
51 |
case AuthStateActions.UPDATE_REFRESH_TOKEN: |
|
52 |
return persist(statePersistName, { |
|
53 |
...state, |
|
54 |
refreshToken: action.payload, |
|
55 |
}) |
|
56 |
|
|
57 |
case AuthStateActions.UPDATE_TOKENS: |
|
58 |
return persist(statePersistName, { ...state, ...action.payload }) |
|
59 |
|
|
60 |
default: |
|
61 |
return state |
|
62 |
} |
|
63 |
} |
|
64 |
|
|
65 |
export default authReducer |
frontend/src/features/Catalog/Catalog.tsx | ||
---|---|---|
1 |
|
|
2 |
const Catalog = () => { |
|
3 |
|
|
4 |
return ( |
|
5 |
<> |
|
6 |
<h1>Catalog</h1> |
|
7 |
</> |
|
8 |
) |
|
9 |
} |
|
10 |
|
|
11 |
export default Catalog |
frontend/src/features/Catalog/CatalogService.ts | ||
---|---|---|
1 |
import axios from "../../api/axios" |
|
2 |
import { CatalogDto } from "../../swagger/data-contracts" |
|
3 |
|
|
4 |
export const getCatalogItems = async (componentMounted: boolean, setCatalog: (catalogItems: CatalogDto[]) => void, ) => { |
|
5 |
try { |
|
6 |
const { data } = await axios.get('/catalog') |
|
7 |
} |
|
8 |
catch (err: any) { |
|
9 |
|
|
10 |
} |
|
11 |
} |
|
12 |
|
|
13 |
export const getCatalogItem = (id: string) => { |
|
14 |
|
|
15 |
} |
frontend/src/features/Home/Home.tsx | ||
---|---|---|
1 |
const Home = () => { |
|
2 |
|
|
3 |
return (<> |
|
4 |
<h1>Home</h1> |
|
5 |
</>) |
|
6 |
} |
|
7 |
|
|
8 |
export default Home |
frontend/src/features/NotFound/NotFound.tsx | ||
---|---|---|
1 |
const NotFound = () => { |
|
2 |
|
|
3 |
return ( |
|
4 |
<> |
|
5 |
<h1>Page Not Found 😡😡😡</h1> |
|
6 |
</> |
|
7 |
) |
|
8 |
} |
|
9 |
|
|
10 |
export default NotFound |
frontend/src/features/redux/store.ts | ||
---|---|---|
1 |
// Store that holds the state of the application |
|
2 |
|
|
3 |
import { combineReducers, createStore } from 'redux' |
|
4 |
import authReducer from '../Auth/authReducer' |
|
5 |
import themeReducer from '../Theme/themeReducer' |
|
6 |
|
|
7 |
const store = createStore( |
|
8 |
combineReducers({ auth: authReducer, theme: themeReducer }), |
|
9 |
{} |
|
10 |
) |
|
11 |
|
|
12 |
export default store |
|
13 |
|
|
14 |
export type AppStore = typeof store |
|
15 |
|
|
16 |
export type RootState = ReturnType<typeof store.getState> |
|
17 |
|
|
18 |
export type AppDispatch = typeof store.dispatch |
frontend/src/index.tsx | ||
---|---|---|
1 |
import React from 'react'; |
|
2 |
import ReactDOM from 'react-dom'; |
|
3 |
import './index.css'; |
|
4 |
import App from './App'; |
|
5 |
import reportWebVitals from './reportWebVitals'; |
|
1 |
import React from 'react' |
|
2 |
import ReactDOM from 'react-dom' |
|
3 |
import './index.css' |
|
4 |
import App from './App' |
|
5 |
import reportWebVitals from './reportWebVitals' |
|
6 |
import { BrowserRouter } from 'react-router-dom' |
|
6 | 7 |
|
7 | 8 |
ReactDOM.render( |
8 |
<React.StrictMode> |
|
9 |
<App /> |
|
10 |
</React.StrictMode>, |
|
11 |
document.getElementById('root') |
|
12 |
); |
|
9 |
<React.StrictMode> |
|
10 |
<BrowserRouter> |
|
11 |
<App /> |
|
12 |
</BrowserRouter> |
|
13 |
</React.StrictMode>, |
|
14 |
document.getElementById('root') |
|
15 |
) |
|
13 | 16 |
|
14 | 17 |
// If you want to start measuring performance in your app, pass a function |
15 | 18 |
// to log results (for example: reportWebVitals(console.log)) |
16 | 19 |
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals |
17 |
reportWebVitals(); |
|
20 |
reportWebVitals() |
frontend/src/logo.svg | ||
---|---|---|
1 |
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg> |
frontend/src/react-app-env.d.ts | ||
---|---|---|
1 |
/// <reference types="react-scripts" /> |
frontend/src/services/AxiosClient.ts | ||
---|---|---|
1 |
import axios from 'axios' |
|
2 |
import Config from '../config/Config' |
|
3 |
|
|
4 |
export default axios.create({ |
|
5 |
baseURL: Config.baseUrl, |
|
6 |
}) |
frontend/src/setupTests.ts | ||
---|---|---|
1 |
// jest-dom adds custom jest matchers for asserting on DOM nodes. |
|
2 |
// allows you to do things like: |
|
3 |
// expect(element).toHaveTextContent(/react/i) |
|
4 |
// learn more: https://github.com/testing-library/jest-dom |
|
5 |
import '@testing-library/jest-dom'; |
frontend/src/swagger/Catalog.ts | ||
---|---|---|
1 |
/* eslint-disable */ |
|
2 |
/* tslint:disable */ |
|
3 |
/* |
|
4 |
* --------------------------------------------------------------- |
|
5 |
* ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## |
|
6 |
* ## ## |
|
7 |
* ## AUTHOR: acacode ## |
|
8 |
* ## SOURCE: https://github.com/acacode/swagger-typescript-api ## |
|
9 |
* --------------------------------------------------------------- |
|
10 |
*/ |
|
11 |
|
|
12 |
import { CatalogDto } from "./data-contracts"; |
|
13 |
import { ContentType, HttpClient, RequestParams } from "./http-client"; |
|
14 |
|
|
15 |
export class Catalog<SecurityDataType = unknown> extends HttpClient<SecurityDataType> { |
|
16 |
/** |
|
17 |
* No description |
|
18 |
* |
|
19 |
* @tags catalog-controller |
|
20 |
* @name UpdateCatalogEntry |
|
21 |
* @request PUT:/catalog/{id} |
|
22 |
*/ |
|
23 |
updateCatalogEntry = (id: string, data: CatalogDto, params: RequestParams = {}) => |
|
24 |
this.request<void, any>({ |
|
25 |
path: `/catalog/${id}`, |
|
26 |
method: "PUT", |
|
27 |
body: data, |
|
28 |
type: ContentType.Json, |
|
29 |
...params, |
|
30 |
}); |
|
31 |
/** |
|
32 |
* No description |
|
33 |
* |
|
34 |
* @tags catalog-controller |
|
35 |
* @name DeleteCatalogEntry |
|
36 |
* @request DELETE:/catalog/{id} |
|
37 |
*/ |
|
38 |
deleteCatalogEntry = (id: string, params: RequestParams = {}) => |
|
39 |
this.request<void, any>({ |
|
40 |
path: `/catalog/${id}`, |
|
41 |
method: "DELETE", |
|
42 |
...params, |
|
43 |
}); |
|
44 |
/** |
|
45 |
* No description |
|
46 |
* |
|
47 |
* @tags catalog-controller |
|
48 |
* @name GetAllUsers1 |
|
49 |
* @request GET:/catalog |
|
50 |
*/ |
|
51 |
getAllUsers1 = (params: RequestParams = {}) => |
|
52 |
this.request<CatalogDto[], any>({ |
|
53 |
path: `/catalog`, |
|
54 |
method: "GET", |
|
55 |
...params, |
|
56 |
}); |
|
57 |
/** |
|
58 |
* No description |
|
59 |
* |
|
60 |
* @tags catalog-controller |
|
61 |
* @name AddCatalogEntry |
|
62 |
* @request POST:/catalog |
|
63 |
*/ |
|
64 |
addCatalogEntry = (data: CatalogDto, params: RequestParams = {}) => |
|
65 |
this.request<void, any>({ |
|
66 |
path: `/catalog`, |
|
67 |
method: "POST", |
|
68 |
body: data, |
|
69 |
type: ContentType.Json, |
|
70 |
...params, |
|
71 |
}); |
|
72 |
} |
frontend/src/swagger/Register.ts | ||
---|---|---|
1 |
/* eslint-disable */ |
|
2 |
/* tslint:disable */ |
|
3 |
/* |
|
4 |
* --------------------------------------------------------------- |
|
5 |
* ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## |
|
6 |
* ## ## |
|
7 |
* ## AUTHOR: acacode ## |
|
8 |
* ## SOURCE: https://github.com/acacode/swagger-typescript-api ## |
|
9 |
* --------------------------------------------------------------- |
|
10 |
*/ |
|
11 |
|
|
12 |
import { UserDto } from "./data-contracts"; |
|
13 |
import { ContentType, HttpClient, RequestParams } from "./http-client"; |
|
14 |
|
|
15 |
export class Register<SecurityDataType = unknown> extends HttpClient<SecurityDataType> { |
|
16 |
/** |
|
17 |
* No description |
|
18 |
* |
|
19 |
* @tags user-controller |
|
20 |
* @name RegisterNewUser |
|
21 |
* @request POST:/register |
|
22 |
*/ |
|
23 |
registerNewUser = (data: UserDto, params: RequestParams = {}) => |
|
24 |
this.request<void, any>({ |
|
25 |
path: `/register`, |
|
26 |
method: "POST", |
|
27 |
body: data, |
|
28 |
type: ContentType.Json, |
|
29 |
...params, |
|
30 |
}); |
|
31 |
} |
frontend/src/swagger/Token.ts | ||
---|---|---|
1 |
/* eslint-disable */ |
|
2 |
/* tslint:disable */ |
|
3 |
/* |
|
4 |
* --------------------------------------------------------------- |
|
5 |
* ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## |
|
6 |
* ## ## |
|
7 |
* ## AUTHOR: acacode ## |
|
8 |
* ## SOURCE: https://github.com/acacode/swagger-typescript-api ## |
|
9 |
* --------------------------------------------------------------- |
|
10 |
*/ |
|
11 |
|
|
12 |
import { HttpClient, RequestParams } from "./http-client"; |
|
13 |
|
|
14 |
export class Token<SecurityDataType = unknown> extends HttpClient<SecurityDataType> { |
|
15 |
/** |
|
16 |
* No description |
|
17 |
* |
|
18 |
* @tags user-controller |
|
19 |
* @name RefreshToken |
|
20 |
* @request GET:/token/refresh |
|
21 |
*/ |
|
22 |
refreshToken = (params: RequestParams = {}) => |
|
23 |
this.request<void, any>({ |
|
24 |
path: `/token/refresh`, |
|
25 |
method: "GET", |
|
26 |
...params, |
|
27 |
}); |
|
28 |
} |
frontend/src/swagger/User.ts | ||
---|---|---|
1 |
/* eslint-disable */ |
|
2 |
/* tslint:disable */ |
|
3 |
/* |
|
4 |
* --------------------------------------------------------------- |
|
5 |
* ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## |
|
6 |
* ## ## |
|
7 |
* ## AUTHOR: acacode ## |
|
8 |
* ## SOURCE: https://github.com/acacode/swagger-typescript-api ## |
|
9 |
* --------------------------------------------------------------- |
|
10 |
*/ |
|
11 |
|
|
12 |
import { UserDto } from "./data-contracts"; |
|
13 |
import { ContentType, HttpClient, RequestParams } from "./http-client"; |
|
14 |
|
|
15 |
export class User<SecurityDataType = unknown> extends HttpClient<SecurityDataType> { |
|
16 |
/** |
|
17 |
* No description |
|
18 |
* |
|
19 |
* @tags user-controller |
|
20 |
* @name UpdateUser |
|
21 |
* @request PUT:/user/{username} |
|
22 |
*/ |
|
23 |
updateUser = (username: string, data: UserDto, params: RequestParams = {}) => |
|
24 |
this.request<void, any>({ |
|
25 |
path: `/user/${username}`, |
|
26 |
method: "PUT", |
|
27 |
body: data, |
|
28 |
type: ContentType.Json, |
|
29 |
...params, |
|
30 |
}); |
|
31 |
/** |
|
32 |
* No description |
|
33 |
* |
|
34 |
* @tags user-controller |
|
35 |
* @name DeleteUser |
|
36 |
* @request DELETE:/user/{username} |
|
37 |
*/ |
|
38 |
deleteUser = (username: string, params: RequestParams = {}) => |
|
39 |
this.request<void, any>({ |
|
40 |
path: `/user/${username}`, |
|
41 |
method: "DELETE", |
|
42 |
...params, |
|
43 |
}); |
|
44 |
} |
frontend/src/swagger/Users.ts | ||
---|---|---|
1 |
/* eslint-disable */ |
|
2 |
/* tslint:disable */ |
|
3 |
/* |
|
4 |
* --------------------------------------------------------------- |
|
5 |
* ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## |
|
6 |
* ## ## |
|
7 |
* ## AUTHOR: acacode ## |
|
8 |
* ## SOURCE: https://github.com/acacode/swagger-typescript-api ## |
|
9 |
* --------------------------------------------------------------- |
|
10 |
*/ |
|
11 |
|
|
12 |
import { UserDto } from "./data-contracts"; |
|
13 |
import { HttpClient, RequestParams } from "./http-client"; |
|
14 |
|
|
15 |
export class Users<SecurityDataType = unknown> extends HttpClient<SecurityDataType> { |
|
16 |
/** |
|
17 |
* No description |
|
18 |
* |
|
19 |
* @tags user-controller |
|
20 |
* @name GetAllUsers |
|
21 |
* @request GET:/users |
|
22 |
*/ |
|
23 |
getAllUsers = (params: RequestParams = {}) => |
|
24 |
this.request<UserDto[], any>({ |
|
25 |
path: `/users`, |
|
26 |
method: "GET", |
|
27 |
...params, |
|
28 |
}); |
|
29 |
} |
frontend/src/swagger/data-contracts.ts | ||
---|---|---|
1 |
/* eslint-disable */ |
|
2 |
/* tslint:disable */ |
|
3 |
/* |
|
4 |
* --------------------------------------------------------------- |
|
5 |
* ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## |
|
6 |
* ## ## |
|
7 |
* ## AUTHOR: acacode ## |
|
8 |
* ## SOURCE: https://github.com/acacode/swagger-typescript-api ## |
|
9 |
* --------------------------------------------------------------- |
|
10 |
*/ |
|
11 |
|
|
12 |
export interface UserDto { |
|
13 |
name?: string; |
|
14 |
email: string; |
|
15 |
canRead?: boolean; |
|
16 |
canWrite?: boolean; |
|
17 |
canDelete?: boolean; |
|
18 |
} |
|
19 |
|
|
20 |
export interface CatalogDto { |
|
21 |
/** @format uuid */ |
|
22 |
id?: string; |
|
23 |
name?: string; |
|
24 |
|
|
25 |
/** @format int32 */ |
|
26 |
certainty?: number; |
|
27 |
|
|
28 |
/** @format double */ |
|
29 |
longitude?: number; |
|
30 |
|
|
31 |
/** @format double */ |
|
32 |
latitude?: number; |
|
33 |
bibliography?: string[]; |
|
34 |
countries?: string[]; |
|
35 |
writtenForms?: string[]; |
|
36 |
alternativeNames?: string[]; |
|
37 |
types?: string[]; |
|
38 |
} |
frontend/src/swagger/http-client.ts | ||
---|---|---|
1 |
/* eslint-disable */ |
|
2 |
/* tslint:disable */ |
|
3 |
/* |
|
4 |
* --------------------------------------------------------------- |
|
5 |
* ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## |
|
6 |
* ## ## |
|
7 |
* ## AUTHOR: acacode ## |
|
8 |
* ## SOURCE: https://github.com/acacode/swagger-typescript-api ## |
|
9 |
* --------------------------------------------------------------- |
|
10 |
*/ |
|
11 |
|
|
12 |
export type QueryParamsType = Record<string | number, any>; |
|
13 |
export type ResponseFormat = keyof Omit<Body, "body" | "bodyUsed">; |
|
14 |
|
|
15 |
export interface FullRequestParams extends Omit<RequestInit, "body"> { |
|
16 |
/** set parameter to `true` for call `securityWorker` for this request */ |
|
17 |
secure?: boolean; |
|
18 |
/** request path */ |
|
19 |
path: string; |
|
20 |
/** content type of request body */ |
|
21 |
type?: ContentType; |
|
22 |
/** query params */ |
|
23 |
query?: QueryParamsType; |
|
24 |
/** format of response (i.e. response.json() -> format: "json") */ |
|
25 |
format?: ResponseFormat; |
|
26 |
/** request body */ |
|
27 |
body?: unknown; |
|
28 |
/** base url */ |
|
29 |
baseUrl?: string; |
|
30 |
/** request cancellation token */ |
|
31 |
cancelToken?: CancelToken; |
|
32 |
} |
|
33 |
|
|
34 |
export type RequestParams = Omit<FullRequestParams, "body" | "method" | "query" | "path">; |
|
35 |
|
|
36 |
export interface ApiConfig<SecurityDataType = unknown> { |
|
37 |
baseUrl?: string; |
|
38 |
baseApiParams?: Omit<RequestParams, "baseUrl" | "cancelToken" | "signal">; |
|
39 |
securityWorker?: (securityData: SecurityDataType | null) => Promise<RequestParams | void> | RequestParams | void; |
|
40 |
customFetch?: typeof fetch; |
|
41 |
} |
|
42 |
|
|
43 |
export interface HttpResponse<D extends unknown, E extends unknown = unknown> extends Response { |
|
44 |
data: D; |
|
45 |
error: E; |
|
46 |
} |
|
47 |
|
|
48 |
type CancelToken = Symbol | string | number; |
|
49 |
|
|
50 |
export enum ContentType { |
|
51 |
Json = "application/json", |
|
52 |
FormData = "multipart/form-data", |
|
53 |
UrlEncoded = "application/x-www-form-urlencoded", |
|
54 |
} |
|
55 |
|
|
56 |
export class HttpClient<SecurityDataType = unknown> { |
|
57 |
public baseUrl: string = "http://localhost:8080"; |
|
58 |
private securityData: SecurityDataType | null = null; |
|
59 |
private securityWorker?: ApiConfig<SecurityDataType>["securityWorker"]; |
|
60 |
private abortControllers = new Map<CancelToken, AbortController>(); |
|
61 |
private customFetch = (...fetchParams: Parameters<typeof fetch>) => fetch(...fetchParams); |
|
62 |
|
|
63 |
private baseApiParams: RequestParams = { |
|
64 |
credentials: "same-origin", |
|
65 |
headers: {}, |
|
66 |
redirect: "follow", |
|
67 |
referrerPolicy: "no-referrer", |
|
68 |
}; |
|
69 |
|
|
70 |
constructor(apiConfig: ApiConfig<SecurityDataType> = {}) { |
|
71 |
Object.assign(this, apiConfig); |
|
72 |
} |
|
73 |
|
|
74 |
public setSecurityData = (data: SecurityDataType | null) => { |
|
75 |
this.securityData = data; |
|
76 |
}; |
|
77 |
|
|
78 |
private encodeQueryParam(key: string, value: any) { |
|
79 |
const encodedKey = encodeURIComponent(key); |
|
80 |
return `${encodedKey}=${encodeURIComponent(typeof value === "number" ? value : `${value}`)}`; |
|
81 |
} |
|
82 |
|
|
83 |
private addQueryParam(query: QueryParamsType, key: string) { |
|
84 |
return this.encodeQueryParam(key, query[key]); |
|
85 |
} |
|
86 |
|
|
87 |
private addArrayQueryParam(query: QueryParamsType, key: string) { |
|
88 |
const value = query[key]; |
|
89 |
return value.map((v: any) => this.encodeQueryParam(key, v)).join("&"); |
|
90 |
} |
|
91 |
|
|
92 |
protected toQueryString(rawQuery?: QueryParamsType): string { |
|
93 |
const query = rawQuery || {}; |
|
94 |
const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); |
|
95 |
return keys |
|
96 |
.map((key) => (Array.isArray(query[key]) ? this.addArrayQueryParam(query, key) : this.addQueryParam(query, key))) |
|
97 |
.join("&"); |
|
98 |
} |
|
99 |
|
|
100 |
protected addQueryParams(rawQuery?: QueryParamsType): string { |
|
101 |
const queryString = this.toQueryString(rawQuery); |
|
102 |
return queryString ? `?${queryString}` : ""; |
|
103 |
} |
|
104 |
|
|
105 |
private contentFormatters: Record<ContentType, (input: any) => any> = { |
|
106 |
[ContentType.Json]: (input: any) => |
|
107 |
input !== null && (typeof input === "object" || typeof input === "string") ? JSON.stringify(input) : input, |
|
108 |
[ContentType.FormData]: (input: any) => |
|
109 |
Object.keys(input || {}).reduce((formData, key) => { |
|
110 |
const property = input[key]; |
|
111 |
formData.append( |
|
112 |
key, |
|
113 |
property instanceof Blob |
|
114 |
? property |
|
115 |
: typeof property === "object" && property !== null |
|
116 |
? JSON.stringify(property) |
|
117 |
: `${property}`, |
|
118 |
); |
|
119 |
return formData; |
|
120 |
}, new FormData()), |
|
121 |
[ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), |
|
122 |
}; |
|
123 |
|
|
124 |
private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { |
|
125 |
return { |
|
126 |
...this.baseApiParams, |
|
127 |
...params1, |
|
128 |
...(params2 || {}), |
|
129 |
headers: { |
|
130 |
...(this.baseApiParams.headers || {}), |
|
131 |
...(params1.headers || {}), |
|
132 |
...((params2 && params2.headers) || {}), |
Také k dispozici: Unified diff
From feature/#9196_Connect_Frontend_With_Backend into develop