Bladeren bron

captcha backend validation, reservation state update, sending email with pdf attachment,profile page buttons working, account activation via mail

mateuszsudra 2 jaren geleden
bovenliggende
commit
8ba288b1a8
27 gewijzigde bestanden met toevoegingen van 538 en 31 verwijderingen
  1. 6 0
      boat-reservation-logic/pom.xml
  2. 20 0
      boat-reservation-logic/src/main/java/pl/sudra/controller/BillController.java
  3. 39 0
      boat-reservation-logic/src/main/java/pl/sudra/controller/PdfController.java
  4. 31 2
      boat-reservation-logic/src/main/java/pl/sudra/controller/UserController.java
  5. 10 1
      boat-reservation-logic/src/main/java/pl/sudra/domain/User.java
  6. 1 1
      boat-reservation-logic/src/main/java/pl/sudra/repository/BillRepository.java
  7. 7 3
      boat-reservation-logic/src/main/java/pl/sudra/securityController/CustomInterceptor.java
  8. 15 0
      boat-reservation-logic/src/main/java/pl/sudra/securityController/JwtTokenUtil.java
  9. 23 10
      boat-reservation-logic/src/main/java/pl/sudra/securityController/SecurityController.java
  10. 3 1
      boat-reservation-logic/src/main/java/pl/sudra/service/BillService.java
  11. 15 1
      boat-reservation-logic/src/main/java/pl/sudra/service/BillServiceImpl.java
  12. 4 0
      boat-reservation-logic/src/main/java/pl/sudra/service/EmailService.java
  13. 126 0
      boat-reservation-logic/src/main/java/pl/sudra/service/EmailServiceImpl.java
  14. 12 0
      boat-reservation-logic/src/main/java/pl/sudra/service/PdfService.java
  15. 102 0
      boat-reservation-logic/src/main/java/pl/sudra/service/PdfServiceImpl.java
  16. 6 0
      boat-reservation-logic/src/main/java/pl/sudra/service/ReCaptchaService.java
  17. 52 0
      boat-reservation-logic/src/main/java/pl/sudra/service/ReCaptchaServiceImpl.java
  18. 8 0
      boat-reservation-view/src/app/admin-panel/admin-panel.component.ts
  19. 3 0
      boat-reservation-view/src/app/domain/reservation.ts
  20. 1 1
      boat-reservation-view/src/app/login-view/login-view.component.html
  21. 1 1
      boat-reservation-view/src/app/navbar/navbar.component.html
  22. 12 2
      boat-reservation-view/src/app/profile-page/profile-page.component.ts
  23. 4 1
      boat-reservation-view/src/app/register-view/register-view.component.ts
  24. 4 5
      boat-reservation-view/src/app/reservation-view/reservation-view.component.ts
  25. 3 2
      boat-reservation-view/src/app/services/auth.service.ts
  26. 20 0
      boat-reservation-view/src/app/services/reservation.service.ts
  27. 10 0
      boat-reservation-view/src/app/services/user.service.ts

+ 6 - 0
boat-reservation-logic/pom.xml

@@ -131,6 +131,12 @@
 <!--            <version>2.2.6.RELEASE</version>-->
 <!--        </dependency>-->
 
+        <!-- for pdf generation -->
+        <dependency>
+            <groupId>com.itextpdf</groupId>
+            <artifactId>itextpdf</artifactId>
+            <version>5.5.13.3</version>
+        </dependency>
 
 
         <!-- for sending emails -->

+ 20 - 0
boat-reservation-logic/src/main/java/pl/sudra/controller/BillController.java

@@ -2,14 +2,18 @@ package pl.sudra.controller;
 
 import org.springframework.data.repository.query.Param;
 import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.CrossOrigin;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
 import pl.sudra.domain.Bill;
 import pl.sudra.domain.Boat;
 import pl.sudra.service.BillService;
 
 import java.util.List;
 
+@RestController
+@CrossOrigin(origins = "http://localhost:1410")
 public class BillController {
     private BillService billService;
 
@@ -26,4 +30,20 @@ public class BillController {
         System.out.println("Getting Bill");
         return billService.getBill(id);
     }
+
+    @RequestMapping(
+            value = "/confirmBill",
+            method = RequestMethod.GET,
+            produces = MediaType.APPLICATION_JSON_VALUE)
+    public void confirmBill(@Param("id") Long id) {
+        billService.confirmReservation(id);
+    }
+
+    @RequestMapping(
+            value = "/cancelBill",
+            method = RequestMethod.GET,
+            produces = MediaType.APPLICATION_JSON_VALUE)
+    public void cancelBill(@Param("id") Long id) {
+        billService.cancelReservation(id);
+    }
 }

