dev/2025-02-19-15-06

This commit is contained in:
geniy 2025-02-19 15:07:10 +03:00
parent 47714bb900
commit dcfa7ab989
22 changed files with 478 additions and 66 deletions

View File

@ -52,6 +52,10 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,52 @@
package com.example.nto.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsService userDetailsService;
public WebSecurityConfig(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/employee/**").hasAnyAuthority("ROLE_EMPLOYEE", "ROLE_ADMIN")
/*.antMatchers("/h2-console/**").permitAll()
.antMatchers("/edu/v1/user/register").permitAll()
.antMatchers("/edu/v1/user/username/{username}").permitAll()
.antMatchers("/edu/v1/authority/**").hasAuthority("ROLE_ADMIN")
.antMatchers("/edu/v1/user/authority/**").hasAuthority("ROLE_ADMIN")
.antMatchers("/edu/v1/user/**").hasAnyAuthority("ROLE_USER", "ROLE_ADMIN")*/
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.headers().frameOptions().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

View File

@ -2,46 +2,53 @@ package com.example.nto.controller;
import com.example.nto.entity.Code;
import com.example.nto.entity.Employee;
import com.example.nto.entity.EmployeeData;
import com.example.nto.entity.Entry;
import com.example.nto.service.EmployeeService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.List;
@RestController
@RequiredArgsConstructor
@RequestMapping("/api")
@RequestMapping("/api/employee")
public class EmployeeController {
private final EmployeeService employeeService;
@GetMapping("/{login}/auth")
private ResponseEntity<Void> auth(@PathVariable("login") String login) {
return employeeService.checkExistence(login) ? new ResponseEntity<>(null, HttpStatus.OK) : new ResponseEntity<>(null, HttpStatus.UNAUTHORIZED);
@PostMapping("/auth")
private void auth() {}
@PostMapping("/info")
private EmployeeData info() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String login = authentication.getName();
return employeeService.info(login);
}
@GetMapping("/{login}/info")
private ResponseEntity<Employee> info(@PathVariable("login") String login) {
if (!employeeService.checkExistence(login)) {
return new ResponseEntity<>(null, HttpStatus.UNAUTHORIZED);
}
return new ResponseEntity<>(employeeService.info(login), HttpStatus.OK);
@PostMapping("/open")
private void open(@RequestParam("value") long value) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String login = authentication.getName();
employeeService.open(login, value);
}
@PatchMapping("/{login}/open")
private ResponseEntity<Void> open(@PathVariable("login") String login, @RequestBody Code value) {
LocalDateTime localDateTime = LocalDateTime.now();
if (!employeeService.checkExistence(login)) {
return new ResponseEntity<>(null, HttpStatus.UNAUTHORIZED);
}
Code code = employeeService.getCode(value.getValue());
if (code == null) {
return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
}
@PostMapping("/get-entry-list")
private List<Entry> getEntryList() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String login = authentication.getName();
return employeeService.getEntryList(login);
}
employeeService.updateTime(login, localDateTime);
return new ResponseEntity<>(null, HttpStatus.OK);
@PostMapping("/am-i-blocked")
private boolean amIBlocked() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String login = authentication.getName();
return employeeService.amIBlocked(login);
}
}

View File

@ -6,6 +6,8 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
@ -15,6 +17,7 @@ import javax.persistence.Id;
@AllArgsConstructor
public class Code {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private long value;
}

View File

@ -4,22 +4,75 @@ import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@Entity
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
public class Employee implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String login;
private String name;
private String photo;
private String position;
private LocalDateTime lastVisit;
private String passwordHashed;
private boolean isBlock;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "relationship_employee_and_role",
joinColumns = @JoinColumn(name = "employee_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<Role> authorities;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return passwordHashed;
}
@Override
public String getUsername() {
return login;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
public boolean isBlock() {
return isBlock;
}
}

View File

@ -0,0 +1,30 @@
package com.example.nto.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.time.LocalDateTime;
@Entity
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EmployeeData {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private long ownerId;
private String name;
private String photo;
private String employeePosition;
private LocalDateTime lastVisit;
}

View File

@ -0,0 +1,29 @@
package com.example.nto.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.time.LocalDateTime;
@Entity
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Entry {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private long employeeId;
private long codeId;
private LocalDateTime entryTime;
private boolean isCard;
}

View File

