diff --git a/readme.md b/README.md similarity index 98% rename from readme.md rename to README.md index a393468..d0d880b 100644 --- a/readme.md +++ b/README.md @@ -1,5 +1,10 @@ # НТО 2024. II отборочный этап. Командные задания — серверная часть +## Схема базы данных +https://www.drawdb.app/editor?shareId=92ab675631181485a028270c35276710 +[Архитектура базы данных](static/bd.png) + + ## 📖 Предыстория В компании S контроль доступа в офис осуществляется с помощью СКУД (системы контроля управления доступом). На данный момент у каждого сотрудника компании есть карта-пропуск с NFC меткой. А у каждой входной двери есть считыватель с обеих сторон. При поднесении карты к считывателю, дверь открывается, а информация о времени входа или выхода сотрудника фиксируется в базе данных. diff --git a/src/main/java/com/example/nto/domain/entity/Employee.java b/src/main/java/com/example/nto/domain/entity/Employee.java new file mode 100644 index 0000000..f667855 --- /dev/null +++ b/src/main/java/com/example/nto/domain/entity/Employee.java @@ -0,0 +1,122 @@ +package com.example.nto.domain.entity; + +import jakarta.persistence.*; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +@Data +@Entity +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "employees") +public class Employee implements UserDetails { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @Column(name = "name") + @NotBlank(message = "Имя пользователя не может быть пустым!") + @Size(max = 100, message = "Максимальная длина имени 100 символов!") + private String name; + + @Column(name = "surname") + @NotBlank(message = "Фамилия пользователя не может быть пустой!") + @Size(max = 100, message = "Максимальная длина фамилии 100 символов!") + private String surname; + + @Column(name = "patronymic") + @Size(max = 100, message = "Максимальная длина отчества 100 символов!") + private String patronymic; + + @Column(name = "about_me") + @Size(max = 300, message = "Максимальная длина поля 'О себе' 300 символов!") + private String aboutMe; + + @Column(name = "telephone", unique = true) + @NotBlank(message = "Телефон не может быть пустым!") + @Size(max = 20, message = "Максимальная длина телефонного номера 20 символов!") + private String telephone; + + @Column(name = "email", unique = true) + @NotBlank(message = "Email не может быть пустым!") + @Size(max = 255, message = "Максимальная длина email 255 символов") + @Email(message = "Email адрес должен быть в формате user@example.com!") + private String email; + + @Column(name = "password") + @NotBlank(message = "Пароль не может быть пустым!") + @Size(max = 300, message = "Максимальная длина пароля 300 символов!") + private String password; + + // @ManyToOne(fetch = FetchType.EAGER) + // @JoinColumn(name = "office_id", referencedColumnName = "id", nullable = false) + // private Office office; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "pos_id", referencedColumnName = "id", nullable = false) + private Position position; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "role_id", referencedColumnName = "id", nullable = false) + private Role role; + + @Column(name = "profile_image_url", nullable = false) + @Size(max = 300, message = "Максимальная длина адреса изображения 300 символов!") + private String profileImageUrl; + + @CreatedDate + @Column(name = "created_at", columnDefinition = "TIMESTAMP", nullable = false) + private LocalDateTime createdAt; + + // @OneToMany(mappedBy = "employee") + // private List visits = new ArrayList<>(); + + @Override + public Collection getAuthorities() { + return List.of(this.role); + } + + @Override + public String getPassword() { + return ""; + } + + @Override + public String getUsername() { + return this.email; + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } +} diff --git a/src/main/java/com/example/nto/domain/entity/Office.java b/src/main/java/com/example/nto/domain/entity/Office.java new file mode 100644 index 0000000..cee9e88 --- /dev/null +++ b/src/main/java/com/example/nto/domain/entity/Office.java @@ -0,0 +1,68 @@ +package com.example.nto.domain.entity; + +import jakarta.persistence.*; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@Entity +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "offices") +public class Office { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @Column(name = "name", unique = true) + @NotBlank(message = "Название не может быть пустым!") + @Size(max = 100, message = "Максимальная длина названия 100 символов!") + private String name; + + @Column(name = "description") + @NotBlank(message = "Описание не может быть пустым!") + @Size(max = 300, message = "Максимальная длина описания 300 символов!") + private String description; + + @Column(name = "address") + @NotBlank(message = "Адрес не может быть пустым!") + @Size(max = 200, message = "Максимальный размер адреса 200 символов!") + private String address; + + @Column(name = "latitude") + @NotNull(message = "Широта не может быть пустой!") + private Double latitude; + + @Column(name = "longitude") + @NotNull(message = "Долгота не может быть пустой!") + private Double longitude; + + @Column(name = "logo_image_url") + @NotBlank(message = "Путь к логотипу не может быть пустой!") + @Size(max = 200, message = "Максимальный размер пути к логотипу 200 символов!") + private String linkLogo; + + @Column(name = "telephone") + @Size(max = 20, message = "Максимальная длина телефонного номера 20 символов!") + private String telephone; + + @Column(name = "email") + @Size(max = 255, message = "Максимальная длина email 255 символов") + @Email(message = "Email адрес должен быть в формате user@example.com!") + private String email; + + @OneToMany(mappedBy = "office") + private List employeeList; + + @OneToMany(mappedBy = "office") + private List terminals; +} diff --git a/src/main/java/com/example/nto/domain/entity/Position.java b/src/main/java/com/example/nto/domain/entity/Position.java new file mode 100644 index 0000000..61d900e --- /dev/null +++ b/src/main/java/com/example/nto/domain/entity/Position.java @@ -0,0 +1,31 @@ +package com.example.nto.domain.entity; + +import jakarta.persistence.*; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@Entity +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "positions") +public class Position { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @Column(name = "name", unique = true) + @NotBlank(message = "Название не может быть пустым!") + @Size(max = 100, message = "Максимальная длина названия 100 символов!") + private String name; + + @OneToMany(mappedBy = "position") + private List employees; +} \ No newline at end of file diff --git a/src/main/java/com/example/nto/domain/entity/Role.java b/src/main/java/com/example/nto/domain/entity/Role.java new file mode 100644 index 0000000..73c2b81 --- /dev/null +++ b/src/main/java/com/example/nto/domain/entity/Role.java @@ -0,0 +1,37 @@ +package com.example.nto.domain.entity; + +import jakarta.persistence.*; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.security.core.GrantedAuthority; + +import java.util.List; + +@Data +@Entity +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "roles") +public class Role implements GrantedAuthority { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private long id; + + @Column(name = "role_name", unique = true) + @NotBlank(message = "Название роли не может быть пустой!") + @Size(max = 100, message = "Максимальная длина роли 100 символов!") + private String roleName; + + @OneToMany(mappedBy = "role") + private List employees; + + @Override + public String getAuthority() { + return this.roleName; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/nto/domain/entity/Terminal.java b/src/main/java/com/example/nto/domain/entity/Terminal.java new file mode 100644 index 0000000..d1ff6aa --- /dev/null +++ b/src/main/java/com/example/nto/domain/entity/Terminal.java @@ -0,0 +1,48 @@ +package com.example.nto.domain.entity; + +import jakarta.persistence.*; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.UuidGenerator; + +import java.util.List; + +@Data +@Entity +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "terminals") +public class Terminal { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @Column(name = "name") + @NotBlank(message = "Название не может быть пустым!") + @Size(max = 100, message = "Максимальная длина названия 100 символов!") + private String name; + + // Мне нужна была рандомная генерация кода для терминала, так что я мог сделать кривую реализацию через самописную функцию, + // но боялся, что она будет генерировать не уникальные значения. (я очень смутно представляю, как эта штука работает) + // Код взят отсюда: https://stackoverflow.com/questions/76723290/using-the-new-type-for-uuidgenerator-instead-of-strategy + @UuidGenerator + @NotBlank(message = "Код не может быть пустым!") + @Column(name = "code", nullable = false, unique = true) + private String code; + + // todo: Протестировать нужен ли тут каскад тип + @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE) + @JoinColumn(name = "office_id", nullable = false) + private Office office; + + @OneToMany(mappedBy = "startTerminal") + private List startVisits; + + @OneToMany(mappedBy = "endTerminal") + private List endVisits; +} diff --git a/src/main/java/com/example/nto/domain/entity/Visit.java b/src/main/java/com/example/nto/domain/entity/Visit.java new file mode 100644 index 0000000..58d2f3b --- /dev/null +++ b/src/main/java/com/example/nto/domain/entity/Visit.java @@ -0,0 +1,43 @@ +package com.example.nto.domain.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Data +@Entity +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "visits") +public class Visit { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "employee_id", referencedColumnName = "id", nullable = false) + private Employee employee; + + @Column(name = "start_visit", columnDefinition = "TIMESTAMP", nullable = false) + private LocalDateTime startVisit; + + @Column(name = "end_visit", columnDefinition = "TIMESTAMP") + private LocalDateTime endVisit; + + @Column(name = "is_finished", nullable = false) + private boolean isFinished = false; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "start_terminal_id", referencedColumnName = "code", nullable = false) + private Terminal startTerminal; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "end_terminal_id", referencedColumnName = "code") + private Terminal endTerminal; +} + diff --git a/src/main/java/com/example/nto/exception/CodeNotFoundException.java b/src/main/java/com/example/nto/domain/exception/CodeNotFoundException.java similarity index 86% rename from src/main/java/com/example/nto/exception/CodeNotFoundException.java rename to src/main/java/com/example/nto/domain/exception/CodeNotFoundException.java index 4261e45..4dd9d0b 100644 --- a/src/main/java/com/example/nto/exception/CodeNotFoundException.java +++ b/src/main/java/com/example/nto/domain/exception/CodeNotFoundException.java @@ -1,4 +1,4 @@ -package com.example.nto.exception; +package com.example.nto.domain.exception; public class CodeNotFoundException extends RuntimeException { // Выдаётся, когда код не найден. Нужна, чтобы возвращать клиенту код 401. diff --git a/src/main/java/com/example/nto/exception/EmployeeNotFoundException.java b/src/main/java/com/example/nto/domain/exception/EmployeeNotFoundException.java similarity index 87% rename from src/main/java/com/example/nto/exception/EmployeeNotFoundException.java rename to src/main/java/com/example/nto/domain/exception/EmployeeNotFoundException.java index e8302e8..e65df2b 100644 --- a/src/main/java/com/example/nto/exception/EmployeeNotFoundException.java +++ b/src/main/java/com/example/nto/domain/exception/EmployeeNotFoundException.java @@ -1,4 +1,4 @@ -package com.example.nto.exception; +package com.example.nto.domain.exception; public class EmployeeNotFoundException extends RuntimeException { // Выдаётся, когда работник не найден. Нужна, чтобы возвращать клиенту код 401. diff --git a/src/main/java/com/example/nto/exception/SomethingWentWrongException.java b/src/main/java/com/example/nto/domain/exception/SomethingWentWrongException.java similarity index 87% rename from src/main/java/com/example/nto/exception/SomethingWentWrongException.java rename to src/main/java/com/example/nto/domain/exception/SomethingWentWrongException.java index f295a6a..1971702 100644 --- a/src/main/java/com/example/nto/exception/SomethingWentWrongException.java +++ b/src/main/java/com/example/nto/domain/exception/SomethingWentWrongException.java @@ -1,4 +1,4 @@ -package com.example.nto.exception; +package com.example.nto.domain.exception; public class SomethingWentWrongException extends RuntimeException { // Выдаётся, при непредвиденной ошибке. Нужна, чтобы возвращать клиенту код 400. diff --git a/src/main/java/com/example/nto/exception/advice/GlobalExceptionalHandler.java b/src/main/java/com/example/nto/domain/exception/advice/GlobalExceptionalHandler.java similarity index 83% rename from src/main/java/com/example/nto/exception/advice/GlobalExceptionalHandler.java rename to src/main/java/com/example/nto/domain/exception/advice/GlobalExceptionalHandler.java index c542d49..cbe6965 100644 --- a/src/main/java/com/example/nto/exception/advice/GlobalExceptionalHandler.java +++ b/src/main/java/com/example/nto/domain/exception/advice/GlobalExceptionalHandler.java @@ -1,8 +1,8 @@ -package com.example.nto.exception.advice; +package com.example.nto.domain.exception.advice; -import com.example.nto.exception.CodeNotFoundException; -import com.example.nto.exception.EmployeeNotFoundException; -import com.example.nto.exception.SomethingWentWrongException; +import com.example.nto.domain.exception.CodeNotFoundException; +import com.example.nto.domain.exception.EmployeeNotFoundException; +import com.example.nto.domain.exception.SomethingWentWrongException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ControllerAdvice; diff --git a/src/main/java/com/example/nto/dto/entity/OfficeDTO.java b/src/main/java/com/example/nto/dto/entity/OfficeDTO.java new file mode 100644 index 0000000..9bf6ae6 --- /dev/null +++ b/src/main/java/com/example/nto/dto/entity/OfficeDTO.java @@ -0,0 +1,14 @@ +package com.example.nto.dto.entity; + + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OfficeDTO { +} diff --git a/src/main/java/com/example/nto/dto/entity/PositionDTO.java b/src/main/java/com/example/nto/dto/entity/PositionDTO.java new file mode 100644 index 0000000..7a9e265 --- /dev/null +++ b/src/main/java/com/example/nto/dto/entity/PositionDTO.java @@ -0,0 +1,22 @@ +package com.example.nto.dto.entity; + + +import com.example.nto.dto.entity.employee.EmployeeItemDTO; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PositionDTO { + private long id; + private String name; + + // Список всех сотрудников с этой должностью. + private List employeeItemDTOList; +} diff --git a/src/main/java/com/example/nto/dto/entity/TerminalDTO.java b/src/main/java/com/example/nto/dto/entity/TerminalDTO.java new file mode 100644 index 0000000..9f3b89c --- /dev/null +++ b/src/main/java/com/example/nto/dto/entity/TerminalDTO.java @@ -0,0 +1,23 @@ +package com.example.nto.dto.entity; + + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TerminalDTO { + private long id; + private String name; + + // ОЧЕНЬ ВАЖНО!!! При создании терминала code не нужен, но отправлять его нужно. + // При создании пиши вместо code, что хочешь он будет просто игнорироваться. + // Мне просто очень лень делать отдельный TerminalCreateDTO ради одного поля. + + private String code; + private String officeName; +} diff --git a/src/main/java/com/example/nto/dto/entity/VisitDTO.java b/src/main/java/com/example/nto/dto/entity/VisitDTO.java new file mode 100644 index 0000000..442963a --- /dev/null +++ b/src/main/java/com/example/nto/dto/entity/VisitDTO.java @@ -0,0 +1,27 @@ +package com.example.nto.dto.entity; + + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class VisitDTO { + private long id; + + // Возвращается время начала и конца посещения в формате LocalDateTime.toString(), + // превратить обратно можно с помощью LocalDateTime.parse(). + private String startVisit; + private String endVisit; + + private boolean isFinished; + + // Возвращается длительность посещения в формате LocalDateTime.toString(), + // превратить обратно можно с помощью LocalDateTime.parse(). + private String durationVisit; + private String officeName; +} diff --git a/src/main/java/com/example/nto/dto/entity/employee/EmployeeCreateDTO.java b/src/main/java/com/example/nto/dto/entity/employee/EmployeeCreateDTO.java new file mode 100644 index 0000000..f196024 --- /dev/null +++ b/src/main/java/com/example/nto/dto/entity/employee/EmployeeCreateDTO.java @@ -0,0 +1,13 @@ +package com.example.nto.dto.entity.employee; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class EmployeeCreateDTO { +} diff --git a/src/main/java/com/example/nto/dto/entity/employee/EmployeeDTO.java b/src/main/java/com/example/nto/dto/entity/employee/EmployeeDTO.java new file mode 100644 index 0000000..450d94b --- /dev/null +++ b/src/main/java/com/example/nto/dto/entity/employee/EmployeeDTO.java @@ -0,0 +1,51 @@ +package com.example.nto.dto.entity.employee; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class EmployeeDTO { + private long id; + private String name; + private String surname; + private String patronymic; + private String telephone; + private String email; + + private long officeId; + private String officeName; + private String officeImageUrl; + + private String position; // Название должности + private String role; // строка либо ROLE_USER, либо ROLE_ADMIN + + private String profileImageUrl; + + // Текущее состояние входа: false - visit (посещение) ещё не началось, true - visit идёт + private boolean visitStatus; + + // Если visitStatus true, то возвращает дату и время начала посещения в формате LocalDateTime.toString(), + // превратить обратно можно с помощью LocalDateTime.parse(). + // Если visitStatus false, то возвращает null. + private String startVisitDateTime; + private List visitsIdLast30Days; // Список Id посещений за последние 30 дней. + + // Возвращает количество отработанных часов за последний месяц. + private long totalTimeVisitsLast30Days; + + // (Возможно это стоит убрать) Название офиса, в котором сейчас находится работник. + // Если visitStatus false, возвращает null. + private String currentOfficeName; + + // Возвращает время регистрации в формате LocalDateTime.toString(), + // превратить обратно можно с помощью LocalDateTime.parse(). + private String createAt; +} + diff --git a/src/main/java/com/example/nto/dto/entity/employee/EmployeeItemDTO.java b/src/main/java/com/example/nto/dto/entity/employee/EmployeeItemDTO.java new file mode 100644 index 0000000..50a72cc --- /dev/null +++ b/src/main/java/com/example/nto/dto/entity/employee/EmployeeItemDTO.java @@ -0,0 +1,14 @@ +package com.example.nto.dto.entity.employee; + + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class EmployeeItemDTO { +} diff --git a/src/main/java/com/example/nto/dto/mappers/OfficeMapper.java b/src/main/java/com/example/nto/dto/mappers/OfficeMapper.java new file mode 100644 index 0000000..193555d --- /dev/null +++ b/src/main/java/com/example/nto/dto/mappers/OfficeMapper.java @@ -0,0 +1,4 @@ +package com.example.nto.dto.mappers; + +public class OfficeMapper { +} diff --git a/src/main/java/com/example/nto/dto/mappers/PositionMapper.java b/src/main/java/com/example/nto/dto/mappers/PositionMapper.java new file mode 100644 index 0000000..486b848 --- /dev/null +++ b/src/main/java/com/example/nto/dto/mappers/PositionMapper.java @@ -0,0 +1,4 @@ +package com.example.nto.dto.mappers; + +public class PositionMapper { +} diff --git a/src/main/java/com/example/nto/dto/mappers/TerminalMapper.java b/src/main/java/com/example/nto/dto/mappers/TerminalMapper.java new file mode 100644 index 0000000..168c442 --- /dev/null +++ b/src/main/java/com/example/nto/dto/mappers/TerminalMapper.java @@ -0,0 +1,4 @@ +package com.example.nto.dto.mappers; + +public class TerminalMapper { +} diff --git a/src/main/java/com/example/nto/dto/mappers/VisitMapper.java b/src/main/java/com/example/nto/dto/mappers/VisitMapper.java new file mode 100644 index 0000000..8d969c8 --- /dev/null +++ b/src/main/java/com/example/nto/dto/mappers/VisitMapper.java @@ -0,0 +1,4 @@ +package com.example.nto.dto.mappers; + +public class VisitMapper { +} diff --git a/src/main/java/com/example/nto/dto/mappers/employee/EmployeeCreateMapper.java b/src/main/java/com/example/nto/dto/mappers/employee/EmployeeCreateMapper.java new file mode 100644 index 0000000..408eae4 --- /dev/null +++ b/src/main/java/com/example/nto/dto/mappers/employee/EmployeeCreateMapper.java @@ -0,0 +1,4 @@ +package com.example.nto.dto.mappers.employee; + +public class EmployeeCreateMapper { +} diff --git a/src/main/java/com/example/nto/dto/mappers/employee/EmployeeItemMapper.java b/src/main/java/com/example/nto/dto/mappers/employee/EmployeeItemMapper.java new file mode 100644 index 0000000..1fffbe6 --- /dev/null +++ b/src/main/java/com/example/nto/dto/mappers/employee/EmployeeItemMapper.java @@ -0,0 +1,4 @@ +package com.example.nto.dto.mappers.employee; + +public class EmployeeItemMapper { +} diff --git a/src/main/java/com/example/nto/dto/mappers/employee/EmployeeMapper.java b/src/main/java/com/example/nto/dto/mappers/employee/EmployeeMapper.java new file mode 100644 index 0000000..5d3b16b --- /dev/null +++ b/src/main/java/com/example/nto/dto/mappers/employee/EmployeeMapper.java @@ -0,0 +1,4 @@ +package com.example.nto.dto.mappers.employee; + +public class EmployeeMapper { +} diff --git a/src/main/java/com/example/nto/utils/DataFormatType.java b/src/main/java/com/example/nto/utils/DataFormatType.java new file mode 100644 index 0000000..0c3e92d --- /dev/null +++ b/src/main/java/com/example/nto/utils/DataFormatType.java @@ -0,0 +1,5 @@ +package com.example.nto.utils; + +public enum DataFormatType { + DATE_TIME, DATE, TIME +} diff --git a/src/main/java/com/example/nto/utils/Utils.java b/src/main/java/com/example/nto/utils/Utils.java new file mode 100644 index 0000000..b8bf742 --- /dev/null +++ b/src/main/java/com/example/nto/utils/Utils.java @@ -0,0 +1,59 @@ +package com.example.nto.utils; + +import lombok.experimental.UtilityClass; + +import java.time.*; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@UtilityClass +public class Utils { + private static final DateTimeFormatter DATE_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("HH:mm:ss"); + + public static String profileFileName(long userId) { + return "profile--" + userId; + } + + public static String generateUniqueName() { + return UUID.randomUUID().toString(); + } + + public static String nowTime(DataFormatType type) { + switch (type) { + case DATE_TIME: return LocalDateTime.now().format(DATE_TIME_FORMAT); + case DATE: return LocalDateTime.now().format(DATE_FORMAT); + case TIME: return LocalDateTime.now().format(TIME_FORMAT); + default: return "Произошла ошибка при форматировании даты или времени."; + } + } + public static LocalDateTime period(LocalDateTime dtStart, LocalDateTime dtEnd) { + // Возвращает разницу между двумя LocalDateTime + Period period = Period.between(dtStart.toLocalDate(), dtEnd.toLocalDate()); + Duration duration = Duration.between(dtStart.toLocalTime(), dtEnd.toLocalTime()); + + LocalDate localDate = LocalDate.of(period.getYears(), period.getMonths(), period.getDays()); + LocalTime localTime = LocalTime.of(duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart()); + + return LocalDateTime.of(localDate, localTime); + } + + public static long periods(List> periods) { + // Количество часов за определенные периоды. + long hours = 0; + for (List period : periods) { + if (period.size() != 2) throw new IllegalStateException("Список с периодом должен содержать 2 элемента!"); + hours += Duration.between(period.get(0), period.get(1)).toHours(); + } + return hours; + } + + public static String convertDistance(float distance) { + if (distance > 1000) return String.format("%.1f", distance / 1000) + " км"; + else return String.format("%.1f", distance) + " м"; + } +} diff --git a/static/bd.png b/static/bd.png new file mode 100644 index 0000000..ac5384f Binary files /dev/null and b/static/bd.png differ