Skip to content

Commit 30777d2

Browse files
committed
reverted "removed database" and adjusted for current project structure
1 parent 63dc2a6 commit 30777d2

25 files changed

+886
-7
lines changed

captchaservice-backend/pom.xml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@
5656

5757
<!-- Additional required dependencies -->
5858
<lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version> <!-- Needed to make MapStruct and Lombok work together -->
59+
60+
<!-- Flyway maven plugin configuration for local stack database -->
61+
<flyway.url>jdbc:postgresql://localhost:5432/postgres</flyway.url>
62+
<flyway.user>admin</flyway.user>
63+
<flyway.password>admin</flyway.password>
64+
<flyway.locations>classpath:db/migration/schema,classpath:db/migration/testdata</flyway.locations>
5965
</properties>
6066

6167

@@ -76,6 +82,14 @@
7682
<dependencies>
7783

7884
<!-- Spring Boot -->
85+
<dependency>
86+
<groupId>org.springframework.boot</groupId>
87+
<artifactId>spring-boot-starter-data-rest</artifactId>
88+
</dependency>
89+
<dependency>
90+
<groupId>org.springframework.boot</groupId>
91+
<artifactId>spring-boot-starter-data-jpa</artifactId>
92+
</dependency>
7993
<dependency>
8094
<groupId>org.springframework.boot</groupId>
8195
<artifactId>spring-boot-starter-web</artifactId>
@@ -131,6 +145,30 @@
131145
<artifactId>json-path</artifactId>
132146
</dependency>
133147

148+
<!-- Database -->
149+
<dependency>
150+
<groupId>org.postgresql</groupId>
151+
<artifactId>postgresql</artifactId>
152+
</dependency>
153+
<dependency>
154+
<groupId>org.hibernate.orm</groupId>
155+
<artifactId>hibernate-core</artifactId>
156+
</dependency>
157+
<!-- Hibernate Model Gen for type safe criterias -->
158+
<dependency>
159+
<groupId>org.hibernate.orm</groupId>
160+
<artifactId>hibernate-jpamodelgen</artifactId>
161+
</dependency>
162+
<!-- Database migrations -->
163+
<dependency>
164+
<groupId>org.flywaydb</groupId>
165+
<artifactId>flyway-core</artifactId>
166+
</dependency>
167+
<dependency>
168+
<groupId>org.flywaydb</groupId>
169+
<artifactId>flyway-database-postgresql</artifactId>
170+
</dependency>
171+
134172
<!-- Other -->
135173
<dependency>
136174
<groupId>org.apache.httpcomponents.client5</groupId>
@@ -189,6 +227,11 @@
189227
<artifactId>junit-jupiter</artifactId>
190228
<scope>test</scope>
191229
</dependency>
230+
<dependency>
231+
<groupId>org.testcontainers</groupId>
232+
<artifactId>postgresql</artifactId>
233+
<scope>test</scope>
234+
</dependency>
192235
<dependency>
193236
<groupId>org.junit.jupiter</groupId>
194237
<artifactId>junit-jupiter-api</artifactId>
@@ -447,6 +490,18 @@
447490
</execution>
448491
</executions>
449492
</plugin>
493+
<plugin>
494+
<!-- Flyway Maven plugin for local database management
495+
Usage:
496+
- Clean database: mvn flyway:clean
497+
- Apply migrations: mvn flyway:migrate
498+
- Reset and migrate: mvn flyway:clean flyway:migrate
499+
500+
Note: Use -Dflyway.cleanDisabled=false when running clean command
501+
-->
502+
<groupId>org.flywaydb</groupId>
503+
<artifactId>flyway-maven-plugin</artifactId>
504+
</plugin>
450505
</plugins>
451506
</build>
452507

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package de.muenchen.captchaservice.common;
2+
3+
import jakarta.persistence.Column;
4+
import jakarta.persistence.GeneratedValue;
5+
import jakarta.persistence.GenerationType;
6+
import jakarta.persistence.Id;
7+
import jakarta.persistence.MappedSuperclass;
8+
import java.io.Serial;
9+
import java.io.Serializable;
10+
import java.util.UUID;
11+
import lombok.EqualsAndHashCode;
12+
import lombok.Getter;
13+
import lombok.NoArgsConstructor;
14+
import lombok.Setter;
15+
import lombok.ToString;
16+
17+
@MappedSuperclass
18+
@NoArgsConstructor
19+
@Getter
20+
@Setter
21+
@ToString
22+
@EqualsAndHashCode
23+
public abstract class BaseEntity implements Serializable {
24+
25+
@Serial
26+
private static final long serialVersionUID = 1L;
27+
28+
@Column(name = "id", length = 36)
29+
@Id
30+
@GeneratedValue(strategy = GenerationType.UUID)
31+
private UUID id;
32+
33+
}