@ -0,0 +1,29 @@
package com.example.nto.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.Builder;
import org.springframework.security.core.GrantedAuthority;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class Role implements GrantedAuthority {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String role;
@Override
public String getAuthority() {
return role;
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,29 @@
package com.example.nto.exception;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(CodeNotFoundException.class)
ResponseEntity<String> codeNotFoundExceptionHandler(NullPointerException e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(EmployeeNotFoundException.class)
ResponseEntity<String> employeeNotFoundExceptionHandler(NullPointerException e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.UNAUTHORIZED);
}
@ExceptionHandler(EmployeeDataNotFoundException.class)
ResponseEntity<String> employeeDataNotFoundExceptionHandler(NullPointerException e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(EmployeeIsBlockedException.class)
ResponseEntity<String> employeeIsBlockedExceptionHandler(NullPointerException e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.LOCKED);
}
}

View File

@ -5,7 +5,9 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface CodeRepository extends JpaRepository<Code, Long> {
@Nullable Code findByValue(Long value);
Optional<Code> findByValue(Long value);
}

View File

@ -0,0 +1,22 @@
package com.example.nto.repository;
import com.example.nto.entity.Code;
import com.example.nto.entity.EmployeeData;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.Optional;
public interface EmployeeDataRepository extends JpaRepository<EmployeeData, Long> {
Optional<EmployeeData> findByOwnerId(long ownerId);
@Query(value = "select e.id from employee_data e where owner_id = :owner_id", nativeQuery = true)
Optional<Long> findIdByOwnerId(@Param("owner_id") long ownerId);
@Modifying
@Query("update EmployeeData e set e.lastVisit = :time where e.id = :id")
void updateTimeById(@Param("id") long id, @Param("time") LocalDateTime lastVisit);
}

View File

@ -4,16 +4,17 @@ import com.example.nto.entity.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.Optional;
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
@Nullable Employee findByLogin(String login);
@Query(value = "select e.id from Employee e where e.login = :login")
Optional<Long> findIdByLogin(@Param("login") String login);
@Modifying
@Query(value = "UPDATE Employee set lastVisit = :localDateTime where login = :login")
void updateTime(String login, LocalDateTime localDateTime);
Optional<Employee> findByLogin(String login);
}

View File

@ -0,0 +1,20 @@
package com.example.nto.repository;
import com.example.nto.entity.Employee;
import com.example.nto.entity.Entry;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
public interface EntryRepository extends JpaRepository<Entry, Long> {
@Modifying
@Query(value = "insert into Entry(employee_id, code_id, entry_time, is_card) values (:employeeId, :codeId, :entryTime, false)", nativeQuery = true)
void insert(@Param("employeeId") long employeeId, @Param("codeId") long codeId, @Param("entryTime") LocalDateTime entryTime);
List<Entry> findAllByEmployeeId(Long employeeId);
}

View File

@ -0,0 +1,8 @@
package com.example.nto.repository;
import com.example.nto.entity.Code;
import com.example.nto.entity.Role;
import org.springframework.data.jpa.repository.JpaRepository;
public interface RoleRepository extends JpaRepository<Role, Long> {
}

View File

@ -2,16 +2,20 @@ package com.example.nto.service;
import com.example.nto.entity.Code;
import com.example.nto.entity.Employee;
import com.example.nto.entity.EmployeeData;
import com.example.nto.entity.Entry;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.RequestParam;
import java.time.LocalDateTime;
import java.util.List;
public interface EmployeeService {
boolean checkExistence(String login);
EmployeeData info(String login);
@Nullable Employee info(String login);
void open(String login, long value);
@Nullable Code getCode(Long value);
List<Entry> getEntryList(String login);
void updateTime(String login, LocalDateTime localDateTime);
boolean amIBlocked(String login);
}

View File

