changes.
This commit is contained in:
commit
53586dff0a
34
.gitignore
vendored
Normal file
34
.gitignore
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
|
/logs/app.log
|
||||||
|
/configurations/Start RDBMS.run.xml
|
||||||
37
README.md
Normal file
37
README.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# Thesis Defense Management System (TDMS)
|
||||||
|
|
||||||
|
# Server module
|
||||||
|
Contains backend server of service
|
||||||
|
> After building executable JAR file will be in `tdms/server/target` folder
|
||||||
|
>
|
||||||
|
> To start:`java -jar <jar-file>`
|
||||||
|
>
|
||||||
|
> URL is: `http://localhost:8080`
|
||||||
|
|
||||||
|
# Web module
|
||||||
|
Contains frontend part of service
|
||||||
|
> go to `tdms/web/` folder
|
||||||
|
>
|
||||||
|
> To start: `npm run dev`
|
||||||
|
>
|
||||||
|
> URL you will see in console
|
||||||
|
|
||||||
|
# How to build
|
||||||
|
1. Install `Maven`
|
||||||
|
2. Install `Java 17`
|
||||||
|
|
||||||
|
> While building, **web** project compiles frontend, and **server** project automatically copies its to `/server/target/classes/static` and into generated `<jar-file>`
|
||||||
|
|
||||||
|
> In IntelliJ Idea you can run `Execute maven goal`, to write further commands
|
||||||
|
|
||||||
|
| Description | Command |
|
||||||
|
|---------------------------|--------------------------------------|
|
||||||
|
| Clear & Run tests & Build | `mvn clear install` |
|
||||||
|
| Run tests & build | `mvn install` |
|
||||||
|
| Skip tests & build | `mvn install -Dmaven.test.skip=true` |
|
||||||
|
>To use multithreading during build process use `-T <threads>` keyword
|
||||||
|
|
||||||
|
### There is final result (add `clear` if you need)
|
||||||
|
```shell
|
||||||
|
mvn install -Dmaven.test.skip=true -T 4
|
||||||
|
```
|
||||||
9
docker-compose.yml
Normal file
9
docker-compose.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: postgres:16.2-alpine3.19
|
||||||
|
environment:
|
||||||
|
- "POSTGRES_DB=tdms"
|
||||||
|
- "POSTGRES_PASSWORD=root"
|
||||||
|
- "POSTGRES_USER=root"
|
||||||
|
ports:
|
||||||
|
- "5400:5432"
|
||||||
31
pom.xml
Normal file
31
pom.xml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<name>TDMS</name>
|
||||||
|
<description>Thesis-Defense-Management-System</description>
|
||||||
|
<version>0.0.1</version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>3.3.2</version>
|
||||||
|
<relativePath/>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<groupId>ru.mskobaro</groupId>
|
||||||
|
<artifactId>tdms</artifactId>
|
||||||
|
<version>0.0.1</version>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<name>${name}</name>
|
||||||
|
<description>${description}</description>
|
||||||
|
|
||||||
|
<modules>
|
||||||
|
<module>web</module>
|
||||||
|
<module>server</module>
|
||||||
|
</modules>
|
||||||
|
</project>
|
||||||
2
server/.gitignore
vendored
Normal file
2
server/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/target
|
||||||
|
/logs/app.log
|
||||||
158
server/pom.xml
Normal file
158
server/pom.xml
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>ru.mskobaro</groupId>
|
||||||
|
<artifactId>tdms</artifactId>
|
||||||
|
<version>0.0.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>server</artifactId>
|
||||||
|
<version>0.0.1</version>
|
||||||
|
|
||||||
|
<name>TDMS::SERVER</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>23</maven.compiler.source>
|
||||||
|
<maven.compiler.target>23</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<lombok.version>1.18.34</lombok.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.flywaydb</groupId>
|
||||||
|
<artifactId>flyway-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.flywaydb</groupId>
|
||||||
|
<artifactId>flyway-database-postgresql</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>${lombok.version}</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-testcontainers</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.testcontainers</groupId>
|
||||||
|
<artifactId>junit-jupiter</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.testcontainers</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>3.14.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-collections4</artifactId>
|
||||||
|
<version>4.4</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<excludes>
|
||||||
|
<exclude>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</exclude>
|
||||||
|
</excludes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.13.0</version>
|
||||||
|
<configuration>
|
||||||
|
<useIncrementalCompilation>true</useIncrementalCompilation>
|
||||||
|
<annotationProcessorPaths>
|
||||||
|
<path>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>${lombok.version}</version>
|
||||||
|
</path>
|
||||||
|
</annotationProcessorPaths>
|
||||||
|
<source>23</source>
|
||||||
|
<target>23</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-resources-plugin</artifactId>
|
||||||
|
<version>3.3.1</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>deploy frontend</id>
|
||||||
|
<phase>process-resources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>copy-resources</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<outputDirectory>target/classes/static</outputDirectory>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>../web/dist</directory>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
21
server/src/main/java/ru/mskobaro/tdms/TdmsApplication.java
Normal file
21
server/src/main/java/ru/mskobaro/tdms/TdmsApplication.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package ru.mskobaro.tdms;
|
||||||
|
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@Slf4j
|
||||||
|
public class TdmsApplication {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Thread.currentThread().setName("spring-bootstrapper");
|
||||||
|
ConfigurableApplicationContext ctx = SpringApplication.run(TdmsApplication.class, args);
|
||||||
|
Environment environment = ctx.getEnvironment();
|
||||||
|
log.info("Server listening on port: {}", environment.getProperty("server.port"));
|
||||||
|
ctx.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
package ru.mskobaro.tdms.business.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
|
import org.hibernate.annotations.UpdateTimestamp;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
@Getter
|
||||||
|
public class AuditInfo {
|
||||||
|
@CreationTimestamp
|
||||||
|
@Column(name = "created_at")
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
@UpdateTimestamp
|
||||||
|
@Column(name = "updated_at")
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package ru.mskobaro.tdms.business.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "commission_member_data")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class CommissionMemberData {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn(name = "partic_id", referencedColumnName = "id")
|
||||||
|
private Participant participant;
|
||||||
|
|
||||||
|
private String workPlace;
|
||||||
|
private String workPosition;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private AuditInfo auditInfo;
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
package ru.mskobaro.tdms.business.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "defense")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class Defense {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@ManyToMany
|
||||||
|
@JoinTable(
|
||||||
|
name = "defense_commission",
|
||||||
|
joinColumns = @JoinColumn(name = "defense_id", referencedColumnName = "id"),
|
||||||
|
inverseJoinColumns = @JoinColumn(name = "commission_member_data_id", referencedColumnName = "id"))
|
||||||
|
private List<CommissionMemberData> commissionMembers;
|
||||||
|
|
||||||
|
private LocalDate defenseDate;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "defense")
|
||||||
|
private List<Group> groups;
|
||||||
|
|
||||||
|
@ManyToMany
|
||||||
|
@JoinTable(
|
||||||
|
name = "defense_best_student_works",
|
||||||
|
joinColumns = @JoinColumn(name = "defense_id", referencedColumnName = "id"),
|
||||||
|
inverseJoinColumns = @JoinColumn(name = "student_data_id", referencedColumnName = "id"))
|
||||||
|
private List<StudentData> bestWorks;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private AuditInfo auditInfo;
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package ru.mskobaro.tdms.business.entity;
|
||||||
|
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
@Entity
|
||||||
|
@Table(name = "diploma_topic")
|
||||||
|
public class DiplomaTopic {
|
||||||
|
@Id
|
||||||
|
@Column(name = "id")
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "name")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "teacher_id")
|
||||||
|
private TeacherData teacher;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "direction_of_preparation_id")
|
||||||
|
private DirectionOfPreparation directionOfPreparation;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private AuditInfo auditInfo;
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
package ru.mskobaro.tdms.business.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "direction_of_preparation")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class DirectionOfPreparation {
|
||||||
|
@Id
|
||||||
|
@Column(name = "id")
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "directionOfPreparation")
|
||||||
|
private List<DiplomaTopic> diplomaTopic;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private AuditInfo auditInfo;
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
package ru.mskobaro.tdms.business.entity;
|
||||||
|
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
@Entity
|
||||||
|
@Table(name = "`group`")
|
||||||
|
public class Group {
|
||||||
|
@Id
|
||||||
|
@Column(name = "id")
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "name")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "group")
|
||||||
|
private List<StudentData> students = new ArrayList<>();
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "direction_of_preparation_id")
|
||||||
|
private DirectionOfPreparation directionOfPreparation;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "defense_id")
|
||||||
|
private Defense defense;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private AuditInfo auditInfo;
|
||||||
|
}
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
package ru.mskobaro.tdms.business.entity;
|
||||||
|
|
||||||
|
import io.micrometer.common.util.StringUtils;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "participant")
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class Participant {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String firstName;
|
||||||
|
private String lastName;
|
||||||
|
private String middleName;
|
||||||
|
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
private String numberPhone;
|
||||||
|
|
||||||
|
@OneToOne(mappedBy = "participant")
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
private boolean deleted;
|
||||||
|
|
||||||
|
@ManyToMany(fetch = FetchType.EAGER)
|
||||||
|
@JoinTable(
|
||||||
|
name = "participant_role",
|
||||||
|
joinColumns = @JoinColumn(name = "partic_id", referencedColumnName = "id"),
|
||||||
|
inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"))
|
||||||
|
private List<Role> roles;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private AuditInfo auditInfo;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
public String getFullName() {
|
||||||
|
return Stream.of(lastName, firstName, middleName)
|
||||||
|
.filter(StringUtils::isNotBlank)
|
||||||
|
.collect(Collectors.joining(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
public String getShortName() {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
if (StringUtils.isNotBlank(lastName)) {
|
||||||
|
builder.append(lastName);
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(firstName)) {
|
||||||
|
builder.append(" ").append(firstName.charAt(0)).append(".");
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(middleName)) {
|
||||||
|
builder.append(" ").append(middleName.charAt(0)).append(".");
|
||||||
|
}
|
||||||
|
return builder.toString().trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
package ru.mskobaro.tdms.business.entity;
|
||||||
|
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.*;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@Entity
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Table(name = "`role`")
|
||||||
|
@EqualsAndHashCode(of = "id")
|
||||||
|
public class Role implements GrantedAuthority {
|
||||||
|
@Id
|
||||||
|
@Column(name = "id")
|
||||||
|
private Long id;
|
||||||
|
@Column(name = "name")
|
||||||
|
private String name;
|
||||||
|
@Column(name = "authority")
|
||||||
|
private String authority;
|
||||||
|
}
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
package ru.mskobaro.tdms.business.entity;
|
||||||
|
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import ru.mskobaro.tdms.integration.database.TeacherDataRepository;
|
||||||
|
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString(exclude = "group")
|
||||||
|
@Entity
|
||||||
|
@Table(name = "student_data")
|
||||||
|
public class StudentData {
|
||||||
|
@Id
|
||||||
|
@Column(name = "id")
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn(name = "partic_id")
|
||||||
|
private Participant participant;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "group_id")
|
||||||
|
private Group group;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "study_form_id")
|
||||||
|
private StudyForm form;
|
||||||
|
|
||||||
|
private Integer protectionOrder;
|
||||||
|
private Integer protectionDay;
|
||||||
|
|
||||||
|
private Integer markComment;
|
||||||
|
private Integer markPractice;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "curator_id")
|
||||||
|
private TeacherData curator;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "diploma_topic_id")
|
||||||
|
private DiplomaTopic diplomaTopic;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private AuditInfo auditInfo;
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
package ru.mskobaro.tdms.business.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "study_form")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class StudyForm {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "name")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private AuditInfo auditInfo;
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
package ru.mskobaro.tdms.business.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.hibernate.annotations.JdbcTypeCode;
|
||||||
|
import org.hibernate.type.SqlTypes;
|
||||||
|
import ru.mskobaro.tdms.business.taskfields.TaskFields;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "task")
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class Task {
|
||||||
|
public enum Type {
|
||||||
|
DIPLOMA_TOPIC_AGREEMENT,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Status {
|
||||||
|
WAIT_FOR_TOPIC_AGREEMENT,
|
||||||
|
DONE,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private Type type;
|
||||||
|
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private Status status;
|
||||||
|
|
||||||
|
@JdbcTypeCode(SqlTypes.JSON)
|
||||||
|
private TaskFields fields;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private AuditInfo auditInfo;
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package ru.mskobaro.tdms.business.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "teacher_data")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class TeacherData {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn(name = "participant_id", referencedColumnName = "id")
|
||||||
|
private Participant participant;
|
||||||
|
|
||||||
|
private String degree;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private AuditInfo auditInfo;
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
package ru.mskobaro.tdms.business.entity;
|
||||||
|
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
@EqualsAndHashCode(of = "id")
|
||||||
|
@Entity
|
||||||
|
@Table(name = "`user`")
|
||||||
|
public class User implements UserDetails {
|
||||||
|
@Id
|
||||||
|
@Column(name = "id")
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
@Column(name = "login")
|
||||||
|
private String login;
|
||||||
|
@Column(name = "password")
|
||||||
|
private String password;
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn(name = "partic_id")
|
||||||
|
private Participant participant;
|
||||||
|
|
||||||
|
@Embedded
|
||||||
|
private AuditInfo auditInfo;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||||
|
return participant.getRoles().stream()
|
||||||
|
.map(Role::getAuthority)
|
||||||
|
.map(SimpleGrantedAuthority::new)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return !participant.isDeleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUsername() {
|
||||||
|
return login;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package ru.mskobaro.tdms.business.exception;
|
||||||
|
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.ErrorDTO;
|
||||||
|
|
||||||
|
public class AccessDeniedException extends BusinessException {
|
||||||
|
public AccessDeniedException() {
|
||||||
|
super("Access denied");
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessDeniedException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ErrorDTO.ErrorCode getErrorCode() {
|
||||||
|
return ErrorDTO.ErrorCode.ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package ru.mskobaro.tdms.business.exception;
|
||||||
|
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.ErrorDTO;
|
||||||
|
|
||||||
|
public class BusinessException extends RuntimeException {
|
||||||
|
public BusinessException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ErrorDTO.ErrorCode getErrorCode() {
|
||||||
|
return ErrorDTO.ErrorCode.BUSINESS_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package ru.mskobaro.tdms.business.exception;
|
||||||
|
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.ErrorDTO;
|
||||||
|
|
||||||
|
public class NotFoundException extends BusinessException {
|
||||||
|
public NotFoundException(Class<?> entityClass, Object id) {
|
||||||
|
super(entityClass.getSimpleName() + " с идентификатором " + id + " не существует");
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotFoundException(Class<?> entityClass) {
|
||||||
|
super(entityClass.getSimpleName() + " не существует");
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotFoundException() {
|
||||||
|
super("Не существует");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void throwIfNull(Object object) {
|
||||||
|
if (object == null) {
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void throwIfNull(Object object, Class<?> entityClass, Object id) {
|
||||||
|
if (object == null) {
|
||||||
|
throw new NotFoundException(entityClass, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ErrorDTO.ErrorCode getErrorCode() {
|
||||||
|
return ErrorDTO.ErrorCode.NOT_FOUND;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
package ru.mskobaro.tdms.business.service;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpSession;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.session.SessionRegistry;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import static org.springframework.security.web.context.HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class AuthenticationService {
|
||||||
|
@Autowired
|
||||||
|
private HttpServletRequest request;
|
||||||
|
@Autowired
|
||||||
|
private AuthenticationManager authenticationManager;
|
||||||
|
@Autowired
|
||||||
|
private SessionRegistry sessionRegistry;
|
||||||
|
|
||||||
|
public void logout() {
|
||||||
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
if (authentication == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String username = authentication.getName();
|
||||||
|
|
||||||
|
HttpSession session = request.getSession(false);
|
||||||
|
if (session != null) {
|
||||||
|
session.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
SecurityContextHolder.clearContext();
|
||||||
|
|
||||||
|
log.info("User {} logged out", username);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void logout(String username) {
|
||||||
|
sessionRegistry.getAllSessions(username, false).forEach(session -> {
|
||||||
|
log.info("Invalidating session for user {}: {}", username, session.getSessionId());
|
||||||
|
session.expireNow();
|
||||||
|
sessionRegistry.removeSessionInformation(session.getSessionId());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void login(String username, String password) {
|
||||||
|
var token = new UsernamePasswordAuthenticationToken(username, password);
|
||||||
|
var authenticated = authenticationManager.authenticate(token);
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(authenticated);
|
||||||
|
request.getSession().setAttribute(SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
|
||||||
|
log.info("User {} logged in, ip: {}", username, request.getRemoteAddr());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package ru.mskobaro.tdms.business.service;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import ru.mskobaro.tdms.integration.database.DefenceRepository;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.DefenceDTO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class DefenceService {
|
||||||
|
@Autowired
|
||||||
|
private DefenceRepository defenceRepository;
|
||||||
|
|
||||||
|
public List<DefenceDTO> getAllDefences() {
|
||||||
|
return defenceRepository.findAll().stream().map(DefenceDTO::from).toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
package ru.mskobaro.tdms.business.service;
|
||||||
|
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.mskobaro.tdms.business.entity.DiplomaTopic;
|
||||||
|
import ru.mskobaro.tdms.business.entity.DirectionOfPreparation;
|
||||||
|
import ru.mskobaro.tdms.business.entity.TeacherData;
|
||||||
|
import ru.mskobaro.tdms.integration.database.DiplomaTopicRepository;
|
||||||
|
import ru.mskobaro.tdms.integration.database.PreparationDirectionRepository;
|
||||||
|
import ru.mskobaro.tdms.integration.database.TeacherDataRepository;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.DiplomaTopicDTO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class DiplomaTopicService {
|
||||||
|
@Autowired
|
||||||
|
private DiplomaTopicRepository diplomaTopicRepository;
|
||||||
|
@Autowired
|
||||||
|
private TeacherDataRepository teacherDataRepository;
|
||||||
|
@Autowired
|
||||||
|
private PreparationDirectionRepository preparationDirectionRepository;
|
||||||
|
|
||||||
|
public List<DiplomaTopic> findAll() {
|
||||||
|
return diplomaTopicRepository.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save(DiplomaTopicDTO diplomaTopicDTO) {
|
||||||
|
boolean isEdit = diplomaTopicDTO.getId() != null;
|
||||||
|
DiplomaTopic diplomaTopic;
|
||||||
|
if (isEdit) {
|
||||||
|
diplomaTopic = diplomaTopicRepository.findByIdThrow(diplomaTopicDTO.getId());
|
||||||
|
} else {
|
||||||
|
diplomaTopic = new DiplomaTopic();
|
||||||
|
}
|
||||||
|
|
||||||
|
diplomaTopic.setName(diplomaTopicDTO.getName());
|
||||||
|
if (diplomaTopicDTO.getTeacher() != null) {
|
||||||
|
TeacherData teacherData = teacherDataRepository.findByIdThrow(diplomaTopicDTO.getTeacher().getId());
|
||||||
|
diplomaTopic.setTeacher(teacherData);
|
||||||
|
}
|
||||||
|
if (diplomaTopicDTO.getPreparationDirection() != null) {
|
||||||
|
DirectionOfPreparation directionOfPreparation = preparationDirectionRepository.findByIdThrow(diplomaTopicDTO.getPreparationDirection().getId());
|
||||||
|
diplomaTopic.setDirectionOfPreparation(directionOfPreparation);
|
||||||
|
}
|
||||||
|
|
||||||
|
diplomaTopicRepository.save(diplomaTopic);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DiplomaTopic> findAllForStudent(Long studentId) {
|
||||||
|
return diplomaTopicRepository.findAllForStudentId(studentId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
package ru.mskobaro.tdms.business.service;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
import ru.mskobaro.tdms.business.entity.DirectionOfPreparation;
|
||||||
|
import ru.mskobaro.tdms.business.entity.Group;
|
||||||
|
import ru.mskobaro.tdms.business.entity.StudentData;
|
||||||
|
import ru.mskobaro.tdms.business.exception.BusinessException;
|
||||||
|
import ru.mskobaro.tdms.integration.database.GroupRepository;
|
||||||
|
import ru.mskobaro.tdms.integration.database.PreparationDirectionRepository;
|
||||||
|
import ru.mskobaro.tdms.integration.database.StudentDataRepository;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.GroupDTO;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.StudentDataDTO;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
@Slf4j
|
||||||
|
public class GroupService {
|
||||||
|
@Autowired
|
||||||
|
private GroupRepository groupRepository;
|
||||||
|
@Autowired
|
||||||
|
private RoleService roleService;
|
||||||
|
@Autowired
|
||||||
|
private StudentDataRepository studentDataRepository;
|
||||||
|
@Autowired
|
||||||
|
private PreparationDirectionRepository preparationDirectionRepository;
|
||||||
|
|
||||||
|
public Collection<GroupDTO> getAllGroups() {
|
||||||
|
List<Group> groups = groupRepository.findAll();
|
||||||
|
return groups.stream().map(g -> GroupDTO.from(g, true)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save(@Valid GroupDTO groupDTO) {
|
||||||
|
boolean editMode = groupDTO.getId() != null;
|
||||||
|
log.info("Saving group: {}. Edit?: {}", groupDTO, editMode);
|
||||||
|
if (!editMode && groupRepository.existsByName(groupDTO.getName())) {
|
||||||
|
throw new BusinessException("Группа с именем " + groupDTO.getName() + " уже существует");
|
||||||
|
}
|
||||||
|
|
||||||
|
Group group = editMode ? groupRepository.findByIdThrow(groupDTO.getId()) : new Group();
|
||||||
|
group.setName(groupDTO.getName());
|
||||||
|
|
||||||
|
studentDataRepository.findAllByGroup_Id(group.getId()).forEach(s -> {
|
||||||
|
s.setGroup(null);
|
||||||
|
studentDataRepository.save(s);
|
||||||
|
});
|
||||||
|
group.getStudents().clear();
|
||||||
|
|
||||||
|
List<Long> studentIds = groupDTO.getStudents().stream().map(StudentDataDTO::getId).toList();
|
||||||
|
if (!CollectionUtils.isEmpty(studentIds)) {
|
||||||
|
List<StudentData> students = studentDataRepository.findAllById(studentIds);
|
||||||
|
students.stream()
|
||||||
|
.filter(s -> roleService.isParticInAuthority(s.getParticipant(), RoleService.Authority.STUDENT))
|
||||||
|
.forEach(s -> {
|
||||||
|
group.getStudents().add(s);
|
||||||
|
s.setGroup(group);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (groupDTO.getPreparationDirection() != null) {
|
||||||
|
DirectionOfPreparation directionOfPreparation = preparationDirectionRepository.findByIdThrow(groupDTO.getPreparationDirection().getId());
|
||||||
|
group.setDirectionOfPreparation(directionOfPreparation);
|
||||||
|
}
|
||||||
|
|
||||||
|
groupRepository.save(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteGroup(Long groupId) {
|
||||||
|
groupRepository.deleteById(groupId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,220 @@
|
|||||||
|
package ru.mskobaro.tdms.business.service;
|
||||||
|
|
||||||
|
import io.micrometer.common.util.StringUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.collections4.ListUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import ru.mskobaro.tdms.business.entity.*;
|
||||||
|
import ru.mskobaro.tdms.business.exception.AccessDeniedException;
|
||||||
|
import ru.mskobaro.tdms.business.exception.BusinessException;
|
||||||
|
import ru.mskobaro.tdms.integration.database.*;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.ParticipantSaveDTO;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
@Slf4j
|
||||||
|
public class ParticipantService {
|
||||||
|
@Autowired
|
||||||
|
private ParticipantRepository participantRepository;
|
||||||
|
@Autowired
|
||||||
|
private UserService userService;
|
||||||
|
@Autowired
|
||||||
|
private RoleService roleService;
|
||||||
|
@Autowired
|
||||||
|
private PasswordEncoder passwordEncoder;
|
||||||
|
@Autowired
|
||||||
|
private UserRepository userRepository;
|
||||||
|
@Autowired
|
||||||
|
private GroupRepository groupRepository;
|
||||||
|
@Autowired
|
||||||
|
private StudentDataRepository studentDataRepository;
|
||||||
|
@Autowired
|
||||||
|
private AuthenticationService authenticationService;
|
||||||
|
@Autowired
|
||||||
|
private TeacherDataRepository teacherDataRepository;
|
||||||
|
|
||||||
|
public ParticipantService(ParticipantRepository participantRepository) {
|
||||||
|
this.participantRepository = participantRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Participant> getAllParticipants() {
|
||||||
|
return participantRepository.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveParticipant(ParticipantSaveDTO participantSaveDTO) {
|
||||||
|
boolean editMode = participantSaveDTO.getId() != null;
|
||||||
|
log.info("Saving participant: {}. Edit: {}", participantSaveDTO, editMode);
|
||||||
|
Participant existingParticipant = null;
|
||||||
|
if (editMode)
|
||||||
|
existingParticipant = participantRepository.findByIdThrow(participantSaveDTO.getId());
|
||||||
|
persistParticipant(participantSaveDTO, existingParticipant, editMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void persistParticipant(ParticipantSaveDTO participantSaveDTO, Participant existingParticipant, boolean editMode) {
|
||||||
|
Participant participant = !editMode ? new Participant() : existingParticipant;
|
||||||
|
User callerUser = userService.getCallerUser();
|
||||||
|
if (callerUser == null)
|
||||||
|
throw new AccessDeniedException();
|
||||||
|
|
||||||
|
participant.setFirstName(participantSaveDTO.getFirstName());
|
||||||
|
participant.setLastName(participantSaveDTO.getLastName());
|
||||||
|
participant.setMiddleName(participantSaveDTO.getMiddleName());
|
||||||
|
participant.setNumberPhone(participantSaveDTO.getNumberPhone());
|
||||||
|
participant.setEmail(participantSaveDTO.getEmail());
|
||||||
|
|
||||||
|
List<Role> roles = persistRoles(participantSaveDTO, existingParticipant, editMode, callerUser, participant);
|
||||||
|
boolean credentialsChanged = persistUserData(participantSaveDTO, existingParticipant, editMode, participant);
|
||||||
|
persistStudentData(participantSaveDTO, existingParticipant, editMode, roles, participant);
|
||||||
|
persistTeacherData(participantSaveDTO, existingParticipant, editMode, roles, participant);
|
||||||
|
|
||||||
|
// TODO: notification task
|
||||||
|
Participant saved = participantRepository.save(participant);
|
||||||
|
log.info("Participant saved: {}", saved.getFullName());
|
||||||
|
|
||||||
|
if (credentialsChanged) {
|
||||||
|
log.info("User {} changed credentials, logging out", saved.getUser().getUsername());
|
||||||
|
authenticationService.logout(saved.getUser().getUsername());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Role> persistRoles(ParticipantSaveDTO participantSaveDTO, Participant existingParticipant, boolean editMode, User callerUser, Participant participant) {
|
||||||
|
boolean isAdmin = roleService.isParticInAuthority(callerUser.getParticipant(), RoleService.Authority.ADMIN);
|
||||||
|
boolean isSecretary = roleService.isParticInAuthority(callerUser.getParticipant(), RoleService.Authority.SECRETARY);
|
||||||
|
boolean isOwner = existingParticipant != null && existingParticipant.getUser() != null
|
||||||
|
&& existingParticipant.getUser().getId().equals(callerUser.getId());
|
||||||
|
if (!isAdmin && !isSecretary && !isOwner)
|
||||||
|
throw new AccessDeniedException();
|
||||||
|
if (participantSaveDTO.getAuthorities() != null && participantSaveDTO.getAuthorities().contains(RoleService.Authority.ADMIN) && !isAdmin)
|
||||||
|
throw new AccessDeniedException("Недостаточно прав для назначения роли администратора");
|
||||||
|
|
||||||
|
List<Role> roles = participantSaveDTO.getAuthorities() != null
|
||||||
|
? participantSaveDTO.getAuthorities()
|
||||||
|
.stream()
|
||||||
|
.map(roleService::getRoleByAuthority)
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (editMode && isOwner && !isAdmin && roles != null && !ListUtils.isEqualList(roles, existingParticipant.getRoles())) {
|
||||||
|
throw new AccessDeniedException("Вы не можете изменять свои роли");
|
||||||
|
} else if (roles != null) {
|
||||||
|
participant.setRoles(roles);
|
||||||
|
}
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean persistUserData(ParticipantSaveDTO participantSaveDTO, Participant existingParticipant, boolean editMode, Participant participant) {
|
||||||
|
boolean credentialsChanged = false;
|
||||||
|
if (participantSaveDTO.getUserData() == null) {
|
||||||
|
return credentialsChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
User user;
|
||||||
|
boolean wasBefore = false;
|
||||||
|
if (editMode && existingParticipant.getUser() != null) {
|
||||||
|
user = existingParticipant.getUser();
|
||||||
|
wasBefore = true;
|
||||||
|
} else {
|
||||||
|
user = new User();
|
||||||
|
}
|
||||||
|
|
||||||
|
String login = participantSaveDTO.getUserData().getLogin();
|
||||||
|
if (StringUtils.isNotBlank(login)) {
|
||||||
|
user.setLogin(login);
|
||||||
|
credentialsChanged = true;
|
||||||
|
} else if (!wasBefore) {
|
||||||
|
throw new BusinessException("Логин не может быть пустым");
|
||||||
|
}
|
||||||
|
|
||||||
|
String password = participantSaveDTO.getUserData().getPassword();
|
||||||
|
if (StringUtils.isNotBlank(password)) {
|
||||||
|
user.setPassword(passwordEncoder.encode(password));
|
||||||
|
credentialsChanged = true;
|
||||||
|
} else if (!wasBefore) {
|
||||||
|
throw new BusinessException("Пароль не может быть пустым");
|
||||||
|
}
|
||||||
|
|
||||||
|
user = userRepository.save(user);
|
||||||
|
participant.setUser(user);
|
||||||
|
user.setParticipant(participant);
|
||||||
|
return credentialsChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void persistTeacherData(ParticipantSaveDTO participantSaveDTO, Participant existingParticipant, boolean editMode, List<Role> roles, Participant participant) {
|
||||||
|
boolean shouldPersistTeacherData = participantSaveDTO.getTeacherData() != null && roles != null
|
||||||
|
&& CollectionUtils.containsAny(roles, roleService.getRoleByAuthority(RoleService.Authority.TEACHER));
|
||||||
|
if (!shouldPersistTeacherData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean alreadyExists = editMode && teacherDataRepository.existsByParticipant_IdAndParticipant_DeletedFalse(existingParticipant.getId());
|
||||||
|
TeacherData teacherData;
|
||||||
|
if (alreadyExists) {
|
||||||
|
teacherData = teacherDataRepository.findByParticipant_Id(existingParticipant.getId());
|
||||||
|
} else {
|
||||||
|
teacherData = new TeacherData();
|
||||||
|
}
|
||||||
|
|
||||||
|
teacherData.setDegree(participantSaveDTO.getTeacherData().getDegree());
|
||||||
|
|
||||||
|
teacherData = teacherDataRepository.save(teacherData);
|
||||||
|
teacherData.setParticipant(participant);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void persistStudentData(ParticipantSaveDTO participantSaveDTO, Participant existingParticipant, boolean editMode, List<Role> roles, Participant participant) {
|
||||||
|
boolean shouldPersistStudentData = participantSaveDTO.getStudentData() != null && roles != null
|
||||||
|
&& CollectionUtils.containsAny(roles, roleService.getRoleByAuthority(RoleService.Authority.STUDENT));
|
||||||
|
if (!shouldPersistStudentData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean alreadyExists = editMode && studentDataRepository.existsByParticipant_IdAndParticipant_DeletedFalse(existingParticipant.getId());
|
||||||
|
StudentData studentData;
|
||||||
|
if (alreadyExists) {
|
||||||
|
studentData = studentDataRepository.findStudentDataByParticipant_Id(existingParticipant.getId());
|
||||||
|
} else {
|
||||||
|
studentData = new StudentData();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (participantSaveDTO.getStudentData().getGroupId() != null) {
|
||||||
|
Group group = groupRepository.findByIdThrow(participantSaveDTO.getStudentData().getGroupId());
|
||||||
|
studentData.setGroup(group);
|
||||||
|
if (!group.getStudents().contains(studentData))
|
||||||
|
group.getStudents().add(studentData);
|
||||||
|
} else {
|
||||||
|
if (editMode) {
|
||||||
|
Group group = groupRepository.findByStudentsContaining(Collections.singletonList(studentData));
|
||||||
|
if (group != null)
|
||||||
|
group.getStudents().remove(studentData);
|
||||||
|
}
|
||||||
|
studentData.setGroup(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (participantSaveDTO.getStudentData().getCuratorId() != null) {
|
||||||
|
TeacherData teacherData = teacherDataRepository.findByIdThrow(participantSaveDTO.getStudentData().getCuratorId());
|
||||||
|
studentData.setCurator(teacherData);
|
||||||
|
} else {
|
||||||
|
studentData.setCurator(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
studentData = studentDataRepository.save(studentData);
|
||||||
|
studentData.setParticipant(participant);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteParticipant(Long id) {
|
||||||
|
if (id == 1) {
|
||||||
|
throw new AccessDeniedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Participant partic = participantRepository.findByIdThrow(id);
|
||||||
|
partic.setDeleted(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package ru.mskobaro.tdms.business.service;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import ru.mskobaro.tdms.business.entity.DirectionOfPreparation;
|
||||||
|
import ru.mskobaro.tdms.integration.database.PreparationDirectionRepository;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.PreparationDirectionDTO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class PreparationDirectionService {
|
||||||
|
@Autowired
|
||||||
|
private PreparationDirectionRepository preparationDirectionRepository;
|
||||||
|
|
||||||
|
public List<DirectionOfPreparation> getAll() {
|
||||||
|
return preparationDirectionRepository.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save(PreparationDirectionDTO preparationDirectionDTO) {
|
||||||
|
boolean editMode = preparationDirectionDTO.getId() != null;
|
||||||
|
DirectionOfPreparation preparationDirection;
|
||||||
|
if (editMode) {
|
||||||
|
preparationDirection = preparationDirectionRepository.findByIdThrow(preparationDirectionDTO.getId());
|
||||||
|
} else {
|
||||||
|
preparationDirection = new DirectionOfPreparation();
|
||||||
|
}
|
||||||
|
preparationDirection.setName(preparationDirectionDTO.getName());
|
||||||
|
preparationDirection.setCode(preparationDirectionDTO.getCode());
|
||||||
|
preparationDirectionRepository.save(preparationDirection);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
package ru.mskobaro.tdms.business.service;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import ru.mskobaro.tdms.business.entity.Participant;
|
||||||
|
import ru.mskobaro.tdms.business.entity.Role;
|
||||||
|
import ru.mskobaro.tdms.integration.database.RoleRepository;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class RoleService {
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public enum Authority {
|
||||||
|
ADMIN("ROLE_ADMINISTRATOR"),
|
||||||
|
COMM_MEMBER("ROLE_COMMISSION_MEMBER"),
|
||||||
|
TEACHER("ROLE_TEACHER"),
|
||||||
|
PLAGIARISM_CHECKER("ROLE_PLAGIARISM_CHECKER"),
|
||||||
|
SECRETARY("ROLE_SECRETARY"),
|
||||||
|
STUDENT("ROLE_STUDENT"),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final String authority;
|
||||||
|
|
||||||
|
@JsonValue
|
||||||
|
public String getAuthority() {
|
||||||
|
return authority;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonCreator
|
||||||
|
public static Authority from(String authority) {
|
||||||
|
for (Authority value : values()) {
|
||||||
|
if (value.getAuthority().equals(authority)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("No such authority: " + authority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<String, Role> roles = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RoleRepository roleRepository;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
@Transactional
|
||||||
|
public void bootstrapRolesCache() {
|
||||||
|
roleRepository.findAll().forEach(role -> roles.put(role.getAuthority(), role));
|
||||||
|
log.info("Roles initialized: {}", roles);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Role getRoleByAuthority(Authority authority) {
|
||||||
|
return roles.get(authority.getAuthority());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isParticInAuthority(Participant participant, Authority authority) {
|
||||||
|
return participant.getRoles().stream()
|
||||||
|
.anyMatch(role -> role.getAuthority().equals(authority.getAuthority()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isParticInAnyAuthority(Participant participant, Authority... authority) {
|
||||||
|
return participant.getRoles().stream()
|
||||||
|
.anyMatch(role -> {
|
||||||
|
for (Authority auth : authority) {
|
||||||
|
if (role.getAuthority().equals(auth.getAuthority())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package ru.mskobaro.tdms.business.service;
|
||||||
|
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.mskobaro.tdms.business.entity.Participant;
|
||||||
|
import ru.mskobaro.tdms.business.entity.StudentData;
|
||||||
|
import ru.mskobaro.tdms.integration.database.StudentDataRepository;
|
||||||
|
import ru.mskobaro.tdms.integration.database.UserRepository;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
@Slf4j
|
||||||
|
public class StudentDataService {
|
||||||
|
@Autowired
|
||||||
|
private StudentDataRepository studentDataRepository;
|
||||||
|
|
||||||
|
public StudentData getStudentByParticIdThrow(Long particId) {
|
||||||
|
return studentDataRepository.findStudentDataByParticipant_Id(particId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<StudentData> getAllStudentsWithoutGroup() {
|
||||||
|
return studentDataRepository.findByGroupIsNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
package ru.mskobaro.tdms.business.service;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class SysInfoService {
|
||||||
|
@Value("${application.version}")
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
package ru.mskobaro.tdms.business.service;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import ru.mskobaro.tdms.business.entity.StudentData;
|
||||||
|
import ru.mskobaro.tdms.business.entity.Task;
|
||||||
|
import ru.mskobaro.tdms.business.entity.User;
|
||||||
|
import ru.mskobaro.tdms.business.taskfields.DiplomaTopicAgreementTaskFields;
|
||||||
|
import ru.mskobaro.tdms.business.taskfields.TaskFields;
|
||||||
|
import ru.mskobaro.tdms.integration.database.StudentDataRepository;
|
||||||
|
import ru.mskobaro.tdms.integration.database.TaskRepository;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.TaskController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class TaskService {
|
||||||
|
@Autowired
|
||||||
|
private TaskRepository taskRepository;
|
||||||
|
@Autowired
|
||||||
|
private UserService userService;
|
||||||
|
@Autowired
|
||||||
|
private StudentDataRepository studentDataRepository;
|
||||||
|
|
||||||
|
public void createTask(Task.Type type, Task.Status status, TaskFields taskFields) {
|
||||||
|
Task task = new Task();
|
||||||
|
task.setType(type);
|
||||||
|
task.setStatus(status);
|
||||||
|
task.setFields(taskFields);
|
||||||
|
taskRepository.save(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task findDiplomaTopicAgreementTaskCallerMaker() {
|
||||||
|
User user = userService.getCallerUser();
|
||||||
|
List<Task> diplomaTopicAgreementTaskByMakerId = taskRepository.findDiplomaTopicAgreementTaskByMakerId(
|
||||||
|
user.getParticipant().getId(), Task.Type.DIPLOMA_TOPIC_AGREEMENT
|
||||||
|
);
|
||||||
|
if (diplomaTopicAgreementTaskByMakerId.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diplomaTopicAgreementTaskByMakerId.size() > 1) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return diplomaTopicAgreementTaskByMakerId.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createDiplomaAgreementTask(TaskController.DiplomaTopicAgreementDTO diplomaTopicAgreementDTO) {
|
||||||
|
DiplomaTopicAgreementTaskFields taskFields = new DiplomaTopicAgreementTaskFields();
|
||||||
|
User user = userService.getCallerUser();
|
||||||
|
StudentData studentData = studentDataRepository.findStudentDataByParticipant_Id(user.getParticipant().getId());
|
||||||
|
|
||||||
|
taskFields.setCheckerParticipantId(user.getParticipant().getId());
|
||||||
|
taskFields.setDiplomaTopicId(diplomaTopicAgreementDTO.getDiplomaTopicId());
|
||||||
|
taskFields.setDiplomaTopicName(diplomaTopicAgreementDTO.getDiplomaTopicName());
|
||||||
|
taskFields.setCheckerParticipantId(studentData.getCurator().getId());
|
||||||
|
|
||||||
|
createTask(Task.Type.DIPLOMA_TOPIC_AGREEMENT, Task.Status.WAIT_FOR_TOPIC_AGREEMENT, taskFields);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package ru.mskobaro.tdms.business.service;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import ru.mskobaro.tdms.business.entity.TeacherData;
|
||||||
|
import ru.mskobaro.tdms.business.exception.NotFoundException;
|
||||||
|
import ru.mskobaro.tdms.integration.database.TeacherDataRepository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
public class TeacherDataService {
|
||||||
|
@Autowired
|
||||||
|
private TeacherDataRepository teacherDataRepository;
|
||||||
|
|
||||||
|
public List<TeacherData> findAll() {
|
||||||
|
return teacherDataRepository.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TeacherData getTeacherDataByParticipantId(Long participantId) {
|
||||||
|
TeacherData teacher = teacherDataRepository.findByParticipant_Id(participantId);
|
||||||
|
if (teacher == null) {
|
||||||
|
throw new NotFoundException(TeacherData.class, participantId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return teacher;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
package ru.mskobaro.tdms.business.service;
|
||||||
|
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.mskobaro.tdms.business.entity.User;
|
||||||
|
import ru.mskobaro.tdms.integration.database.UserRepository;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.UserDTO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
@Slf4j
|
||||||
|
public class UserService implements UserDetailsService {
|
||||||
|
@Autowired
|
||||||
|
private UserRepository userRepository;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||||
|
log.debug("Loading user with username: {}", username);
|
||||||
|
User user = userRepository.findUserByLogin(username).orElseThrow(
|
||||||
|
() -> new UsernameNotFoundException("User with login " + username + " not found"));
|
||||||
|
log.debug("User with login {} loaded", username);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<UserDTO> getAllUsers() {
|
||||||
|
log.debug("Loading all users");
|
||||||
|
List<UserDTO> users = userRepository.findAll().stream()
|
||||||
|
.map(UserDTO::fromEntity)
|
||||||
|
.toList();
|
||||||
|
log.info("{} users loaded", users.size());
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getCallerUser() {
|
||||||
|
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
|
if (!(principal instanceof User)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (User) principal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package ru.mskobaro.tdms.business.taskfields;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class DiplomaTopicAgreementTaskFields extends MakerCheckerTaskFields {
|
||||||
|
private String diplomaTopicName;
|
||||||
|
private Long diplomaTopicId;
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package ru.mskobaro.tdms.business.taskfields;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class MakerCheckerTaskFields extends MakerTaskFields {
|
||||||
|
private Long checkerParticipantId;
|
||||||
|
private LocalDateTime approvedAt;
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package ru.mskobaro.tdms.business.taskfields;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class MakerTaskFields extends TaskFields {
|
||||||
|
private Long makerParticipantId;
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package ru.mskobaro.tdms.business.taskfields;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class TaskFields {
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package ru.mskobaro.tdms.integration.database;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import ru.mskobaro.tdms.business.entity.Defense;
|
||||||
|
import ru.mskobaro.tdms.business.exception.NotFoundException;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface DefenceRepository extends JpaRepository<Defense, Long> {
|
||||||
|
default Defense findByIdThrow(Long id) {
|
||||||
|
return this.findById(id).orElseThrow(() -> new NotFoundException(Defense.class, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Query("SELECT d from Defense d " +
|
||||||
|
"left join fetch d.bestWorks bw " +
|
||||||
|
"left join fetch d.commissionMembers cm " +
|
||||||
|
"where d.id = :id " +
|
||||||
|
"and bw.participant.deleted = false " +
|
||||||
|
"and cm.participant.deleted = false")
|
||||||
|
Optional<Defense> findById(Long id);
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package ru.mskobaro.tdms.integration.database;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import ru.mskobaro.tdms.business.entity.DiplomaTopic;
|
||||||
|
import ru.mskobaro.tdms.business.entity.DirectionOfPreparation;
|
||||||
|
import ru.mskobaro.tdms.business.entity.StudentData;
|
||||||
|
import ru.mskobaro.tdms.business.exception.NotFoundException;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface DiplomaTopicRepository extends JpaRepository<DiplomaTopic, Long> {
|
||||||
|
default DiplomaTopic findByIdThrow(Long id) {
|
||||||
|
return this.findById(id).orElseThrow(() -> new NotFoundException(DiplomaTopic.class, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Query("SELECT d FROM DiplomaTopic d WHERE d.id = :id AND d.teacher.participant.deleted = false")
|
||||||
|
Optional<DiplomaTopic> findById(Long id);
|
||||||
|
|
||||||
|
@Query("SELECT d FROM DiplomaTopic d " +
|
||||||
|
"inner join d.directionOfPreparation dp " +
|
||||||
|
"inner join StudentData sd on sd.id = :studentIdwhere " +
|
||||||
|
"where dp = sd.group.directionOfPreparation")
|
||||||
|
List<DiplomaTopic> findAllForStudentId(Long studentId);
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
package ru.mskobaro.tdms.integration.database;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import ru.mskobaro.tdms.business.entity.Group;
|
||||||
|
import ru.mskobaro.tdms.business.entity.StudentData;
|
||||||
|
import ru.mskobaro.tdms.business.exception.NotFoundException;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface GroupRepository extends JpaRepository<Group, Long> {
|
||||||
|
default Group findByIdThrow(Long id) {
|
||||||
|
return this.findById(id).orElseThrow(() -> new NotFoundException(Group.class, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Query("SELECT g FROM Group g left join fetch g.students sd WHERE g.id = :id")
|
||||||
|
Optional<Group> findById(Long id);
|
||||||
|
|
||||||
|
boolean existsByName(String name);
|
||||||
|
|
||||||
|
@Query("SELECT g FROM Group g left join fetch g.students sd WHERE sd IN :students")
|
||||||
|
Group findByStudentsContaining(List<StudentData> students);
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
package ru.mskobaro.tdms.integration.database;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import ru.mskobaro.tdms.business.entity.DiplomaTopic;
|
||||||
|
import ru.mskobaro.tdms.business.entity.Participant;
|
||||||
|
import ru.mskobaro.tdms.business.exception.NotFoundException;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface ParticipantRepository extends JpaRepository<Participant, Long> {
|
||||||
|
|
||||||
|
default Participant findByIdThrow(Long id) {
|
||||||
|
return this.findById(id).orElseThrow(() -> new NotFoundException(DiplomaTopic.class, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Query("SELECT p FROM Participant p WHERE p.id = :id AND p.deleted = false")
|
||||||
|
Optional<Participant> findById(Long id);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Query("SELECT p from Participant p where p.deleted = false")
|
||||||
|
List<Participant> findAll();
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package ru.mskobaro.tdms.integration.database;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import ru.mskobaro.tdms.business.entity.DirectionOfPreparation;
|
||||||
|
import ru.mskobaro.tdms.business.exception.NotFoundException;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface PreparationDirectionRepository extends JpaRepository<DirectionOfPreparation, Long> {
|
||||||
|
default DirectionOfPreparation findByIdThrow(Long id) {
|
||||||
|
return this.findById(id).orElseThrow(() -> new NotFoundException(DirectionOfPreparation.class, id));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package ru.mskobaro.tdms.integration.database;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import ru.mskobaro.tdms.business.entity.Role;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface RoleRepository extends JpaRepository<Role, Long> {
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package ru.mskobaro.tdms.integration.database;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.EntityGraph;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import ru.mskobaro.tdms.business.entity.StudentData;
|
||||||
|
import ru.mskobaro.tdms.business.exception.NotFoundException;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface StudentDataRepository extends JpaRepository<StudentData, Long> {
|
||||||
|
default StudentData findByIdThrow(Long id) {
|
||||||
|
return this.findById(id).orElseThrow(() -> new NotFoundException(StudentData.class, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@EntityGraph(type = EntityGraph.EntityGraphType.LOAD, attributePaths = {"group.students"})
|
||||||
|
@Query("SELECT s FROM StudentData s join fetch s.participant p WHERE p.id = :id AND p.deleted = false")
|
||||||
|
StudentData findStudentDataByParticipant_Id(Long id);
|
||||||
|
|
||||||
|
boolean existsByParticipant_IdAndParticipant_DeletedFalse(Long id);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@EntityGraph(type = EntityGraph.EntityGraphType.LOAD, attributePaths = {"participant.roles"})
|
||||||
|
@Query("SELECT s FROM StudentData s join fetch s.participant p WHERE s.id in :ids AND p.deleted = false")
|
||||||
|
List<StudentData> findAllById(Iterable<Long> ids);
|
||||||
|
|
||||||
|
@Query("SELECT s FROM StudentData s join fetch s.participant p WHERE s.group is null and p.deleted = false")
|
||||||
|
List<StudentData> findByGroupIsNull();
|
||||||
|
|
||||||
|
@Query("SELECT s FROM StudentData s join fetch s.participant p join fetch s.group g WHERE g.id = :id AND p.deleted = false")
|
||||||
|
List<StudentData> findAllByGroup_Id(Long id);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Query("SELECT s FROM StudentData s join fetch s.participant p WHERE s.id = :id AND p.deleted = false")
|
||||||
|
Optional<StudentData> findById(Long id);
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
package ru.mskobaro.tdms.integration.database;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import ru.mskobaro.tdms.business.entity.Task;
|
||||||
|
import ru.mskobaro.tdms.business.exception.NotFoundException;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface TaskRepository extends JpaRepository<Task, Long> {
|
||||||
|
default Task findByIdThrow(Long id) {
|
||||||
|
return findById(id).orElseThrow(() -> new NotFoundException(Task.class, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Query(value = "SELECT t FROM task t " +
|
||||||
|
"WHERE t.type = :type " +
|
||||||
|
"and t.fields->>'makerParticipantId' = :id", nativeQuery = true)
|
||||||
|
List<Task> findDiplomaTopicAgreementTaskByMakerId(Long id, Task.Type type);
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package ru.mskobaro.tdms.integration.database;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import ru.mskobaro.tdms.business.entity.TeacherData;
|
||||||
|
import ru.mskobaro.tdms.business.exception.NotFoundException;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface TeacherDataRepository extends JpaRepository<TeacherData, Long> {
|
||||||
|
default TeacherData findByIdThrow(Long id) {
|
||||||
|
return this.findById(id).orElseThrow(() -> new NotFoundException(TeacherData.class, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Query("SELECT t FROM TeacherData t WHERE t.id = :id AND t.participant.deleted = false")
|
||||||
|
Optional<TeacherData> findById(Long id);
|
||||||
|
|
||||||
|
boolean existsByParticipant_IdAndParticipant_DeletedFalse(Long id);
|
||||||
|
|
||||||
|
@Query("SELECT t FROM TeacherData t WHERE t.participant.id = :id AND t.participant.deleted = false")
|
||||||
|
TeacherData findByParticipant_Id(Long id);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Query("select t from TeacherData t where t.participant.deleted = false")
|
||||||
|
List<TeacherData> findAll();
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package ru.mskobaro.tdms.integration.database;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import ru.mskobaro.tdms.business.entity.User;
|
||||||
|
import ru.mskobaro.tdms.business.exception.NotFoundException;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface UserRepository extends JpaRepository<User, Long> {
|
||||||
|
default User findByIdThrow(Long id) {
|
||||||
|
return this.findById(id).orElseThrow(() -> new NotFoundException(User.class, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Query("SELECT u from User u join fetch u.participant p where u.id = :id and p.deleted = false")
|
||||||
|
Optional<User> findById(Long id);
|
||||||
|
|
||||||
|
@Query("SELECT u from User u join fetch u.participant p where u.login = :login and p.deleted = false")
|
||||||
|
Optional<User> findUserByLogin(String login);
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import ru.mskobaro.tdms.business.service.DefenceService;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.DefenceDTO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/defence")
|
||||||
|
public class DefenceController {
|
||||||
|
@Autowired
|
||||||
|
private DefenceService defenceService;
|
||||||
|
|
||||||
|
@GetMapping("/all")
|
||||||
|
public List<DefenceDTO> getAllDefences() {
|
||||||
|
return defenceService.getAllDefences();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import ru.mskobaro.tdms.business.service.DiplomaTopicService;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.DiplomaTopicDTO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/diploma-topic/")
|
||||||
|
@Validated
|
||||||
|
public class DiplomaTopicController {
|
||||||
|
@Autowired
|
||||||
|
private DiplomaTopicService diplomaTopicService;
|
||||||
|
|
||||||
|
@GetMapping("/all")
|
||||||
|
public List<DiplomaTopicDTO> getAll() {
|
||||||
|
return diplomaTopicService.findAll().stream().map(DiplomaTopicDTO::from).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/save")
|
||||||
|
public void save(@RequestBody DiplomaTopicDTO diplomaTopicDTO) {
|
||||||
|
diplomaTopicService.save(diplomaTopicDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/all-for-student")
|
||||||
|
public List<DiplomaTopicDTO> getAllForStudent(@RequestParam Long studentId) {
|
||||||
|
return diplomaTopicService.findAllForStudent(studentId).stream().map(DiplomaTopicDTO::from).toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import ru.mskobaro.tdms.business.service.GroupService;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.GroupDTO;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/group")
|
||||||
|
public class GroupController {
|
||||||
|
@Autowired
|
||||||
|
private GroupService groupService;
|
||||||
|
|
||||||
|
@GetMapping("/get-all-groups")
|
||||||
|
public Collection<GroupDTO> getAllGroups() {
|
||||||
|
return groupService.getAllGroups();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/save")
|
||||||
|
public void save(@RequestBody @Valid GroupDTO groupDTO) {
|
||||||
|
groupService.save(groupDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/delete")
|
||||||
|
public void delete(@RequestParam(value = "id") Long groupId) {
|
||||||
|
groupService.deleteGroup(groupId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import ru.mskobaro.tdms.business.service.ParticipantService;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.IdDto;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.ParticipantDTO;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.ParticipantSaveDTO;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/participant")
|
||||||
|
public class ParticipantController {
|
||||||
|
@Autowired
|
||||||
|
private ParticipantService participantService;
|
||||||
|
|
||||||
|
@GetMapping("/get-all-participants")
|
||||||
|
public Collection<ParticipantDTO> getAllParticipants() {
|
||||||
|
return participantService.getAllParticipants().stream()
|
||||||
|
.map(ParticipantDTO::fromEntity)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/save")
|
||||||
|
public void registerParticipant(@Valid @RequestBody ParticipantSaveDTO participantSaveDTO) {
|
||||||
|
participantService.saveParticipant(participantSaveDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/delete")
|
||||||
|
public void deleteParticipant(@RequestBody IdDto id) {
|
||||||
|
participantService.deleteParticipant(id.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import ru.mskobaro.tdms.business.service.PreparationDirectionService;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.PreparationDirectionDTO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/prep-direction")
|
||||||
|
public class PreparationDirectionController {
|
||||||
|
@Autowired
|
||||||
|
private PreparationDirectionService preparationDirectionService;
|
||||||
|
|
||||||
|
@GetMapping("/get-all")
|
||||||
|
public List<PreparationDirectionDTO> getAll() {
|
||||||
|
return preparationDirectionService.getAll().stream().map(PreparationDirectionDTO::from).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("save")
|
||||||
|
public void save(@RequestBody PreparationDirectionDTO preparationDirectionDTO) {
|
||||||
|
preparationDirectionService.save(preparationDirectionDTO);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import ru.mskobaro.tdms.business.entity.StudentData;
|
||||||
|
import ru.mskobaro.tdms.business.service.StudentDataService;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.GroupDTO;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.StudentDataDTO;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/student/")
|
||||||
|
public class StudentController {
|
||||||
|
@Autowired
|
||||||
|
private StudentDataService studentDataService;
|
||||||
|
|
||||||
|
@GetMapping(value = "/by-partic-id")
|
||||||
|
public StudentDataDTO getCurrentStudent(@RequestParam(value = "id") Long particId) {
|
||||||
|
StudentData studentData = studentDataService.getStudentByParticIdThrow(particId);
|
||||||
|
return StudentDataDTO.from(studentData, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "all-without-group")
|
||||||
|
public Collection<StudentDataDTO> getAllStudentsWithoutGroup() {
|
||||||
|
return studentDataService.getAllStudentsWithoutGroup().stream()
|
||||||
|
.map(sd -> StudentDataDTO.from(sd, true))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import ru.mskobaro.tdms.business.service.SysInfoService;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/sysinfo")
|
||||||
|
public class SysInfoController {
|
||||||
|
@Autowired
|
||||||
|
private SysInfoService sysInfoService;
|
||||||
|
|
||||||
|
@GetMapping("/version")
|
||||||
|
public String getVersion() {
|
||||||
|
return sysInfoService.getVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
// @GetMapping("/status")
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import ru.mskobaro.tdms.business.service.TaskService;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.TaskDto;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/task")
|
||||||
|
public class TaskController {
|
||||||
|
@Autowired
|
||||||
|
private TaskService taskService;
|
||||||
|
|
||||||
|
@GetMapping("/diploma-agreement-maker")
|
||||||
|
public TaskDto diplomaTopicAgreementMaker() {
|
||||||
|
return TaskDto.from(taskService.findDiplomaTopicAgreementTaskCallerMaker());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/create-topic-agreement")
|
||||||
|
public void createDiplomaTopicAgreement(@RequestBody DiplomaTopicAgreementDTO diplomaTopicAgreementDTO) {
|
||||||
|
taskService.createDiplomaAgreementTask(diplomaTopicAgreementDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public static class DiplomaTopicAgreementDTO {
|
||||||
|
private String diplomaTopicName;
|
||||||
|
private Long diplomaTopicId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import ru.mskobaro.tdms.business.service.TeacherDataService;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.TeacherDataDTO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/teacher-data")
|
||||||
|
public class TeacherDataController {
|
||||||
|
@Autowired
|
||||||
|
private TeacherDataService teacherDataService;
|
||||||
|
|
||||||
|
@GetMapping("/get-all")
|
||||||
|
public List<TeacherDataDTO> getAllTeacherData() {
|
||||||
|
return teacherDataService.findAll().stream().map(TeacherDataDTO::from).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/by-partic-id")
|
||||||
|
public TeacherDataDTO getTeacherDataByParticipantId(@RequestParam Long id) {
|
||||||
|
return TeacherDataDTO.from(teacherDataService.getTeacherDataByParticipantId(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import ru.mskobaro.tdms.business.entity.User;
|
||||||
|
import ru.mskobaro.tdms.business.service.AuthenticationService;
|
||||||
|
import ru.mskobaro.tdms.business.service.UserService;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.LoginDTO;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.UserDTO;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/user")
|
||||||
|
@Slf4j
|
||||||
|
public class UserController {
|
||||||
|
@Autowired
|
||||||
|
private AuthenticationService authenticationService;
|
||||||
|
@Autowired
|
||||||
|
private UserService userService;
|
||||||
|
|
||||||
|
@GetMapping("/current")
|
||||||
|
public ResponseEntity<UserDTO> getCurrentUser() {
|
||||||
|
User user = userService.getCallerUser();
|
||||||
|
return user == null
|
||||||
|
? ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()
|
||||||
|
: ResponseEntity.ok(UserDTO.fromEntity(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/logout")
|
||||||
|
public void logout() {
|
||||||
|
authenticationService.logout();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/login")
|
||||||
|
public void login(@RequestBody @Valid LoginDTO loginDTO) {
|
||||||
|
authenticationService.login(loginDTO.getLogin(), loginDTO.getPassword());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller.payload;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import ru.mskobaro.tdms.business.entity.CommissionMemberData;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class CommissionMemberDTO {
|
||||||
|
private Long id;
|
||||||
|
private ParticipantDTO participant;
|
||||||
|
private String workPlace;
|
||||||
|
private String workPosition;
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
public static CommissionMemberDTO from(CommissionMemberData commissionMemberData) {
|
||||||
|
CommissionMemberDTO dto = new CommissionMemberDTO();
|
||||||
|
dto.setId(commissionMemberData.getId());
|
||||||
|
dto.setParticipant(ParticipantDTO.fromEntity(commissionMemberData.getParticipant()));
|
||||||
|
dto.setWorkPlace(commissionMemberData.getWorkPlace());
|
||||||
|
dto.setWorkPosition(commissionMemberData.getWorkPosition());
|
||||||
|
dto.setCreatedAt(commissionMemberData.getAuditInfo().getCreatedAt());
|
||||||
|
dto.setUpdatedAt(commissionMemberData.getAuditInfo().getUpdatedAt());
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller.payload;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import ru.mskobaro.tdms.business.entity.Defense;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class DefenceDTO {
|
||||||
|
private Long id;
|
||||||
|
private List<CommissionMemberDTO> commissionMembers;
|
||||||
|
private List<GroupDTO> groups;
|
||||||
|
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
public static DefenceDTO from(Defense defense) {
|
||||||
|
DefenceDTO dto = new DefenceDTO();
|
||||||
|
dto.setId(defense.getId());
|
||||||
|
|
||||||
|
if (CollectionUtils.isNotEmpty(defense.getCommissionMembers())) {
|
||||||
|
dto.setCommissionMembers(
|
||||||
|
defense.getCommissionMembers().stream()
|
||||||
|
.map(CommissionMemberDTO::from)
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
dto.setGroups(defense.getGroups().stream().map(g -> GroupDTO.from(g, true)).toList());
|
||||||
|
dto.setCreatedAt(defense.getAuditInfo().getCreatedAt());
|
||||||
|
dto.setUpdatedAt(defense.getAuditInfo().getUpdatedAt());
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller.payload;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import ru.mskobaro.tdms.business.entity.DiplomaTopic;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString
|
||||||
|
public class DiplomaTopicDTO {
|
||||||
|
private Long id;
|
||||||
|
private String name;
|
||||||
|
private TeacherDataDTO teacher;
|
||||||
|
private PreparationDirectionDTO preparationDirection;
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
public static DiplomaTopicDTO from(DiplomaTopic diplomaTopic) {
|
||||||
|
DiplomaTopicDTO dto = new DiplomaTopicDTO();
|
||||||
|
dto.setId(diplomaTopic.getId());
|
||||||
|
dto.setName(diplomaTopic.getName());
|
||||||
|
if (diplomaTopic.getTeacher() != null) {
|
||||||
|
dto.setTeacher(TeacherDataDTO.from(diplomaTopic.getTeacher()));
|
||||||
|
}
|
||||||
|
if (diplomaTopic.getDirectionOfPreparation() != null) {
|
||||||
|
dto.setPreparationDirection(PreparationDirectionDTO.from(diplomaTopic.getDirectionOfPreparation()));
|
||||||
|
}
|
||||||
|
dto.setCreatedAt(diplomaTopic.getAuditInfo().getCreatedAt());
|
||||||
|
dto.setUpdatedAt(diplomaTopic.getAuditInfo().getUpdatedAt());
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller.payload;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
public record ErrorDTO(String message, ErrorCode errorCode) {
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Getter
|
||||||
|
public enum ErrorCode {
|
||||||
|
BUSINESS_ERROR(HttpStatus.BAD_REQUEST),
|
||||||
|
VALIDATION_ERROR(HttpStatus.BAD_REQUEST),
|
||||||
|
INTERNAL_ERROR(HttpStatus.INTERNAL_SERVER_ERROR),
|
||||||
|
NOT_FOUND(HttpStatus.NOT_FOUND),
|
||||||
|
ACCESS_DENIED(HttpStatus.FORBIDDEN),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final HttpStatus httpStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller.payload;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import jakarta.validation.constraints.Pattern;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import ru.mskobaro.tdms.business.entity.Group;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
public class GroupDTO {
|
||||||
|
private Long id;
|
||||||
|
@NotEmpty(message = "Имя группы не может быть пустым")
|
||||||
|
@Size(min = 3, max = 50, message = "Имя группы должно быть от 3 до 50 символов")
|
||||||
|
@Pattern(regexp = "^[а-яА-ЯёЁ0-9_-]*$", message = "Имя группы должно содержать только русские буквы, дефис, нижнее подчеркивание и цифры")
|
||||||
|
private String name;
|
||||||
|
private List<StudentDataDTO> students;
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
private PreparationDirectionDTO preparationDirection;
|
||||||
|
|
||||||
|
public static GroupDTO from(Group group, boolean includeStudents) {
|
||||||
|
GroupDTO dto = new GroupDTO();
|
||||||
|
dto.setId(group.getId());
|
||||||
|
dto.setName(group.getName());
|
||||||
|
if (includeStudents && group.getStudents() != null) {
|
||||||
|
dto.setStudents(
|
||||||
|
group.getStudents()
|
||||||
|
.stream()
|
||||||
|
.filter(sd -> !sd.getParticipant().isDeleted())
|
||||||
|
.map(sd -> StudentDataDTO.from(sd, false))
|
||||||
|
.toList());
|
||||||
|
}
|
||||||
|
if (group.getDirectionOfPreparation() != null) {
|
||||||
|
dto.setPreparationDirection(PreparationDirectionDTO.from(group.getDirectionOfPreparation()));
|
||||||
|
}
|
||||||
|
dto.setCreatedAt(group.getAuditInfo().getCreatedAt());
|
||||||
|
dto.setUpdatedAt(group.getAuditInfo().getUpdatedAt());
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller.payload;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
public class IdDto {
|
||||||
|
private Long id;
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller.payload;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import jakarta.validation.constraints.Pattern;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class LoginDTO {
|
||||||
|
@NotEmpty(message = "Логин не может быть пустым")
|
||||||
|
@Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "Логин должен содержать только латинские буквы, цифры и знак подчеркивания")
|
||||||
|
@Size(min = 5, message = "Логин должен содержать минимум 5 символов")
|
||||||
|
@Size(max = 32, message = "Логин должен содержать максимум 32 символов")
|
||||||
|
private String login;
|
||||||
|
@NotEmpty(message = "Пароль не может быть пустым")
|
||||||
|
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{8,}$", message = "Пароль должен содержать хотя бы одну цифру, одну заглавную и одну строчную букву, минимум 8 символов")
|
||||||
|
private String password;
|
||||||
|
}
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller.payload;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
|
||||||
|
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import ru.mskobaro.tdms.business.entity.Participant;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
|
||||||
|
public class ParticipantDTO {
|
||||||
|
private Long id;
|
||||||
|
private String firstName;
|
||||||
|
private String lastName;
|
||||||
|
private String middleName;
|
||||||
|
private String email;
|
||||||
|
private String numberPhone;
|
||||||
|
private UserDTO user;
|
||||||
|
private List<RoleDTO> roles;
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
public static ParticipantDTO fromEntity(Participant participant) {
|
||||||
|
ParticipantDTO participantDTO = new ParticipantDTO();
|
||||||
|
participantDTO.setId(participant.getId());
|
||||||
|
participantDTO.setFirstName(participant.getFirstName());
|
||||||
|
participantDTO.setLastName(participant.getLastName());
|
||||||
|
participantDTO.setMiddleName(participant.getMiddleName());
|
||||||
|
participantDTO.setEmail(participant.getEmail());
|
||||||
|
participantDTO.setNumberPhone(participant.getNumberPhone());
|
||||||
|
participantDTO.setRoles(RoleDTO.from(participant));
|
||||||
|
participantDTO.setCreatedAt(participant.getAuditInfo().getCreatedAt());
|
||||||
|
participantDTO.setUpdatedAt(participant.getAuditInfo().getUpdatedAt());
|
||||||
|
|
||||||
|
if (participant.getUser() != null) {
|
||||||
|
participantDTO.setUser(UserDTO.fromEntity(participant.getUser(), participantDTO));
|
||||||
|
}
|
||||||
|
|
||||||
|
return participantDTO;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller.payload;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import jakarta.validation.constraints.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import ru.mskobaro.tdms.business.service.RoleService.Authority;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public class ParticipantSaveDTO {
|
||||||
|
private Long id;
|
||||||
|
@NotEmpty(message = "Имя не может быть пустым")
|
||||||
|
@Pattern(regexp = "^[a-zA-Zа-яА-ЯёЁ\\s-]+$", message = "Имя должно содержать только буквы английского или русского алфавита, пробелы и дефис")
|
||||||
|
private String firstName;
|
||||||
|
@NotEmpty(message = "Фамилия не может быть пустой")
|
||||||
|
@Pattern(regexp = "^[a-zA-Zа-яА-ЯёЁ\\s-]+$", message = "Фамилия должна содержать только буквы английского или русского алфавита, пробелы и дефис")
|
||||||
|
private String lastName;
|
||||||
|
private String middleName;
|
||||||
|
@NotNull(message = "Почта не может быть пустой")
|
||||||
|
@Email(message = "Почта должна быть валидным адресом электронной почты")
|
||||||
|
private String email;
|
||||||
|
@NotNull(message = "Номер телефона не может быть пустым")
|
||||||
|
@Pattern(regexp = "^\\+[1-9]\\d{6,14}$", message = "Номер телефона должен начинаться с '+' и содержать от 7 до 15 цифр")
|
||||||
|
private String numberPhone;
|
||||||
|
private List<Authority> authorities;
|
||||||
|
|
||||||
|
@Valid
|
||||||
|
private UserRegistrationDTO userData;
|
||||||
|
@Valid
|
||||||
|
private StudentRegistrationDTO studentData;
|
||||||
|
@Valid
|
||||||
|
private TeacherRegistrationDTO teacherData;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public static class UserRegistrationDTO {
|
||||||
|
@Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "Логин должен содержать только латинские буквы, цифры и знак подчеркивания")
|
||||||
|
@Size(min = 5, message = "Логин должен содержать минимум 5 символов")
|
||||||
|
@Size(max = 32, message = "Логин должен содержать максимум 32 символов")
|
||||||
|
private String login;
|
||||||
|
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{8,}$", message = "Пароль должен содержать хотя бы одну цифру, одну заглавную и одну строчную букву, минимум 8 символов")
|
||||||
|
private String password;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public static class StudentRegistrationDTO {
|
||||||
|
private Long groupId;
|
||||||
|
private Long curatorId;
|
||||||
|
private Long diplomaTopicId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public static class TeacherRegistrationDTO {
|
||||||
|
private List<Long> curatingGroups;
|
||||||
|
private List<Long> advisingStudents;
|
||||||
|
private String degree;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller.payload;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import ru.mskobaro.tdms.business.entity.DirectionOfPreparation;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class PreparationDirectionDTO {
|
||||||
|
private Long id;
|
||||||
|
private String name;
|
||||||
|
private String code;
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
public static PreparationDirectionDTO from(DirectionOfPreparation preparationDirection) {
|
||||||
|
PreparationDirectionDTO dto = new PreparationDirectionDTO();
|
||||||
|
dto.setId(preparationDirection.getId());
|
||||||
|
dto.setName(preparationDirection.getName());
|
||||||
|
dto.setCode(preparationDirection.getCode());
|
||||||
|
dto.setCreatedAt(preparationDirection.getAuditInfo().getCreatedAt());
|
||||||
|
dto.setUpdatedAt(preparationDirection.getAuditInfo().getUpdatedAt());
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller.payload;
|
||||||
|
|
||||||
|
|
||||||
|
import ru.mskobaro.tdms.business.entity.Participant;
|
||||||
|
import ru.mskobaro.tdms.business.entity.Role;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
public record RoleDTO(String name, String code) {
|
||||||
|
|
||||||
|
public static RoleDTO from(Role role) {
|
||||||
|
return new RoleDTO(role.getName(), role.getAuthority());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<RoleDTO> from(Participant participant) {
|
||||||
|
return participant.getRoles().stream().map(RoleDTO::from).toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller.payload;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import ru.mskobaro.tdms.business.entity.StudentData;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
public class StudentDataDTO {
|
||||||
|
private Long id;
|
||||||
|
private GroupDTO group;
|
||||||
|
private ParticipantDTO participant;
|
||||||
|
private TeacherDataDTO curator;
|
||||||
|
private DiplomaTopicDTO diplomaTopic;
|
||||||
|
|
||||||
|
public static StudentDataDTO from(StudentData studentData, boolean includeGroup) {
|
||||||
|
StudentDataDTO dto = new StudentDataDTO();
|
||||||
|
dto.setId(studentData.getId());
|
||||||
|
if (includeGroup && studentData.getGroup() != null) {
|
||||||
|
dto.setGroup(GroupDTO.from(studentData.getGroup(), false));
|
||||||
|
}
|
||||||
|
dto.setParticipant(ParticipantDTO.fromEntity(studentData.getParticipant()));
|
||||||
|
if (studentData.getCurator() != null) {
|
||||||
|
dto.setCurator(TeacherDataDTO.from(studentData.getCurator()));
|
||||||
|
}
|
||||||
|
if (studentData.getDiplomaTopic() != null) {
|
||||||
|
dto.setDiplomaTopic(DiplomaTopicDTO.from(studentData.getDiplomaTopic()));
|
||||||
|
}
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller.payload;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import ru.mskobaro.tdms.business.entity.Task;
|
||||||
|
import ru.mskobaro.tdms.business.taskfields.TaskFields;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class TaskDto {
|
||||||
|
private Long id;
|
||||||
|
private Task.Type type;
|
||||||
|
private Task.Status status;
|
||||||
|
private TaskFields fields;
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
private LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
|
||||||
|
public static TaskDto from(Task task) {
|
||||||
|
TaskDto dto = new TaskDto();
|
||||||
|
dto.setId(task.getId());
|
||||||
|
dto.setType(task.getType());
|
||||||
|
dto.setStatus(task.getStatus());
|
||||||
|
dto.setFields(task.getFields());
|
||||||
|
dto.setCreatedAt(task.getAuditInfo().getCreatedAt());
|
||||||
|
dto.setUpdatedAt(task.getAuditInfo().getUpdatedAt());
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller.payload;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import ru.mskobaro.tdms.business.entity.TeacherData;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class TeacherDataDTO {
|
||||||
|
private Long id;
|
||||||
|
private ParticipantDTO participant;
|
||||||
|
private String degree;
|
||||||
|
private String createdAt;
|
||||||
|
private String updatedAt;
|
||||||
|
|
||||||
|
public static TeacherDataDTO from(TeacherData teacherData) {
|
||||||
|
TeacherDataDTO dto = new TeacherDataDTO();
|
||||||
|
dto.setId(teacherData.getId());
|
||||||
|
dto.setParticipant(ParticipantDTO.fromEntity(teacherData.getParticipant()));
|
||||||
|
dto.setDegree(teacherData.getDegree());
|
||||||
|
dto.setCreatedAt(teacherData.getAuditInfo().getCreatedAt().toString());
|
||||||
|
dto.setUpdatedAt(teacherData.getAuditInfo().getUpdatedAt().toString());
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.controller.payload;
|
||||||
|
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
|
||||||
|
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
|
||||||
|
import lombok.Builder;
|
||||||
|
import ru.mskobaro.tdms.business.entity.User;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
|
||||||
|
public record UserDTO(
|
||||||
|
Long id,
|
||||||
|
String login,
|
||||||
|
ParticipantDTO participant,
|
||||||
|
LocalDateTime createdAt,
|
||||||
|
LocalDateTime updatedAt
|
||||||
|
) {
|
||||||
|
public static UserDTO fromEntity(User user) {
|
||||||
|
return UserDTO.builder()
|
||||||
|
.id(user.getId())
|
||||||
|
.login(user.getLogin())
|
||||||
|
.participant(ParticipantDTO.fromEntity(user.getParticipant()))
|
||||||
|
.createdAt(user.getAuditInfo().getCreatedAt())
|
||||||
|
.updatedAt(user.getAuditInfo().getUpdatedAt())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UserDTO fromEntity(User user, ParticipantDTO participant) {
|
||||||
|
return UserDTO.builder()
|
||||||
|
.id(user.getId())
|
||||||
|
.login(user.getLogin())
|
||||||
|
.participant(participant)
|
||||||
|
.createdAt(user.getAuditInfo().getCreatedAt())
|
||||||
|
.updatedAt(user.getAuditInfo().getUpdatedAt())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,73 @@
|
|||||||
|
package ru.mskobaro.tdms.presentation.exception;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.support.DefaultMessageSourceResolvable;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.validation.BindException;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
import org.springframework.web.servlet.resource.NoResourceFoundException;
|
||||||
|
import ru.mskobaro.tdms.business.exception.AccessDeniedException;
|
||||||
|
import ru.mskobaro.tdms.business.exception.BusinessException;
|
||||||
|
import ru.mskobaro.tdms.presentation.controller.payload.ErrorDTO;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.springframework.http.HttpStatus.*;
|
||||||
|
import static org.springframework.http.HttpStatus.NOT_FOUND;
|
||||||
|
import static ru.mskobaro.tdms.presentation.controller.payload.ErrorDTO.ErrorCode.*;
|
||||||
|
|
||||||
|
@RestControllerAdvice
|
||||||
|
@Slf4j
|
||||||
|
public class ApplicationExceptionHandler {
|
||||||
|
@ExceptionHandler(BindException.class)
|
||||||
|
@ResponseStatus(BAD_REQUEST)
|
||||||
|
public ErrorDTO handleMethodArgumentNotValidException(BindException e) {
|
||||||
|
log.debug("Validation error: {}", e.getMessage());
|
||||||
|
String validationErrors = e.getAllErrors().stream()
|
||||||
|
.map(DefaultMessageSourceResolvable::getDefaultMessage)
|
||||||
|
.collect(Collectors.joining("\n"));
|
||||||
|
return new ErrorDTO(validationErrors, VALIDATION_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(BusinessException.class)
|
||||||
|
public ErrorDTO handleBusinessException(BusinessException e, HttpServletResponse response) {
|
||||||
|
log.warn("Business error: {}", e.getMessage());
|
||||||
|
response.setStatus(e.getErrorCode().getHttpStatus().value());
|
||||||
|
return new ErrorDTO(e.getMessage(), e.getErrorCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler({org.springframework.security.access.AccessDeniedException.class, AccessDeniedException.class})
|
||||||
|
@ResponseStatus(FORBIDDEN)
|
||||||
|
public ErrorDTO handleAccessDeniedException(RuntimeException e) {
|
||||||
|
log.warn("Access denied: {}", e.getMessage());
|
||||||
|
return new ErrorDTO("Доступ запрещен", ACCESS_DENIED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(AuthenticationException.class)
|
||||||
|
@ResponseStatus(UNAUTHORIZED)
|
||||||
|
public ErrorDTO handleAuthenticationException(AuthenticationException e) {
|
||||||
|
log.warn("Authentication error: {}", e.getMessage());
|
||||||
|
return new ErrorDTO("Неверный логин или пароль", ACCESS_DENIED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(NoResourceFoundException.class)
|
||||||
|
@ResponseStatus(NOT_FOUND)
|
||||||
|
public ErrorDTO handleNoResourceFoundException(NoResourceFoundException e) {
|
||||||
|
UUID uuid = UUID.randomUUID();
|
||||||
|
String message = e.getMessage().substring(0, e.getMessage().length() - 1);
|
||||||
|
log.error("{} ({})", message, uuid);
|
||||||
|
return new ErrorDTO("Идентификатор ошибки: (" + uuid + ")\nРесурс не был наеден, обратитесь к администратору", ErrorDTO.ErrorCode.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(Exception.class)
|
||||||
|
@ResponseStatus(INTERNAL_SERVER_ERROR)
|
||||||
|
public ErrorDTO handleUnexpectedException(Exception e) {
|
||||||
|
UUID uuid = UUID.randomUUID();
|
||||||
|
log.error("Unexpected exception ({})", uuid, e);
|
||||||
|
return new ErrorDTO("Идентификатор ошибки: (" + uuid + ")\nПроизошла непредвиденная ошибка, обратитесь к администратору", INTERNAL_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,142 @@
|
|||||||
|
package ru.mskobaro.tdms.system.config;
|
||||||
|
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.ProviderManager;
|
||||||
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
|
||||||
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
|
import org.springframework.security.core.session.SessionRegistry;
|
||||||
|
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.context.SecurityContextHolderFilter;
|
||||||
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
|
import org.springframework.web.cors.CorsConfigurationSource;
|
||||||
|
import ru.mskobaro.tdms.system.web.LoggingRequestFilter;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static ru.mskobaro.tdms.business.service.RoleService.Authority.ADMIN;
|
||||||
|
import static ru.mskobaro.tdms.business.service.RoleService.Authority.SECRETARY;
|
||||||
|
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Configuration
|
||||||
|
public class SecurityConfig {
|
||||||
|
@Autowired
|
||||||
|
private Environment environment;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity,
|
||||||
|
AuthenticationManager authenticationManager,
|
||||||
|
CorsConfigurationSource cors
|
||||||
|
) throws Exception {
|
||||||
|
return httpSecurity
|
||||||
|
.addFilterAfter(new LoggingRequestFilter(), SecurityContextHolderFilter.class)
|
||||||
|
.authorizeHttpRequests(this::configureHttpAuthorization)
|
||||||
|
// .csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
|
||||||
|
.csrf(AbstractHttpConfigurer::disable)
|
||||||
|
.cors(a -> a.configurationSource(cors))
|
||||||
|
.authenticationManager(authenticationManager)
|
||||||
|
.sessionManagement(cfg -> {
|
||||||
|
cfg.sessionCreationPolicy(SessionCreationPolicy.NEVER);
|
||||||
|
cfg.maximumSessions(1);
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Primary
|
||||||
|
public CorsConfigurationSource corsConfiguration(
|
||||||
|
@Value("${application.domain}") String domain,
|
||||||
|
@Value("${application.port}") String port,
|
||||||
|
@Value("${application.protocol}") String protocol
|
||||||
|
) {
|
||||||
|
CorsConfiguration corsConfiguration = new CorsConfiguration();
|
||||||
|
corsConfiguration.setAllowedMethods(List.of(HttpMethod.GET.name(), HttpMethod.POST.name(), HttpMethod.OPTIONS.name()));
|
||||||
|
corsConfiguration.setAllowedHeaders(List.of("Authorization", "Content-Type"));
|
||||||
|
corsConfiguration.setAllowCredentials(true);
|
||||||
|
corsConfiguration.setMaxAge(Duration.ofDays(1));
|
||||||
|
corsConfiguration.addAllowedOrigin(StringUtils.join(protocol, "://", domain, ":", port));
|
||||||
|
|
||||||
|
if (environment.matchesProfiles("dev")) {
|
||||||
|
corsConfiguration.addAllowedOrigin("http://localhost:8888");
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("CORS configuration: [headers: {}, methods: {}, origins: {}, credentials: {}, maxAge: {}]",
|
||||||
|
corsConfiguration.getAllowedHeaders(), corsConfiguration.getAllowedMethods(), corsConfiguration.getAllowedOrigins(),
|
||||||
|
corsConfiguration.getAllowCredentials(), corsConfiguration.getMaxAge());
|
||||||
|
return request -> corsConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public AuthenticationManager authenticationManager(UserDetailsService userDetailsService) {
|
||||||
|
DaoAuthenticationProvider provider = new DaoAuthenticationProvider(passwordEncoder());
|
||||||
|
provider.setUserDetailsService(userDetailsService);
|
||||||
|
return new ProviderManager(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SessionRegistry sessionRegistry() {
|
||||||
|
return new SessionRegistryImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PasswordEncoder passwordEncoder() {
|
||||||
|
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureHttpAuthorization(
|
||||||
|
AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry httpAuthorization
|
||||||
|
) {
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/sysinfo/**").permitAll();
|
||||||
|
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/user/logout").authenticated();
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/user/login").permitAll();
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/user/current").permitAll();
|
||||||
|
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/participant/get-all-participants").permitAll();
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/participant/get-possible-curators").permitAll();
|
||||||
|
// Сложная логика авторизации, так что проверяем явно в ParticipantService
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/participant/save").authenticated();
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/participant/delete").hasAuthority(ADMIN.getAuthority());
|
||||||
|
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/group/get-all-groups").permitAll();
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/group/save").hasAnyAuthority(ADMIN.getAuthority(), SECRETARY.getAuthority());
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/group/delete").hasAnyAuthority(ADMIN.getAuthority());
|
||||||
|
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/student/by-partic-id").permitAll();
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/student/all-without-group").permitAll();
|
||||||
|
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/teacher-data/get-all").permitAll();
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/teacher-data/by-partic-id").permitAll();
|
||||||
|
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/prep-direction/get-all").permitAll();
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/prep-direction/save").hasAnyAuthority(ADMIN.getAuthority(), SECRETARY.getAuthority());
|
||||||
|
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/defence/all").permitAll();
|
||||||
|
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/diploma-topic/all").permitAll();
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/diploma-topic/all-for-student").permitAll();
|
||||||
|
httpAuthorization.requestMatchers("/api/v1/diploma-topic/save").hasAnyAuthority(ADMIN.getAuthority(), SECRETARY.getAuthority());
|
||||||
|
|
||||||
|
httpAuthorization.requestMatchers("/api/**").denyAll();
|
||||||
|
|
||||||
|
httpAuthorization.requestMatchers("/**").permitAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package ru.mskobaro.tdms.system.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
import org.springframework.web.servlet.resource.PathResourceResolver;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebConfig implements WebMvcConfigurer {
|
||||||
|
@Override
|
||||||
|
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||||
|
registry.addResourceHandler("/**")
|
||||||
|
.addResourceLocations("classpath:/static/")
|
||||||
|
.resourceChain(true)
|
||||||
|
.addResolver(new PathResourceResolver() {
|
||||||
|
@Override
|
||||||
|
protected Resource getResource(String resourcePath, Resource location) throws IOException {
|
||||||
|
Resource requestedResource = location.createRelative(resourcePath);
|
||||||
|
return requestedResource.exists() && requestedResource.isReadable()
|
||||||
|
? requestedResource
|
||||||
|
: location.createRelative("index.html");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package ru.mskobaro.tdms.system.web;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class AccessDeniedExceptionHandler implements AccessDeniedHandler {
|
||||||
|
@Autowired
|
||||||
|
private HandlerExceptionResolver handlerExceptionResolver;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) {
|
||||||
|
handlerExceptionResolver.resolveException(request, response, null, new ru.mskobaro.tdms.business.exception.AccessDeniedException());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package ru.mskobaro.tdms.system.web;
|
||||||
|
|
||||||
|
import jakarta.servlet.FilterChain;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import jakarta.servlet.http.HttpSession;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class LoggingRequestFilter extends OncePerRequestFilter {
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||||
|
UUID uuid = UUID.randomUUID();
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
String username = SecurityContextHolder.getContext().getAuthentication() != null ?
|
||||||
|
SecurityContextHolder.getContext().getAuthentication().getName() : "anonymousUser";
|
||||||
|
HttpSession session = request.getSession(false);
|
||||||
|
log.info("Request received: [{}] {} user: {}, session: {}, remote ip: {} [{}]",
|
||||||
|
request.getMethod(), request.getRequestURI(), username,
|
||||||
|
session == null ? "no" : session.getId(), request.getRemoteAddr(), uuid);
|
||||||
|
try {
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
} finally {
|
||||||
|
long duration = System.currentTimeMillis() - startTime;
|
||||||
|
log.info("Response with {} status duration: {} ms [{}]", response.getStatus(), duration, uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package ru.mskobaro.tdms.system.web;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpSessionEvent;
|
||||||
|
import jakarta.servlet.http.HttpSessionListener;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
|
||||||
|
public class LoggingSessionListener implements HttpSessionListener {
|
||||||
|
@Override
|
||||||
|
public void sessionCreated(HttpSessionEvent se) {
|
||||||
|
log.debug("Session created: {}, user {}", se.getSession().getId(),
|
||||||
|
SecurityContextHolder.getContext().getAuthentication().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sessionDestroyed(HttpSessionEvent se) {
|
||||||
|
log.debug("Session destroyed: {}", se.getSession().getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"name": "db.url",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "Database url."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "db.user",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "Database user."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "db.password",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "Database password."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "db.schema",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "Database schema."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "application.name",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "Service name."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "application.version",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "Service version."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "application.type",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "Service build type."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "application.domain",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "Service domain."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "application.port",
|
||||||
|
"type": "java.lang.Integer",
|
||||||
|
"description": "Service port."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "application.protocol",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "Service protocol."
|
||||||
|
}
|
||||||
|
] }
|
||||||
5
server/src/main/resources/application-dev.yml
Normal file
5
server/src/main/resources/application-dev.yml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
application:
|
||||||
|
type: development
|
||||||
|
port: 8080
|
||||||
|
domain: localhost
|
||||||
|
protocol: http
|
||||||
42
server/src/main/resources/application.yml
Normal file
42
server/src/main/resources/application.yml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
db:
|
||||||
|
url: jdbc:postgresql://localhost:5400/tdms
|
||||||
|
schema: public
|
||||||
|
user: root
|
||||||
|
password: root
|
||||||
|
application:
|
||||||
|
name: @name@
|
||||||
|
version: @version@
|
||||||
|
type: production
|
||||||
|
port: 443
|
||||||
|
domain: tdms.tu-bryansk.ru
|
||||||
|
protocol: https
|
||||||
|
|
||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: ${application.name}
|
||||||
|
datasource:
|
||||||
|
url: ${db.url}
|
||||||
|
username: ${db.user}
|
||||||
|
password: ${db.password}
|
||||||
|
hikari:
|
||||||
|
schema: ${db.schema}
|
||||||
|
jpa:
|
||||||
|
open-in-view: false
|
||||||
|
hibernate.ddl-auto: validate
|
||||||
|
flyway:
|
||||||
|
url: ${db.url}
|
||||||
|
user: ${db.user}
|
||||||
|
password: ${db.password}
|
||||||
|
schemas: ${db.schema}
|
||||||
|
banner:
|
||||||
|
location: banner.txt
|
||||||
|
server:
|
||||||
|
port: ${application.port}
|
||||||
|
address: ${application.domain}
|
||||||
|
compression:
|
||||||
|
enabled: true
|
||||||
|
management:
|
||||||
|
endpoints:
|
||||||
|
web:
|
||||||
|
exposure:
|
||||||
|
exclude: "*"
|
||||||
5
server/src/main/resources/banner.txt
Normal file
5
server/src/main/resources/banner.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
__________ __ ________ ____ ____ ___
|
||||||
|
/_ __/ __ \/ |/ / ___/ _ __ / __ \ / __ \ < /
|
||||||
|
/ / / / / / /|_/ /\__ \ | | / / / / / / / / / / / /
|
||||||
|
/ / / /_/ / / / /___/ / | |/ /_/ /_/ /_/ /_/ /_ / /
|
||||||
|
/_/ /_____/_/ /_//____/ |___/(_)____/(_)____/(_)_/
|
||||||
@ -0,0 +1,280 @@
|
|||||||
|
CREATE TABLE defense
|
||||||
|
(
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
defense_date DATE,
|
||||||
|
created_at TIMESTAMP WITHOUT TIME ZONE,
|
||||||
|
updated_at TIMESTAMP WITHOUT TIME ZONE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE defense_best_student_works
|
||||||
|
(
|
||||||
|
defense_id BIGINT,
|
||||||
|
student_data_id BIGINT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE defense_commission
|
||||||
|
(
|
||||||
|
defense_id BIGINT,
|
||||||
|
commission_member_data_id BIGINT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE diploma_topic
|
||||||
|
(
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
name TEXT,
|
||||||
|
teacher_id BIGINT,
|
||||||
|
direction_of_preparation_id BIGINT,
|
||||||
|
created_at TIMESTAMP WITHOUT TIME ZONE,
|
||||||
|
updated_at TIMESTAMP WITHOUT TIME ZONE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE direction_of_preparation
|
||||||
|
(
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
name TEXT,
|
||||||
|
code TEXT,
|
||||||
|
created_at TIMESTAMP WITHOUT TIME ZONE,
|
||||||
|
updated_at TIMESTAMP WITHOUT TIME ZONE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "group"
|
||||||
|
(
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
name TEXT,
|
||||||
|
defense_id BIGINT,
|
||||||
|
direction_of_preparation_id BIGINT,
|
||||||
|
created_at TIMESTAMP WITHOUT TIME ZONE,
|
||||||
|
updated_at TIMESTAMP WITHOUT TIME ZONE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE participant
|
||||||
|
(
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
first_name TEXT,
|
||||||
|
last_name TEXT,
|
||||||
|
middle_name TEXT,
|
||||||
|
email TEXT,
|
||||||
|
number_phone TEXT,
|
||||||
|
deleted BOOLEAN DEFAULT FALSE,
|
||||||
|
created_at TIMESTAMP WITHOUT TIME ZONE,
|
||||||
|
updated_at TIMESTAMP WITHOUT TIME ZONE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE participant_role
|
||||||
|
(
|
||||||
|
partic_id BIGINT NOT NULL,
|
||||||
|
role_id BIGINT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE role
|
||||||
|
(
|
||||||
|
id BIGINT PRIMARY KEY,
|
||||||
|
name TEXT,
|
||||||
|
authority TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
/* todo */
|
||||||
|
CREATE TABLE student_data
|
||||||
|
(
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
partic_id BIGINT,
|
||||||
|
study_form_id BIGINT,
|
||||||
|
|
||||||
|
curator_id BIGINT,
|
||||||
|
protection_order INTEGER,
|
||||||
|
protection_day INTEGER,
|
||||||
|
|
||||||
|
mark_comment INTEGER,
|
||||||
|
mark_practice INTEGER,
|
||||||
|
|
||||||
|
predefnese_comment TEXT,
|
||||||
|
normal_control BOOLEAN,
|
||||||
|
anti_plagiarism INTEGER,
|
||||||
|
record_book_returned BOOLEAN,
|
||||||
|
work TEXT,
|
||||||
|
diploma_topic_id BIGINT,
|
||||||
|
adviser_teacher_partic_id BIGINT,
|
||||||
|
group_id BIGINT,
|
||||||
|
marks_3 BIGINT,
|
||||||
|
marks_4 BIGINT,
|
||||||
|
marks_5 BIGINT,
|
||||||
|
commission_mark BIGINT,
|
||||||
|
estimated BOOLEAN,
|
||||||
|
diploma_with_honors BOOLEAN,
|
||||||
|
magistracy_recommendation BOOLEAN,
|
||||||
|
magistracy_wanted BOOLEAN,
|
||||||
|
created_at TIMESTAMP WITHOUT TIME ZONE,
|
||||||
|
updated_at TIMESTAMP WITHOUT TIME ZONE
|
||||||
|
);
|
||||||
|
|
||||||
|
/* not implemented */
|
||||||
|
create table questionnaire
|
||||||
|
(
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
student_data_id BIGINT,
|
||||||
|
data TEXT,
|
||||||
|
created_at TIMESTAMP WITHOUT TIME ZONE,
|
||||||
|
updated_at TIMESTAMP WITHOUT TIME ZONE
|
||||||
|
);
|
||||||
|
|
||||||
|
create table study_form
|
||||||
|
(
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
name TEXT,
|
||||||
|
created_at TIMESTAMP WITHOUT TIME ZONE,
|
||||||
|
updated_at TIMESTAMP WITHOUT TIME ZONE
|
||||||
|
);
|
||||||
|
|
||||||
|
/* todo */
|
||||||
|
create table stud_comment
|
||||||
|
(
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
comment TEXT,
|
||||||
|
created_at TIMESTAMP WITHOUT TIME ZONE,
|
||||||
|
updated_at TIMESTAMP WITHOUT TIME ZONE
|
||||||
|
);
|
||||||
|
|
||||||
|
/* todo */
|
||||||
|
create table student_data_comment
|
||||||
|
(
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
student_data_id BIGINT,
|
||||||
|
stud_comment_id BIGINT,
|
||||||
|
created_at TIMESTAMP WITHOUT TIME ZONE,
|
||||||
|
updated_at TIMESTAMP WITHOUT TIME ZONE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE teacher_data
|
||||||
|
(
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
participant_id BIGINT,
|
||||||
|
degree TEXT NOT NULL,
|
||||||
|
created_at TIMESTAMP WITHOUT TIME ZONE,
|
||||||
|
updated_at TIMESTAMP WITHOUT TIME ZONE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE commission_member_data
|
||||||
|
(
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
partic_id BIGINT,
|
||||||
|
work_place TEXT,
|
||||||
|
work_position TEXT,
|
||||||
|
created_at TIMESTAMP WITHOUT TIME ZONE,
|
||||||
|
updated_at TIMESTAMP WITHOUT TIME ZONE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "user"
|
||||||
|
(
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
login TEXT,
|
||||||
|
password TEXT,
|
||||||
|
partic_id BIGINT,
|
||||||
|
created_at TIMESTAMP WITHOUT TIME ZONE,
|
||||||
|
updated_at TIMESTAMP WITHOUT TIME ZONE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE task
|
||||||
|
(
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
type TEXT,
|
||||||
|
status TEXT,
|
||||||
|
fields jsonb,
|
||||||
|
created_at TIMESTAMP WITHOUT TIME ZONE,
|
||||||
|
updated_at TIMESTAMP WITHOUT TIME ZONE
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE defense_commission
|
||||||
|
ADD CONSTRAINT FK_DEFCOM_ON_DEFNESE FOREIGN KEY (defense_id) REFERENCES defense (id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE defense_commission
|
||||||
|
ADD CONSTRAINT FK_DEFCOM_ON_COMMEMD FOREIGN KEY (commission_member_data_id) REFERENCES commission_member_data (id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE "group"
|
||||||
|
ADD CONSTRAINT FK_GROUP_ON_defnese FOREIGN KEY (defense_id) REFERENCES defense (id) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE "group"
|
||||||
|
ADD CONSTRAINT FK_GROUP_ON_DOP FOREIGN KEY (direction_of_preparation_id) REFERENCES direction_of_preparation (id) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE participant_role
|
||||||
|
ADD CONSTRAINT FK_PARROL_ON_PARTICIPANT FOREIGN KEY (partic_id) REFERENCES participant (id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE participant_role
|
||||||
|
ADD CONSTRAINT FK_PARROL_ON_ROLE FOREIGN KEY (role_id) REFERENCES role (id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE student_data
|
||||||
|
ADD CONSTRAINT UC_STUDENT_DATA_PARTIC UNIQUE (partic_id);
|
||||||
|
|
||||||
|
ALTER TABLE student_data
|
||||||
|
ADD CONSTRAINT FK_STUDENT_DATA_ON_ADVISER_TEACHER_PARTIC FOREIGN KEY (adviser_teacher_partic_id) REFERENCES participant (id) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE student_data
|
||||||
|
ADD CONSTRAINT FK_STUDENT_DATA_ON_DIPLOMA_TOPIC FOREIGN KEY (diploma_topic_id) REFERENCES diploma_topic (id) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE student_data
|
||||||
|
ADD CONSTRAINT FK_STUDENT_DATA_ON_GROUP FOREIGN KEY (group_id) REFERENCES "group" (id) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE student_data
|
||||||
|
ADD CONSTRAINT FK_STUDENT_DATA_ON_PARTIC FOREIGN KEY (partic_id) REFERENCES participant (id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE participant
|
||||||
|
ADD CONSTRAINT UC_PARTICIPANT_EMAIL UNIQUE (email);
|
||||||
|
|
||||||
|
ALTER TABLE participant
|
||||||
|
ADD CONSTRAINT UC_PARTICIPANT_NUMBER_PHONE UNIQUE (number_phone);
|
||||||
|
|
||||||
|
ALTER TABLE "user"
|
||||||
|
ADD CONSTRAINT UC_USER_LOGIN UNIQUE (login);
|
||||||
|
|
||||||
|
ALTER TABLE "user"
|
||||||
|
ADD CONSTRAINT UC_USER_PARTIC UNIQUE (partic_id);
|
||||||
|
|
||||||
|
ALTER TABLE "user"
|
||||||
|
ADD CONSTRAINT FK_USER_ON_PARTIC FOREIGN KEY (partic_id) REFERENCES participant (id);
|
||||||
|
|
||||||
|
ALTER TABLE teacher_data
|
||||||
|
ADD CONSTRAINT UC_TEACHER_DATA_PARTIC UNIQUE (participant_id);
|
||||||
|
|
||||||
|
ALTER TABLE teacher_data
|
||||||
|
ADD CONSTRAINT FK_TEACHER_DATA_ON_PARTIC FOREIGN KEY (participant_id) REFERENCES participant (id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE commission_member_data
|
||||||
|
ADD CONSTRAINT UC_COMMISION_MEMBER_DATA_PARTIC UNIQUE (partic_id);
|
||||||
|
|
||||||
|
ALTER TABLE commission_member_data
|
||||||
|
ADD CONSTRAINT FK_COMMISION_MEMBER_DATA_ON_PARTIC FOREIGN KEY (partic_id) REFERENCES participant (id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE direction_of_preparation
|
||||||
|
ADD CONSTRAINT UC_DIRECTION_OF_PREPARATION_NAME UNIQUE (name);
|
||||||
|
|
||||||
|
ALTER TABLE direction_of_preparation
|
||||||
|
ADD CONSTRAINT UC_DIRECTION_OF_PREPARATION_CODE UNIQUE (code);
|
||||||
|
|
||||||
|
ALTER TABLE diploma_topic
|
||||||
|
ADD CONSTRAINT UC_DIPLOMA_TOPIC_NAME FOREIGN KEY (direction_of_preparation_id) REFERENCES direction_of_preparation (id) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE defense_best_student_works
|
||||||
|
ADD CONSTRAINT FK_DEFENSE_BEST_STUDENT_WORKS_ON_DEFENSE FOREIGN KEY (defense_id) REFERENCES defense (id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE defense_best_student_works
|
||||||
|
ADD CONSTRAINT FK_DEFENSE_BEST_STUDENT_WORKS_ON_STUDENT_DATA FOREIGN KEY (student_data_id) REFERENCES student_data (id) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE stud_comment
|
||||||
|
ADD CONSTRAINT UC_STUD_COMMENT_COMMENT UNIQUE (comment);
|
||||||
|
|
||||||
|
ALTER TABLE student_data
|
||||||
|
ADD CONSTRAINT UC_STUDENT_DATA_DIPLOMA_TOPIC FOREIGN KEY (diploma_topic_id) REFERENCES diploma_topic (id) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE student_data
|
||||||
|
ADD CONSTRAINT UC_STUDENT_DATA_STUDY_FORM FOREIGN KEY (study_form_id) REFERENCES study_form (id) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE student_data
|
||||||
|
ADD CONSTRAINT UC_STUDENT_DATA_CURATOR FOREIGN KEY (curator_id) REFERENCES teacher_data (id) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE study_form
|
||||||
|
ADD CONSTRAINT UC_STUDY_FORM_NAME UNIQUE (name);
|
||||||
|
|
||||||
|
alter table questionnaire
|
||||||
|
add constraint UC_QUESTIONNAIRE_STUDENT_DATA_ID unique (student_data_id);
|
||||||
|
|
||||||
|
alter table questionnaire
|
||||||
|
add constraint FK_QUESTIONNAIRE_STUDENT_DATA foreign key (student_data_id) references student_data (id) on delete cascade on update cascade;
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
insert into role (id, name, authority)
|
||||||
|
values (1, 'Преподаватель', 'ROLE_TEACHER'),
|
||||||
|
(2, 'Студент', 'ROLE_STUDENT'),
|
||||||
|
(3, 'Член комиссии ГЭК', 'ROLE_COMMISSION_MEMBER'),
|
||||||
|
(4, 'Администратор', 'ROLE_ADMINISTRATOR'),
|
||||||
|
(5, 'Секретарь', 'ROLE_SECRETARY'),
|
||||||
|
(6, 'Проверяющий на плагиат', 'ROLE_PLAGIARISM_CHECKER');
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
insert into participant (id, first_name, email, number_phone, created_at, updated_at)
|
||||||
|
values (1,
|
||||||
|
'Администратор',
|
||||||
|
'admin@tdms.tu-bryansk.ru',
|
||||||
|
'+74832580058',
|
||||||
|
now(),
|
||||||
|
now());
|
||||||
|
|
||||||
|
insert into "user" (id, login, password, partic_id, created_at, updated_at)
|
||||||
|
values (1,
|
||||||
|
'admin',
|
||||||
|
'{noop}Admin000',
|
||||||
|
1,
|
||||||
|
now(),
|
||||||
|
now());
|
||||||
|
|
||||||
|
insert into participant_role (partic_id, role_id)
|
||||||
|
values (1, 4);
|
||||||
|
|
||||||
|
select setval('participant_id_seq', (select max(id) from participant));
|
||||||
|
select setval('user_id_seq', (select max(id) from "user"));
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
create table defense
|
||||||
|
(
|
||||||
|
id bigserial primary key,
|
||||||
|
defence_date timestamptz,
|
||||||
|
|
||||||
|
created_at timestamptz not null,
|
||||||
|
updated_at timestamptz
|
||||||
|
);
|
||||||
|
|
||||||
|
-- COMMENTS
|
||||||
|
comment on table defense is 'Таблица для хранения данных о защитах';
|
||||||
|
comment on column defense.defence_date is 'Дата защиты';
|
||||||
40
server/src/main/resources/db/test-data/diploma_topic.sql
Normal file
40
server/src/main/resources/db/test-data/diploma_topic.sql
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
INSERT INTO diploma_topic (name)
|
||||||
|
VALUES ('Мобильное приложение для заказа автозапчастей на платформе ABCP'),
|
||||||
|
('Подсистема уведомления пользователей для программного комплекса "РискПроф. Учебный центр"'),
|
||||||
|
('Веб-приложение "Таск-менеджер"'),
|
||||||
|
('Интернет-магазин электроники'),
|
||||||
|
('Информационная система для студентов БГТУ в Telegram'),
|
||||||
|
('Автоматизированная система тестирования сотрудников для определения их компетенций: модуль подготовки тестов и учета результатов'),
|
||||||
|
('Инструментарий для разработки динамической экосистемы игрового пространства. Подсистема управления поведением внутриигровых агентов'),
|
||||||
|
('Корпоративное веб-приложение по управлению задачами'),
|
||||||
|
('Подсистемы визуализации и аналитики для онлайн-сервиса поддержки scrum-доски'),
|
||||||
|
('Интерактивная система обучения приемам работы с криптовалютой'),
|
||||||
|
('Автоматизированная система учета деятельности салона по продаже автомобилей'),
|
||||||
|
('Обучающее мобильное android-приложение'),
|
||||||
|
('Автоматизированная система учета зуботехнической CAD/CAM лаборатории'),
|
||||||
|
('Автоматизированная система тестирования сотрудников для определения их компетенций: модуль регистрации и управления кабинетами'),
|
||||||
|
('Система мониторинга успеваемости обучающихся и посещаемости занятий образовательного учреждения'),
|
||||||
|
('Мобильное приложение для организации работы репетитора'),
|
||||||
|
('Модуль "Редактор рисков" для программного комплекса управления профессиональными рисками "1С. ЕОС ПБ"'),
|
||||||
|
('Онлайн-сервис по продаже товаров (на примере ООО «ЭПК-2»'),
|
||||||
|
('Веб-сервис по обучению Microsoft Excel'),
|
||||||
|
('Инструментарий для разработки динамической экосистемы игрового пространства. Подсистема генерации наполнения помещений'),
|
||||||
|
('Подсистема интеграции с федеральной государственной информационной системой по охране труда для программного комплекса «РискПроф. Учебный центр»'),
|
||||||
|
('Разработка приложения голосовой авторизации на основе нейросетевого подхода'),
|
||||||
|
('Автоматизированная система учета деятельности спортивного клуба'),
|
||||||
|
('Модуль "Специальная оценка условий труда" для программного комплекса управления профессиональными рисками "1С. ЕОС ПБ"'),
|
||||||
|
('Интернет-магазин по продаже спортивной обуви'),
|
||||||
|
('Приложение интерактивной исторической карты'),
|
||||||
|
('Миграция системы учёта с 1С:УТ на 1С:КА'),
|
||||||
|
('Программный комплекс для автоматизированного проведения опросов и тестирования пользователей'),
|
||||||
|
('Автоматизированное тестирование программного комплекса «Федеральная государственная информационная система специальной оценки условий труда»'),
|
||||||
|
('Модуль "Единая информационно-справочная подсистема" для федеральной государственной информационной системы по охране труда'),
|
||||||
|
('Подсистема сопровождения обучения по охране труда для программного комплекса «РискПроф. Учебный центр»'),
|
||||||
|
('Программное обеспечение системы обучения и тестирования в мессенджере Telegram'),
|
||||||
|
('Онлайн-калькулятор индексов влияния в играх взвешенного голосования'),
|
||||||
|
('Telegram-бот с функциями обработки изображений'),
|
||||||
|
('Подсистема администрирования автоматизированной системы для проведения платежей и перевода денежных средств'),
|
||||||
|
('Подсистема администрирования для программного комплекса распределения студентов по руководителям выпускных квалификационных работ'),
|
||||||
|
('Библиотека контроля качества данных в базах и хранилищах данных для программного комплекса MetaControl'),
|
||||||
|
('Инструментарий для разработки динамической экосистемы игрового пространства. Подсистема генерации карты помещений'),
|
||||||
|
('Программная система решения транспортной задачи методом генетического алгоритма для торговой сети');
|
||||||
3
server/src/main/resources/db/test-data/group.sql
Normal file
3
server/src/main/resources/db/test-data/group.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
INSERT INTO "group" (name, curator_teacher_id, created_at, updated_at)
|
||||||
|
VALUES ('ИВТ-1', 40, now(), now()),
|
||||||
|
('ИВТ-2', 40, now(), now());
|
||||||
98
server/src/main/resources/db/test-data/student.sql
Normal file
98
server/src/main/resources/db/test-data/student.sql
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
do
|
||||||
|
$$
|
||||||
|
begin
|
||||||
|
INSERT INTO studentData (form,
|
||||||
|
protection_order,
|
||||||
|
magistracy,
|
||||||
|
digital_format_present,
|
||||||
|
mark_comment,
|
||||||
|
mark_practice,
|
||||||
|
predefence_comment,
|
||||||
|
normal_control,
|
||||||
|
anti_plagiarism,
|
||||||
|
note,
|
||||||
|
record_book_returned,
|
||||||
|
work,
|
||||||
|
user_id,
|
||||||
|
diploma_topic_id,
|
||||||
|
mentor_user_id,
|
||||||
|
group_id,
|
||||||
|
created_at)
|
||||||
|
VALUES (true, 1100, 'ПРИ, ИВТ или другой вуз', true, 5, 5, 'ок', 'Подписано', 7862, 'Акт о внедрении', true,
|
||||||
|
'нет', 1, 1, 40, 3, now()),
|
||||||
|
(true, 1110, 'Да, но не уверен, в БГТУ ли', true, 5, 5, 'ок', 'Подписано', 8196,
|
||||||
|
'Заявка, Акт о внедрении', true, 'ООО "ЦИРОБЗ"', 2, 2, 40, 3, now()),
|
||||||
|
(true, 3500, 'Нет', true, 3, 3,
|
||||||
|
'Критически низкий уровень. Допущен под ответственность руководителя ВКР', 'Подписано', 7141, 'Иниц',
|
||||||
|
true, 'нет', 3, 3, 41, 3, now()),
|
||||||
|
(true, 1800, 'Да, но не уверен, в БГТУ ли', true, 4, 5, 'Усилить работу', 'Подписано', 5381, 'Иниц',
|
||||||
|
true, 'нет', 4, 4, 42, 3, now()),
|
||||||
|
(true, 2100, 'ИВТ, ПРИ', true, 5, 5, 'ок', 'Подписано', 8146, 'Заявка, Акт о внедрении', true, 'нет', 5,
|
||||||
|
5, 43, 3, now()),
|
||||||
|
(true, 1100, 'ИВТ, ПРИ', true, 5, 5, 'ок', 'Подписано', 7965, 'Иниц', true, 'нет', 6, 6, 41, 3, now()),
|
||||||
|
(true, 1200, 'нет', true, 5, 4, 'Усилить работу', 'Подписано', 8583, Null, true,
|
||||||
|
'Газ Энерго Комплект (ГЭК)', 7, 7, 44, 3, now()),
|
||||||
|
(true, 1700, 'Нет', true, 5, 5,
|
||||||
|
'Критически низкий уровень. Допущен под ответственность руководителя ВКР', 'Подписано', 6647, Null,
|
||||||
|
true, 'нет', 8, 8, 45, 3, now()),
|
||||||
|
(true, 3300, 'ИВТ, ПРИ или другой вуз', true, 5, 5, 'Усилить работу', 'Подписано', 6741,
|
||||||
|
'Заявка, Акт о внедрении', true, 'нет', 9, 9, 46, 3, now()),
|
||||||
|
(true, 1200, 'ИВТ', true, 5, 5, 'ок', 'Подписано', 7645, 'Заявка, Акт о внедрении', true, 'нет', 10, 10,
|
||||||
|
40, 3, now()),
|
||||||
|
(true, 3700, 'нет', true, 3, 3,
|
||||||
|
'Критически низкий уровень. Допущен под ответственность руководителя ВКР', '1', 3093, 'Иниц', true,
|
||||||
|
'нет', 11, 11, 45, 3, now()),
|
||||||
|
(true, 1900, 'Нет', true, 5, 5, 'ок', 'Подписано', 8175, 'Заявка, Акт о внедрении', true, 'нет', 12, 12,
|
||||||
|
42, 3, now()),
|
||||||
|
(true, 3200, 'ИВТ', true, 5, 5, 'Усилить работу', 'Подписано', 7805, 'Акт', true, 'нет', 13, 13, 46, 3,
|
||||||
|
now()),
|
||||||
|
(true, 1200, 'ИВТ, ПРИ', true, 4, 4, 'ок', 'рек', 7590, 'Иниц', true, 'нет', 14, 14, 45, 3, now()),
|
||||||
|
(true, 3900, 'нет', true, 5, 5, 'Усилить работу', 'Подписано', 6463, 'Заявка, Акт о внедрении', true,
|
||||||
|
'нет', 15, 15, 40, 3, now()),
|
||||||
|
(true, 2200, 'ИВТ', true, 5, 5, 'ок', 'Подписано', 7441, Null, true, 'ООО "ЦИРОБЗ"', 16, 16, 44, 3,
|
||||||
|
now()),
|
||||||
|
(true, 1130, 'Нет', true, 5, 4,
|
||||||
|
'Критически низкий уровень. Допущен под ответственность руководителя ВКР', 'Подписано', 7319,
|
||||||
|
'Заявка, Акт о внедрении', true, 'нет', 17, 17, 40, 3, now()),
|
||||||
|
(true, 2400, 'ИВТ', true, 4, 5, 'ок', 'Подписано', 6436, Null, true, 'нет', 18, 18, 45, 3, now()),
|
||||||
|
(true, 1600, 'ИВТ', true, 5, 5, 'Усилить работу', 'Подписано', 6227, 'Исслед', true, 'АО "БЭМЗ"', 19, 19,
|
||||||
|
47, 3, now()),
|
||||||
|
(true, 1400, 'Нет', true, 5, 5, 'ок', 'Подписано', 8935, 'Иниц', true, 'ООО "ЦИРОБЗ"', 20, 20, 44, 4,
|
||||||
|
now()),
|
||||||
|
(true, 2900, 'ИВТ', true, 5, 5, 'ок', 'Подписано', 7971, 'Заявка, Акт о внедрении', true, 'нет', 21, 21,
|
||||||
|
40, 4, now()),
|
||||||
|
(true, 2600, 'ИВТ, ПРИ', true, 3, 3, 'ок', 'Подписано', 7284, Null, true, 'нет', 22, 22, 48, 4, now()),
|
||||||
|
(true, 3100, 'ИВТ, ПРИ', true, 5, 5, 'Усилить работу', 'Подписано', 4966, 'Заявка, Акт о внедрении',
|
||||||
|
true, 'нет', 23, 23, 45, 4, now()),
|
||||||
|
(true, 3110, 'Нет', true, 5, 5, 'ок', 'Подписано', 7174, Null, true, 'нет', 24, 24, 40, 4, now()),
|
||||||
|
(true, 3800, 'Нет', true, 5, 5, 'ок', 'Подписано', 7233, Null, true, 'нет', 25, 25, 45, 4, now()),
|
||||||
|
(true, 3300, 'ИВТ', true, 5, 5, 'ок', 'Подписано', 7133, Null, true, 'нет', 26, 26, 43, 4, now()),
|
||||||
|
(true, 3130, 'ИВТ', true, 5, 5, 'ок', 'Подписано', 8083, 'Заявка, Акт о внедрении', true, 'нет', 27, 27,
|
||||||
|
49, 4, now()),
|
||||||
|
(true, 3400, 'Нет', true, 5, 4,
|
||||||
|
'Критически низкий уровень. Допущен под ответственность руководителя ВКР', 'Подписано', 7968, 'Иниц',
|
||||||
|
true, 'нет', 28, 28, 50, 4, now()),
|
||||||
|
(true, 3120, 'ИВТ или ПРИ', true, 5, 5, 'ок', 'Подписано', 7940, 'Исслед', true, 'ООО "ЦИРОБЗ"', 29, 29,
|
||||||
|
40, 4, now()),
|
||||||
|
(true, 2800, 'Нет (возможно)', true, 4, 4, 'Усилить работу', 'рек', 6775, 'Заявка, Акт о внедрении',
|
||||||
|
true, 'нет', 30, 30, 40, 4, now()),
|
||||||
|
(true, 2100, 'Нет (возможно)', true, 5, 5, 'ок', 'Подписано', 7637, 'Заявка, Акт о внедрении', true,
|
||||||
|
'нет', 31, 31, 40, 4, now()),
|
||||||
|
(true, 2700, 'ИВТ', true, 5, 5, 'ок', 'Подписано', 8544, 'Заявка, Акт о внедрении', true, 'нет', 32, 32,
|
||||||
|
45, 4, now()),
|
||||||
|
(true, 2130, 'ИВТ, ПРИ', true, 5, 5, 'ок', 'Подписано', 7166, 'Заявка, Акт о внедрении', true, 'нет', 33,
|
||||||
|
33, 51, 4, now()),
|
||||||
|
(true, 2110, 'ИВТ', true, 5, 5, 'ок', 'Подписано', 6075, 'Заявка, Акт о внедрении', true, 'нет', 34, 34,
|
||||||
|
52, 4, now()),
|
||||||
|
(true, 3100, 'ИВТ', true, 5, 5, 'ок', 'Подписано', 7057, 'Заявка, Акт о внедрении', true, 'нет', 35, 35,
|
||||||
|
50, 4, now()),
|
||||||
|
(true, 2120, 'В БГТУ на другой кафедре (38.04.01 Экономика или 27.04.05. Инноватика)', true, 5, 5, 'ок',
|
||||||
|
'Подписано', 7057, 'Заявка, Акт о внедрении', true, 'нет', 36, 36, 51, 4, now()),
|
||||||
|
(true, 2500, 'ИВТ', true, 5, 5, 'ок', 'Подписано', 6583, 'Заявка, Акт о внедрении', true, 'нет', 37, 37,
|
||||||
|
53, 4, now()),
|
||||||
|
(true, 1300, 'ИВТ, ПРИ', true, 5, 5, 'ок', 'Подписано', 8444, 'Заявка, Акт о внедрении', true, 'нет', 38,
|
||||||
|
38, 44, 4, now()),
|
||||||
|
(true, 3600, 'ИВТ', true, 5, 5, 'ок', 'Подписано', 7631, 'Заявка, Акт о внедрении', true, 'нет', 39, 39,
|
||||||
|
45, 4, now());
|
||||||
|
end
|
||||||
|
$$;
|
||||||
82
server/src/main/resources/db/test-data/user.sql
Normal file
82
server/src/main/resources/db/test-data/user.sql
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
INSERT INTO "user" (login, password, full_name, mail, number_phone, created_at)
|
||||||
|
VALUES ('akulenko_mikhail', '{noop}1', 'Акуленко Михаил Вячеславович', 'akulenko.mikhail@example.com',
|
||||||
|
'+79110000001', NOW()),
|
||||||
|
('borovikov_artem', '{noop}1', 'Боровиков Артём Викторович', 'borovikov.artem@example.com', '+79110000002',
|
||||||
|
NOW()),
|
||||||
|
('bykonya_alexey', '{noop}1', 'Быконя Алексей Николаевич', 'bykonya.alexey@example.com', '+79110000003',
|
||||||
|
NOW()),
|
||||||
|
('ermakov_alexander', '{noop}1', 'Ермаков Александр Сергеевич', 'ermakov.alexander@example.com',
|
||||||
|
'+79110000004', NOW()),
|
||||||
|
('zgursky_evgeny', '{noop}1', 'Згурский Евгений Олегович', 'zgursky.evgeny@example.com', '+79110000005',
|
||||||
|
NOW()),
|
||||||
|
('ibishov_tural', '{noop}1', 'Ибишов Турал Садай оглы', 'ibishov.tural@example.com', '+79110000006', NOW()),
|
||||||
|
('ignatenko_vladimir', '{noop}1', 'Игнатенко Владимир Алексеевич', 'ignatenko.vladimir@example.com',
|
||||||
|
'+79110000007', NOW()),
|
||||||
|
('lazukin_danila', '{noop}1', 'Лазукин Данила Дмитриевич', 'lazukin.danila@example.com', '+79110000008',
|
||||||
|
NOW()),
|
||||||
|
('mitiaev_danila', '{noop}1', 'Митяев Данила Алексеевич', 'mitiaev.danila@example.com', '+79110000009',
|
||||||
|
NOW()),
|
||||||
|
('neshkov_daniil', '{noop}1', 'Нешков Даниил Владимирович', 'neshkov.daniil@example.com', '+79110000010',
|
||||||
|
NOW()),
|
||||||
|
('petrov_pavel', '{noop}1', 'Петров Павел Сергеевич', 'petrov.pavel@example.com', '+79110000011', NOW()),
|
||||||
|
('sazonov_andrey', '{noop}1', 'Сазонов Андрей Андреевич', 'sazonov.andrey@example.com', '+79110000012',
|
||||||
|
NOW()),
|
||||||
|
('solokhin_maxim', '{noop}1', 'Солохин Максим Николаевич', 'solokhin.maxim@example.com', '+79110000013',
|
||||||
|
NOW()),
|
||||||
|
('sochinsky_artem', '{noop}1', 'Сочинский Артем Александрович', 'sochinsky.artem@example.com',
|
||||||
|
'+79110000014', NOW()),
|
||||||
|
('trisvyatsky_kirill', '{noop}1', 'Трисвятский Кирилл Андреевич', 'trisvyatsky.kirill@example.com',
|
||||||
|
'+79110000015', NOW()),
|
||||||
|
('turov_alexander', '{noop}1', 'Туров Александр Сергеевич', 'turov.alexander@example.com', '+79110000016',
|
||||||
|
NOW()),
|
||||||
|
('shevtsova_alexandra', '{noop}1', 'Шевцова Александра Валерьевна', 'shevtsova.alexandra@example.com',
|
||||||
|
'+79110000017', NOW()),
|
||||||
|
('kibalyuk_artem', '{noop}1', 'Кибалюк Артем Сергеевич', 'kibalyuk.artem@example.com', '+79110000018', NOW()),
|
||||||
|
('shulindin_artem', '{noop}1', 'Шулындин Артём Андреевич', 'shulindin.artem@example.com', '+79110000019',
|
||||||
|
NOW()),
|
||||||
|
('belyaev_egor', '{noop}1', 'Беляев Егор Андреевич', 'belyaev.egor@example.com', '+79110000020', NOW()),
|
||||||
|
('berezhnoy_igor', '{noop}1', 'Бережной Игорь Александрович', 'berezhnoy.igor@example.com', '+79110000021',
|
||||||
|
NOW()),
|
||||||
|
('bogun_pavel', '{noop}1', 'Богун Павел Сергеевич', 'bogun.pavel@example.com', '+79110000022', NOW()),
|
||||||
|
('vaseykin_nikita', '{noop}1', 'Васейкин Никита Павлович', 'vaseykin.nikita@example.com', '+79110000023',
|
||||||
|
NOW()),
|
||||||
|
('gomonov_nikita', '{noop}1', 'Гомонов Никита Алексеевич', 'gomonov.nikita@example.com', '+79110000024',
|
||||||
|
NOW()),
|
||||||
|
('druyan_oleg', '{noop}1', 'Друян Олег Викторович', 'druyan.oleg@example.com', '+79110000025', NOW()),
|
||||||
|
('ivanov_kirill', '{noop}1', 'Иванов Кирилл Эдуардович', 'ivanov.kirill@example.com', '+79110000026', NOW()),
|
||||||
|
('ivanova_veronika', '{noop}1', 'Иванова Вероника Евгеньевна', 'ivanova.veronika@example.com',
|
||||||
|
'+79110000027', NOW()),
|
||||||
|
('izotov_ivan', '{noop}1', 'Изотов Иван Алексеевич', 'izotov.ivan@example.com', '+79110000028', NOW()),
|
||||||
|
('isakov_zahar', '{noop}1', 'Исаков Захар Александрович', 'isakov.zahar@example.com', '+79110000029', NOW()),
|
||||||
|
('iskritsky_daniil', '{noop}1', 'Искрицкий Даниил Павлович', 'iskritsky.daniil@example.com', '+79110000030',
|
||||||
|
NOW()),
|
||||||
|
('linko_daria', '{noop}1', 'Линько Дарья Андреевна', 'linko.daria@example.com', '+79110000031', NOW()),
|
||||||
|
('logutov_kirill', '{noop}1', 'Логутов Кирилл Александрович', 'logutov.kirill@example.com', '+79110000032',
|
||||||
|
NOW()),
|
||||||
|
('nekrassov_sergey', '{noop}1', 'Некрасов Сергей Игоревич', 'nekrassov.sergey@example.com', '+79110000033',
|
||||||
|
NOW()),
|
||||||
|
('sinyagin_ilya', '{noop}1', 'Синягин Илья Александрович', 'sinyagin.ilya@example.com', '+79110000034',
|
||||||
|
NOW()),
|
||||||
|
('sopriko_daniil', '{noop}1', 'Соприко Даниил Сергеевич', 'sopriko.daniil@example.com', '+79110000035',
|
||||||
|
NOW()),
|
||||||
|
('turovsky_ivan', '{noop}1', 'Туровский Иван Алексеевич', 'turovsky.ivan@example.com', '+79110000036', NOW()),
|
||||||
|
('frantsev_sergey', '{noop}1', 'Францев Сергей Дмитриевич', 'frantsev.sergey@example.com', '+79110000037',
|
||||||
|
NOW()),
|
||||||
|
('chepurnoy_maxim', '{noop}1', 'Чепурной Максим Романович', 'chepurnoy.maxim@example.com', '+79110000038',
|
||||||
|
NOW()),
|
||||||
|
('schemelinin_dmitry', '{noop}1', 'Щемелинин Дмитрий Михайлович', 'schemelinin.dmitry@example.com',
|
||||||
|
'+79110000039', NOW()),
|
||||||
|
('bulatitsky_d_i_1', '{noop}1', 'Булатицкий Д. И.', 'bulatitsky.d.i.1@example.com', '+79110000040', NOW()),
|
||||||
|
('kopeliovich_d_i_1', '{noop}1', 'Копелиович Д. И.', 'kopeliovich.d.i.1@example.com', '+79110000041', NOW()),
|
||||||
|
('dergachev_k_v', '{noop}1', 'Дергачев К. В.', 'dergachev.k.v@example.com', '+79110000042', NOW()),
|
||||||
|
('trubakov_e_o', '{noop}1', 'Трубаков Е. О.', 'trubakov.e.o@example.com', '+79110000043', NOW()),
|
||||||
|
('radchenko_a_o', '{noop}1', 'Радченко А. О.', 'radchenko.a.o@example.com', '+79110000044', NOW()),
|
||||||
|
('zimin_s_n_1', '{noop}1', 'Зимин С. Н.', 'zimin.s.n.1@example.com', '+79110000045', NOW()),
|
||||||
|
('koptenok_e_v', '{noop}1', 'Коптенок Е. В.', 'koptenok.e.v@example.com', '+79110000046', NOW()),
|
||||||
|
('mikhaleva_o_a', '{noop}1', 'Михалева О. А.', 'mikhaleva.o.a@example.com', '+79110000047', NOW()),
|
||||||
|
('gulakov_k_v', '{noop}1', 'Гулаков К. В.', 'gulakov.k.v@example.com', '+79110000048', NOW()),
|
||||||
|
('titarev_d_v', '{noop}1', 'Титарёв Д. В.', 'titarev.d.v@example.com', '+79110000049', NOW()),
|
||||||
|
('izrailev_v_ya_1', '{noop}1', 'Израилев В. Я.', 'izrailev.v.ya.1@example.com', '+79110000050', NOW()),
|
||||||
|
('podvesovsky_a_g_1', '{noop}1', 'Подвесовский А. Г.', 'podvesovsky.a.g.1@example.com', '+79110000051', NOW()),
|
||||||
|
('trubakov_a_o', '{noop}1', 'Трубаков А. О.', 'trubakov.a.o@example.com', '+79110000059', NOW()),
|
||||||
|
('lageriev_d_g', '{noop}1', 'Лагерев Д. Г.', 'lageriev.d.g@example.com', '+79110000052', NOW());
|
||||||
58
server/src/main/resources/db/test-data/user_role.sql
Normal file
58
server/src/main/resources/db/test-data/user_role.sql
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
do
|
||||||
|
$$
|
||||||
|
declare
|
||||||
|
teacher_id bigint := 1;
|
||||||
|
student_id bigint := 2;
|
||||||
|
commission_member_id bigint := 3;
|
||||||
|
administrator_id bigint := 4;
|
||||||
|
secretary_id bigint := 5;
|
||||||
|
begin
|
||||||
|
INSERT INTO user_role (user_id, role_id)
|
||||||
|
VALUES (1, student_id),
|
||||||
|
(2, student_id),
|
||||||
|
(3, student_id),
|
||||||
|
(4, student_id),
|
||||||
|
(5, student_id),
|
||||||
|
(6, student_id),
|
||||||
|
(7, student_id),
|
||||||
|
(8, student_id),
|
||||||
|
(9, student_id),
|
||||||
|
(10, student_id),
|
||||||
|
(11, student_id),
|
||||||
|
(12, student_id),
|
||||||
|
(13, student_id),
|
||||||
|
(14, student_id),
|
||||||
|
(15, student_id),
|
||||||
|
(16, student_id),
|
||||||
|
(17, student_id),
|
||||||
|
(18, student_id),
|
||||||
|
(19, student_id),
|
||||||
|
(20, student_id),
|
||||||
|
(21, student_id),
|
||||||
|
(22, student_id),
|
||||||
|
(23, student_id),
|
||||||
|
(24, student_id),
|
||||||
|
(25, student_id),
|
||||||
|
(26, student_id),
|
||||||
|
(27, student_id),
|
||||||
|
(28, student_id),
|
||||||
|
(29, student_id),
|
||||||
|
(30, student_id),
|
||||||
|
(31, student_id),
|
||||||
|
(32, student_id),
|
||||||
|
(33, student_id),
|
||||||
|
(34, student_id),
|
||||||
|
(35, student_id),
|
||||||
|
(36, student_id),
|
||||||
|
(37, teacher_id),
|
||||||
|
(37, administrator_id),
|
||||||
|
(38, commission_member_id),
|
||||||
|
(39, teacher_id),
|
||||||
|
(40, teacher_id),
|
||||||
|
(41, teacher_id),
|
||||||
|
(42, teacher_id),
|
||||||
|
(43, teacher_id),
|
||||||
|
(44, secretary_id),
|
||||||
|
(45, secretary_id);
|
||||||
|
end
|
||||||
|
$$;
|
||||||
22
server/src/main/resources/logback.xml
Normal file
22
server/src/main/resources/logback.xml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<configuration>
|
||||||
|
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
|
||||||
|
<file>logs/app.log</file>
|
||||||
|
<append>false</append>
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<logger name="ru.mskobaro.tdms" level="debug"/>
|
||||||
|
|
||||||
|
<root level="warn">
|
||||||
|
<appender-ref ref="CONSOLE" />
|
||||||
|
<appender-ref ref="FILE" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
||||||
26
web/.gitignore
vendored
Normal file
26
web/.gitignore
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
node
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
12
web/babel.config.json
Normal file
12
web/babel.config.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
["@babel/preset-env", {"modules": false}],
|
||||||
|
"@babel/preset-react",
|
||||||
|
"@babel/preset-typescript"
|
||||||
|
],
|
||||||
|
"plugins": [
|
||||||
|
["@babel/plugin-proposal-decorators", { "legacy": true }],
|
||||||
|
["@babel/plugin-proposal-class-properties"],
|
||||||
|
["@babel/plugin-transform-typescript"]
|
||||||
|
]
|
||||||
|
}
|
||||||
7045
web/package-lock.json
generated
Normal file
7045
web/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
44
web/package.json
Normal file
44
web/package.json
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"build": "webpack --mode production",
|
||||||
|
"dev": "webpack-dev-server --mode development"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-svg-core": "^6.6.0",
|
||||||
|
"@fortawesome/free-brands-svg-icons": "^6.6.0",
|
||||||
|
"@fortawesome/free-regular-svg-icons": "^6.6.0",
|
||||||
|
"@fortawesome/free-solid-svg-icons": "^6.6.0",
|
||||||
|
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||||
|
"@types/lodash": "^4.17.15",
|
||||||
|
"axios": "^1.7.7",
|
||||||
|
"bootstrap": "^5.3.3",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"mobx": "^6.13.1",
|
||||||
|
"mobx-react": "^9.1.1",
|
||||||
|
"mobx-state-router": "^6.0.1",
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-bootstrap": "^2.10.4",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
|
"uuid": "^11.0.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/plugin-proposal-decorators": "^7.25.7",
|
||||||
|
"@babel/preset-env": "^7.25.8",
|
||||||
|
"@babel/preset-react": "^7.25.7",
|
||||||
|
"@types/react": "^18.2.0",
|
||||||
|
"@types/react-dom": "^18.2.0",
|
||||||
|
"@types/webpack": "^5.28.5",
|
||||||
|
"copy-webpack-plugin": "^13.0.0",
|
||||||
|
"css-loader": "^7.1.2",
|
||||||
|
"html-webpack-plugin": "^5.6.2",
|
||||||
|
"style-loader": "^4.0.0",
|
||||||
|
"ts-loader": "^9.5.1",
|
||||||
|
"typescript": "^5.6.3",
|
||||||
|
"webpack": "^5.95.0",
|
||||||
|
"webpack-cli": "^5.1.4",
|
||||||
|
"webpack-dev-server": "^5.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
87
web/pom.xml
Normal file
87
web/pom.xml
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>ru.mskobaro</groupId>
|
||||||
|
<artifactId>tdms</artifactId>
|
||||||
|
<version>0.0.1</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>web</artifactId>
|
||||||
|
<version>0.0.1</version>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<name>TDMS::WEB</name>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.github.eirslett</groupId>
|
||||||
|
<artifactId>frontend-maven-plugin</artifactId>
|
||||||
|
<version>1.15.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>install nodejs and npm</id>
|
||||||
|
<goals>
|
||||||
|
<goal>install-node-and-npm</goal>
|
||||||
|
</goals>
|
||||||
|
<phase>generate-resources</phase>
|
||||||
|
<configuration>
|
||||||
|
<nodeVersion>v20.12.0</nodeVersion>
|
||||||
|
<npmVersion>10.5.0</npmVersion>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>install dependencies</id>
|
||||||
|
<goals>
|
||||||
|
<goal>npm</goal>
|
||||||
|
</goals>
|
||||||
|
<phase>generate-resources</phase>
|
||||||
|
<configuration>
|
||||||
|
<arguments>install</arguments>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>build frontend</id>
|
||||||
|
<goals>
|
||||||
|
<goal>npm</goal>
|
||||||
|
</goals>
|
||||||
|
<phase>generate-resources</phase>
|
||||||
|
<configuration>
|
||||||
|
<arguments>run build</arguments>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<nodeVersion>v20.12.0</nodeVersion>
|
||||||
|
<workingDirectory>./</workingDirectory>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-clean-plugin</artifactId>
|
||||||
|
<version>3.3.2</version>
|
||||||
|
<configuration>
|
||||||
|
<filesets>
|
||||||
|
<fileset>
|
||||||
|
<directory>./dist</directory>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
<followSymlinks>false</followSymlinks>
|
||||||
|
</fileset>
|
||||||
|
<fileset>
|
||||||
|
<directory>./node</directory>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
<followSymlinks>false</followSymlinks>
|
||||||
|
</fileset>
|
||||||
|
</filesets>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
34
web/src/Application.tsx
Normal file
34
web/src/Application.tsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import ReactDOM from 'react-dom/client'
|
||||||
|
import {RouterContext, RouterView, ViewMap} from "mobx-state-router";
|
||||||
|
import {initApp} from "./utils/init";
|
||||||
|
import React from "react";
|
||||||
|
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||||
|
import './index.css'
|
||||||
|
import {RootStoreContext} from './utils/context';
|
||||||
|
import {Home} from "./components/layout/Home";
|
||||||
|
import {GroupListPage} from "./components/group/GroupListPage";
|
||||||
|
import {Error} from "./components/layout/Error";
|
||||||
|
import {ParticipantListPage} from "./components/participant/ParticipantListPage";
|
||||||
|
import {DefenceListPage} from "./components/defence/DefenceListPage";
|
||||||
|
import {PreparationDirectionListPage} from "./components/dictionary/PreparationDirectionList";
|
||||||
|
import {DiplomaTopicListPage} from "./components/dictionary/DiplomaTopicList";
|
||||||
|
|
||||||
|
const viewMap: ViewMap = {
|
||||||
|
home: <Home/>,
|
||||||
|
participantList: <ParticipantListPage/>,
|
||||||
|
groupList: <GroupListPage/>,
|
||||||
|
defenceList: <DefenceListPage/>,
|
||||||
|
themeList: <DiplomaTopicListPage/>,
|
||||||
|
preparationDirectionList: <PreparationDirectionListPage/>,
|
||||||
|
error: <Error/>,
|
||||||
|
}
|
||||||
|
|
||||||
|
const rootStore = initApp();
|
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
|
<RootStoreContext.Provider value={rootStore}>
|
||||||
|
<RouterContext.Provider value={rootStore.routerStore}>
|
||||||
|
<RouterView viewMap={viewMap}/>
|
||||||
|
</RouterContext.Provider>
|
||||||
|
</RootStoreContext.Provider>
|
||||||
|
);
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user