+ 39 - 0
boat-reservation-logic/src/main/java/pl/sudra/controller/PdfController.java

@@ -0,0 +1,39 @@
+package pl.sudra.controller;
+
+import com.itextpdf.text.DocumentException;
+import jakarta.mail.MessagingException;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.data.repository.query.Param;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+import pl.sudra.service.EmailService;
+import pl.sudra.service.PdfService;
+import pl.sudra.service.UserService;
+
+@RestController
+@CrossOrigin(origins = "http://localhost:1410")
+public class PdfController {
+    private PdfService pdfService;
+    private UserService userService;
+    private EmailService emailService;
+
+    public PdfController(PdfService pdfService, UserService userService, EmailService emailService) {
+        this.pdfService = pdfService;
+        this.userService = userService;
+        this.emailService = emailService;
+    }
+
+    @RequestMapping(
+            value = "/pdf",
+            method = RequestMethod.GET,
+            produces = MediaType.APPLICATION_JSON_VALUE)
+    public void pdf(@Param("username") String username, HttpServletResponse response) throws MessagingException, DocumentException {
+        emailService.sendMailWithPDF(username,
+                "Hello " + username + "!\n\nIn the attachment you can find billing with all your reservations.\n\nHave a good day!",
+                "Oslo Boating Service. Your billing is here!");
+//        pdfService.generatePDF(userService.findByUsername(username).get());
+    }
+}

+ 31 - 2
boat-reservation-logic/src/main/java/pl/sudra/controller/UserController.java

@@ -1,24 +1,30 @@
 package pl.sudra.controller;
 
 import org.springframework.data.repository.query.Param;
+import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.CrossOrigin;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
 import pl.sudra.domain.User;
+import pl.sudra.repository.UserRepository;
 import pl.sudra.service.UserService;
 
 import java.util.List;
-import java.util.Optional;
+
+import static pl.sudra.securityController.JwtTokenUtil.validateToken;
 
 @RestController
 @CrossOrigin(origins = "http://localhost:1410")
 public class UserController {
     private final UserService userService;
+    private final UserRepository userRepository;
 
-    public UserController(UserService userService) {
+    public UserController(UserService userService, UserRepository userRepository) {
         this.userService = userService;
+        this.userRepository = userRepository;
     }
 
     @RequestMapping(
@@ -51,4 +57,27 @@ public class UserController {
     public void deleteUser(@Param("id") Long id) {
         this.userService.deleteUser(id);
     }
+
+    @RequestMapping(
+            value = "/activateUser",
+            method = RequestMethod.GET,
+            produces = MediaType.APPLICATION_JSON_VALUE)
+    public ResponseEntity<String> activateUser(@Param("username") String username, @Param("token") String token) {
+        User u = this.userService.findByUsername(username).get();
+        if(u.isEnabled()){
+            return ResponseEntity
+                    .status(HttpStatus.FORBIDDEN)
+                    .body("{\"message\": \"User already activated.\"}");
+        }
+        if(!validateToken(token)){
+            return ResponseEntity
+                    .status(HttpStatus.FORBIDDEN)
+                    .body("{\"message\": \"Activation link has expired.\"}");
+        }
+        u.setEnabled(true);
+        this.userService.registerUser(u);
+        return ResponseEntity
+                .status(HttpStatus.OK)
+                .body("{\"message\": \"Account Activated\"}");
+    }
 }

+ 10 - 1
boat-reservation-logic/src/main/java/pl/sudra/domain/User.java

@@ -36,12 +36,21 @@ public class User {
     //    @NotNull
 //    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
     private String role;
+    @NotNull
+    private boolean enabled = false;
 
     public void setRole(String role) {
         this.role = role;
     }
 
-//    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+    //    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
 //    private List<Reservation> reservations;
 
 //    public void setReservations(Collection<Reservation> reservations) {

+ 1 - 1
boat-reservation-logic/src/main/java/pl/sudra/repository/BillRepository.java

@@ -6,7 +6,7 @@ import pl.sudra.domain.Bill;
 import java.util.List;
 
 public interface BillRepository  extends JpaRepository<Bill, Long> {
-    Bill findBoatById(long id);
+    Bill findBillById(long id);
 
     List<Bill> findAllByStatus(String waitingForPayment);
 }

+ 7 - 3
boat-reservation-logic/src/main/java/pl/sudra/securityController/CustomInterceptor.java

@@ -17,7 +17,9 @@ public class CustomInterceptor implements HandlerInterceptor {
             "/hello",
             "/login",
             "/register",
-            "/getAllBoats"
+            "/getAllBoats",
+            "/activateUser",
+            "/pdf"
     );
     List<String> customer_and_above = List.of(
             "/createReservation",
@@ -25,7 +27,9 @@ public class CustomInterceptor implements HandlerInterceptor {
             "/getUser",
             "/findReservationsOfUserId",
             "/getBoatNameById",
-            "/getBill"
+            "/getBill",
+            "/confirmBill",
+            "/cancelBill"
     );
     List<String> manager_and_above = Stream.concat(customer_and_above.stream(),
                     List.of(
@@ -47,7 +51,7 @@ public class CustomInterceptor implements HandlerInterceptor {
         if (Objects.equals(request.getMethod(), "OPTIONS")) {
             response.setHeader("Access-Control-Allow-Origin", "*");
             response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
-            response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
+            response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, recaptcha");
             response.setHeader("Access-Control-Max-Age", "3600");
             return true;
         }

+ 15 - 0
boat-reservation-logic/src/main/java/pl/sudra/securityController/JwtTokenUtil.java

@@ -19,6 +19,7 @@ public class JwtTokenUtil {
 //    private static final long EXPIRATION_TIME = 1000 * 30; // 30 sec
 //    private static final long EXPIRATION_TIME = 1000 * 60 * 30; // 30 min
     private static final long EXPIRATION_TIME = 1000 * 60 * 60 * 24; // 1 day
+    private static final long EXPIRATION_TIME_USER_ACTIVATION = 1000 * 60 * 60 * 24; // 1 day
 
     public static String generateToken(String username, Long id, String role) {
         Date now = new Date();
@@ -37,6 +38,20 @@ public class JwtTokenUtil {
                 .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
                 .compact();
     }
+    public static String generateTokenUserActivation() {
+        Date now = new Date();
+        Date expiration = new Date(now.getTime() + EXPIRATION_TIME_USER_ACTIVATION);
+
+        Claims claims = Jwts.claims();
+
+        claims.put("iat", now);
+        claims.put("exp", expiration);
+
+        return Jwts.builder()
+                .setClaims(claims)
+                .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
+                .compact();
+    }
 
     public static boolean validateToken(String token) {
         try {

+ 23 - 10
boat-reservation-logic/src/main/java/pl/sudra/securityController/SecurityController.java

@@ -1,6 +1,7 @@
 package pl.sudra.securityController;
 
 
+import jakarta.servlet.http.HttpServletRequest;
 import jakarta.validation.Valid;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
@@ -13,6 +14,7 @@ import pl.sudra.domain.LoginDto;
 import pl.sudra.domain.Role;
 import pl.sudra.domain.User;
 import pl.sudra.service.EmailService;
+import pl.sudra.service.ReCaptchaService;
 import pl.sudra.service.RoleService;
 import pl.sudra.service.UserService;
 
@@ -21,29 +23,33 @@ import java.util.stream.Collectors;
 
 import org.springframework.context.support.DefaultMessageSourceResolvable;
 
+import static pl.sudra.securityController.JwtTokenUtil.generateTokenUserActivation;
+
 @RestController
 @CrossOrigin(origins = "http://localhost:1410")
 public class SecurityController {
     private final UserService userService;
     private final RoleService roleService;
     private final EmailService emailService;
+    private final ReCaptchaService reCaptchaService;
     @Autowired
     private PasswordEncoder passwordEncoder;
 
-    public SecurityController(UserService userService, RoleService roleService, EmailService emailService) {
+    public SecurityController(UserService userService, RoleService roleService, EmailService emailService, ReCaptchaService reCaptchaService) {
         this.userService = userService;
         this.roleService = roleService;
         this.emailService = emailService;
+        this.reCaptchaService = reCaptchaService;
     }
 
     @RequestMapping(
             value = "/register",
             method = RequestMethod.POST,
             produces = MediaType.APPLICATION_JSON_VALUE)
-    public ResponseEntity<?> Register(@Valid @RequestBody User user, BindingResult bindingResult) {
+    public ResponseEntity<?> Register(@Valid @RequestBody User user, BindingResult bindingResult, HttpServletRequest request) {
         // validation check
         System.out.println("register - validation check");
-        if (bindingResult.hasErrors()) {
+        if (bindingResult.hasErrors() || !reCaptchaService.verify(request.getHeader("recaptcha"))) {
             List<String> errors = bindingResult.getAllErrors()
                     .stream()
                     .map(DefaultMessageSourceResolvable::getDefaultMessage)
@@ -51,6 +57,9 @@ public class SecurityController {
 
             ValidationErrorResponse errorResponse = new ValidationErrorResponse();
             errorResponse.setMessage("Validation Error");
+            if (!reCaptchaService.verify(request.getHeader("recaptcha"))) {
+                errors.add("Captcha validation failed.");
+            }
             errorResponse.setErrors(errors);
 
             return ResponseEntity.badRequest().body(errorResponse);
@@ -84,14 +93,16 @@ public class SecurityController {
 
         user.setRole(roles);
 
-        System.out.println("hej" + user.toString());
-
         this.userService.registerUser(user);
 
         this.emailService.sendMail(
                 user.getEmail(),
-                "Welcome in our app!",
-                "Account Created");
+                "Welcome in our app!\n\n" +
+                        "Please activate your account by accessing this link:\n\n" +
+                        "http://localhost:2137/activateUser?" +
+                        "username=" + user.getUsername() + "&" +
+                        "token=" + generateTokenUserActivation(),
+                "Oslo Boating Service. Activate your account!");
 
         return ResponseEntity
                 .status(HttpStatus.OK)
@@ -122,9 +133,11 @@ public class SecurityController {
                 );
                 System.out.println(jwtToken);
 
-//                return ResponseEntity.ok()
-//                        .header("Authorization", "Bearer " + jwtToken)
-//                        .body("Request is valid");
+                if (!user.get().isEnabled()) {
+                    return ResponseEntity
+                            .status(HttpStatus.FORBIDDEN)
+                            .body("{\"message\": \"Account not activated. Check your email inbox.\"}");
+                }
 
                 return ResponseEntity
                         .status(HttpStatus.OK)

+ 3 - 1
boat-reservation-logic/src/main/java/pl/sudra/service/BillService.java

@@ -12,5 +12,7 @@ public interface BillService {
 	void removeBill(long id);
 	Bill getBill(long id);
 	void cancelUnpaidReservations();
-	
+	void confirmReservation(Long id);
+	void cancelReservation(Long id);
+
 }

+ 15 - 1
boat-reservation-logic/src/main/java/pl/sudra/service/BillServiceImpl.java

@@ -44,7 +44,7 @@ public class BillServiceImpl implements BillService {
 
     @Override
     public Bill getBill(long id) {
-        return billRepository.findBoatById(id);
+        return billRepository.findBillById(id);
     }
 
     // every day at 6 AM
@@ -66,5 +66,19 @@ public class BillServiceImpl implements BillService {
             }
         });
     }
+
+    @Override
+    public void confirmReservation(Long id) {
+        Bill b = billRepository.findBillById(id);
+        b.setStatus("Confirmed");
+        billRepository.saveAndFlush(b);
+    }
+
+    @Override
+    public void cancelReservation(Long id) {
+        Bill b = billRepository.findBillById(id);
+        b.setStatus("Cancelled");
+        billRepository.saveAndFlush(b);
+    }
 }
 

+ 4 - 0
boat-reservation-logic/src/main/java/pl/sudra/service/EmailService.java

@@ -1,5 +1,9 @@
 package pl.sudra.service;
 
+import com.itextpdf.text.DocumentException;
+import jakarta.mail.MessagingException;
+
 public interface EmailService {
     void sendMail(String receiver, String content, String subject);
+    void sendMailWithPDF(String username, String content, String subject) throws MessagingException, DocumentException;
 }

+ 126 - 0
boat-reservation-logic/src/main/java/pl/sudra/service/EmailServiceImpl.java

@@ -1,10 +1,26 @@
 package pl.sudra.service;
 
+import com.itextpdf.text.*;
+import com.itextpdf.text.pdf.PdfPCell;
+import com.itextpdf.text.pdf.PdfPTable;
+import com.itextpdf.text.pdf.PdfWriter;
+import jakarta.mail.MessagingException;
+import jakarta.mail.internet.MimeMessage;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.ByteArrayResource;
 import org.springframework.mail.MailException;
 import org.springframework.mail.SimpleMailMessage;
 import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.MimeMessageHelper;
 import org.springframework.stereotype.Service;
+import pl.sudra.domain.Boat;
+import pl.sudra.domain.Reservation;
+import pl.sudra.domain.User;
+
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
 
 @Service
 public class EmailServiceImpl implements EmailService {
@@ -12,6 +28,18 @@ public class EmailServiceImpl implements EmailService {
     @Autowired
     private JavaMailSender javaMailSender;
 
+    private PdfService pdfService;
+    private UserService userService;
+    private ReservationService reservationService;
+    private BoatService boatService;
+
+    public EmailServiceImpl(PdfService pdfService, UserService userService, ReservationService reservationService, BoatService boatService) {
+        this.pdfService = pdfService;
+        this.userService = userService;
+        this.reservationService = reservationService;
+        this.boatService = boatService;
+    }
+
     public void sendMail(String receiver, String content, String subject) throws MailException {
         SimpleMailMessage mail = new SimpleMailMessage();
         mail.setFrom("EmailAuthor-SpringApplication"); // you may specify the name of the "from" field
@@ -21,5 +49,103 @@ public class EmailServiceImpl implements EmailService {
         javaMailSender.send(mail);
     }
 
+    public ByteArrayOutputStream generatePDF(User user) throws DocumentException {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+        Document document = new Document();
+        PdfWriter writer = PdfWriter.getInstance(document, outputStream);
+
+        document.open();
+        Font font = FontFactory.getFont(FontFactory.HELVETICA, 20);
+
+        // Create a paragraph with centered and bigger text
+        Paragraph paragraph = new Paragraph("BILLING\n", font);
+        paragraph.setAlignment(Element.ALIGN_CENTER);
+
+        document.add(paragraph);
+        document.add(new Paragraph("\tUser Info:\n\n"));
+
+        PdfPTable userInfoTable = new PdfPTable(4);
+//        userInfoTable.setWidthPercentage(100);
+        userInfoTable.setWidths(new float[]{30.0F, 90.0F, 170.0F, 60.0F});
+        System.out.println("WIDTH: " + userInfoTable.getTotalWidth());
+
+        // Add table headers
+        for (String header : List.of("ID", "USERNAME", "EMAIL", "ROLES")) {
+            PdfPCell cell = new PdfPCell(new Paragraph(header));
+            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
+
+            userInfoTable.addCell(cell);
+        }
+        // Add user info
+        for (String text : List.of(user.getId().toString(), user.getUsername(), user.getEmail(), user.getRole())) {
+            PdfPCell cell = new PdfPCell(new Paragraph(text));
+            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
+            userInfoTable.addCell(cell);
+        }
+
+        document.add(userInfoTable);
+
+        document.add(new Paragraph("\n\tUser's reservations info:\n\n"));
+
+        List<Reservation> reservations = reservationService.findReservationsByUserId(user.getId());
+        List<Boat> boats = boatService.getBoats();
+
+        PdfPTable table = new PdfPTable(7);
+
+        // Set table width as a percentage of the page width
+        table.setWidthPercentage(100);
+
+        // Add table headers
+        for (String header : List.of("ID", "BOAT", "DATE", "FROM", "TO", "COST", "STATUS")) {
+            PdfPCell cell = new PdfPCell(new Paragraph(header));
+            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
+
+            table.addCell(cell);
+        }
+
+        for (Reservation res : reservations) {
+            // Add user info
+            for (String text : List.of(
+                    res.getId().toString(),
+                    boats.stream().filter(boat -> Objects.equals(boat.getId(), res.getBoatId())).findFirst().get().getName(),
+                    res.getDate().toString(),
+                    "" + res.getStartHour(),
+                    "" + res.getEndHour(),
+                    res.getBill().getTotalCost().toString(),
+                    res.getBill().getStatus())) {
+                PdfPCell cell = new PdfPCell(new Paragraph(text));
+                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
+                table.addCell(cell);
+            }
+        }
+
+        // Add table to the document
+        document.add(table);
+        document.close();
+
+        return outputStream;
+    }
+
+    @Override
+    public void sendMailWithPDF(String username, String content, String subject) throws MailException, MessagingException, DocumentException {
+//        SimpleMailMessage mail = new SimpleMailMessage();
+        MimeMessage message = javaMailSender.createMimeMessage();
+        MimeMessageHelper helper = new MimeMessageHelper(message, true);
+
+        User u = userService.findByUsername(username).get();
+
+        helper.setFrom("EmailAuthor-SpringApplication"); // you may specify the name of the "from" field
+        helper.setTo(u.getEmail());
+        helper.setSubject(subject);
+        helper.setText(content);
+
+        helper.addAttachment(
+                username + "_billing.pdf",
+                new ByteArrayResource(generatePDF(u).toByteArray()));
+
+        javaMailSender.send(message);
+    }
+
 }
 

+ 12 - 0
boat-reservation-logic/src/main/java/pl/sudra/service/PdfService.java

@@ -0,0 +1,12 @@
+package pl.sudra.service;
+
+import jakarta.servlet.http.HttpServletResponse;
+import pl.sudra.domain.User;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+
+public interface PdfService {
+    public OutputStream generatePDF(User user, HttpServletResponse response);
+    public ByteArrayOutputStream generatePDF(User user);
+}

+ 102 - 0
boat-reservation-logic/src/main/java/pl/sudra/service/PdfServiceImpl.java

@@ -0,0 +1,102 @@
+package pl.sudra.service;
+
+import com.itextpdf.text.Chunk;
+import com.itextpdf.text.Document;
+import com.itextpdf.text.DocumentException;
+import com.itextpdf.text.Paragraph;
+import com.itextpdf.text.pdf.PdfPTable;
+import com.itextpdf.text.pdf.PdfWriter;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.stereotype.Service;
+import pl.sudra.domain.User;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+@Service
+public class PdfServiceImpl implements PdfService{
+    @Override
+    public OutputStream generatePDF(User user, HttpServletResponse response) {
+        try{
+            OutputStream o = response.getOutputStream();
+            response.setCharacterEncoding("UTF-8");
+            response.setContentType("application/pdf");
+            response.setHeader("Content-Disposition", "inline; filename=" + user.getUsername() + ".pdf");
+            Document pdf = new Document();
+            PdfWriter.getInstance(pdf, o);
+            pdf.open();
+            pdf.add(new Paragraph("Pdf example - Spring Framework & iText library"));
+            pdf.add(new Paragraph(Chunk.NEWLINE));
+            PdfPTable table = new PdfPTable(2);
+            table.addCell("FirsName");
+            table.addCell("appUser.getFirstName()");
+//            table.addCell(appUser.getFirstName());
+            table.addCell("LastName");
+            table.addCell("appUser.getLastName()");
+//            table.addCell(appUser.getLastName());
+            table.addCell("PESEL");
+            table.addCell("appUser.getPesel().getPESEL()");
+//            table.addCell(appUser.getPesel().getPESEL());
+            table.addCell("Login");
+            table.addCell("appUser.getLogin()");
+//            table.addCell(appUser.getLogin());
+            table.addCell("Email");
+            table.addCell("appUser.getEmail()");
+//            table.addCell(appUser.getEmail());
+            table.addCell("Active");
+            table.addCell("String.valueOf(appUser.isEnabled())");
+//            table.addCell(String.valueOf(appUser.isEnabled()));
+            pdf.add(table);
+            pdf.close();
+            o.close();
+            return o;
+        }
+        catch (IOException| DocumentException e){
+            e.printStackTrace();
+        }
+        return null;
+    }
+    @Override
+    public ByteArrayOutputStream generatePDF(User user) {
+        try{
+            ByteArrayOutputStream o = new ByteArrayOutputStream();
+//            ByteArrayOutputStream o = response.getOutputStream();
+//            response.setCharacterEncoding("UTF-8");
+//            response.setContentType("application/pdf");
+//            response.setHeader("Content-Disposition", "inline; filename=" + user.getUsername() + ".pdf");
+            Document pdf = new Document();
+            PdfWriter.getInstance(pdf, o);
+            pdf.open();
+            pdf.add(new Paragraph("Pdf example - Spring Framework & iText library"));
+            pdf.add(new Paragraph(Chunk.NEWLINE));
+            PdfPTable table = new PdfPTable(2);
+            table.addCell("FirsName");
+            table.addCell("appUser.getFirstName()");
+//            table.addCell(appUser.getFirstName());
+            table.addCell("LastName");
+            table.addCell("appUser.getLastName()");
+//            table.addCell(appUser.getLastName());
+            table.addCell("PESEL");
+            table.addCell("appUser.getPesel().getPESEL()");
+//            table.addCell(appUser.getPesel().getPESEL());
+            table.addCell("Login");
+            table.addCell("appUser.getLogin()");
+//            table.addCell(appUser.getLogin());
+            table.addCell("Email");
+            table.addCell("appUser.getEmail()");
+//            table.addCell(appUser.getEmail());
+            table.addCell("Active");
+            table.addCell("String.valueOf(appUser.isEnabled())");
+//            table.addCell(String.valueOf(appUser.isEnabled()));
+            pdf.add(table);
+            pdf.close();
+            o.close();
+            return o;
+        }
+        catch (IOException| DocumentException e){
+            e.printStackTrace();
+        }
+        return null;
+    }
+}

+ 6 - 0
boat-reservation-logic/src/main/java/pl/sudra/service/ReCaptchaService.java

@@ -0,0 +1,6 @@
+package pl.sudra.service;
+
+public interface ReCaptchaService {
+    boolean verify(String captcha);
+}
+

+ 52 - 0
boat-reservation-logic/src/main/java/pl/sudra/service/ReCaptchaServiceImpl.java

@@ -0,0 +1,52 @@
+package pl.sudra.service;
+
+import jakarta.json.Json;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonReader;
+import org.springframework.stereotype.Service;
+
+import javax.net.ssl.HttpsURLConnection;
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.net.URL;
+
+@Service
+public class ReCaptchaServiceImpl implements ReCaptchaService {
+    private static final String URL = "https://www.google.com/recaptcha/api/siteverify";
+    private static final String GOOGLE_KEY = "6LcqrYQlAAAAAAdyX-4dWY-jGPPomTtWRd6pIpk6";
+
+    @Override
+    public boolean verify(String captcha) {
+        if (captcha == null || "".equals(captcha)) return false;
+        try {
+            URL obj = new URL(URL);
+            HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
+            con.setRequestMethod("POST");
+            String postParams = "secret=" + GOOGLE_KEY + "&response=" + captcha;
+            // Send post request
+            con.setDoOutput(true);
+            DataOutputStream wr = new DataOutputStream(con.getOutputStream());
+            wr.writeBytes(postParams);
+            wr.flush();
+            wr.close();
+            BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
+            String inputLine;
+            StringBuilder response = new StringBuilder();
+            while ((inputLine = in.readLine()) != null) {
+                response.append(inputLine);
+            }
+            in.close();
+            //parse JSON response and return 'success' value
+            JsonReader jsonReader = Json.createReader(new StringReader(response.toString()));
+            JsonObject jsonObject = jsonReader.readObject();
+            jsonReader.close();
+            return jsonObject.getBoolean("success");
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+}
+

+ 8 - 0
boat-reservation-view/src/app/admin-panel/admin-panel.component.ts

@@ -43,5 +43,13 @@ export class AdminPanelComponent {
   deleteUser(id: number) {
     this.users = this.users.filter(u => u.id !== id)
     this.userService.deleteUser(id)
+    if(id.toString() === sessionStorage.getItem("username_id")){
+      this.logout()
+    }
+  }
+
+  logout() {
+    sessionStorage.clear()
+    window.location.href = "http://localhost:1410/"
   }
 }

+ 3 - 0
boat-reservation-view/src/app/domain/reservation.ts

@@ -5,6 +5,9 @@ export class Reservation {
   date = ''
   startHour = ''
   endHour = ''
+  bill = {
+    status: ''
+  }
 
   constructor(id: string, client_id: string, boat_id: string, date: string, start_hour: string, end_hour: string) {
     this.id = id;

+ 1 - 1
boat-reservation-view/src/app/login-view/login-view.component.html

@@ -31,7 +31,7 @@
   <p>Don't have an account?</p>
   <input class="enabled"
          type="submit"
-         value="REGISTER HERE"
+         value="Register"
          routerLink="/register"
          routerLinkActive="activebutton"
          style="width: 210px">

+ 1 - 1
boat-reservation-view/src/app/navbar/navbar.component.html

@@ -41,7 +41,7 @@
     <div class="navbar-button"
          routerLink="/profile"
          routerLinkActive="activebutton"
-         *ngIf="isManager">
+         *ngIf="isLogged">
       <a>
         PROFILE PAGE
       </a>

+ 12 - 2
boat-reservation-view/src/app/profile-page/profile-page.component.ts

@@ -59,17 +59,27 @@ export class ProfilePageComponent {
 
   deleteAccount() {
     this.userService.deleteUser(this.user_info.id)
+    this.logout()
   }
 
   sendEmail() {
-    console.log("email")
+    this.userService.pdf(this.user_info.username)
   }
 
   confirmReservation(id: number) {
+    this.reservationService.confirmReservation(id)
     console.log(id)
+    console.log(this.reservations_info)
+    this.reservations_info.find(r => r.bill.id === id).bill.status = "Confirmed"
   }
 
   cancelReservation(id: number) {
-    console.log(id)
+    this.reservationService.cancelReservation(id)
+    this.reservations_info.find(r => r.bill.id === id).bill.status = "Cancelled"
+  }
+
+  logout() {
+    sessionStorage.clear()
+    window.location.href = "http://localhost:1410/"
   }
 }

+ 4 - 1
boat-reservation-view/src/app/register-view/register-view.component.ts

@@ -13,6 +13,7 @@ export class RegisterViewComponent {
   formData: FormGroup;
   isCaptchaResolved: boolean = false;
   errors = ""
+  captchaResponse: string | null = null;
 
   constructor(private authService: AuthService,
               private formBuilder: FormBuilder) {
@@ -27,6 +28,7 @@ export class RegisterViewComponent {
 
   resolved(captchaResponse: string) {
     console.log(`Resolved captcha with response: ${captchaResponse}`);
+    this.captchaResponse = captchaResponse;
     this.isCaptchaResolved = captchaResponse !== null;
   }
 
@@ -36,7 +38,8 @@ export class RegisterViewComponent {
     this.authService.register(
       this.formData.get('username')?.value,
       this.formData.get('password')?.value,
-      this.formData.get('email')?.value).subscribe(
+      this.formData.get('email')?.value,
+      this.captchaResponse!).subscribe(
       (response) => {
         console.log('POST request successful', response);
 

+ 4 - 5
boat-reservation-view/src/app/reservation-view/reservation-view.component.ts

@@ -63,8 +63,7 @@ export class ReservationViewComponent {
 
     if (now > selected) {
       return true
-    }
-    else if (now.getDate() == selected.getDate()){
+    } else if (now.getDate() == selected.getDate()) {
       return this.fromHour <= new Date().getHours()
     }
     return false
@@ -151,9 +150,9 @@ export class ReservationViewComponent {
     this.reservationService.findReservations(parseInt(this.boat), this.date).subscribe(
       response => {
         console.log(response)
-        this.reservedHours = response.map(reservation =>
-          [reservation.startHour, reservation.endHour]
-        )
+        this.reservedHours = response
+          .filter(reservation => reservation.bill.status !== 'Cancelled')
+          .map(reservation => [reservation.startHour, reservation.endHour])
         this.setHourSquaresByDatabase(this.reservedHours)
         this.setHourSquaresBySelectedHours()
       }

+ 3 - 2
boat-reservation-view/src/app/services/auth.service.ts

@@ -28,7 +28,7 @@ export class AuthService {
     return this.http.post<any>(url, loginDto, {headers})
   }
 
-  register(username: string, password: string, email: string): Observable<any> {
+  register(username: string, password: string, email: string, captcha:string): Observable<any> {
     console.log("register")
     const url = 'http://localhost:2137/register';
     let registerDto = {
@@ -37,7 +37,8 @@ export class AuthService {
       "email": email
     }
     const headers = new HttpHeaders()
-      .set('Content-Type', 'application/json');
+      .set('Content-Type', 'application/json')
+      .set('recaptcha', captcha);
 
     return this.http.post(url, registerDto, {headers})
   }

+ 20 - 0
boat-reservation-view/src/app/services/reservation.service.ts

@@ -55,6 +55,26 @@ export class ReservationService {
       });
   }
 
+  cancelReservation(id: number): any {
+    const url = 'http://localhost:2137/cancelBill?id=' + id;
+
+    const headers = new HttpHeaders()
+      .set('Content-Type', 'application/json')
+      .set('Authorization', sessionStorage.getItem("jwtToken")!);
+
+    return this.http.get<any>(url, {headers}).subscribe();
+  }
+
+  confirmReservation(id: number): any {
+    const url = 'http://localhost:2137/confirmBill?id=' + id;
+
+    const headers = new HttpHeaders()
+      .set('Content-Type', 'application/json')
+      .set('Authorization', sessionStorage.getItem("jwtToken")!);
+
+    return this.http.get<any>(url, {headers}).subscribe();
+  }
+
   clearBoat() {
 
   }

+ 10 - 0
boat-reservation-view/src/app/services/user.service.ts

@@ -50,4 +50,14 @@ export class UserService {
 
     return this.http.get<User>(url, {headers})
   }
+
+  pdf(username: string) {
+    const url = 'http://localhost:2137/pdf?username=' + username;
+
+    const headers = new HttpHeaders()
+      .set('Content-Type', 'application/json')
+      .set('Authorization', sessionStorage.getItem("jwtToken")!);
+
+    return this.http.get<User>(url, {headers}).subscribe()
+  }
 }