diff --git a/src/main/java/xyz/playedu/api/controller/backend/CourseHourController.java b/src/main/java/xyz/playedu/api/controller/backend/CourseHourController.java new file mode 100644 index 0000000..e58d4c7 --- /dev/null +++ b/src/main/java/xyz/playedu/api/controller/backend/CourseHourController.java @@ -0,0 +1,73 @@ +package xyz.playedu.api.controller.backend; + +import org.apache.ibatis.annotations.Delete; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import xyz.playedu.api.PlayEduBackendThreadLocal; +import xyz.playedu.api.domain.CourseHour; +import xyz.playedu.api.event.CourseHourCreatedEvent; +import xyz.playedu.api.event.CourseHourDestroyEvent; +import xyz.playedu.api.exception.NotFoundException; +import xyz.playedu.api.request.backend.CourseHourRequest; +import xyz.playedu.api.service.CourseHourService; +import xyz.playedu.api.types.JsonResponse; + +import java.util.Date; +import java.util.List; + +/** + * @Author 杭州白书科技有限公司 + * @create 2023/2/26 17:50 + */ +@RestController +@RequestMapping("/backend/v1/course/{courseId}/hour") +public class CourseHourController { + + @Autowired + private CourseHourService hourService; + + @Autowired + private ApplicationContext ctx; + + @GetMapping("/index") + public JsonResponse index(@PathVariable(name = "courseId") Integer courseId) { + List hours = hourService.getHoursByCourseId(courseId); + return JsonResponse.data(hours); + } + + @GetMapping("/create") + public JsonResponse create(@PathVariable(name = "courseId") Integer courseId) { + return JsonResponse.data(null); + } + + @PostMapping("/create") + public JsonResponse store(@PathVariable(name = "courseId") Integer courseId, @RequestBody @Validated CourseHourRequest req) { + CourseHour courseHour = hourService.create(courseId, req.getChapterId(), req.getTitle(), req.getType(), req.getDuration(), req.getPublishedAt()); + ctx.publishEvent(new CourseHourCreatedEvent(this, PlayEduBackendThreadLocal.getAdminUserID(), courseHour.getCourseId(), courseHour.getChapterId(), courseHour.getId(), new Date())); + return JsonResponse.success(); + } + + @GetMapping("/{id}") + public JsonResponse edit(@PathVariable(name = "courseId") Integer courseId, @PathVariable(name = "id") Integer id) throws NotFoundException { + CourseHour courseHour = hourService.findOrFail(id, courseId); + return JsonResponse.data(courseHour); + } + + @PutMapping("/{id}") + public JsonResponse update(@PathVariable(name = "courseId") Integer courseId, @PathVariable(name = "id") Integer id, @RequestBody @Validated CourseHourRequest req) throws NotFoundException { + CourseHour courseHour = hourService.findOrFail(id, courseId); + hourService.update(courseHour, req.getChapterId(), req.getTitle(), req.getDuration(), req.getPublishedAt()); + return JsonResponse.success(); + } + + @DeleteMapping("/{id}") + public JsonResponse destroy(@PathVariable(name = "courseId") Integer courseId, @PathVariable(name = "id") Integer id) throws NotFoundException { + CourseHour courseHour = hourService.findOrFail(id, courseId); + hourService.removeById(courseHour.getId()); + ctx.publishEvent(new CourseHourDestroyEvent(this, PlayEduBackendThreadLocal.getAdminUserID(), courseHour.getCourseId(), courseHour.getChapterId(), courseHour.getId(), new Date())); + return JsonResponse.success(); + } + +} diff --git a/src/main/java/xyz/playedu/api/domain/CourseChapter.java b/src/main/java/xyz/playedu/api/domain/CourseChapter.java index 0fc6217..9dd36f1 100644 --- a/src/main/java/xyz/playedu/api/domain/CourseChapter.java +++ b/src/main/java/xyz/playedu/api/domain/CourseChapter.java @@ -4,19 +4,21 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; + import java.io.Serializable; import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; /** - * * @TableName course_chapters */ -@TableName(value ="course_chapters") +@TableName(value = "course_chapters") @Data public class CourseChapter implements Serializable { /** - * + * */ @TableId(type = IdType.AUTO) private Integer id; @@ -24,6 +26,7 @@ public class CourseChapter implements Serializable { /** * 课程ID */ + @JsonProperty("course_id") private Integer courseId; /** @@ -36,14 +39,10 @@ public class CourseChapter implements Serializable { */ private Integer sort; - /** - * - */ + @JsonProperty("created_at") private Date createdAt; - /** - * - */ + @JsonProperty("updated_at") private Date updatedAt; @TableField(exist = false) @@ -62,11 +61,11 @@ public class CourseChapter implements Serializable { } CourseChapter other = (CourseChapter) that; return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId())) - && (this.getCourseId() == null ? other.getCourseId() == null : this.getCourseId().equals(other.getCourseId())) - && (this.getName() == null ? other.getName() == null : this.getName().equals(other.getName())) - && (this.getSort() == null ? other.getSort() == null : this.getSort().equals(other.getSort())) - && (this.getCreatedAt() == null ? other.getCreatedAt() == null : this.getCreatedAt().equals(other.getCreatedAt())) - && (this.getUpdatedAt() == null ? other.getUpdatedAt() == null : this.getUpdatedAt().equals(other.getUpdatedAt())); + && (this.getCourseId() == null ? other.getCourseId() == null : this.getCourseId().equals(other.getCourseId())) + && (this.getName() == null ? other.getName() == null : this.getName().equals(other.getName())) + && (this.getSort() == null ? other.getSort() == null : this.getSort().equals(other.getSort())) + && (this.getCreatedAt() == null ? other.getCreatedAt() == null : this.getCreatedAt().equals(other.getCreatedAt())) + && (this.getUpdatedAt() == null ? other.getUpdatedAt() == null : this.getUpdatedAt().equals(other.getUpdatedAt())); } @Override diff --git a/src/main/java/xyz/playedu/api/domain/CourseDepartment.java b/src/main/java/xyz/playedu/api/domain/CourseDepartment.java index 3ff06bf..b4fdd4c 100644 --- a/src/main/java/xyz/playedu/api/domain/CourseDepartment.java +++ b/src/main/java/xyz/playedu/api/domain/CourseDepartment.java @@ -1,8 +1,6 @@ package xyz.playedu.api.domain; -import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import java.io.Serializable; diff --git a/src/main/java/xyz/playedu/api/domain/CourseHour.java b/src/main/java/xyz/playedu/api/domain/CourseHour.java new file mode 100644 index 0000000..9eac886 --- /dev/null +++ b/src/main/java/xyz/playedu/api/domain/CourseHour.java @@ -0,0 +1,126 @@ +package xyz.playedu.api.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import java.io.Serializable; +import java.util.Date; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * @TableName course_hour + */ +@TableName(value = "course_hour") +@Data +public class CourseHour implements Serializable { + /** + * + */ + @TableId(type = IdType.AUTO) + private Integer id; + + /** + * 课程ID + */ + @JsonProperty("course_id") + private Integer courseId; + + /** + * 章节ID + */ + @JsonProperty("chapter_id") + private Integer chapterId; + + /** + * 课时名 + */ + private String title; + + /** + * 课时类型 + */ + private String type; + + /** + * 时长[s] + */ + private Integer duration; + + /** + * 发布时间 + */ + @JsonProperty("published_at") + private Date publishedAt; + + @JsonProperty("created_at") + private Date createdAt; + + @JsonProperty("updated_at") + private Date updatedAt; + + @TableField(exist = false) + private static final long serialVersionUID = 1L; + + @Override + public boolean equals(Object that) { + if (this == that) { + return true; + } + if (that == null) { + return false; + } + if (getClass() != that.getClass()) { + return false; + } + CourseHour other = (CourseHour) that; + return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId())) + && (this.getCourseId() == null ? other.getCourseId() == null : this.getCourseId().equals(other.getCourseId())) + && (this.getChapterId() == null ? other.getChapterId() == null : this.getChapterId().equals(other.getChapterId())) + && (this.getTitle() == null ? other.getTitle() == null : this.getTitle().equals(other.getTitle())) + && (this.getType() == null ? other.getType() == null : this.getType().equals(other.getType())) + && (this.getDuration() == null ? other.getDuration() == null : this.getDuration().equals(other.getDuration())) + && (this.getPublishedAt() == null ? other.getPublishedAt() == null : this.getPublishedAt().equals(other.getPublishedAt())) + && (this.getCreatedAt() == null ? other.getCreatedAt() == null : this.getCreatedAt().equals(other.getCreatedAt())) + && (this.getUpdatedAt() == null ? other.getUpdatedAt() == null : this.getUpdatedAt().equals(other.getUpdatedAt())); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((getId() == null) ? 0 : getId().hashCode()); + result = prime * result + ((getCourseId() == null) ? 0 : getCourseId().hashCode()); + result = prime * result + ((getChapterId() == null) ? 0 : getChapterId().hashCode()); + result = prime * result + ((getTitle() == null) ? 0 : getTitle().hashCode()); + result = prime * result + ((getType() == null) ? 0 : getType().hashCode()); + result = prime * result + ((getDuration() == null) ? 0 : getDuration().hashCode()); + result = prime * result + ((getPublishedAt() == null) ? 0 : getPublishedAt().hashCode()); + result = prime * result + ((getCreatedAt() == null) ? 0 : getCreatedAt().hashCode()); + result = prime * result + ((getUpdatedAt() == null) ? 0 : getUpdatedAt().hashCode()); + return result; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getSimpleName()); + sb.append(" ["); + sb.append("Hash = ").append(hashCode()); + sb.append(", id=").append(id); + sb.append(", courseId=").append(courseId); + sb.append(", chapterId=").append(chapterId); + sb.append(", title=").append(title); + sb.append(", type=").append(type); + sb.append(", duration=").append(duration); + sb.append(", publishedAt=").append(publishedAt); + sb.append(", createdAt=").append(createdAt); + sb.append(", updatedAt=").append(updatedAt); + sb.append(", serialVersionUID=").append(serialVersionUID); + sb.append("]"); + return sb.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/xyz/playedu/api/event/CourseHourCreatedEvent.java b/src/main/java/xyz/playedu/api/event/CourseHourCreatedEvent.java new file mode 100644 index 0000000..af78679 --- /dev/null +++ b/src/main/java/xyz/playedu/api/event/CourseHourCreatedEvent.java @@ -0,0 +1,30 @@ +package xyz.playedu.api.event; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.context.ApplicationEvent; + +import java.util.Date; + +/** + * @Author 杭州白书科技有限公司 + * @create 2023/2/26 18:20 + */ +@Setter +@Getter +public class CourseHourCreatedEvent extends ApplicationEvent { + private Integer adminId; + private Integer hourId; + private Integer courseId; + private Integer chapterId; + private Date date; + + public CourseHourCreatedEvent(Object source, Integer adminId, Integer courseId, Integer chapterId, Integer hourId, Date date) { + super(source); + this.adminId = adminId; + this.courseId = courseId; + this.chapterId = chapterId; + this.hourId = hourId; + this.date = date; + } +} diff --git a/src/main/java/xyz/playedu/api/event/CourseHourDestroyEvent.java b/src/main/java/xyz/playedu/api/event/CourseHourDestroyEvent.java new file mode 100644 index 0000000..5096f0f --- /dev/null +++ b/src/main/java/xyz/playedu/api/event/CourseHourDestroyEvent.java @@ -0,0 +1,30 @@ +package xyz.playedu.api.event; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.context.ApplicationEvent; + +import java.util.Date; + +/** + * @Author 杭州白书科技有限公司 + * @create 2023/2/26 17:52 + */ +@Getter +@Setter +public class CourseHourDestroyEvent extends ApplicationEvent { + private Integer adminId; + private Integer hourId; + private Integer courseId; + private Integer chapterId; + private Date date; + + public CourseHourDestroyEvent(Object source, Integer adminId, Integer courseId, Integer chapterId, Integer hourId, Date date) { + super(source); + this.adminId = adminId; + this.courseId = courseId; + this.chapterId = chapterId; + this.hourId = hourId; + this.date = date; + } +} diff --git a/src/main/java/xyz/playedu/api/listener/CourseHourCreatedListener.java b/src/main/java/xyz/playedu/api/listener/CourseHourCreatedListener.java new file mode 100644 index 0000000..02c370f --- /dev/null +++ b/src/main/java/xyz/playedu/api/listener/CourseHourCreatedListener.java @@ -0,0 +1,29 @@ +package xyz.playedu.api.listener; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; +import xyz.playedu.api.event.CourseHourCreatedEvent; +import xyz.playedu.api.service.CourseHourService; +import xyz.playedu.api.service.CourseService; + +/** + * @Author 杭州白书科技有限公司 + * @create 2023/2/26 18:22 + */ +@Component +public class CourseHourCreatedListener { + + @Autowired + private CourseHourService hourService; + + @Autowired + private CourseService courseService; + + @EventListener + public void courseClassHourUpdate(CourseHourCreatedEvent event) { + Integer classHour = hourService.getCourseClassHourByCourseId(event.getCourseId()); + courseService.updateClassHour(event.getCourseId(), classHour); + } + +} diff --git a/src/main/java/xyz/playedu/api/listener/CourseHourDestroyListener.java b/src/main/java/xyz/playedu/api/listener/CourseHourDestroyListener.java new file mode 100644 index 0000000..5a113c4 --- /dev/null +++ b/src/main/java/xyz/playedu/api/listener/CourseHourDestroyListener.java @@ -0,0 +1,29 @@ +package xyz.playedu.api.listener; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; +import xyz.playedu.api.event.CourseHourDestroyEvent; +import xyz.playedu.api.service.CourseHourService; +import xyz.playedu.api.service.CourseService; + +/** + * @Author 杭州白书科技有限公司 + * @create 2023/2/26 18:12 + */ +@Component +public class CourseHourDestroyListener { + + @Autowired + private CourseHourService hourService; + + @Autowired + private CourseService courseService; + + @EventListener + public void courseClassHourUpdate(CourseHourDestroyEvent event) { + Integer classHour = hourService.getCourseClassHourByCourseId(event.getCourseId()); + courseService.updateClassHour(event.getCourseId(), classHour); + } + +} diff --git a/src/main/java/xyz/playedu/api/mapper/CourseHourMapper.java b/src/main/java/xyz/playedu/api/mapper/CourseHourMapper.java new file mode 100644 index 0000000..884c8d4 --- /dev/null +++ b/src/main/java/xyz/playedu/api/mapper/CourseHourMapper.java @@ -0,0 +1,20 @@ +package xyz.playedu.api.mapper; + +import org.apache.ibatis.annotations.Mapper; +import xyz.playedu.api.domain.CourseHour; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** +* @author tengteng +* @description 针对表【course_hour】的数据库操作Mapper +* @createDate 2023-02-26 18:10:09 +* @Entity xyz.playedu.api.domain.CourseHour +*/ +@Mapper +public interface CourseHourMapper extends BaseMapper { + +} + + + + diff --git a/src/main/java/xyz/playedu/api/request/backend/CourseHourRequest.java b/src/main/java/xyz/playedu/api/request/backend/CourseHourRequest.java new file mode 100644 index 0000000..b27f93c --- /dev/null +++ b/src/main/java/xyz/playedu/api/request/backend/CourseHourRequest.java @@ -0,0 +1,36 @@ +package xyz.playedu.api.request.backend; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.Date; + +/** + * @Author 杭州白书科技有限公司 + * @create 2023/2/26 18:00 + */ +@Data +public class CourseHourRequest { + + @NotNull(message = "chapter_id参数不存在") + @JsonProperty("chapter_id") + private Integer chapterId; + + @NotNull(message = "title参数不存在") + @NotBlank(message = "请输入课时标题") + private String title; + + @NotNull(message = "type参数不存在") + @NotBlank(message = "请选择课时类型") + private String type; + + @NotNull(message = "duration参数不存在") + private Integer duration; + + @NotNull(message = "published_at参数不存在") + @JsonProperty("published_at") + private Date publishedAt; + +} diff --git a/src/main/java/xyz/playedu/api/request/backend/LoginRequest.java b/src/main/java/xyz/playedu/api/request/backend/LoginRequest.java index fe9eac3..f3e8ef5 100644 --- a/src/main/java/xyz/playedu/api/request/backend/LoginRequest.java +++ b/src/main/java/xyz/playedu/api/request/backend/LoginRequest.java @@ -1,5 +1,6 @@ package xyz.playedu.api.request.backend; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; import lombok.Data; import xyz.playedu.api.request.backend.types.ImageCaptchaRequestInterface; @@ -20,8 +21,10 @@ public class LoginRequest implements Serializable, ImageCaptchaRequestInterface public String password; @NotNull(message = "请输入图形验证码") + @JsonProperty("captcha_value") public String captchaValue; @NotNull(message = "captchaKey参数为空") + @JsonProperty("captcha_key") public String captchaKey; } diff --git a/src/main/java/xyz/playedu/api/service/CourseHourService.java b/src/main/java/xyz/playedu/api/service/CourseHourService.java new file mode 100644 index 0000000..32eac98 --- /dev/null +++ b/src/main/java/xyz/playedu/api/service/CourseHourService.java @@ -0,0 +1,29 @@ +package xyz.playedu.api.service; + +import xyz.playedu.api.domain.CourseHour; +import com.baomidou.mybatisplus.extension.service.IService; +import xyz.playedu.api.exception.NotFoundException; + +import java.util.Date; +import java.util.List; + +/** + * @author tengteng + * @description 针对表【course_hour】的数据库操作Service + * @createDate 2023-02-26 17:48:12 + */ +public interface CourseHourService extends IService { + + List getHoursByCourseId(Integer courseId); + + CourseHour create(Integer courseId, Integer chapterId, String title, String type, Integer duration, Date publishedAt); + + void update(CourseHour courseHour, Integer chapterId, String title, Integer duration, Date publishedAt); + + CourseHour findOrFail(Integer id) throws NotFoundException; + + CourseHour findOrFail(Integer id, Integer courseId) throws NotFoundException; + + Integer getCourseClassHourByCourseId(Integer courseId); + +} diff --git a/src/main/java/xyz/playedu/api/service/CourseService.java b/src/main/java/xyz/playedu/api/service/CourseService.java index b4066b1..1e7eff8 100644 --- a/src/main/java/xyz/playedu/api/service/CourseService.java +++ b/src/main/java/xyz/playedu/api/service/CourseService.java @@ -34,4 +34,6 @@ public interface CourseService extends IService { List getDepIdsByCourseId(Integer courseId); List getCategoryIdsByCourseId(Integer courseId); + + void updateClassHour(Integer courseId, Integer classHour); } diff --git a/src/main/java/xyz/playedu/api/service/impl/CourseHourServiceImpl.java b/src/main/java/xyz/playedu/api/service/impl/CourseHourServiceImpl.java new file mode 100644 index 0000000..bde3823 --- /dev/null +++ b/src/main/java/xyz/playedu/api/service/impl/CourseHourServiceImpl.java @@ -0,0 +1,83 @@ +package xyz.playedu.api.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import xyz.playedu.api.domain.CourseHour; +import xyz.playedu.api.exception.NotFoundException; +import xyz.playedu.api.service.CourseHourService; +import xyz.playedu.api.mapper.CourseHourMapper; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.List; + +/** + * @author tengteng + * @description 针对表【course_hour】的数据库操作Service实现 + * @createDate 2023-02-26 17:48:12 + */ +@Service +public class CourseHourServiceImpl extends ServiceImpl implements CourseHourService { + + @Override + public List getHoursByCourseId(Integer courseId) { + return list(query().getWrapper().eq("course_id", courseId).orderByAsc("published_at")); + } + + @Override + public CourseHour create(Integer courseId, Integer chapterId, String title, String type, Integer duration, Date publishedAt) { + CourseHour courseHour = new CourseHour(); + courseHour.setCourseId(courseId); + courseHour.setChapterId(chapterId); + courseHour.setTitle(title); + courseHour.setType(type); + courseHour.setDuration(duration); + courseHour.setPublishedAt(publishedAt); + courseHour.setCreatedAt(new Date()); + courseHour.setUpdatedAt(new Date()); + + save(courseHour); + + return courseHour; + } + + @Override + public void update(CourseHour courseHour, Integer chapterId, String title, Integer duration, Date publishedAt) { + CourseHour newCourseHour = new CourseHour(); + newCourseHour.setId(courseHour.getId()); + newCourseHour.setChapterId(chapterId); + newCourseHour.setTitle(title); + newCourseHour.setDuration(duration); + newCourseHour.setPublishedAt(publishedAt); + newCourseHour.setCreatedAt(new Date()); + newCourseHour.setUpdatedAt(new Date()); + + updateById(newCourseHour); + } + + @Override + public CourseHour findOrFail(Integer id) throws NotFoundException { + CourseHour courseHour = getOne(query().getWrapper().eq("id", id)); + if (courseHour == null) { + throw new NotFoundException("课时不存在"); + } + return courseHour; + } + + @Override + public CourseHour findOrFail(Integer id, Integer courseId) throws NotFoundException { + CourseHour courseHour = getOne(query().getWrapper().eq("id", id).eq("course_id", courseId)); + if (courseHour == null) { + throw new NotFoundException("课时不存在"); + } + return courseHour; + } + + @Override + public Integer getCourseClassHourByCourseId(Integer courseId) { + return Math.toIntExact(count(query().getWrapper().eq("course_id", courseId))); + } +} + + + + diff --git a/src/main/java/xyz/playedu/api/service/impl/CourseServiceImpl.java b/src/main/java/xyz/playedu/api/service/impl/CourseServiceImpl.java index 912eec9..7772e95 100644 --- a/src/main/java/xyz/playedu/api/service/impl/CourseServiceImpl.java +++ b/src/main/java/xyz/playedu/api/service/impl/CourseServiceImpl.java @@ -175,6 +175,14 @@ public class CourseServiceImpl extends ServiceImpl impleme public List getCategoryIdsByCourseId(Integer courseId) { return categoryCourseService.getCategoryIdsByCourseId(courseId); } + + @Override + public void updateClassHour(Integer courseId, Integer classHour) { + Course course = new Course(); + course.setId(courseId); + course.setClassHour(classHour); + updateById(course); + } } diff --git a/src/main/resources/mapper/CourseHourMapper.xml b/src/main/resources/mapper/CourseHourMapper.xml new file mode 100644 index 0000000..8778b94 --- /dev/null +++ b/src/main/resources/mapper/CourseHourMapper.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + id,course_id,chapter_id, + title,type,duration, + published_at,created_at,updated_at + +