From 28ffc91a07325a62c63d0295576a65a70afed5b7 Mon Sep 17 00:00:00 2001 From: evilimkova <evilimkova@onpointserv.com> Date: Wed, 29 Mar 2023 15:34:42 +0200 Subject: [PATCH] Certificate Create and FindById --- .../dto/certificate/CertificateSimpleDto.java | 43 ++++++++ application/module-certificate/pom.xml | 12 ++ .../fuseri/modulecertificate/Certificate.java | 104 ++++++++++++++++++ .../service/CertificateController.java | 15 ++- .../service/CertificateFacade.java | 41 +++++++ .../service/CertificateMapper.java | 49 +++++++++ .../service/CertificateRepository.java | 11 ++ .../service/CertificateService.java | 36 ++++++ .../service/ResourceNotFoundException.java | 22 ++++ .../src/main/resources/application.properties | 11 +- 10 files changed, 338 insertions(+), 6 deletions(-) create mode 100644 application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateSimpleDto.java create mode 100644 application/module-certificate/src/main/java/org/fuseri/modulecertificate/Certificate.java create mode 100644 application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateFacade.java create mode 100644 application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateMapper.java create mode 100644 application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateRepository.java create mode 100644 application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateService.java create mode 100644 application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/ResourceNotFoundException.java diff --git a/application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateSimpleDto.java b/application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateSimpleDto.java new file mode 100644 index 00000000..883c0fda --- /dev/null +++ b/application/model/src/main/java/org/fuseri/model/dto/certificate/CertificateSimpleDto.java @@ -0,0 +1,43 @@ +package org.fuseri.model.dto.certificate; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; +import org.fuseri.model.dto.common.DomainObjectDto; + +import java.time.Instant; + +/** + * This class represents a Data Transfer Object (DTO) for Certificate entities. + * It is used to transfer Certificate data between different layers of the application. + * It extends the DomainObjectDto class and includes additional Certificate-specific fields. + */ +@Getter +@Setter +public class CertificateSimpleDto extends DomainObjectDto { + @NotBlank + @NotNull + private String userId; + @NotBlank + @NotNull + private Instant generatedAt; + @NotBlank + @NotNull + private String courseId; + @NotBlank + @NotNull + private String certificateFile; + @NotBlank + @NotNull + private String certificateFileName; + + public CertificateSimpleDto(String id, String userId, Instant generatedAt, String courseId, String certificateFile, String certificateFileName) { + this.setId(id); + this.userId = userId; + this.generatedAt = generatedAt; + this.courseId = courseId; + this.certificateFile = certificateFile; + this.certificateFileName = certificateFileName; + } +} diff --git a/application/module-certificate/pom.xml b/application/module-certificate/pom.xml index 2513ce45..9ab80d52 100644 --- a/application/module-certificate/pom.xml +++ b/application/module-certificate/pom.xml @@ -61,6 +61,18 @@ <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-tx</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-data-jpa</artifactId> + </dependency> + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + </dependency> </dependencies> <build> diff --git a/application/module-certificate/src/main/java/org/fuseri/modulecertificate/Certificate.java b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/Certificate.java new file mode 100644 index 00000000..cdefa730 --- /dev/null +++ b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/Certificate.java @@ -0,0 +1,104 @@ +package org.fuseri.modulecertificate; + +import jakarta.persistence.*; + +import java.io.Serializable; +import java.time.Instant; +import java.util.Objects; + +@Entity +@Table(name = "certificate") +public class Certificate implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id_certificate") + private Long id; + @Column(name = "id_user") + private String userId; + @Column(name = "generatedAt") + @Temporal(TemporalType.TIMESTAMP) + private Instant generatedAt; + @Column(name = "id_course") + private String courseId; + @Column(name = "certificate_file") + private String certificateFile; + @Column(name = "certificate_file_name") + private String certificateFileName; + + public Certificate() { + } + + public Certificate(String userId, Instant generatedAt, String courseId, String certificateFile, String certificateFileName) { + this.userId = userId; + this.generatedAt = generatedAt; + this.courseId = courseId; + this.certificateFile = certificateFile; + this.certificateFileName = certificateFileName; + } + + public Long getId() { + return id; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Instant getGeneratedAt() { + return generatedAt; + } + + public void setGeneratedAt(Instant generatedAt) { + this.generatedAt = generatedAt; + } + + public String getCourseId() { + return courseId; + } + + public void setCourseId(String courseId) { + this.courseId = courseId; + } + + public String getCertificateFile() { + return certificateFile; + } + + public void setCertificateFile(String certificateFile) { + this.certificateFile = certificateFile; + } + + public String getCertificateFileName() { + return certificateFileName; + } + + public void setCertificateFileName(String certificateFileName) { + this.certificateFileName = certificateFileName; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Certificate certificate)) { + return false; + } + return Objects.equals(getUserId(), certificate.getUserId()) + && Objects.equals(getGeneratedAt(), certificate.getGeneratedAt()) + && Objects.equals(getCourseId(), certificate.getCourseId()) + && Objects.equals(getCertificateFile(), certificate.getCertificateFile()) + && Objects.equals(getCertificateFileName(), certificate.getCertificateFileName()); + } + + @Override + public int hashCode() { + return Objects.hash(getUserId(), getGeneratedAt(), getCourseId(), getCertificateFile(), getCertificateFileName()); + } +} + diff --git a/application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateController.java b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateController.java index bfb64473..173e7254 100644 --- a/application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateController.java +++ b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateController.java @@ -3,6 +3,7 @@ package org.fuseri.modulecertificate.service; import jakarta.validation.Valid; import org.fuseri.model.dto.certificate.CertificateCreateDto; import org.fuseri.model.dto.certificate.CertificateDto; +import org.fuseri.model.dto.certificate.CertificateSimpleDto; import org.fuseri.model.dto.common.Result; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @@ -18,10 +19,14 @@ import java.util.List; @RequestMapping("/certificates") public class CertificateController { + private final CertificateFacade certificateFacade; + @Autowired - public CertificateController() { + public CertificateController(CertificateFacade certificateFacade) { + this.certificateFacade = certificateFacade; } + /** * Generates certificate for specified user and course. * @@ -29,8 +34,8 @@ public class CertificateController { * @return CertificateDto with data of generated certificate */ @PostMapping("/generate") - public CertificateDto generate(@Valid @RequestBody CertificateCreateDto certificateCreateDto) { - return new CertificateDto(); + public CertificateSimpleDto generate(@Valid @RequestBody CertificateCreateDto certificateCreateDto) { + return certificateFacade.generate(certificateCreateDto); } /** @@ -40,8 +45,8 @@ public class CertificateController { * @return CertificateDto with data of previously generated certificate with specified ID */ @GetMapping("/find") - public CertificateDto find(@RequestParam String id) { - return new CertificateDto(); + public CertificateSimpleDto find(@RequestParam Long id) { + return certificateFacade.findById(id); } /** diff --git a/application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateFacade.java b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateFacade.java new file mode 100644 index 00000000..719e2343 --- /dev/null +++ b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateFacade.java @@ -0,0 +1,41 @@ +package org.fuseri.modulecertificate.service; + + +import org.fuseri.model.dto.certificate.CertificateCreateDto; +import org.fuseri.model.dto.certificate.CertificateDto; +import org.fuseri.model.dto.certificate.CertificateSimpleDto; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +public class CertificateFacade { + + private final CertificateService certificateService; + private final CertificateMapper certificateMapper; + + @Autowired + public CertificateFacade(CertificateService certificateService, CertificateMapper certificateMapper) { + this.certificateService = certificateService; + this.certificateMapper = certificateMapper; + } + + @Cacheable(cacheNames = "certificates", key = "#id") + @Transactional(readOnly = true) + public CertificateSimpleDto findById(Long id) { + return certificateMapper.mapToSimpleDto(certificateService.findById(id)); + } + + @Transactional() + public CertificateSimpleDto generate(CertificateCreateDto certificateCreateDto) { + return certificateMapper.mapToSimpleDto(certificateService.save(certificateMapper.mapToCertificate(certificateCreateDto))); + } + //@Transactional(readOnly = true) + //public Page<CertificateDto> findAll(Pageable pageable) { + //return certificateMapper.mapToPageDto(certificateService.findAll(pageable)); + //} +} diff --git a/application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateMapper.java b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateMapper.java new file mode 100644 index 00000000..4ec2332e --- /dev/null +++ b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateMapper.java @@ -0,0 +1,49 @@ +package org.fuseri.modulecertificate.service; + +import org.fuseri.model.dto.certificate.CertificateCreateDto; +import org.fuseri.model.dto.certificate.CertificateSimpleDto; +import org.fuseri.modulecertificate.Certificate; +import org.mapstruct.Mapper; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; + +import java.time.Instant; +import java.util.List; + +@Mapper(componentModel = "spring") +public interface CertificateMapper { + + default CertificateSimpleDto mapToSimpleDto(Certificate certificate) + { + if ( certificate == null ) { + return null; + } + + return new CertificateSimpleDto( + certificate.getId().toString(), + certificate.getUserId(), + certificate.getGeneratedAt(), + certificate.getCourseId(), + certificate.getCertificateFile(), + certificate.getCertificateFileName()); + } + + default Certificate mapToCertificate(CertificateCreateDto certificateCreateDto) + { + if ( certificateCreateDto == null ) { + return null; + } + + return new Certificate(certificateCreateDto.getUser().getId(), + Instant.now(), + certificateCreateDto.getCourse().getId(), + null, + null); + } + + //List<CertificateDto> mapToList(List<Certificate> certificates); + + //default Page<CertificateDto> mapToPageDto(Page<Certificate> certificates) { + //return new PageImpl<>(mapToList(certificates.getContent()), certificates.getPageable(), certificates.getTotalPages()); + //} +} diff --git a/application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateRepository.java b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateRepository.java new file mode 100644 index 00000000..c5f5444e --- /dev/null +++ b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateRepository.java @@ -0,0 +1,11 @@ +package org.fuseri.modulecertificate.service; + +import org.fuseri.modulecertificate.Certificate; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + + +@Repository +public interface CertificateRepository extends JpaRepository<Certificate, Long> { + +} diff --git a/application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateService.java b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateService.java new file mode 100644 index 00000000..d5371de7 --- /dev/null +++ b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/CertificateService.java @@ -0,0 +1,36 @@ +package org.fuseri.modulecertificate.service; + +import org.fuseri.modulecertificate.Certificate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class CertificateService { + + private final CertificateRepository certificateRepository; + + @Autowired + public CertificateService(CertificateRepository certificateRepository) { + this.certificateRepository = certificateRepository; + } + + @Transactional(readOnly = true) + public Certificate findById(Long id) { + return certificateRepository.findById(id) + .orElseThrow(() -> new ResourceNotFoundException("Certificate with id: " + id + " was not found.")); + } + + @Transactional(readOnly = true) + public Certificate save(Certificate certificate) { + return certificateRepository.save(certificate); + } + + @Transactional(readOnly = true) + public Page<Certificate> findAll(Pageable pageable) { + return certificateRepository.findAll(pageable); + } +} + diff --git a/application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/ResourceNotFoundException.java b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/ResourceNotFoundException.java new file mode 100644 index 00000000..d24c445d --- /dev/null +++ b/application/module-certificate/src/main/java/org/fuseri/modulecertificate/service/ResourceNotFoundException.java @@ -0,0 +1,22 @@ +package org.fuseri.modulecertificate.service; + +public class ResourceNotFoundException extends RuntimeException { + public ResourceNotFoundException() { + } + + public ResourceNotFoundException(String message) { + super(message); + } + + public ResourceNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + public ResourceNotFoundException(Throwable cause) { + super(cause); + } + + public ResourceNotFoundException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/application/module-certificate/src/main/resources/application.properties b/application/module-certificate/src/main/resources/application.properties index 17abda7a..21fb3ce4 100644 --- a/application/module-certificate/src/main/resources/application.properties +++ b/application/module-certificate/src/main/resources/application.properties @@ -1 +1,10 @@ -server.port=5001 \ No newline at end of file +server.port=5001 + +spring.jpa.open-in-view=false +spring.datasource.url=jdbc:h2:mem:social-network;MODE=PostgreSQL +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=SedaQ-app +spring.datasource.password=$argon2id$v=19$m=16,t=2,p=1$YmF0bWFuYmF0bWFu$MdHYB359HdivAb9J6CaILw +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect +# showing SQL is generally good practice for running project locally to check whether there is not an issue with implementation of JPA methods. +spring.jpa.show-sql=true \ No newline at end of file -- GitLab