Compare commits

...

6 Commits

Author SHA1 Message Date
Zuev
18f47c6d3d fix: adapt init.sql lessons table to match Create-Lesson branch entity 2026-02-25 23:27:17 +03:00
ProstoDenya01
007b4fb619 Поправил id дисциплины 2026-02-25 23:13:49 +03:00
ProstoDenya01
678cf94ad3 Merge remote-tracking branch 'refs/remotes/origin/main' into Create-Lesson
# Conflicts:
#	db/init/init.sql
2026-02-25 22:57:32 +03:00
ProstoDenya01
94aa164930 Добавил еще немного 2026-02-25 22:56:44 +03:00
ProstoDenya01
e44ac04cac Добавил еще немного 2026-02-25 14:35:20 +03:00
ProstoDenya01
c3d5246874 Написал запрос на создание занятия 2026-02-18 18:46:24 +03:00
6 changed files with 447 additions and 57 deletions

View File

@@ -0,0 +1,67 @@
package com.magistr.app.controller;
import com.magistr.app.dto.CreateLessonRequest;
import com.magistr.app.dto.LessonResponse;
import com.magistr.app.model.Lesson;
import com.magistr.app.repository.LessonRepository;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/users/test")
public class TestController {
private final LessonRepository lessonRepository;
public TestController(LessonRepository lessonRepository) {
this.lessonRepository = lessonRepository;
}
@PostMapping("/create")
public ResponseEntity<?> createLesson(@RequestBody CreateLessonRequest request) {
if (request.getTeacherId() == null || request.getTeacherId() == 0) {
return ResponseEntity.badRequest().body(Map.of("message", "ID преподавателя обязателен"));
}
if (request.getGroupId() == null || request.getGroupId() == 0) {
return ResponseEntity.badRequest().body(Map.of("message", "ID группы обязателен"));
}
if (request.getLessonTypeId() == null || request.getLessonTypeId() == 0) {
return ResponseEntity.badRequest().body(Map.of("message", "ID предмета обязателен"));
}
if (request.getDay() == null || request.getDay().isBlank()) {
return ResponseEntity.badRequest().body(Map.of("message", "Выбор дня обязателен"));
}
if (request.getWeek() == null || request.getWeek().isBlank()) {
return ResponseEntity.badRequest().body(Map.of("message", "Выбор недели обязателен"));
}
if (request.getTime() == null || request.getTime().isBlank()) {
return ResponseEntity.badRequest().body(Map.of("message", "Время обязательно"));
}
Lesson lesson = new Lesson();
lesson.setTeacherId(request.getTeacherId());
lesson.setLessonTypeId(request.getLessonTypeId());
lesson.setGroupId(request.getGroupId());
lesson.setDay(request.getDay());
lesson.setWeek(request.getWeek());
lesson.setTime(request.getTime());
lessonRepository.save(lesson);
return ResponseEntity.ok(new LessonResponse(lesson.getId(), lesson.getDay(), lesson.getWeek(), lesson.getTime()));
}
@GetMapping
public List<LessonResponse> getAllLessons() {
return lessonRepository.findAll().stream()
.map(l -> new LessonResponse(l.getId(), l.getTeacherId(), l.getLessonTypeId(), l.getDay(), l.getWeek(), l.getTime()))
.toList();
}
@GetMapping("/ping")
public String ping() {
return "pong";
}
}

View File