captchaservice-backend/src/main/java/de/muenchen/captchaservice/configuration/hazelcast/HazelcastProperties.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ public class HazelcastProperties {
2323
/**
2424
* General timeout for Hazelcast data.
2525
*/
26-
private int timeoutSeconds = 86400;
26+
private int timeoutSeconds = 86_400;
2727
}

captchaservice-backend/src/main/java/de/muenchen/captchaservice/service/captcha/CaptchaService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ public void invalidatePayload(final Altcha.Payload payload) {
6969
}
7070

7171
public boolean isPayloadInvalidated(final String siteKey, final Altcha.Payload payload) {
72-
CaptchaSite site = captchaProperties.sites().get(siteKey);
73-
String payloadHash = getPayloadHash(payload);
72+
final CaptchaSite site = captchaProperties.sites().get(siteKey);
73+
final String payloadHash = getPayloadHash(payload);
7474
final long payloadHashCount = invalidatedPayloads.keySet().stream().filter(s -> s.startsWith(String.format("%s_", payloadHash))).count();
7575
return payloadHashCount >= site.maxVerifiesPerPayload();
7676
}

captchaservice-backend/src/main/java/de/muenchen/captchaservice/service/siteauth/SiteAuthService.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ public SiteAuthService(final CaptchaProperties captchaProperties) {
1515

1616
public boolean isAuthorized(final String siteKey, final String siteSecret) {
1717
final CaptchaSite site = captchaProperties.sites().get(siteKey);
18-
if (site == null) return false;
19-
return site.secret().equals(siteSecret);
18+
return site != null && site.secret().equals(siteSecret);
2019
}
2120

2221
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package de.muenchen.captchaservice.theentity;
2+
3+
import de.muenchen.captchaservice.common.BaseEntity;
4+
import jakarta.persistence.Column;
5+
import jakarta.persistence.Entity;
6+
import jakarta.validation.constraints.NotNull;
7+
import jakarta.validation.constraints.Size;
8+
import lombok.EqualsAndHashCode;
9+
import lombok.Getter;
10+
import lombok.NoArgsConstructor;
11+
import lombok.Setter;
12+
import lombok.ToString;
13+
14+
/**
15+
* This class represents a TheEntity.
16+
* <p>
17+
* The entity's content will be loaded according to the reference variable.
18+
* </p>
19+
*/
20+
@Entity
21+
// Definition of getter, setter, ...
22+
@Getter
23+
@Setter
24+
@ToString(callSuper = true)
25+
@EqualsAndHashCode(callSuper = true)
26+
@NoArgsConstructor
27+
public class TheEntity extends BaseEntity {
28+
29+
private static final long serialVersionUID = 1L;
30+
31+
// ========= //
32+
// Variables //
33+
// ========= //
34+
35+
@Column(nullable = false, length = 8)
36+
@NotNull
37+
@Size(min = 2, max = 8)
38+
private String textAttribute;
39+
40+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package de.muenchen.captchaservice.theentity;
2+
3+
import de.muenchen.captchaservice.theentity.dto.TheEntityRequestDTO;
4+
import de.muenchen.captchaservice.theentity.dto.TheEntityMapper;
5+
import de.muenchen.captchaservice.theentity.dto.TheEntityResponseDTO;
6+
7+
import jakarta.validation.Valid;
8+
import lombok.RequiredArgsConstructor;
9+
import org.springframework.data.domain.Page;
10+
import org.springframework.data.domain.PageImpl;
11+
import org.springframework.http.HttpStatus;
12+
import java.util.List;
13+
import java.util.UUID;
14+
import lombok.extern.slf4j.Slf4j;
15+
import org.springframework.web.bind.annotation.DeleteMapping;
16+
import org.springframework.web.bind.annotation.GetMapping;
17+
import org.springframework.web.bind.annotation.PathVariable;
18+
import org.springframework.web.bind.annotation.PostMapping;
19+
import org.springframework.web.bind.annotation.PutMapping;
20+
import org.springframework.web.bind.annotation.RequestBody;
21+
import org.springframework.web.bind.annotation.RequestMapping;
22+
import org.springframework.web.bind.annotation.RequestParam;
23+
import org.springframework.web.bind.annotation.ResponseStatus;
24+
import org.springframework.web.bind.annotation.RestController;
25+
26+
@RestController
27+
@Slf4j
28+
@RequiredArgsConstructor
29+
@RequestMapping("/theEntity")
30+
public class TheEntityController {
31+
32+
private final TheEntityService theEntityService;
33+
private final TheEntityMapper theEntityMapper;
34+
35+
@GetMapping("{theEntityID}")
36+
@ResponseStatus(HttpStatus.OK)
37+
public TheEntityResponseDTO getTheEntity(@PathVariable("theEntityID") final UUID theEntityId) {
38+
return theEntityMapper.toDTO(theEntityService.getTheEntity(theEntityId));
39+
}
40+
41+
@GetMapping
42+
@ResponseStatus(HttpStatus.OK)
43+
public Page<TheEntityResponseDTO> getTheEntitiesByPageAndSize(@RequestParam(defaultValue = "0") final int pageNumber,
44+
@RequestParam(defaultValue = "10") final int pageSize) {
45+
final Page<TheEntity> pageWithEntity = theEntityService.getAllEntities(pageNumber, pageSize);
46+
final List<TheEntityResponseDTO> theEntityRequestDTOList = pageWithEntity.getContent().stream().map(theEntityMapper::toDTO).toList();
47+
return new PageImpl<>(theEntityRequestDTOList, pageWithEntity.getPageable(), pageWithEntity.getTotalElements());
48+
}
49+
50+
@PostMapping
51+
@ResponseStatus(HttpStatus.CREATED)
52+
public TheEntityResponseDTO saveTheEntity(@Valid @RequestBody final TheEntityRequestDTO theEntityRequestDTO) {
53+
return theEntityMapper.toDTO(theEntityService.createTheEntity(theEntityMapper.toEntity(theEntityRequestDTO)));
54+
}
55+
56+
@PutMapping("/{theEntityId}")
57+
@ResponseStatus(HttpStatus.OK)
58+
public TheEntityResponseDTO updateTheEntity(@Valid @RequestBody final TheEntityRequestDTO theEntityRequestDTO,
59+
@PathVariable("theEntityId") final UUID theEntityId) {
60+
return theEntityMapper.toDTO(theEntityService.updateTheEntity(theEntityMapper.toEntity(theEntityRequestDTO), theEntityId));
61+
}
62+
63+
@DeleteMapping("/{theEntityId}")
64+
@ResponseStatus(HttpStatus.OK)
65+
public void deleteTheEntity(@PathVariable("theEntityId") final UUID theEntityId) {
66+
theEntityService.deleteTheEntity(theEntityId);
67+
}
68+
69+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package de.muenchen.captchaservice.theentity;
2+
3+
import java.util.UUID;
4+
import org.springframework.data.repository.CrudRepository;
5+
import org.springframework.data.repository.PagingAndSortingRepository;
6+
import org.springframework.stereotype.Repository;
7+
8+
@Repository
9+
public interface TheEntityRepository extends PagingAndSortingRepository<TheEntity, UUID>, CrudRepository<TheEntity, UUID> {
10+
11+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package de.muenchen.captchaservice.theentity;
2+
3+
import de.muenchen.captchaservice.common.NotFoundException;
4+
import de.muenchen.captchaservice.security.Authorities;
5+
import java.util.UUID;
6+
import lombok.RequiredArgsConstructor;
7+
import lombok.extern.slf4j.Slf4j;
8+
import org.springframework.data.domain.Page;
9+
import org.springframework.data.domain.PageRequest;
10+
import org.springframework.data.domain.Pageable;
11+
import org.springframework.security.access.prepost.PreAuthorize;
12+
import org.springframework.stereotype.Service;
13+
14+
import static de.muenchen.captchaservice.common.ExceptionMessageConstants.MSG_NOT_FOUND;
15+
16+
@Service
17+
@Slf4j
18+
@RequiredArgsConstructor
19+
20+
public class TheEntityService {
21+
22+
private final TheEntityRepository theEntityRepository;
23+
24+
@PreAuthorize(Authorities.HAS_AUTHORITY_READ_THEENTITY)
25+
public TheEntity getTheEntity(final UUID theEntityId) {
26+
log.info("Get TheEntity with ID {}", theEntityId);
27+
return getEntityOrThrowException(theEntityId);
28+
}
29+
30+
@PreAuthorize(Authorities.HAS_AUTHORITY_READ_THEENTITY)
31+
public Page<TheEntity> getAllEntities(final int pageNumber, final int pageSize) {
32+
log.info("Get all TheEntity with at Page {} with a PageSize of {}", pageNumber, pageSize);
33+
final Pageable pageRequest = PageRequest.of(pageNumber, pageSize);
34+
return theEntityRepository.findAll(pageRequest);
35+
}
36+
37+
@PreAuthorize(Authorities.HAS_AUTHORITY_WRITE_THEENTITY)
38+
public TheEntity createTheEntity(final TheEntity entity) {
39+
log.debug("Create TheEntity {}", entity);
40+
return theEntityRepository.save(entity);
41+
}
42+
43+
@PreAuthorize(Authorities.HAS_AUTHORITY_WRITE_THEENTITY)
44+
public TheEntity updateTheEntity(final TheEntity entity, final UUID theEntityId) {
45+
final TheEntity foundEntity = getEntityOrThrowException(theEntityId);
46+
foundEntity.setTextAttribute(entity.getTextAttribute());
47+
log.debug("Update TheEntity {}", foundEntity);
48+
return theEntityRepository.save(foundEntity);
49+
}
50+
51+
@PreAuthorize(Authorities.HAS_AUTHORITY_DELETE_THEENTITY)
52+
public void deleteTheEntity(final UUID theEntityId) {
53+
log.debug("Delete TheEntity with ID {}", theEntityId);
54+
theEntityRepository.deleteById(theEntityId);
55+
}
56+
57+
private TheEntity getEntityOrThrowException(final UUID theEntityId) {
58+
return theEntityRepository
59+
.findById(theEntityId)
60+
.orElseThrow(() -> new NotFoundException(String.format(MSG_NOT_FOUND, theEntityId)));
61+
}
62+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package de.muenchen.captchaservice.theentity.dto;
2+
3+
import de.muenchen.captchaservice.theentity.TheEntity;
4+
import org.mapstruct.Mapper;
5+
import org.mapstruct.Mapping;
6+
7+
@Mapper
8+
public interface TheEntityMapper {
9+
10+
TheEntityResponseDTO toDTO(TheEntity theEntity);
11+
12+
@Mapping(target = "id", ignore = true)
13+
TheEntity toEntity(TheEntityRequestDTO theEntityRequestDTO);
14+
}

0 commit comments

Comments
 (0)