diff --git a/module09/src/test/java/ru/sberbank/edu/AppTest.java b/module09/src/test/java/ru/sberbank/edu/AppTest.java deleted file mode 100644 index 895d735c..00000000 --- a/module09/src/test/java/ru/sberbank/edu/AppTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package ru.sberbank.edu; - -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -/** - * Unit test for simple App. - */ -public class AppTest - extends TestCase -{ - /** - * Create the test case - * - * @param testName name of the test case - */ - public AppTest( String testName ) - { - super( testName ); - } - - /** - * @return the suite of tests being tested - */ - public static Test suite() - { - return new TestSuite( AppTest.class ); - } - - /** - * Rigourous Test :-) - */ - public void testApp() - { - assertTrue( true ); - } -} diff --git a/module13/.gitignore b/module13/.gitignore new file mode 100644 index 00000000..5ff6309b --- /dev/null +++ b/module13/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/module13/README.md b/module13/README.md new file mode 100644 index 00000000..8c663473 --- /dev/null +++ b/module13/README.md @@ -0,0 +1,9 @@ +# Module 13. Docker + +### Требования: +Доработать ДЗ 12, добавить возможность запускать приложение в контейнере. + +## Критерии приемки: + +1. Для запуска приложения использовать Docker (docker-compose.yml). +2. В качестве бд использовать PostgreSQL (предпочтение) или любую другую бд. \ No newline at end of file diff --git a/module13/docker-compose.yml b/module13/docker-compose.yml new file mode 100644 index 00000000..de348b7d --- /dev/null +++ b/module13/docker-compose.yml @@ -0,0 +1,27 @@ +version: '3.8' + +services: + app: + build: . + ports: + - "8080:8080" + environment: + - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/postgres + - SPRING_DATASOURCE_USERNAME=postgres + - SPRING_DATASOURCE_PASSWORD=mypassword + depends_on: + - db + + db: + image: postgres:latest + environment: + - POSTGRES_DB=postgres + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=mypassword + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + +volumes: + postgres_data: \ No newline at end of file diff --git a/module13/dockerfile b/module13/dockerfile new file mode 100644 index 00000000..838255fe --- /dev/null +++ b/module13/dockerfile @@ -0,0 +1,4 @@ +FROM openjdk:17-slim +COPY target/module13-0.0.1-SNAPSHOT.jar app.jar +EXPOSE 8080 +ENTRYPOINT ["java", "-jar", "/app.jar"] \ No newline at end of file diff --git a/module13/pom.xml b/module13/pom.xml new file mode 100644 index 00000000..fc1a80c0 --- /dev/null +++ b/module13/pom.xml @@ -0,0 +1,65 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.2.0 + + + ru.edu + module13 + 0.0.1-SNAPSHOT + module13 + module13 + + 17 + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-security + + + + org.postgresql + postgresql + runtime + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + org.projectlombok + lombok + RELEASE + compile + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/module13/src/main/java/ru/edu/module13/Application.java b/module13/src/main/java/ru/edu/module13/Application.java new file mode 100644 index 00000000..106b56b5 --- /dev/null +++ b/module13/src/main/java/ru/edu/module13/Application.java @@ -0,0 +1,13 @@ +package ru.edu.module13; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/module13/src/main/java/ru/edu/module13/config/SecurityConfig.java b/module13/src/main/java/ru/edu/module13/config/SecurityConfig.java new file mode 100644 index 00000000..f3a98e80 --- /dev/null +++ b/module13/src/main/java/ru/edu/module13/config/SecurityConfig.java @@ -0,0 +1,60 @@ +package ru.edu.module13.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import ru.edu.module13.entity.Auth; +import ru.edu.module13.repository.AuthRepository; + +import java.util.stream.Collectors; + +@Configuration +@EnableWebSecurity +public class SecurityConfig { + @Autowired + private AuthRepository authRepository; + + @Bean + public UserDetailsService userDetailsService() { + return username -> { + Auth auth = authRepository.findByUsername(username); + if (auth == null) { + throw new UsernameNotFoundException("Пользователь " + username + " не найден."); + } + return new org.springframework.security.core.userdetails.User( + auth.getUsername(), + auth.getPassword(), + auth.getRoles().stream() + .map(role -> new SimpleGrantedAuthority(role.getName())) + .collect(Collectors.toList())); + }; + } + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + .csrf((csrf) -> csrf.disable()) + .authorizeHttpRequests((authorize) -> authorize + .requestMatchers(HttpMethod.GET).hasAuthority("ROLE_USER") + .requestMatchers(HttpMethod.POST).hasAuthority("ROLE_ADMIN") + .anyRequest().authenticated()) + .httpBasic(Customizer.withDefaults()); + + return http.build(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/module13/src/main/java/ru/edu/module13/controller/UsersRestController.java b/module13/src/main/java/ru/edu/module13/controller/UsersRestController.java new file mode 100644 index 00000000..11ed15ca --- /dev/null +++ b/module13/src/main/java/ru/edu/module13/controller/UsersRestController.java @@ -0,0 +1,49 @@ +package ru.edu.module13.controller; + +import org.springframework.web.bind.annotation.*; +import ru.edu.module13.entity.MyUser; +import ru.edu.module13.repository.MyUserRepository; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/users") +public class UsersRestController { + private MyUserRepository myUserRepository; + public UsersRestController(MyUserRepository myUserRepository) { + this.myUserRepository = myUserRepository; + } + + @GetMapping + public List getUsers() { + return myUserRepository.findAll(); + } + @PostMapping + public MyUser createUser(@RequestBody MyUser user) { + return myUserRepository.save(user); + } + @PutMapping("/{id}") + public MyUser updateUser(@PathVariable Long id, @RequestBody MyUser myUserDetails) { + MyUser myUser = myUserRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found with id " + id)); + + myUser.setName(myUserDetails.getName()); + myUser.setAge(myUserDetails.getAge()); + return myUserRepository.save(myUser); + } + @DeleteMapping("/{id}") + public Map deleteUser(@PathVariable Long id) { + MyUser myUser = myUserRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found with id " + id)); + + myUserRepository.delete(myUser); + Map response = new HashMap<>(); + response.put("deleted", Boolean.TRUE); + return response; + } + @GetMapping("/{id}") + public MyUser getUserById(@PathVariable Long id) { + return myUserRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found with id " + id)); + } + +} diff --git a/module13/src/main/java/ru/edu/module13/entity/Auth.java b/module13/src/main/java/ru/edu/module13/entity/Auth.java new file mode 100644 index 00000000..4496f45c --- /dev/null +++ b/module13/src/main/java/ru/edu/module13/entity/Auth.java @@ -0,0 +1,36 @@ +package ru.edu.module13.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.HashSet; +import java.util.Set; + +@Entity +@Table(name = "auth") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class Auth { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String username; + private String password; + + @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) + @JoinTable( + name = "auth_roles", + joinColumns = @JoinColumn(name = "auth_id"), + inverseJoinColumns = @JoinColumn(name = "role_id") + ) + private Set roles = new HashSet<>(); + + +} diff --git a/module13/src/main/java/ru/edu/module13/entity/MyUser.java b/module13/src/main/java/ru/edu/module13/entity/MyUser.java new file mode 100644 index 00000000..c9ab9022 --- /dev/null +++ b/module13/src/main/java/ru/edu/module13/entity/MyUser.java @@ -0,0 +1,21 @@ +package ru.edu.module13.entity; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class MyUser { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + private Integer age; +} \ No newline at end of file diff --git a/module13/src/main/java/ru/edu/module13/entity/Role.java b/module13/src/main/java/ru/edu/module13/entity/Role.java new file mode 100644 index 00000000..b33402b8 --- /dev/null +++ b/module13/src/main/java/ru/edu/module13/entity/Role.java @@ -0,0 +1,23 @@ +package ru.edu.module13.entity; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Table(name = "roles") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class Role { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + + +} diff --git a/module13/src/main/java/ru/edu/module13/repository/AuthRepository.java b/module13/src/main/java/ru/edu/module13/repository/AuthRepository.java new file mode 100644 index 00000000..80cd756a --- /dev/null +++ b/module13/src/main/java/ru/edu/module13/repository/AuthRepository.java @@ -0,0 +1,10 @@ +package ru.edu.module13.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import ru.edu.module13.entity.Auth; + +@Repository +public interface AuthRepository extends JpaRepository { + Auth findByUsername(String username); +} \ No newline at end of file diff --git a/module13/src/main/java/ru/edu/module13/repository/MyUserRepository.java b/module13/src/main/java/ru/edu/module13/repository/MyUserRepository.java new file mode 100644 index 00000000..4cd17489 --- /dev/null +++ b/module13/src/main/java/ru/edu/module13/repository/MyUserRepository.java @@ -0,0 +1,10 @@ +package ru.edu.module13.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import ru.edu.module13.entity.MyUser; + +@Repository +public interface MyUserRepository extends JpaRepository { + +} diff --git a/module13/src/main/java/ru/edu/module13/repository/RoleRepository.java b/module13/src/main/java/ru/edu/module13/repository/RoleRepository.java new file mode 100644 index 00000000..6346bd00 --- /dev/null +++ b/module13/src/main/java/ru/edu/module13/repository/RoleRepository.java @@ -0,0 +1,10 @@ +package ru.edu.module13.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import ru.edu.module13.entity.Role; + +@Repository +public interface RoleRepository extends JpaRepository { + Role findByName(String name); +} diff --git a/module13/src/main/resources/application.yaml b/module13/src/main/resources/application.yaml new file mode 100644 index 00000000..eea6b4e6 --- /dev/null +++ b/module13/src/main/resources/application.yaml @@ -0,0 +1,25 @@ +logging: + level: + root: WARN + +server: + port: 8080 + address: 0.0.0.0 + +spring: + datasource: + url: jdbc:postgresql://localhost:5432/postgres + driverClassName: org.postgresql.Driver + username: postgres + password: mypassword + jpa: + defer-datasource-initialization: true + hibernate: + ddl-auto: create-drop + properties: + hibernate: + show_sql: true + format_sql: true + sql: + init: + mode: always diff --git a/module13/src/main/resources/data.sql b/module13/src/main/resources/data.sql new file mode 100644 index 00000000..ccab0b85 --- /dev/null +++ b/module13/src/main/resources/data.sql @@ -0,0 +1,6 @@ +INSERT INTO roles (name) VALUES ('ROLE_ADMIN'); +INSERT INTO roles (name) VALUES ('ROLE_USER'); +INSERT INTO auth (username, password) VALUES ('admin', '$2a$10$rnxHUAo/gTfmUm2Rmf7lfeyIwMKcVOiU9cdnGWIrFDXivSGOsCvde'); +INSERT INTO auth_roles (auth_id, role_id) SELECT (SELECT id FROM auth WHERE username = 'admin'), (SELECT id FROM roles WHERE name = 'ROLE_ADMIN'); +INSERT INTO auth (username, password) VALUES ('user', '$2a$10$rnxHUAo/gTfmUm2Rmf7lfeyIwMKcVOiU9cdnGWIrFDXivSGOsCvde'); +INSERT INTO auth_roles (auth_id, role_id) SELECT (SELECT id FROM auth WHERE username = 'user'), (SELECT id FROM roles WHERE name = 'ROLE_USER'); \ No newline at end of file diff --git a/pom.xml b/pom.xml index 0b768ddf..da2e5414 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,9 @@ module08 module09 module10 + module11 module12 + module13 pom