checkpoint1

This commit is contained in:
Samsung 2026-02-25 14:29:55 +03:00
parent 29c44d684f
commit 712dad45f7
14 changed files with 152 additions and 31 deletions

View File

@ -56,6 +56,10 @@
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.8.8</version> <version>2.8.8</version>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -0,0 +1,33 @@
package com.example.nto.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/h2-console").permitAll()
.requestMatchers("/register").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
}

View File

@ -2,6 +2,7 @@ package com.example.nto.controller;
import com.example.nto.controller.dto.EmployeeDto; import com.example.nto.controller.dto.EmployeeDto;
import com.example.nto.controller.dto.EmployeeRegisterDto;
import com.example.nto.service.EmployeeService; import com.example.nto.service.EmployeeService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@ -14,16 +15,20 @@ public class EmployeeController {
private final EmployeeService employeeService; private final EmployeeService employeeService;
@GetMapping("/{code}/auth") @GetMapping("/{username}/auth")
@ResponseStatus(code = HttpStatus.OK) @ResponseStatus(code = HttpStatus.OK)
public void login(@PathVariable String code) { public void login(@PathVariable String username) {
employeeService.auth(code); employeeService.auth(username);
} }
@GetMapping("/{code}/info") @GetMapping("/{username}/info")
@ResponseStatus(code = HttpStatus.OK) @ResponseStatus(code = HttpStatus.OK)
public EmployeeDto getByCode(@PathVariable String code) { public EmployeeDto getByCode(@PathVariable String username) {
return employeeService.getByCode(code); return employeeService.getByUsername(username);
} }
@GetMapping("/register")
@ResponseStatus(code = HttpStatus.CREATED)
public void register(EmployeeRegisterDto employeeRegisterDto) {employeeService.register(employeeRegisterDto);}
} }

View File

@ -0,0 +1,16 @@
package com.example.nto.controller.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EmployeeRegisterDto {
private String name;
private String username;
private String password;
}

View File

@ -5,7 +5,10 @@ import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.List; import java.util.List;
@Data @Data
@ -23,12 +26,16 @@ public class Employee {
@Column(name = "name") @Column(name = "name")
private String name; private String name;
@Column(name = "code") @Column(name = "username")
private String code; private String username;
@Column(name = "password")
private String password;
@Column(name = "photo_url") @Column(name = "photo_url")
private String photoUrl; private String photoUrl;
@OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.LAZY) @OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Booking> bookingList; private List<Booking> bookingList;
} }

View File

@ -0,0 +1,7 @@
package com.example.nto.exception;
public class EmployeeAlreadyExistsException extends RuntimeException {
public EmployeeAlreadyExistsException(String message) {
super(message);
}
}

View File

@ -0,0 +1,7 @@
package com.example.nto.exception;
public class PasswordNotCorrectException extends RuntimeException {
public PasswordNotCorrectException(String message) {
super(message);
}
}

View File

@ -1,8 +1,6 @@
package com.example.nto.exception.handler; package com.example.nto.exception.handler;
import com.example.nto.exception.BookingAlreadyExistsException; import com.example.nto.exception.*;
import com.example.nto.exception.EmployeeNotFoundException;
import com.example.nto.exception.PlaceNotFoundException;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ControllerAdvice;
@ -25,8 +23,19 @@ public class GlobalExceptionHandler {
return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST); return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
} }
@ExceptionHandler(EmployeeAlreadyExistsException.class)
public ResponseEntity<String> handleEmployeeAlreadyExistsException(EmployeeAlreadyExistsException e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.CONFLICT);
}
@ExceptionHandler(PasswordNotCorrectException.class)
public ResponseEntity<String> handlePasswordNotCorrectException(PasswordNotCorrectException e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.CONFLICT);
}
@ExceptionHandler(Exception.class) @ExceptionHandler(Exception.class)
public ResponseEntity<String> handleGenericException(Exception e) { public ResponseEntity<String> handleGenericException(Exception e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST); return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
} }
} }

View File

@ -8,5 +8,5 @@ import java.util.Optional;
public interface EmployeeRepository extends JpaRepository<Employee, Long> { public interface EmployeeRepository extends JpaRepository<Employee, Long> {
@EntityGraph(attributePaths = {"bookingList", "bookingList.place"}) @EntityGraph(attributePaths = {"bookingList", "bookingList.place"})
Optional<Employee> findByCode(String code); Optional<Employee> findByUsername(String username);
} }

View File

@ -1,9 +1,12 @@
package com.example.nto.service; package com.example.nto.service;
import com.example.nto.controller.dto.EmployeeDto; import com.example.nto.controller.dto.EmployeeDto;
import com.example.nto.controller.dto.EmployeeRegisterDto;
public interface EmployeeService { public interface EmployeeService {
EmployeeDto getByCode(String code); EmployeeDto getByUsername(String username);
void auth(String code); void auth(String username);
void register(EmployeeRegisterDto employeeRegisterDto);
} }

View File

