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