@ -2,39 +2,92 @@ package com.example.nto.service.impl;
import com.example.nto.entity.Code;
import com.example.nto.entity.Employee;
import com.example.nto.entity.EmployeeData;
import com.example.nto.entity.Entry;
import com.example.nto.exception.CodeNotFoundException;
import com.example.nto.exception.EmployeeDataNotFoundException;
import com.example.nto.exception.EmployeeIsBlockedException;
import com.example.nto.exception.EmployeeNotFoundException;
import com.example.nto.repository.CodeRepository;
import com.example.nto.repository.EmployeeDataRepository;
import com.example.nto.repository.EmployeeRepository;
import com.example.nto.repository.EntryRepository;
import com.example.nto.service.EmployeeService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
@Service
@RequiredArgsConstructor
public class EmployeeServiceImpl implements EmployeeService {
private final EmployeeRepository employeeRepository;
private final EmployeeDataRepository employeeDataRepository;
private final CodeRepository codeRepository;
private final EntryRepository entryRepository;
@Override
public boolean checkExistence(String login) {
return employeeRepository.findByLogin(login) != null;
public EmployeeData info(String login) {
Optional<Long> employee = employeeRepository.findIdByLogin(login);
if (employee.isEmpty()) {
throw new EmployeeNotFoundException("Employee Not Found");
}
Optional<EmployeeData> employeeData = employeeDataRepository.findByOwnerId(employee.get());
if (employeeData.isEmpty()) {
throw new EmployeeDataNotFoundException("Employee Data Not Found");
}
return employeeData.get();
}
@Override
public Employee info(String login) {
return employeeRepository.findByLogin(login);
}
@Override
public Code getCode(Long value) {
return codeRepository.findByValue(value);
}
@Override
@Transactional
public void updateTime(String login, LocalDateTime localDateTime) {
employeeRepository.updateTime(login, localDateTime);
@Override
public void open(String login, long value) {
Optional<Employee> employee = employeeRepository.findByLogin(login);
if (employee.isEmpty()) {
throw new EmployeeNotFoundException("Employee Not Found");
}
if (employee.get().isBlock()) {
throw new EmployeeIsBlockedException("Employee Is Blocked");
}
Optional<Long> employeeData = employeeDataRepository.findIdByOwnerId(employee.get().getId());
if (employeeData.isEmpty()) {
throw new EmployeeDataNotFoundException("Employee Data Not Found");
}
Optional<Code> code = codeRepository.findByValue(value);
if (code.isEmpty()) {
throw new CodeNotFoundException("Code Not Found");
}
employeeDataRepository.updateTimeById(employeeData.get(), LocalDateTime.now());
entryRepository.insert(employee.get().getId(), code.get().getId(), LocalDateTime.now());
}
@Override
public List<Entry> getEntryList(String login) {
Optional<Long> employee = employeeRepository.findIdByLogin(login);
if (employee.isEmpty()) {
throw new EmployeeNotFoundException("Employee Not Found");
}
return entryRepository.findAllByEmployeeId(employee.get());
}
@Override
public boolean amIBlocked(String login) {
Optional<Employee> employee = employeeRepository.findByLogin(login);
if (employee.isEmpty()) {
throw new EmployeeNotFoundException("Employee Not Found");
}
return employee.get().isBlock();
}
}

View File

@ -0,0 +1,29 @@
package com.example.nto.service.impl;
import com.example.nto.entity.Employee;
import com.example.nto.exception.EmployeeNotFoundException;
import com.example.nto.repository.EmployeeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
@RequiredArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {
private final EmployeeRepository employeeRepository;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
Optional<Employee> employee = employeeRepository.findByLogin(s);
if (employee.isEmpty()) {
throw new EmployeeNotFoundException("Employee Not Found");
}
return employee.get();
}
}

View File

@ -1,14 +1,23 @@
INSERT INTO employee (id, login, name, photo, position, last_visit)
VALUES
(1, 'pivanov', 'Иванов Петр Федорович', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Разработчик', '2024-02-12T08:30'),
(2, 'ipetrov', 'Петров Иван Константинович', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Аналитик', '2024-02-13T08:35'),
(3, 'asemenov', 'Семенов Анатолий Анатольевич', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Разработчик', '2024-02-13T08:31'),
(4, 'afedorov', 'Федоров Александр Сергеевич', 'https://funnyducks.ru/upload/iblock/0cd/0cdeb7ec3ed6fddda0f90fccee05557d.jpg', 'Тестировщик', '2024-02-12T08:36');
INSERT INTO role (role) VALUES ('ROLE_EMPLOYEE');
INSERT INTO role (role) VALUES ('ROLE_ADMIN');
INSERT INTO code (id, value)
INSERT INTO employee (login, password_hashed, is_block)
VALUES ('admin', '$2a$10$jUSU1.20p4yQLIm3Pjclce92lWKB0ND7NIFCi8L1AaP9eARC9jBqO', false);
INSERT INTO employee (login, password_hashed, is_block)
VALUES ('employee', '$2a$12$tcu/4mrJaMwLO5Uskojstu45joSdR2E5/WrLRELDis554DAo.Y5tS', false);
INSERT INTO employee_data (owner_id, name, photo, employee_position, last_visit)
VALUES (1, 'dangeon master', 'photo', 'fucking slave', '2024-02-12T08:30');
INSERT INTO employee_data (owner_id, name, photo, employee_position, last_visit)
VALUES (2, 'dangeon master', 'photo', 'fucking slave', '2024-02-12T08:30');
INSERT INTO relationship_employee_and_role (employee_id, role_id) VALUES (1, 2);
INSERT INTO relationship_employee_and_role (employee_id, role_id) VALUES (2, 1);
INSERT INTO code (value)
VALUES
(1, 1234567890123456789),
(2, 9223372036854775807),
(3, 1122334455667788990),
(4, 998877665544332211),
(5, 5566778899001122334);
(1234567890123456789),
(9223372036854775807),
(1122334455667788990),
(998877665544332211),
(5566778899001122334);