@ -37,8 +37,8 @@ public class BookingServiceImpl implements BookingService {
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public Map<LocalDate, List<PlaceDto>> getFreePlace(String code) { public Map<LocalDate, List<PlaceDto>> getFreePlace(String username) {
employeeService.auth(code); employeeService.auth(username);
List<Place> allPlaces = placeRepository.findAll(); List<Place> allPlaces = placeRepository.findAll();
@ -72,15 +72,15 @@ public class BookingServiceImpl implements BookingService {
@Override @Override
@Transactional @Transactional
public Booking create(String code, BookingCreateDto bookingCreateDto) { public Booking create(String username, BookingCreateDto bookingCreateDto) {
LocalDate date = bookingCreateDto.getDate(); LocalDate date = bookingCreateDto.getDate();
LocalDate today = LocalDate.now(ZoneId.systemDefault()); LocalDate today = LocalDate.now(ZoneId.systemDefault());
if (date.isBefore(today) || date.isAfter(today.plusDays(daysAhead))) { if (date.isBefore(today) || date.isAfter(today.plusDays(daysAhead))) {
throw new IllegalArgumentException("Date is out of booking window"); throw new IllegalArgumentException("Date is out of booking window");
} }
Employee employee = employeeRepository.findByCode(code) Employee employee = employeeRepository.findByUsername(username)
.orElseThrow(() -> new EmployeeNotFoundException("Employee with " + code + " code not found!")); .orElseThrow(() -> new EmployeeNotFoundException("Employee with " + username + " code not found!"));
long placeId = bookingCreateDto.getPlaceId(); long placeId = bookingCreateDto.getPlaceId();
Place place = placeRepository.findById(placeId) Place place = placeRepository.findById(placeId)

View File

@ -1,10 +1,15 @@
package com.example.nto.service.impl; package com.example.nto.service.impl;
import com.example.nto.controller.dto.EmployeeDto; import com.example.nto.controller.dto.EmployeeDto;
import com.example.nto.controller.dto.EmployeeRegisterDto;
import com.example.nto.entity.Employee;
import com.example.nto.exception.EmployeeAlreadyExistsException;
import com.example.nto.exception.EmployeeNotFoundException; import com.example.nto.exception.EmployeeNotFoundException;
import com.example.nto.exception.PasswordNotCorrectException;
import com.example.nto.repository.EmployeeRepository; import com.example.nto.repository.EmployeeRepository;
import com.example.nto.service.EmployeeService; import com.example.nto.service.EmployeeService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -13,19 +18,40 @@ import org.springframework.transaction.annotation.Transactional;
public class EmployeeServiceImpl implements EmployeeService { public class EmployeeServiceImpl implements EmployeeService {
private final EmployeeRepository employeeRepository; private final EmployeeRepository employeeRepository;
private PasswordEncoder passwordEncoder;
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public EmployeeDto getByCode(String code) { public EmployeeDto getByUsername(String username) {
return employeeRepository.findByCode(code).map(EmployeeDto::toDto) return employeeRepository.findByUsername(username).map(EmployeeDto::toDto)
.orElseThrow(() -> new EmployeeNotFoundException("Employee with " + code + " code not found!")); .orElseThrow(() -> new EmployeeNotFoundException("Employee with " + username + " code not found!"));
} }
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public void auth(String code) { public void auth(String username) {
if (employeeRepository.findByCode(code).isEmpty()) { if (employeeRepository.findByUsername(username).isEmpty()) {
throw new EmployeeNotFoundException("Employee with " + code + " code not found!"); throw new EmployeeNotFoundException("Employee with " + username + " username not found!");
} }
} }
@Override
public void register(EmployeeRegisterDto employeeRegisterDto) {
if (employeeRepository.findByUsername(employeeRegisterDto.getUsername()).isPresent()){
throw new EmployeeAlreadyExistsException("Employee with " + employeeRegisterDto.getUsername() + " username already exist");
};
Employee employee = new Employee();
if (passwordEncoder.encode(employee.getPassword()).length() < 8) {
throw new PasswordNotCorrectException("The password is too short!!!");
}
employee.setName(employeeRegisterDto.getName());
employee.setUsername(employeeRegisterDto.getUsername());
employee.setPassword(passwordEncoder.encode(employeeRegisterDto.getPassword()));
employeeRepository.save(employee);
}
} }

View File

@ -21,10 +21,14 @@
<constraints nullable="false"/> <constraints nullable="false"/>
</column> </column>
<column name="code" type="VARCHAR(100)"> <column name="username" type="VARCHAR(100)">
<constraints nullable="false" unique="true"/> <constraints nullable="false" unique="true"/>
</column> </column>
<column name="password" type="VARCHAR(50)">
<constraints nullable="false"/>
</column>
<column name="photo_url" type="VARCHAR(100)"/> <column name="photo_url" type="VARCHAR(100)"/>
</createTable> </createTable>
</changeSet> </changeSet>

View File

@ -1,5 +1,5 @@
name;code;photo_url name;username;password;photo_url
Ivanov Ivan;1111;https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg Ivanov Ivan;iivanov;YWRtaW4=;https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg
Petrov Petr;2222;https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg Petrov Petr;ppetrov;YWRtaW4=;https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg
Kozlov Oleg;3333;https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg Kozlov Oleg;okozlov;YWRtaW4=;https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg
Smirnova Anna;4444;https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg Smirnova Anna;asmirnova;YWRtaW4=;https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg
1 name code username password photo_url
2 Ivanov Ivan 1111 iivanov YWRtaW4= https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg
3 Petrov Petr 2222 ppetrov YWRtaW4= https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg
4 Kozlov Oleg 3333 okozlov YWRtaW4= https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg
5 Smirnova Anna 4444 asmirnova YWRtaW4= https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg