wpfat23-5 2 năm trước cách đây
mục cha
commit
7eec40da33
28 tập tin đã thay đổi với 1109 bổ sung65 xóa
  1. 63 4
      pom.xml
  2. 36 0
      src/main/java/org/example/CorsFilter.java
  3. 5 1
      src/main/java/org/example/JwtFilter.java
  4. 65 0
      src/main/java/org/example/component/ScheduledTasks.java
  5. 4 1
      src/main/java/org/example/configuration/AppInitializer.java
  6. 32 0
      src/main/java/org/example/configuration/EmailManagerConfiguration.java
  7. 1 1
      src/main/java/org/example/configuration/HibernatePersistenceConfiguration.java
  8. 83 0
      src/main/java/org/example/configuration/PostConstructInit.java
  9. 19 0
      src/main/java/org/example/configuration/SchedulingConfig.java
  10. 24 0
      src/main/java/org/example/configuration/SpringConfig.java
  11. 2 7
      src/main/java/org/example/configuration/SpringInit.java
  12. 66 0
      src/main/java/org/example/controller/BikeController.java
  13. 0 24
      src/main/java/org/example/controller/HelloController.java
  14. 93 16
      src/main/java/org/example/controller/LoginController.java
  15. 57 0
      src/main/java/org/example/controller/PdfController.java
  16. 95 0
      src/main/java/org/example/controller/UserController.java
  17. 42 0
      src/main/java/org/example/domain/Address.java
  18. 88 0
      src/main/java/org/example/domain/Bike.java
  19. 13 2
      src/main/java/org/example/domain/LoginRequest.java
  20. 42 0
      src/main/java/org/example/domain/LoginRequestCaptcha.java
  21. 61 0
      src/main/java/org/example/domain/Role.java
  22. 103 9
      src/main/java/org/example/domain/User.java
  23. 12 0
      src/main/java/org/example/repository/BikeRepository.java
  24. 13 0
      src/main/java/org/example/repository/RoleRepository.java
  25. 7 0
      src/main/java/org/example/service/EmailService.java
  26. 26 0
      src/main/java/org/example/service/EmailServiceImpl.java
  27. 6 0
      src/main/java/org/example/service/ReCaptchaService.java
  28. 51 0
      src/main/java/org/example/service/ReCaptchaServiceImpl.java

+ 63 - 4
pom.xml

@@ -12,6 +12,7 @@
         <maven.compiler.source>11</maven.compiler.source>
         <maven.compiler.target>11</maven.compiler.target>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <spring.version>6.0.2</spring.version>
     </properties>
 
     <packaging>war</packaging>
@@ -20,8 +21,15 @@
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-webmvc</artifactId>
-            <version>6.0.5</version>
+            <version>${spring.version}</version>
         </dependency>
+        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>2.15.2</version>
+        </dependency>
+
         <dependency>
             <groupId>jakarta.servlet</groupId>
             <artifactId>jakarta.servlet-api</artifactId>
@@ -51,7 +59,7 @@
         <dependency>
             <groupId>org.springframework.security</groupId>
             <artifactId>spring-security-web</artifactId>
-            <version>6.0.2</version>
+            <version>${spring.version}</version>
         </dependency>
         <dependency>
             <groupId>org.apache.tomcat.embed</groupId>
@@ -74,19 +82,70 @@
         <dependency>
             <groupId>org.springframework.security</groupId>
             <artifactId>spring-security-config</artifactId>
-            <version>5.7.7</version>
+<!--
+            <version>${spring.version}</version>
+-->
         </dependency>
         <dependency>
             <groupId>org.springframework.security</groupId>
             <artifactId>spring-security-jwt</artifactId>
             <version>1.1.1.RELEASE</version>
         </dependency>
-
+        <dependency>
+            <groupId>com.itextpdf</groupId>
+            <artifactId>itextpdf</artifactId>
+            <version>5.5.13</version>
+        </dependency>
         <dependency>
             <groupId>javax.xml.bind</groupId>
             <artifactId>jaxb-api</artifactId>
             <version>2.1</version>
         </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.26</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.security</groupId>
+            <artifactId>spring-security-config</artifactId>
+            <version>5.8.3</version>
+        </dependency>
+        <!-- for sending emails -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context-support</artifactId>
+            <version>6.0.7</version>
+        </dependency>
+        <dependency>
+            <groupId>jakarta.mail</groupId>
+            <artifactId>jakarta.mail-api</artifactId>
+            <version>2.1.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.mail</groupId>
+            <artifactId>jakarta.mail</artifactId>
+            <version>2.0.1</version>
+        </dependency>
+        <!-- for reCaptcha utils -->
+        <dependency>
+            <groupId>jakarta.json</groupId>
+            <artifactId>jakarta.json-api</artifactId>
+            <version>2.1.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish</groupId>
+            <artifactId>jakarta.json</artifactId>
+            <version>2.0.1</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/commons-validator/commons-validator -->
+        <dependency>
+            <groupId>commons-validator</groupId>
+            <artifactId>commons-validator</artifactId>
+            <version>1.7</version>
+        </dependency>
+
     </dependencies>
 
 </project>

+ 36 - 0
src/main/java/org/example/CorsFilter.java

@@ -0,0 +1,36 @@
+package org.example;
+
+import jakarta.servlet.*;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+@Component
+
+public class CorsFilter implements Filter {
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+        HttpServletResponse httpResponse = (HttpServletResponse) response;
+        HttpServletRequest requestt = (HttpServletRequest) request;
+
+        httpResponse.setHeader("Access-Control-Allow-Origin", "*");
+        httpResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
+        httpResponse.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
+        httpResponse.setHeader("Access-Control-Max-Age", "3600");
+        // Allow credentials (e.g., cookies, authorization headers) if needed
+        httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
+
+        // Allow all exposed headers (customize this based on your requirements)
+        httpResponse.setHeader("Access-Control-Expose-Headers", "*");
+
+        if ("OPTIONS".equalsIgnoreCase(requestt.getMethod())) {
+            httpResponse.setStatus(HttpServletResponse.SC_OK);
+        } else {
+            chain.doFilter(request, response);
+        }
+    }
+
+}

+ 5 - 1
src/main/java/org/example/JwtFilter.java

@@ -5,10 +5,14 @@ import io.jsonwebtoken.Jwts;
 import io.jsonwebtoken.SignatureException;
 import jakarta.servlet.*;
 import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
 
 
+import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
-
+@Component
 public class JwtFilter implements Filter {
 
     @Override

+ 65 - 0
src/main/java/org/example/component/ScheduledTasks.java

@@ -0,0 +1,65 @@
+package org.example.component;
+
+import org.example.domain.Bike;
+import org.example.repository.BikeRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+@Component
+public class ScheduledTasks {
+
+    @Autowired
+    BikeRepository bikeRepository;
+
+    public static boolean compareAndPerformAction(Date date1, Date date2) {
+        if (date1.compareTo(date2) > 0) {
+            //System.out.println("Action performed: First date is greater than the second date.");
+            return true;
+        } else {
+//            System.out.println("No action performed: Second date is greater than or equal to the first date.");
+            return false;
+        }
+    }
+
+    @Scheduled(fixedRate = 5000) // Run every 5 seconds
+    public void checkingDates() {
+        List<Bike> bikes = bikeRepository.findAll();
+        for (Bike bike :
+                bikes) {
+            Date from = bike.getRentedFrom();
+            Date to = bike.getRentedTo();
+            if (from != null && to != null) {
+                if (compareAndPerformAction(new Date(), to)) {
+                    bike.setUser(null);
+                    bike.setRentedFrom(null);
+                    bike.setRentedTo(null);
+                    bike.setPaid(false);
+                    bikeRepository.save(bike);
+                }
+            }
+        }
+    }
+
+    @Scheduled(fixedRate = 5000) // Run every 5 seconds
+    public void checkingIfBikeIsPaid() {
+        List<Bike> bikes = bikeRepository.findAll();
+        for (Bike bike :
+                bikes) {
+            Date from = bike.getRentedFrom();
+            Date to = bike.getRentedTo();
+            if (from != null && to != null && (!bike.isPaid())) {
+                bike.setUser(null);
+                bike.setRentedFrom(null);
+                bike.setRentedTo(null);
+                bike.setPaid(false);
+                bikeRepository.save(bike);
+            }
+        }
+    }
+}

+ 4 - 1
src/main/java/org/example/configuration/AppInitializer.java

@@ -6,6 +6,7 @@ import javax.servlet.ServletException;
 
 import jakarta.servlet.FilterRegistration;
 import jakarta.servlet.ServletRegistration;
+import org.example.CorsFilter;
 import org.example.JwtFilter;
 import org.springframework.web.filter.DelegatingFilterProxy;
 import org.springframework.web.WebApplicationInitializer;
@@ -16,7 +17,9 @@ public class AppInitializer implements WebApplicationInitializer {
 
     @Override
     public void onStartup(jakarta.servlet.ServletContext servletContext) {
-        // Register your JwtFilter
+        FilterRegistration.Dynamic corsFilter = servletContext.addFilter("CorsFilter", CorsFilter.class);
+        corsFilter.addMappingForUrlPatterns(null, false, "/*");
+
         FilterRegistration.Dynamic jwtFilter = servletContext.addFilter("JwtFilter", JwtFilter.class);
         jwtFilter.addMappingForUrlPatterns(null, false, "/api/*");
     }

+ 32 - 0
src/main/java/org/example/configuration/EmailManagerConfiguration.java

@@ -0,0 +1,32 @@
+package org.example.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.JavaMailSenderImpl;
+import java.util.Properties;
+
+@Configuration
+public class EmailManagerConfiguration {
+
+    @Bean
+    public JavaMailSender getJavaMailSender() {
+        JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
+        mailSender.setHost("YOUR_HOST");
+        mailSender.setPort(465); //SSL config
+
+        mailSender.setUsername("EMAIL");
+        mailSender.setPassword("PASSWORD");
+
+        Properties props = mailSender.getJavaMailProperties();
+        props.put("mail.transport.protocol", "smtp");
+        props.put("mail.smtp.auth", "true");
+        props.put("mail.smtp.starttls.enable", "true");
+        props.put("mail.debug", "true");
+        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
+
+        return mailSender;
+    }
+}
+
+

+ 1 - 1
src/main/java/org/example/configuration/HibernatePersistenceConfiguration.java

@@ -34,7 +34,7 @@ public class HibernatePersistenceConfiguration {
     private Properties getHibernateProperties() {
         Properties properties = new Properties();
         properties.put("hibernate.show_sql", "true");
-        properties.put("hibernate.hbm2ddl.auto", "update");
+        properties.put("hibernate.hbm2ddl.auto", "create");
         properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
         properties.put("hibernate.default_schema", "public");
         return properties;

+ 83 - 0
src/main/java/org/example/configuration/PostConstructInit.java

@@ -0,0 +1,83 @@
+package org.example.configuration;
+
+
+import org.example.domain.Address;
+import org.example.domain.Bike;
+import org.example.domain.Role;
+import org.example.domain.User;
+import org.example.repository.BikeRepository;
+import org.example.repository.RoleRepository;
+import org.example.repository.UserRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.sql.Date;
+import java.time.LocalDate;
+import java.util.*;
+
+
+@Component
+public class PostConstructInit {
+
+    @Autowired
+    UserRepository userRepository;
+
+    @Autowired
+    BikeRepository bikeRepository;
+
+    @Autowired
+    RoleRepository roleRepository;
+
+    @PostConstruct
+    public void init() {
+        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
+
+
+        Role userRole = new Role();
+        userRole.setRoleName("User");
+        Role managerRole = new Role();
+        managerRole.setRoleName("Manager");
+        Role adminRole = new Role();
+        adminRole.setRoleName("Admin");
+
+        User newUser = new User("login", bCryptPasswordEncoder.encode("pass"), "", new ArrayList<>(), new ArrayList<>());
+        newUser.setActive(true);
+
+        newUser.getRoles().add(userRole);
+        newUser.getRoles().add(managerRole);
+        newUser.getRoles().add(adminRole);
+        Address address = new Address();
+        address.setAddress("Łódź");
+        newUser.setAddress(address);
+
+        userRepository.save(newUser);
+
+        User user = userRepository.findByLogin("login");
+
+        LocalDate startDate = LocalDate.now().plusDays(10);  // Start from the current date plus 10 days
+
+        for (int i = 0; i < 6; i++) {
+            LocalDate rentedFrom = startDate.plusDays(i);
+            LocalDate rentedTo = rentedFrom.plusDays(4);
+
+            bikeRepository.save(new Bike(
+                    Date.valueOf(rentedFrom),
+                    Date.valueOf(rentedTo),
+                    5,
+                    user
+            ));
+        }
+        for (int i = 0; i < 6; i++) {
+            bikeRepository.save(new Bike(
+                    null,
+                    null,
+                    5,
+                    null
+            ));
+        }
+
+
+    }
+}

+ 19 - 0
src/main/java/org/example/configuration/SchedulingConfig.java

@@ -0,0 +1,19 @@
+package org.example.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
+
+@Configuration
+@EnableScheduling
+public class SchedulingConfig {
+
+    @Bean
+    public ThreadPoolTaskScheduler taskScheduler() {
+        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
+        scheduler.setPoolSize(10); // Set the number of threads in the pool
+        scheduler.setThreadNamePrefix("MyScheduler-");
+        return scheduler;
+    }
+}

+ 24 - 0
src/main/java/org/example/configuration/SpringConfig.java

@@ -0,0 +1,24 @@
+package org.example.configuration;
+
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import java.util.List;
+
+@Configuration
+@EnableWebMvc
+@EnableScheduling
+@ComponentScan("org.example")
+public class SpringConfig implements WebMvcConfigurer {
+
+    @Override
+    public void configureMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
+        messageConverters.add(new MappingJackson2HttpMessageConverter());
+    }
+
+}

+ 2 - 7
src/main/java/org/example/configuration/SpringInit.java

@@ -11,7 +11,7 @@ import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatche
 public class SpringInit extends AbstractAnnotationConfigDispatcherServletInitializer {
 
     protected Class<?>[] getRootConfigClasses() {
-        return new Class[] {HibernatePersistenceConfiguration.class};
+        return new Class[] {SpringConfig.class, HibernatePersistenceConfiguration.class, SchedulingConfig.class, EmailManagerConfiguration.class};
     }
 
     protected Class<?>[] getServletConfigClasses() {
@@ -22,12 +22,7 @@ public class SpringInit extends AbstractAnnotationConfigDispatcherServletInitial
         return new String[]{"/"};
     }
 
-/*
-    @Override
-    protected Filter[] getServletFilters() {
-        return new Filter[]{new JwtFilter()};
-    }
-*/
+
 
 }
 

+ 66 - 0
src/main/java/org/example/controller/BikeController.java

@@ -0,0 +1,66 @@
+package org.example.controller;
+
+import org.example.domain.Bike;
+import org.example.domain.User;
+import org.example.repository.BikeRepository;
+import org.example.repository.UserRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Optional;
+
+@RestController
+@RequestMapping(("api"))
+public class BikeController {
+
+    @Autowired
+    UserRepository userRepository;
+
+    @Autowired
+    BikeRepository bikeRepository;
+
+    @RequestMapping("/getAllBikes")
+    @ResponseBody
+    public List<Bike> getBikesList() {
+        return bikeRepository.findAll();
+    }
+
+    @RequestMapping("/createNewBike/{price}")
+    public void createNewBike(@PathVariable int price) {
+        bikeRepository.save(new Bike(
+                null,
+                null,
+                price,
+                null
+        ));
+    }
+
+    @RequestMapping("/rentABike/{login}/{bikeId}")
+    public void rentABike(@PathVariable String login, @PathVariable Long bikeId, @RequestBody Bike newDataBike) {
+        Optional<Bike> bike = bikeRepository.findById(bikeId);
+        User user = userRepository.findByLogin(login);
+        System.out.println("Bike rented");
+        if (bike.isPresent()) {
+            System.out.println("Bike present");
+            Bike bike1 = bike.get();
+            bike1.setRentedFrom(newDataBike.getRentedFrom());
+            bike1.setRentedTo(newDataBike.getRentedTo());
+            bike1.setPrice(newDataBike.getPrice());
+            bike1.setUser(user);
+            bikeRepository.save(bike1);
+            System.out.println("Bike rented");
+        }
+    }
+    @RequestMapping("/payForABike/{bikeId}")
+    public boolean payForABike(@PathVariable Long bikeId) {
+        Optional<Bike> bike = bikeRepository.findById(bikeId);
+        Bike bikeObject = bike.get();
+        if (bikeObject.getUser() == null) return false;
+        bikeObject.setPaid(true);
+        bikeRepository.save(bikeObject);
+        return true;
+    }
+
+
+}

+ 0 - 24
src/main/java/org/example/controller/HelloController.java

@@ -1,24 +0,0 @@
-package org.example.controller;
-
-import org.example.domain.User;
-import org.example.repository.UserRepository;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController("api")
-public class HelloController {
-
-    @Autowired
-    UserRepository userRepository;
-
-    @RequestMapping ("/hello")
-    public String helloWord() {
-        userRepository.save(new User("login", "pass"));
-
-        return "a";
-    }
-}

+ 93 - 16
src/main/java/org/example/controller/LoginController.java

@@ -1,28 +1,105 @@
 package org.example.controller;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
 import io.jsonwebtoken.Jwts;
 import io.jsonwebtoken.SignatureAlgorithm;
+
+import org.apache.commons.validator.routines.EmailValidator;
 import org.example.domain.LoginRequest;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.example.domain.LoginRequestCaptcha;
+import org.example.domain.Role;
+import org.example.domain.User;
+import org.example.repository.RoleRepository;
+import org.example.repository.UserRepository;
+import org.example.service.EmailServiceImpl;
+import org.example.service.ReCaptchaService;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.web.bind.annotation.*;
 
+import java.util.ArrayList;
 import java.util.Date;
 
 @RestController
 public class LoginController {
-    @RequestMapping(value="/login")
-    public String login() {
-        long currentTimeMillis = System.currentTimeMillis();
-        return Jwts.builder()
-                .setSubject("user.getLogin()")
-                .claim("roles","user")
-                .setIssuedAt(new Date(currentTimeMillis))
-                .setExpiration(new Date(currentTimeMillis + 60 * 60 * 1000)) //60min
-                .signWith(SignatureAlgorithm.HS256, "example")
-                .compact();
+    @Autowired
+    UserRepository userRepository;
+
+    @Autowired
+    EmailServiceImpl emailServiceImpl;
+
+    @Autowired
+    RoleRepository roleRepository;
+    ReCaptchaService reCaptchaService;
+
+    @Autowired
+    public void setReCaptchaService(ReCaptchaService reCaptchaService) {
+        this.reCaptchaService = reCaptchaService;
+    }
+
+    @RequestMapping(value = "/login")
+    public String login(@RequestBody LoginRequestCaptcha user) {
+        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
+        User foundUser = userRepository.findByLogin(user.getLogin());
+
+        if (foundUser == null || !foundUser.isActive() || !validateLogin(user)) {
+            return "";
+        } else if (bCryptPasswordEncoder.matches(user.getPassword(), foundUser.getPassword()) && reCaptchaService.verify(user.getCaptcha())) {
+            long currentTimeMillis = System.currentTimeMillis();
+            return Jwts.builder().setSubject(user.getLogin()).claim("roles", "user").setIssuedAt(new Date(currentTimeMillis)).setExpiration(new Date(currentTimeMillis + 60 * 60 * 1000)) //60min
+                    .signWith(SignatureAlgorithm.HS256, "example").compact();
+        }
+        return "";
+    }
+
+    private boolean validateLogin(LoginRequestCaptcha user) {
+        if (user.getLogin() == null || user.getPassword() == null) return false;
+        else return true;
+    }
+
+    @RequestMapping("/register")
+    public ResponseEntity<String> register(@RequestBody LoginRequest user) {
+        if (!validateRegister(user))
+            return new ResponseEntity<>("Invalid data", HttpStatus.BAD_REQUEST);
+        User foundUser = userRepository.findByLogin(user.getLogin());
+        if (foundUser == null) {
+            BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
+
+            User newUser = new User(user.getLogin(), bCryptPasswordEncoder.encode(user.getPassword()), user.getEmail(), new ArrayList<>(), new ArrayList<>());
+            userRepository.save(newUser);
+
+            Role userRole = roleRepository.findByRoleName("User");
+            newUser.getRoles().add(userRole);
+
+            userRepository.save(newUser);
+            emailServiceImpl.sendMail(newUser.getEmail(), "http://localhost:8080/activation?user=" + newUser.getLogin() + "&token=" +
+                    newUser.getActivationToken(), "activation");
+
+            return new ResponseEntity<>(HttpStatus.OK);
+        } else {
+            return new ResponseEntity<>("User with that name was found", HttpStatus.BAD_REQUEST);
+        }
+    }
+
+    private boolean validateRegister(LoginRequest user) {
+        EmailValidator emailValidator = EmailValidator.getInstance();
+
+        if (user.getLogin() == null || user.getEmail() == null || user.getPassword() == null) return false;
+        else if (user.getLogin().length() < 4 || user.getLogin().length() > 18) return false;
+        else if (user.getPassword().length() < 3 || user.getPassword().length() > 18) return false;
+        else if (user.getEmail().length() < 4 || user.getEmail().length() > 25) return false;
+        else if (!emailValidator.isValid(user.getEmail())) return false;
+        else return true;
+    }
+
+    @RequestMapping("/activation")
+    public void activation(@RequestParam String user, @RequestParam String token) {
+        User foundUser = userRepository.findByLogin(user);
+        if (foundUser.getActivationToken().equals(token)) {
+            foundUser.setActive(true);
+            userRepository.save(foundUser);
+        }
     }
 }

+ 57 - 0
src/main/java/org/example/controller/PdfController.java

@@ -0,0 +1,57 @@
+package org.example.controller;
+
+import com.itextpdf.text.Document;
+import com.itextpdf.text.DocumentException;
+import com.itextpdf.text.Paragraph;
+import com.itextpdf.text.pdf.PdfWriter;
+import jakarta.servlet.http.HttpServletResponse;
+import org.example.domain.Bike;
+import org.example.repository.BikeRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.temporal.ChronoUnit;
+import java.util.concurrent.TimeUnit;
+
+@RestController
+@RequestMapping(("api"))
+public class PdfController {
+
+    @Autowired
+    BikeRepository bikeRepository;
+
+    @GetMapping("/download-pdf/{bikeId}")
+    public void downloadPdf(HttpServletResponse response, @PathVariable int bikeId) throws IOException, DocumentException {
+        Bike bike = bikeRepository.findById(bikeId);
+        if (bike.getUser() == null) return;
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        Document document = new Document();
+        PdfWriter.getInstance(document, outputStream);
+        document.open();
+        document.add(new Paragraph("Invoice"));
+        document.add(new Paragraph("\n"));
+        document.add(new Paragraph("bikeId: " + bikeId));
+        document.add(new Paragraph("price for one day: " + bike.getPrice() + "$"));
+        long diffInMilliseconds = Math.abs(bike.getRentedFrom().getTime() - bike.getRentedTo().getTime());
+        long daysBetween = TimeUnit.MILLISECONDS.toDays(diffInMilliseconds) + 1;
+        document.add(new Paragraph("days: " + daysBetween));
+        document.add(new Paragraph("price: " + daysBetween * bike.getPrice() + "$"));
+
+        document.close();
+        byte[] pdfBytes = outputStream.toByteArray();
+
+
+        response.setContentType(MediaType.APPLICATION_PDF_VALUE);
+        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=sample.pdf");
+        response.getOutputStream().write(pdfBytes);
+    }
+}

+ 95 - 0
src/main/java/org/example/controller/UserController.java

@@ -0,0 +1,95 @@
+package org.example.controller;
+
+import org.example.domain.Address;
+import org.example.domain.Role;
+import org.example.domain.User;
+import org.example.repository.BikeRepository;
+import org.example.repository.RoleRepository;
+import org.example.repository.UserRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+@RequestMapping(("api"))
+public class UserController {
+
+    @Autowired
+    UserRepository userRepository;
+
+    @Autowired
+    RoleRepository roleRepository;
+
+
+    @RequestMapping("/getUserData/{login}")
+    public User getUserData(@PathVariable String login) {
+        User user = userRepository.findByLogin(login);
+        return user;
+    }
+
+    @RequestMapping("/getUserData")
+    public List<User> getUsersData() {
+        return userRepository.findAll();
+    }
+
+    @RequestMapping("/addRole/{login}/{role}")
+    public void addRole(@PathVariable String login, @PathVariable String role) {
+        System.out.println("Save role");
+        User user = userRepository.findByLogin(login);
+        Role roleObject = roleRepository.findByRoleName(role);
+        user.getRoles().add(roleObject);
+        userRepository.save(user);
+        System.out.println("Save role");
+    }
+
+    @RequestMapping("/removeRole/{login}/{role}")
+    public void removeRole(@PathVariable String login, @PathVariable String role) {
+        System.out.println("Remove role");
+        User user = userRepository.findByLogin(login);
+        Role roleObject = roleRepository.findByRoleName(role);
+        user.getRoles().remove(roleObject);
+        userRepository.save(user);
+        System.out.println("Remove role");
+    }
+
+    @RequestMapping("/toggleRole/{login}/{role}")
+    public void toggleRole(@PathVariable String login, @PathVariable String role) {
+        User user = userRepository.findByLogin(login);
+        Role roleObject = roleRepository.findByRoleName(role);
+        List<Role> userRolesList = user.getRoles();
+        if (userRolesList.contains(roleObject)) {
+            removeRole(login, role);
+        } else {
+            addRole(login, role);
+        }
+        userRepository.save(user);
+    }
+
+    @RequestMapping("/setAddress/{login}/{address}")
+    public void setAddress(@PathVariable String login, @PathVariable String address) {
+        User user = userRepository.findByLogin(login);
+        Address newAddress = new Address();
+        newAddress.setAddress(address);
+        user.setAddress(newAddress);
+        userRepository.save(user);
+    }
+
+    @RequestMapping("/getAddress/{login}")
+    public String getAddress(@PathVariable String login) {
+        User user = userRepository.findByLogin(login);
+        return user.getAddress().getAddress();
+    }
+
+    @RequestMapping("/setPassword/{login}/{password}")
+    public void getAddress(@PathVariable String login, @PathVariable String password) {
+        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
+
+        User user = userRepository.findByLogin(login);
+        user.setPassword(bCryptPasswordEncoder.encode(password));
+        userRepository.save(user);
+    }
+}

+ 42 - 0
src/main/java/org/example/domain/Address.java

@@ -0,0 +1,42 @@
+package org.example.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import jakarta.persistence.*;
+
+@Entity
+public class Address {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    private Long id;
+
+    @JsonIgnore
+    @OneToOne(mappedBy = "address")
+    private User user;
+
+    private String address;
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public User getUser() {
+        return user;
+    }
+
+    public void setUser(User user) {
+        this.user = user;
+    }
+}

+ 88 - 0
src/main/java/org/example/domain/Bike.java

@@ -0,0 +1,88 @@
+package org.example.domain;
+
+import jakarta.persistence.*;
+
+import java.sql.Date;
+
+@Entity
+public class Bike {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    private Date rentedFrom;
+    private Date rentedTo;
+    private int price;
+
+    private boolean paid;
+
+    public boolean isPaid() {
+        return paid;
+    }
+
+    public void setPaid(boolean paid) {
+        this.paid = paid;
+    }
+
+    @ManyToOne
+    @JoinColumn(name = "user_id")
+    private User user;
+
+
+    public Bike(Date rentedFrom, Date rentedTo, int price, User lender) {
+        this.rentedFrom = rentedFrom;
+        this.rentedTo = rentedTo;
+        this.price = price;
+        this.user = lender;
+    }
+
+    public User getUser() {
+        return user;
+    }
+
+    public void setUser(User user) {
+        this.user = user;
+    }
+
+
+
+    public Bike() {
+
+    }
+
+
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Date getRentedFrom() {
+        return rentedFrom;
+    }
+
+    public void setRentedFrom(Date rentedFrom) {
+        this.rentedFrom = rentedFrom;
+    }
+
+    public Date getRentedTo() {
+        return rentedTo;
+    }
+
+    public void setRentedTo(Date rentedTo) {
+        this.rentedTo = rentedTo;
+    }
+
+
+
+    public int getPrice() {
+        return price;
+    }
+
+    public void setPrice(int price) {
+        this.price = price;
+    }
+}

+ 13 - 2
src/main/java/org/example/domain/LoginRequest.java

@@ -1,8 +1,19 @@
 package org.example.domain;
 
+
 public class LoginRequest {
-    private String login;
-    private String password;
+    public String login;
+    public String password;
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public String email;
 
     public String getLogin() {
         return login;

+ 42 - 0
src/main/java/org/example/domain/LoginRequestCaptcha.java

@@ -0,0 +1,42 @@
+package org.example.domain;
+
+
+public class LoginRequestCaptcha {
+    public String login;
+    public String password;
+    public String captcha;
+
+    public String getCaptcha() {
+        return captcha;
+    }
+
+    public void setCaptcha(String captcha) {
+        this.captcha = captcha;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public String email;
+
+    public String getLogin() {
+        return login;
+    }
+
+    public void setLogin(String login) {
+        this.login = login;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+}

+ 61 - 0
src/main/java/org/example/domain/Role.java

@@ -0,0 +1,61 @@
+package org.example.domain;
+
+import com.fasterxml.jackson.annotation.JsonBackReference;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import jakarta.persistence.*;
+
+import java.util.List;
+import java.util.Objects;
+
+@Entity
+public class Role {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long Id;
+    private String roleName;
+
+    // Existing fields and annotations
+
+    public Long getId() {
+        return Id;
+    }
+
+    public void setId(Long id) {
+        Id = id;
+    }
+
+    public String getRoleName() {
+        return roleName;
+    }
+
+    public void setRoleName(String roleName) {
+        this.roleName = roleName;
+    }
+    @ManyToMany(mappedBy = "roles", fetch = FetchType.EAGER)
+    @JsonIgnore
+    private List<User> users;
+
+    // Existing methods and constructors
+
+    public List<User> getUsers() {
+        return users;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        Role role = (Role) o;
+        return Objects.equals(Id, role.Id) && Objects.equals(roleName, role.roleName) ;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(Id, roleName, users);
+    }
+
+    public void setUsers(List<User> users) {
+        this.users = users;
+    }
+}

+ 103 - 9
src/main/java/org/example/domain/User.java

@@ -1,15 +1,81 @@
 package org.example.domain;
 
-import jakarta.persistence.Entity;
-import jakarta.persistence.GeneratedValue;
-import jakarta.persistence.GenerationType;
-import jakarta.persistence.Id;
+import com.fasterxml.jackson.annotation.JsonBackReference;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonManagedReference;
+import jakarta.persistence.*;
+import org.springframework.data.repository.cdi.Eager;
+
+import java.util.List;
+import java.util.UUID;
 
 @Entity
 public class User {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
+    private String login;
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    private String email;
+    private String activationToken;
+
+    public String getActivationToken() {
+        return activationToken;
+    }
+
+    public void setActivationToken(String activationToken) {
+        this.activationToken = activationToken;
+    }
+
+    public boolean isActive() {
+        return active;
+    }
+
+    public void setActive(boolean active) {
+        this.active = active;
+    }
+
+    private boolean active;
+    @JsonIgnore
+    private String password;
+
+    public Address getAddress() {
+        return address;
+    }
+
+    public void setAddress(Address address) {
+        this.address = address;
+    }
+
+    @OneToOne(cascade = CascadeType.ALL)
+    @JoinColumn(name = "address_id", referencedColumnName = "id")
+    private Address address;
+
+    @JsonIgnore
+
+    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
+    private List<Bike> bikesList;
+
+    public List<Bike> getBikesList() {
+        return bikesList;
+    }
+
+    public void setBikesList(List<Bike> bikesList) {
+        this.bikesList = bikesList;
+    }
+
+    public User() {
+
+    }
 
     public String getLogin() {
         return login;
@@ -27,16 +93,25 @@ public class User {
         this.password = password;
     }
 
-    private String login;
-    private String password;
-
-    public User(String login, String password) {
+    public User(String login, String password, String email, List<Bike> bikesList, List<Role> roles) {
+        this.email = email;
         this.login = login;
         this.password = password;
+        this.bikesList = bikesList;
+        this.roles = roles;
+        this.activationToken = String.valueOf(UUID.randomUUID());
+        this.active = false;
     }
 
-    public User() {
+    public User(String login, String password, List<Bike> bikesList) {
+        this.login = login;
+        this.password = password;
+        this.bikesList = bikesList;
+    }
 
+    public User(String login, String password) {
+        this.login = login;
+        this.password = password;
     }
 
     public void setId(Long id) {
@@ -46,4 +121,23 @@ public class User {
     public Long getId() {
         return id;
     }
+    // Existing fields and annotations
+    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
+    @JoinTable(
+            name = "user_role",
+            joinColumns = @JoinColumn(name = "user_id"),
+            inverseJoinColumns = @JoinColumn(name = "role_id")
+    )
+    private List<Role> roles;
+
+    // Existing methods and constructors
+
+    public List<Role> getRoles() {
+        return roles;
+    }
+
+    public void setRoles(List<Role> roles) {
+        this.roles = roles;
+    }
+
 }

+ 12 - 0
src/main/java/org/example/repository/BikeRepository.java

@@ -0,0 +1,12 @@
+package org.example.repository;
+
+import org.example.domain.Bike;
+import org.example.domain.User;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.List;
+
+public interface BikeRepository extends JpaRepository<Bike, Long> {
+    Bike findById (long id);
+    List<Bike> findAll();
+}

+ 13 - 0
src/main/java/org/example/repository/RoleRepository.java

@@ -0,0 +1,13 @@
+package org.example.repository;
+
+import org.example.domain.Bike;
+import org.example.domain.Role;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.List;
+
+public interface RoleRepository extends JpaRepository<Role, Long> {
+    Role findById (long id);
+
+    Role findByRoleName(String user);
+}

+ 7 - 0
src/main/java/org/example/service/EmailService.java

@@ -0,0 +1,7 @@
+package org.example.service;
+
+public interface EmailService {
+    void sendMail(String receiver, String content, String subject);
+}
+
+

+ 26 - 0
src/main/java/org/example/service/EmailServiceImpl.java

@@ -0,0 +1,26 @@
+package org.example.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.mail.MailException;
+import org.springframework.mail.SimpleMailMessage;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.stereotype.Service;
+
+@Service
+public class EmailServiceImpl implements EmailService {
+
+    @Autowired
+    private JavaMailSender javaMailSender;
+
+    public void sendMail(String receiver, String content, String subject) throws MailException {
+        SimpleMailMessage mail = new SimpleMailMessage();
+        mail.setFrom("EMAIL");
+        mail.setTo(receiver);
+        mail.setSubject(subject);
+        mail.setText(content);
+        javaMailSender.send(mail);
+    }
+
+}
+
+

+ 6 - 0
src/main/java/org/example/service/ReCaptchaService.java

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

+ 51 - 0
src/main/java/org/example/service/ReCaptchaServiceImpl.java

@@ -0,0 +1,51 @@
+package org.example.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 = "YOUR_GOOGLE_KEY";
+
+    @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;
+        }
+    }
+}
+