@@ -0,0 +1,62 @@
package com.magistr.app.dto;
public class CreateLessonRequest {
private Long teacherId;
private Long groupId;
private Long lessonTypeId;
private String day;
private String week;
private String time;
public CreateLessonRequest() {
}
public Long getTeacherId() {
return teacherId;
}
public void setTeacherId(Long teacherId) {
this.teacherId = teacherId;
}
public Long getGroupId() {
return groupId;
}
public void setGroupId(Long groupId) {
this.groupId = groupId;
}
public Long getLessonTypeId() {
return lessonTypeId;
}
public void setLessonTypeId(Long lessonTypeId) {
this.lessonTypeId= lessonTypeId;
}
public String getDay() {
return day;
}
public void setDay(String day) {
this.day = day;
}
public String getWeek() {
return week;
}
public void setWeek(String week) {
this.week = week;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}

View File

@@ -0,0 +1,87 @@
package com.magistr.app.dto;
public class LessonResponse {
private Long id;
private Long teacherId;
private Long groupId;
private Long lessonTypeId;
private String day;
private String week;
private String time;
public LessonResponse() {
}
public LessonResponse(Long lessonTypeId, String day, String week, String time) {
this.lessonTypeId = lessonTypeId;
this.day = day;
this.week = week;
this.time = time;
}
public LessonResponse(Long id, Long teacherId, Long lessonTypeId, String day, String week, String time) {
this.id = id;
this.teacherId = teacherId;
this.lessonTypeId = lessonTypeId;
this.day = day;
this.week = week;
this.time = time;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getTeacherId() {
return teacherId;
}
public void setTeacherId(Long teacherId) {
this.teacherId = teacherId;
}
public Long getGroupId() {
return groupId;
}
public void setGroupId(Long groupId) {
this.groupId = groupId;
}
public Long getLessonTypeId() {
return lessonTypeId;
}
public void setLessonTypeId(Long lessonTypeId) {
this.lessonTypeId = lessonTypeId;
}
public String getDay() {
return day;
}
public void setDay(String day) {
this.day = day;
}
public String getWeek() {
return week;
}
public void setWeek(String week) {
this.week = week;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}

View File

@@ -0,0 +1,89 @@
package com.magistr.app.model;
import jakarta.persistence.*;
@Entity
@Table(name = "lessons")
public class Lesson {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "teacher_id", nullable = false)
private Long teacherId;
@Column(name = "group_id", nullable = false)
private Long groupId;
@Column(name = "lesson_type_id", nullable = false)
private Long lessonTypeId;
@Column(name = "day", nullable = false, length = 255)
private String day;
@Column(name = "week", nullable = false, length = 255)
private String week;
@Column(name = "time", nullable = false, length = 255)
private String time;
public Lesson() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getTeacherId() {
return teacherId;
}
public void setTeacherId(Long teacherId) {
this.teacherId = teacherId;
}
public Long getGroupId() {
return groupId;
}
public void setGroupId(Long groupId) {
this.groupId = groupId;
}
public Long getLessonTypeId() {
return lessonTypeId;
}
public void setLessonTypeId(Long lessonTypeId) {
this.lessonTypeId = lessonTypeId;
}
public String getDay() {
return day;
}
public void setDay(String day) {
this.day = day;
}
public String getWeek() {
return week;
}
public void setWeek(String week) {
this.week = week;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}

View File

@@ -0,0 +1,11 @@
package com.magistr.app.repository;
import com.magistr.app.model.Lesson;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface LessonRepository extends JpaRepository<Lesson, Long> {
Optional<Lesson> findByLessonTypeId(Long lessonTypeId);
}

View File

@@ -1,10 +1,18 @@
-- ==========================================
-- Инициализация расширений
-- ==========================================
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- ==========================================
-- Пользователи и роли
-- ==========================================
CREATE TABLE IF NOT EXISTS users (
id BIGSERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
role VARCHAR(20) NOT NULL DEFAULT 'STUDENT'
role VARCHAR(20) NOT NULL DEFAULT 'STUDENT',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Админ по умолчанию: admin / admin (bcrypt через pgcrypto)
@@ -12,19 +20,49 @@ INSERT INTO users (username, password, role)
VALUES ('admin', crypt('admin', gen_salt('bf', 10)), 'ADMIN')
ON CONFLICT (username) DO NOTHING;
-- ==========================================
-- Образовательные формы
-- ==========================================
CREATE TABLE IF NOT EXISTS education_forms (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) UNIQUE NOT NULL
name VARCHAR(100) UNIQUE NOT NULL,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO education_forms (name) VALUES ('Бакалавриат'), ('Магистратура'), ('Специалитет')
INSERT INTO education_forms (name) VALUES
('Бакалавриат'),
('Магистратура'),
('Специалитет')
ON CONFLICT (name) DO NOTHING;
-- ==========================================
-- Учебные группы
-- ==========================================
CREATE TABLE IF NOT EXISTS student_groups (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) UNIQUE NOT NULL,
education_form_id BIGINT NOT NULL REFERENCES education_forms(id)
education_form_id BIGINT NOT NULL REFERENCES education_forms(id),
course INT CHECK (course BETWEEN 1 AND 6),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Тестовая базовая группа для работы
INSERT INTO student_groups (name, education_form_id, course)
VALUES ('ИВТ-21-1', 1, 3)
ON CONFLICT (name) DO NOTHING;
-- ==========================================
-- Подгруппы (например: "ИВТ-21-1 Подгруппа 1")
-- ==========================================
CREATE TABLE IF NOT EXISTS subgroups (
id BIGSERIAL PRIMARY KEY,
group_id BIGINT NOT NULL REFERENCES student_groups(id) ON DELETE CASCADE,
name VARCHAR(100) NOT NULL,
student_capacity INT,
UNIQUE(group_id, name)
);
-- ==========================================
-- Справочники
-- ==========================================
@@ -32,7 +70,10 @@ CREATE TABLE IF NOT EXISTS student_groups (
-- Дисциплины
CREATE TABLE IF NOT EXISTS subjects (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(200) UNIQUE NOT NULL
name VARCHAR(200) UNIQUE NOT NULL,
code VARCHAR(20),
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO subjects (name) VALUES
@@ -46,96 +87,129 @@ ON CONFLICT (name) DO NOTHING;
-- Типы занятий
CREATE TABLE IF NOT EXISTS lesson_types (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(50) UNIQUE NOT NULL
name VARCHAR(50) UNIQUE NOT NULL,
color_code VARCHAR(7) DEFAULT '#3788d8', -- для цветовой индикации в календаре
duration_minutes INT DEFAULT 90
);
INSERT INTO lesson_types (name) VALUES
('Лекция'),
('Практика'),
('Лабораторная работа')
INSERT INTO lesson_types (name, color_code) VALUES
('Лекция', '#FF6B6B'),
('Практика', '#4ECDC4'),
('Лабораторная работа', '#45B7D1')
ON CONFLICT (name) DO NOTHING;
-- Оборудование
CREATE TABLE IF NOT EXISTS equipments (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(50) UNIQUE NOT NULL
name VARCHAR(50) UNIQUE NOT NULL,
description TEXT,
inventory_number VARCHAR(50)
);
INSERT INTO equipments (name) VALUES
('Проектор'),
('ПК'),
('Лаборатория'),
('Интерактивная доска')
('Интерактивная доска'),
('Документ-камера'),
('Аудиосистема')
ON CONFLICT (name) DO NOTHING;
-- Аудитории
CREATE TABLE IF NOT EXISTS classrooms (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(50) UNIQUE NOT NULL,
capacity INT NOT NULL,
is_available BOOLEAN DEFAULT TRUE
capacity INT NOT NULL CHECK (capacity > 0),
building VARCHAR(50),
floor INT,
is_available BOOLEAN DEFAULT TRUE,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO classrooms (name, capacity) VALUES
('101 Ленинская', 120),
('202 IT Lab', 20),
('303 Обычная', 30)
INSERT INTO classrooms (name, capacity, building, floor) VALUES
('101 Ленинская', 120, 'Главный корпус', 1),
('202 IT Lab', 20, 'Корпус IT', 2),
('303 Обычная', 30, 'Главный корпус', 3)
ON CONFLICT (name) DO NOTHING;
-- Привязка оборудования к аудиториям (Many-to-Many)
CREATE TABLE IF NOT EXISTS classroom_equipments (
classroom_id BIGINT NOT NULL REFERENCES classrooms(id) ON DELETE CASCADE,
equipment_id BIGINT NOT NULL REFERENCES equipments(id) ON DELETE CASCADE,
quantity INT DEFAULT 1 CHECK (quantity > 0),
notes TEXT,
PRIMARY KEY (classroom_id, equipment_id)
);
-- Заполнение привязок оборудования (на основе ID базовых данных)
-- '101 Ленинская' -> Проектор (1), Интерактивная доска (4)
INSERT INTO classroom_equipments (classroom_id, equipment_id) VALUES
(1, 1), (1, 4),
-- '202 IT Lab' -> ПК (2), Проектор (1), Лаборатория (3)
(2, 2), (2, 1), (2, 3)
-- '303 Обычная' -> ничего
ON CONFLICT DO NOTHING;
-- Заполнение привязок оборудования с использованием подзапросов
INSERT INTO classroom_equipments (classroom_id, equipment_id, quantity)
SELECT c.id, e.id,
CASE
WHEN e.name = 'ПК' AND c.name = '202 IT Lab' THEN 15
WHEN e.name = 'ПК' THEN 1
ELSE 1
END
FROM classrooms c, equipments e
WHERE
(c.name = '101 Ленинская' AND e.name IN ('Проектор', 'Интерактивная доска', 'Аудиосистема'))
OR (c.name = '202 IT Lab' AND e.name IN ('ПК', 'Проектор', 'Лаборатория', 'Интерактивная доска'))
OR (c.name = '303 Обычная' AND e.name IN ('Проектор'))
ON CONFLICT (classroom_id, equipment_id) DO NOTHING;
-- ==========================================
-- Связи для преподавателей и студентов
-- Связи для преподавателей
-- ==========================================
-- Подгруппы (например: "ИВТ-21-1 Подгруппа 1")
CREATE TABLE IF NOT EXISTS subgroups (
id BIGSERIAL PRIMARY KEY,
group_id BIGINT NOT NULL REFERENCES student_groups(id) ON DELETE CASCADE,
name VARCHAR(100) NOT NULL,
UNIQUE(group_id, name)
);
-- Тестовая базовая группа для работы
INSERT INTO student_groups (name, education_form_id)
VALUES ('ИВТ-21-1', 1)
ON CONFLICT (name) DO NOTHING;
-- Привязка преподавателей к дисциплинам
CREATE TABLE IF NOT EXISTS teacher_subjects (
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
subject_id BIGINT NOT NULL REFERENCES subjects(id) ON DELETE CASCADE,
qualification_level VARCHAR(50),
experience_years INT,
PRIMARY KEY(user_id, subject_id)
);
-- Какие типы занятий может вести преподаватель по дисциплине
CREATE TABLE IF NOT EXISTS teacher_lesson_types (
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
subject_id BIGINT NOT NULL REFERENCES subjects(id) ON DELETE CASCADE,
lesson_type_id BIGINT NOT NULL REFERENCES lesson_types(id) ON DELETE CASCADE,
PRIMARY KEY (user_id, subject_id, lesson_type_id)
);
-- ==========================================
-- Основная таблица Расписания (Lessons)
-- ==========================================
CREATE TABLE IF NOT EXISTS lessons (
id BIGSERIAL PRIMARY KEY,
teacher_id BIGINT NOT NULL REFERENCES users(id),
subject_id BIGINT NOT NULL REFERENCES subjects(id),
group_id BIGINT NOT NULL REFERENCES student_groups(id),
lesson_type_id BIGINT NOT NULL REFERENCES lesson_types(id),
classroom_id BIGINT NOT NULL REFERENCES classrooms(id),
group_id BIGINT NOT NULL REFERENCES student_groups(id), -- первичная группа
subgroup_id BIGINT REFERENCES subgroups(id), -- необязательно (если делим группу)
day_of_week INT NOT NULL CHECK (day_of_week BETWEEN 1 AND 7), -- 1=Понедельник, 7=Воскресенье
is_even_week BOOLEAN NOT NULL, -- Четная/нечетная неделя
start_time TIME NOT NULL, -- Напр. '08:00:00'
end_time TIME NOT NULL -- Напр. '09:30:00'
day VARCHAR(255) NOT NULL,
week VARCHAR(255) NOT NULL,
time VARCHAR(255) NOT NULL
);
-- ==========================================
-- Функция обновления timestamp
-- ==========================================
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = CURRENT_TIMESTAMP;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Триггеры для обновления updated_at
CREATE TRIGGER update_users_updated_at
BEFORE UPDATE ON users
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
-- ==========================================
-- Комментарии к таблицам и полям (для документации)
-- ==========================================
COMMENT ON TABLE users IS 'Пользователи системы (студенты, преподаватели, администраторы)';
COMMENT ON TABLE lessons IS 'Основное расписание занятий';