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