feat: add lesson
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
package aplp.backend.lms.course.domain.entities;
|
package aplp.backend.lms.course.domain.entities;
|
||||||
|
|
||||||
|
import aplp.backend.core.common.entity.BaseEntity;
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
@@ -18,31 +19,11 @@ import java.time.Instant;
|
|||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public class Course {
|
public class Course extends BaseEntity {
|
||||||
|
|
||||||
@Id
|
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Column(nullable = false, length = 200)
|
@Column(nullable = false, length = 200)
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
@Column(length = 1000)
|
@Column(length = 1000)
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
@CreatedBy
|
|
||||||
@Column(name = "created_by", updatable = false)
|
|
||||||
private Long createdBy;
|
|
||||||
|
|
||||||
@LastModifiedBy
|
|
||||||
@Column(name = "updated_by")
|
|
||||||
private Long updatedBy;
|
|
||||||
|
|
||||||
@CreatedDate
|
|
||||||
@Column(name = "created_at", nullable = false, updatable = false)
|
|
||||||
private Instant createdAt;
|
|
||||||
|
|
||||||
@LastModifiedDate
|
|
||||||
@Column(name = "updated_at", nullable = false)
|
|
||||||
private Instant updatedAt;
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package aplp.backend.lms.lesson.api.controller;
|
||||||
|
|
||||||
|
import aplp.backend.lms.lesson.application.dtos.LessonReqDto;
|
||||||
|
import aplp.backend.lms.lesson.application.dtos.LessonResDto;
|
||||||
|
import aplp.backend.lms.lesson.application.services.LessonService;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/lessons")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class LessonController {
|
||||||
|
|
||||||
|
private final LessonService lessonService;
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public List<LessonResDto> getAll() {
|
||||||
|
return lessonService.getAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public LessonResDto getById(@PathVariable Long id) {
|
||||||
|
return lessonService.getById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
@ResponseStatus(HttpStatus.CREATED)
|
||||||
|
public LessonResDto create(@Valid @RequestBody LessonReqDto request) {
|
||||||
|
return lessonService.create(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}")
|
||||||
|
public LessonResDto update(
|
||||||
|
@PathVariable Long id,
|
||||||
|
@Valid @RequestBody LessonReqDto request) {
|
||||||
|
return lessonService.update(id, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||||
|
public void delete(@PathVariable Long id) {
|
||||||
|
lessonService.delete(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package aplp.backend.lms.lesson.application.dtos;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
|
public record LessonReqDto(
|
||||||
|
@NotBlank(message = "Lesson code is required")
|
||||||
|
@Size(max = 50, message = "Lesson code must not exceed 50 characters")
|
||||||
|
String lessonCode,
|
||||||
|
|
||||||
|
@NotBlank(message = "Lesson name is required")
|
||||||
|
@Size(max = 200, message = "Lesson name must not exceed 200 characters")
|
||||||
|
String lessonName,
|
||||||
|
|
||||||
|
@Size(max = 1000, message = "Description must not exceed 1000 characters")
|
||||||
|
String description
|
||||||
|
) {}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package aplp.backend.lms.lesson.application.dtos;
|
||||||
|
|
||||||
|
import aplp.backend.lms.lesson.domain.entities.Lesson;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
public record LessonResDto(
|
||||||
|
Long id,
|
||||||
|
String lessonCode,
|
||||||
|
String lessonName,
|
||||||
|
String description,
|
||||||
|
LocalDateTime createdAt,
|
||||||
|
LocalDateTime updatedAt
|
||||||
|
) {
|
||||||
|
public static LessonResDto from(Lesson lesson) {
|
||||||
|
return new LessonResDto(
|
||||||
|
lesson.getId(),
|
||||||
|
lesson.getLessonCode(),
|
||||||
|
lesson.getLessonName(),
|
||||||
|
lesson.getDescription(),
|
||||||
|
lesson.getCreatedAt(),
|
||||||
|
lesson.getUpdatedAt()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package aplp.backend.lms.lesson.application.mappers;
|
||||||
|
|
||||||
|
import aplp.backend.lms.lesson.application.dtos.LessonReqDto;
|
||||||
|
import aplp.backend.lms.lesson.application.dtos.LessonResDto;
|
||||||
|
import aplp.backend.lms.lesson.domain.entities.Lesson;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.MappingTarget;
|
||||||
|
|
||||||
|
@Mapper(componentModel = "spring")
|
||||||
|
public interface LessonMapper {
|
||||||
|
|
||||||
|
LessonResDto toResponse(Lesson lesson);
|
||||||
|
|
||||||
|
Lesson toEntity(LessonReqDto request);
|
||||||
|
|
||||||
|
void updateEntity(
|
||||||
|
LessonReqDto request,
|
||||||
|
@MappingTarget Lesson lesson
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package aplp.backend.lms.lesson.application.services;
|
||||||
|
|
||||||
|
import aplp.backend.core.common.exception.ResourceNotFoundException;
|
||||||
|
import aplp.backend.lms.lesson.application.dtos.LessonReqDto;
|
||||||
|
import aplp.backend.lms.lesson.application.dtos.LessonResDto;
|
||||||
|
import aplp.backend.lms.lesson.application.mappers.LessonMapper;
|
||||||
|
import aplp.backend.lms.lesson.domain.entities.Lesson;
|
||||||
|
import aplp.backend.lms.lesson.domain.repositories.LessonRepository;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class LessonService {
|
||||||
|
|
||||||
|
private final LessonRepository lessonRepository;
|
||||||
|
private final LessonMapper lessonMapper;
|
||||||
|
|
||||||
|
public List<LessonResDto> getAll() {
|
||||||
|
return lessonRepository.findAll()
|
||||||
|
.stream()
|
||||||
|
.map(LessonResDto::from)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public LessonResDto getById(Long id) {
|
||||||
|
Lesson lesson = lessonRepository.findById(id)
|
||||||
|
.orElseThrow(() -> new ResourceNotFoundException("Lesson not found"));
|
||||||
|
|
||||||
|
return LessonResDto.from(lesson);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LessonResDto create(LessonReqDto request) {
|
||||||
|
Lesson lesson = lessonMapper.toEntity(request);
|
||||||
|
return lessonMapper.toResponse(lessonRepository.save(lesson));
|
||||||
|
}
|
||||||
|
|
||||||
|
public LessonResDto update(Long id, LessonReqDto request) {
|
||||||
|
Lesson lesson = lessonRepository.findById(id)
|
||||||
|
.orElseThrow(() -> new ResourceNotFoundException("Lesson not found"));
|
||||||
|
|
||||||
|
lessonMapper.updateEntity(request, lesson);
|
||||||
|
|
||||||
|
return lessonMapper.toResponse(lessonRepository.save(lesson));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete(Long id) {
|
||||||
|
lessonRepository.deleteById(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package aplp.backend.lms.lesson.domain.entities;
|
||||||
|
|
||||||
|
import aplp.backend.core.common.entity.BaseEntity;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "lessons")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class Lesson extends BaseEntity {
|
||||||
|
|
||||||
|
@Column(name = "lesson_code", nullable = false, length = 50, unique = true)
|
||||||
|
private String lessonCode;
|
||||||
|
|
||||||
|
@Column(name = "lesson_name", nullable = false, length = 200)
|
||||||
|
private String lessonName;
|
||||||
|
|
||||||
|
@Column(length = 1000)
|
||||||
|
private String description;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package aplp.backend.lms.lesson.domain.repositories;
|
||||||
|
|
||||||
|
import aplp.backend.lms.lesson.domain.entities.Lesson;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface LessonRepository {
|
||||||
|
|
||||||
|
Optional<Lesson> findById(Long id);
|
||||||
|
|
||||||
|
List<Lesson> findAll();
|
||||||
|
|
||||||
|
Lesson save(Lesson lesson);
|
||||||
|
|
||||||
|
void deleteById(Long id);
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package aplp.backend.lms.lesson.infrastructure.persistence;
|
||||||
|
|
||||||
|
import aplp.backend.lms.lesson.domain.entities.Lesson;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface LessonJpaRepository extends JpaRepository<Lesson, Long> {
|
||||||
|
}
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
package aplp.backend.lms.lesson.infrastructure.persistence;
|
||||||
|
|
||||||
|
import aplp.backend.lms.lesson.domain.entities.Lesson;
|
||||||
|
import aplp.backend.lms.lesson.domain.repositories.LessonRepository;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class LessonRepositoryImpl implements LessonRepository {
|
||||||
|
private final LessonJpaRepository repository;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Lesson> findById(Long id) {
|
||||||
|
return repository.findById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Lesson> findAll() {
|
||||||
|
return repository.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Lesson save(Lesson lesson) {
|
||||||
|
return repository.save(lesson);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteById(Long id) {
|
||||||
|
repository.deleteById(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
-- Flyway Migration V2: Add audit columns to courses
|
|
||||||
|
|
||||||
ALTER TABLE courses
|
|
||||||
ADD COLUMN IF NOT EXISTS created_by BIGINT,
|
|
||||||
ADD COLUMN IF NOT EXISTS updated_by BIGINT,
|
|
||||||
ADD COLUMN IF NOT EXISTS created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
||||||
ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ NOT NULL DEFAULT now();
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
-- Flyway Migration V3: Create lessons table
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS lessons (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
lesson_code VARCHAR(50) NOT NULL UNIQUE,
|
||||||
|
lesson_name VARCHAR(200) NOT NULL,
|
||||||
|
description VARCHAR(1000),
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
|
created_by VARCHAR(255),
|
||||||
|
updated_by VARCHAR(255),
|
||||||
|
deleted_at TIMESTAMPTZ,
|
||||||
|
deleted_by VARCHAR(255)
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user