diff --git a/README.md b/README.md new file mode 100644 index 0000000..f5631b0 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ + +# 構成 + +**DDD-based Hexagonal Architecture** +- Primary Port... HttpHandler +- Hub... Domain, UseCase, Service +- Secondary Port... DataSource/DataStore + +## ユースケース + +- 認証 +- 科目を閲覧する + + +- 申請履歴を閲覧する +- 申請する + - 事前申請と先着申請 +- キャンセルする + + +- 抽選する +- 登録する \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index c26d4c8..e129a9e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,6 +18,7 @@ dependencies { implementation ("org.http4k:http4k-core") implementation( "org.http4k:http4k-server-jetty:4.48.0.0") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.1") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") testImplementation ("org.http4k:http4k-client-jetty:4.48.0.0") diff --git a/src/main/kotlin/data/Repository/course.json b/src/main/kotlin/data/dataSource/fakeCourseData.json similarity index 100% rename from src/main/kotlin/data/Repository/course.json rename to src/main/kotlin/data/dataSource/fakeCourseData.json diff --git a/src/main/kotlin/data/dataSource/fakeStudentsData.json b/src/main/kotlin/data/dataSource/fakeStudentsData.json new file mode 100644 index 0000000..e69de29 diff --git a/src/main/kotlin/data/database/Database.kt b/src/main/kotlin/data/database/Database.kt deleted file mode 100644 index 4fb715d..0000000 --- a/src/main/kotlin/data/database/Database.kt +++ /dev/null @@ -1,4 +0,0 @@ -package data.database - -class Database { -} \ No newline at end of file diff --git a/src/main/kotlin/data/repository/CourseMembersRepository.kt b/src/main/kotlin/data/repository/CourseMembersRepository.kt new file mode 100644 index 0000000..655e2ee --- /dev/null +++ b/src/main/kotlin/data/repository/CourseMembersRepository.kt @@ -0,0 +1,5 @@ +package data.repository + +interface CourseMembersRepository { + fun save() +} \ No newline at end of file diff --git a/src/main/kotlin/data/repository/CourseTakingApplicationListsRepository.kt b/src/main/kotlin/data/repository/CourseTakingApplicationListsRepository.kt new file mode 100644 index 0000000..4df004d --- /dev/null +++ b/src/main/kotlin/data/repository/CourseTakingApplicationListsRepository.kt @@ -0,0 +1,14 @@ +package data.repository + +import domain.entity.CourseTakingApplication +import domain.entity.CourseTakingApplicationId +import domain.entity.CourseTakingApplicationList +import domain.entity.StudentId + +interface CourseTakingApplicationListsRepository { + + /*TODO: ApplicationList生成生成責務はここが持っている*/ + suspend fun findByStudentId(studentId: StudentId): CourseTakingApplicationList + suspend fun save(courseTakingApplicationList: CourseTakingApplicationList) + +} \ No newline at end of file diff --git a/src/main/kotlin/data/repository/CourseTakingApplicationsHistoryRepository.kt b/src/main/kotlin/data/repository/CourseTakingApplicationsHistoryRepository.kt new file mode 100644 index 0000000..e4501cc --- /dev/null +++ b/src/main/kotlin/data/repository/CourseTakingApplicationsHistoryRepository.kt @@ -0,0 +1,7 @@ +package data.repository + +interface CourseTakingApplicationsHistoryRepository { + suspend fun findAll() + suspend fun delete() + suspend fun save() +} \ No newline at end of file diff --git a/src/main/kotlin/data/repository/CoursesRepository.kt b/src/main/kotlin/data/repository/CoursesRepository.kt new file mode 100644 index 0000000..51404cf --- /dev/null +++ b/src/main/kotlin/data/repository/CoursesRepository.kt @@ -0,0 +1,5 @@ +package data.repository + +interface CoursesRepository { + suspend fun findAll() +} \ No newline at end of file diff --git a/src/main/kotlin/data/repository/StudentsRepository.kt b/src/main/kotlin/data/repository/StudentsRepository.kt new file mode 100644 index 0000000..58a9292 --- /dev/null +++ b/src/main/kotlin/data/repository/StudentsRepository.kt @@ -0,0 +1,5 @@ +package data.repository + +interface StudentsRepository { + suspend fun findById() +} \ No newline at end of file diff --git a/src/main/kotlin/data/repository/impl/FakeCourseMembersRepository.kt b/src/main/kotlin/data/repository/impl/FakeCourseMembersRepository.kt new file mode 100644 index 0000000..7628192 --- /dev/null +++ b/src/main/kotlin/data/repository/impl/FakeCourseMembersRepository.kt @@ -0,0 +1,9 @@ +package data.repository.impl + +import data.repository.CourseMembersRepository + +class FakeCourseMembersRepository : CourseMembersRepository { + override fun save() { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/src/main/kotlin/data/repository/impl/FakeCourseTakingApplicationsHistoryRepository.kt b/src/main/kotlin/data/repository/impl/FakeCourseTakingApplicationsHistoryRepository.kt new file mode 100644 index 0000000..88933ca --- /dev/null +++ b/src/main/kotlin/data/repository/impl/FakeCourseTakingApplicationsHistoryRepository.kt @@ -0,0 +1,17 @@ +package data.repository.impl + +import data.repository.CourseTakingApplicationsHistoryRepository + +class FakeCourseTakingApplicationsHistoryRepository : CourseTakingApplicationsHistoryRepository { + override suspend fun findAll() { + TODO("Not yet implemented") + } + + override suspend fun delete() { + TODO("Not yet implemented") + } + + override suspend fun save() { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/src/main/kotlin/data/repository/impl/FakeCourseTakingApplicationsRepository.kt b/src/main/kotlin/data/repository/impl/FakeCourseTakingApplicationsRepository.kt new file mode 100644 index 0000000..63cf1a4 --- /dev/null +++ b/src/main/kotlin/data/repository/impl/FakeCourseTakingApplicationsRepository.kt @@ -0,0 +1,15 @@ +package data.repository.impl + +import data.repository.CourseTakingApplicationListsRepository +import domain.entity.CourseTakingApplicationList +import domain.entity.StudentId + +class FakeCourseTakingApplicationsRepository : CourseTakingApplicationListsRepository { + override suspend fun findByStudentId(studentId: StudentId): CourseTakingApplicationList { + TODO("Not yet implemented") + } + + override suspend fun save(courseTakingApplicationList: CourseTakingApplicationList) { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/src/main/kotlin/data/repository/impl/FakeCoursesRepository.kt b/src/main/kotlin/data/repository/impl/FakeCoursesRepository.kt new file mode 100644 index 0000000..b1a5e66 --- /dev/null +++ b/src/main/kotlin/data/repository/impl/FakeCoursesRepository.kt @@ -0,0 +1,9 @@ +package data.repository.impl + +import data.repository.CoursesRepository + +class FakeCoursesRepository : CoursesRepository { + override suspend fun findAll() { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/src/main/kotlin/data/repository/impl/StudentsRepository.kt b/src/main/kotlin/data/repository/impl/StudentsRepository.kt new file mode 100644 index 0000000..69b6967 --- /dev/null +++ b/src/main/kotlin/data/repository/impl/StudentsRepository.kt @@ -0,0 +1,9 @@ +package data.repository.impl + +import data.repository.StudentsRepository + +class FakeStudentsRepository : StudentsRepository { + override suspend fun findById() { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/src/main/kotlin/domain/CourseTakingApplication.kt b/src/main/kotlin/domain/CourseTakingApplication.kt deleted file mode 100644 index 47fa5cd..0000000 --- a/src/main/kotlin/domain/CourseTakingApplication.kt +++ /dev/null @@ -1,13 +0,0 @@ -package domain - -typealias CourseTakingApplicationId = Identifier - -data class CourseTakingApplication( - val id: CourseTakingApplicationId, - val courseId: String, - val Status: Status -) - -enum class Status{ - UNCONFIRMED,CONFIRMED -} \ No newline at end of file diff --git a/src/main/kotlin/domain/CourseTakingApplicationList.kt b/src/main/kotlin/domain/CourseTakingApplicationList.kt deleted file mode 100644 index 863fd60..0000000 --- a/src/main/kotlin/domain/CourseTakingApplicationList.kt +++ /dev/null @@ -1,7 +0,0 @@ -package domain - -class CourseTakingApplicationList() { - fun getCourseTakingApplicationList(userId: String): List = TODO() - fun createCourseTakingApplication(application: CourseTakingApplication): Nothing = TODO() - fun deleteCourseTakingApplication(applicationId: String): Nothing = TODO() -} \ No newline at end of file diff --git a/src/main/kotlin/domain/CourseTakingManager.kt b/src/main/kotlin/domain/CourseTakingManager.kt deleted file mode 100644 index dc91e17..0000000 --- a/src/main/kotlin/domain/CourseTakingManager.kt +++ /dev/null @@ -1,11 +0,0 @@ -package domain - -class CourseTakingManager { - private val FirstServedState :Boolean = TODO("先着申請に空きがあるのかどうか") - - suspend fun applyCourseTaking(course:CourseId):Nothing = TODO("Async " + - "userからidを取ってくる" + - "CourseTakingApplicationを作成する(DBとの通信はListがする?)") - - fun cancenCourseTaking(courseTakingApplicationId: CourseTakingApplicationId):Nothing = TODO() -} \ No newline at end of file diff --git a/src/main/kotlin/domain/Hub.kt b/src/main/kotlin/domain/Hub.kt new file mode 100644 index 0000000..436834d --- /dev/null +++ b/src/main/kotlin/domain/Hub.kt @@ -0,0 +1,9 @@ +package domain + +interface IHub { + +} + +class Hub: IHub { + +} \ No newline at end of file diff --git a/src/main/kotlin/domain/Course.kt b/src/main/kotlin/domain/entity/Course.kt similarity index 76% rename from src/main/kotlin/domain/Course.kt rename to src/main/kotlin/domain/entity/Course.kt index ff1d2b9..33e0932 100644 --- a/src/main/kotlin/domain/Course.kt +++ b/src/main/kotlin/domain/entity/Course.kt @@ -1,4 +1,6 @@ -package domain +package domain.entity + +import domain.entity.common.Identifier typealias CourseId = Identifier class Course( @@ -7,7 +9,7 @@ class Course( val capacity: Int ) { - fun getId():CourseId {return id} + fun getId(): CourseId {return id} fun getName():String {return name} fun getCapacity():Int{return capacity} diff --git a/src/main/kotlin/domain/CourseList.kt b/src/main/kotlin/domain/entity/CourseList.kt similarity index 76% rename from src/main/kotlin/domain/CourseList.kt rename to src/main/kotlin/domain/entity/CourseList.kt index bb85180..ae6fe29 100644 --- a/src/main/kotlin/domain/CourseList.kt +++ b/src/main/kotlin/domain/entity/CourseList.kt @@ -1,4 +1,4 @@ -package domain +package domain.entity class CourseList() { fun getCourseList(): List = TODO() diff --git a/src/main/kotlin/domain/entity/CourseTakingApplication.kt b/src/main/kotlin/domain/entity/CourseTakingApplication.kt new file mode 100644 index 0000000..cfb960f --- /dev/null +++ b/src/main/kotlin/domain/entity/CourseTakingApplication.kt @@ -0,0 +1,44 @@ +package domain.entity + +import domain.entity.common.Identifier +import java.util.UUID + +typealias CourseTakingApplicationId = Identifier + +class CourseTakingApplication( + id: CourseTakingApplicationId, + courseId: CourseId, + status: Status +) { + private val _id = id + private val _courseId = courseId + private var _status = status + + fun getId(): CourseTakingApplicationId { + return _id + } + + fun getCourseId(): CourseId { + return _courseId + } + + fun getStatus(): Status { + return _status + } + + /*登録される*/ + fun confirm(){ + _status = Status.UNCONFIRMED + } + + /*抽選で落選する*/ + fun invalidate(){ + _status = Status.INVALIDATED + } + + +} + +enum class Status { + UNCONFIRMED, CONFIRMED, INVALIDATED +} \ No newline at end of file diff --git a/src/main/kotlin/domain/entity/CourseTakingApplicationList.kt b/src/main/kotlin/domain/entity/CourseTakingApplicationList.kt new file mode 100644 index 0000000..0e1e16d --- /dev/null +++ b/src/main/kotlin/domain/entity/CourseTakingApplicationList.kt @@ -0,0 +1,18 @@ +package domain.entity + +import java.util.* + +class CourseTakingApplicationList( + studentId: StudentId +) { + private var _courseTakingApplicationList = mutableListOf() + fun createCourseTakingApplication(courseTakingApplicationId: CourseTakingApplicationId, courseId: CourseId){ + val newApplication = CourseTakingApplication(courseTakingApplicationId, courseId, Status.UNCONFIRMED) + _courseTakingApplicationList.add(newApplication) + } + fun deleteCourseTakingApplication(courseTakingApplicationId: CourseTakingApplicationId){ + _courseTakingApplicationList.removeIf { courseTakingApplication -> + courseTakingApplication.getId() == courseTakingApplicationId + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/domain/User.kt b/src/main/kotlin/domain/entity/User.kt similarity index 60% rename from src/main/kotlin/domain/User.kt rename to src/main/kotlin/domain/entity/User.kt index 6a58a8a..8df11ab 100644 --- a/src/main/kotlin/domain/User.kt +++ b/src/main/kotlin/domain/entity/User.kt @@ -1,4 +1,6 @@ -package domain +package domain.entity + +import domain.entity.common.Identifier typealias StudentId = Identifier @@ -9,8 +11,8 @@ class Student( val id: StudentId, val name: String ): User() { - fun getId(): StudentId{ + fun getId(): StudentId { return id } } -class Teacher():User() \ No newline at end of file +class Teacher(): User() \ No newline at end of file diff --git a/src/main/kotlin/domain/Identifier.kt b/src/main/kotlin/domain/entity/common/Identifier.kt similarity index 65% rename from src/main/kotlin/domain/Identifier.kt rename to src/main/kotlin/domain/entity/common/Identifier.kt index e7f58c6..a2c1f8e 100644 --- a/src/main/kotlin/domain/Identifier.kt +++ b/src/main/kotlin/domain/entity/common/Identifier.kt @@ -1,4 +1,4 @@ -package domain +package domain.entity.common data class Identifier(val raw: RawT) diff --git a/src/main/kotlin/domain/courseTakingHub.kt b/src/main/kotlin/domain/entity/courseTakingHub.kt similarity index 94% rename from src/main/kotlin/domain/courseTakingHub.kt rename to src/main/kotlin/domain/entity/courseTakingHub.kt index 62e99ed..57fc869 100644 --- a/src/main/kotlin/domain/courseTakingHub.kt +++ b/src/main/kotlin/domain/entity/courseTakingHub.kt @@ -1,4 +1,4 @@ -package domain +package domain.entity interface CourseTakingHub{ diff --git a/src/main/kotlin/domain/CourseRegistrationManager.kt b/src/main/kotlin/domain/service/CourseRegistrationService.kt similarity index 57% rename from src/main/kotlin/domain/CourseRegistrationManager.kt rename to src/main/kotlin/domain/service/CourseRegistrationService.kt index d9ac138..c875542 100644 --- a/src/main/kotlin/domain/CourseRegistrationManager.kt +++ b/src/main/kotlin/domain/service/CourseRegistrationService.kt @@ -1,10 +1,10 @@ -package domain +package domain.service -class CourseRegistrationManager { +import domain.entity.CourseTakingApplication + +interface CourseRegistrationService { fun drawing(courseTakingApplicationList: List): List - = TODO("抽選") - fun registerMembers(courseTakingApplicationList: List):Nothing = - TODO("登録する") + fun registerMembers(courseTakingApplicationList: List) } \ No newline at end of file diff --git a/src/main/kotlin/domain/service/CourseTakingApplicationService.kt b/src/main/kotlin/domain/service/CourseTakingApplicationService.kt new file mode 100644 index 0000000..20678cf --- /dev/null +++ b/src/main/kotlin/domain/service/CourseTakingApplicationService.kt @@ -0,0 +1,13 @@ +package domain.service + +import domain.entity.CourseId +import domain.entity.CourseTakingApplicationId +import domain.entity.StudentId +import org.http4k.core.Request +interface CourseTakingApplicationService { + val firstServedState :Boolean + suspend fun applyCourseTaking(courseTakingApplicationId: CourseTakingApplicationId, studentId:StudentId, courseId: CourseId) + + suspend fun cancelCourseTaking(studentId:StudentId,courseTakingApplicationId: CourseTakingApplicationId) + +} \ No newline at end of file diff --git a/src/main/kotlin/domain/service/impl/CourseTakingApplicationServiceImpl.kt b/src/main/kotlin/domain/service/impl/CourseTakingApplicationServiceImpl.kt new file mode 100644 index 0000000..b7f55d3 --- /dev/null +++ b/src/main/kotlin/domain/service/impl/CourseTakingApplicationServiceImpl.kt @@ -0,0 +1,41 @@ +package domain.service.impl + +import data.repository.CourseTakingApplicationListsRepository +import domain.entity.* +import domain.service.CourseTakingApplicationService +import org.http4k.core.Request + +/* +* 履修の申請に関する機能を提供するクラス +* +* */ +class CourseTakingApplicationServiceImpl( + val repository: CourseTakingApplicationListsRepository +) : CourseTakingApplicationService { + + override val firstServedState: Boolean + get() = TODO("Not yet implemented") + + override suspend fun applyCourseTaking( + courseTakingApplicationId: CourseTakingApplicationId, + studentId: StudentId, + courseId: CourseId + ) { + val courseTakingApplicationList = getCourseTakingApplicationList(studentId) + courseTakingApplicationList.createCourseTakingApplication(courseTakingApplicationId, courseId) + repository.save(courseTakingApplicationList) + } + + override suspend fun cancelCourseTaking( + studentId: StudentId, + courseTakingApplicationId: CourseTakingApplicationId + ) { + val courseTakingApplicationList = getCourseTakingApplicationList(studentId) + courseTakingApplicationList.deleteCourseTakingApplication(courseTakingApplicationId) + repository.save(courseTakingApplicationList) + } + + private suspend fun getCourseTakingApplicationList(studentId: StudentId): CourseTakingApplicationList { + return repository.findByStudentId(studentId) + } +} \ No newline at end of file diff --git a/src/main/kotlin/webServer/Main.kt b/src/main/kotlin/webServer/Main.kt index 0d2d68f..df23613 100644 --- a/src/main/kotlin/webServer/Main.kt +++ b/src/main/kotlin/webServer/Main.kt @@ -1,19 +1,12 @@ package webServer -import commands.CourseTakingApplicationCommandHandler -import domain.CourseTakingApplicationHub -import domain.CourseTakingHub -import jdk.internal.org.jline.utils.Colors.s -import org.http4k.server.Jetty -import org.http4k.server.asServer -import java.util.* - fun main(args: Array) { - val commandHandler = CourseTakingApplicationCommandHandler() +/* val hub = CourseTakingApplicationHub( commandHandler) CourseTaking(hub).asServer(Jetty(8080)).start() +*/ println("Server started at http://localhost:8080") diff --git a/src/main/kotlin/webServer/Routes.kt b/src/main/kotlin/webServer/Routes.kt index 8c96d24..94f8e46 100644 --- a/src/main/kotlin/webServer/Routes.kt +++ b/src/main/kotlin/webServer/Routes.kt @@ -1,69 +1,139 @@ package webServer -import domain.CourseTakingApplication -import domain.CourseTakingHub -import domain.User +import domain.entity.CourseId +import domain.entity.CourseTakingApplication +import domain.entity.CourseTakingApplicationId +import domain.entity.StudentId +import domain.service.CourseTakingApplicationService +import kotlinx.coroutines.* import org.http4k.core.* -import org.http4k.core.body.form import org.http4k.routing.bind import org.http4k.routing.path import org.http4k.routing.routes +import java.util.* +import org.http4k.core.ContentType.Companion.APPLICATION_JSON +import org.http4k.core.Status.Companion.OK /* * TODO: * 抽選、先着管理、登録、科目取得 * */ -class CourseTaking(val hub: CourseTakingHub): HttpHandler { +class CourseTakingApplication(val courseTakingApplicationService: CourseTakingApplicationService) : HttpHandler { override fun invoke(request: Request): Response = httpHandler(request) val httpHandler = routes( "/ping" bind Method.GET to { Response(Status.OK) }, + /*QUERY*/ + "/course" bind Method.GET to ::getCourses, "/application/{user}" bind Method.GET to ::getApplications, + /*courseTaking*/ "/application/{user}" bind Method.POST to ::applyCourseTaking, "/application/{user}" bind Method.DELETE to ::cancelCourseTaking, - "/course" bind Method.GET to ::getCourses, - "/course/{courseId}" bind Method.GET to ::drawing, - "/course/{courseId}" bind Method.PATCH to ::updateCourseCapacity, + /*courseRegistration*/ + "/course/{courseId}" bind Method.GET to ::drawAndRegisterCourseMembers, + "/course/{courseId}" bind Method.PATCH to ::addCourseCapacity, "/course/{courseId}" bind Method.POST to ::registerCourseMembers, ) - private fun getCourses(request: Request): Response{ + private fun getCourses(request: Request): Response { TODO("履修可能な科目を返す") + /*requestから学年,専攻,学期,曜日,時限を取得*/ + + + /*responseを返す*/ } //Request -> User -> Result -> Response private fun getApplications(request: Request): Response { TODO() + /*requestからuserを取得*/ + + + /*responseを返す*/ } //Request -> User,Application -> Result -> Response + @OptIn(ExperimentalCoroutinesApi::class) private fun applyCourseTaking(request: Request): Response { - TODO() + val result = CoroutineScope(Dispatchers.IO).async { + runCatching { + /*requestからuser, applicationを取得*/ + val studentId: StudentId = StudentId(request.path("studentId") ?: "") + val courseId: CourseId = CourseId(request.path("courseId") ?: "") + + val courseTakingApplicationId = CourseTakingApplicationId(UUID.randomUUID().toString()) + courseTakingApplicationService.applyCourseTaking( + courseTakingApplicationId, + studentId, + courseId + ) + + } + } + + /*responseを返す*/ + + return if(result.getCompleted().isSuccess){ + JsonData("Successed").toOKResponse() + }else{ + /*TODO: エラーハンドリング*/ + return Response(Status.BAD_REQUEST) + } } //Request -> User,Application -> Result -> Response private fun cancelCourseTaking(request: Request): Response { - TODO() + TODO("requestからcourseI") + /*requestからapplicationIdを取得*/ + + + /*responseを返す*/ } - private fun drawing(request: Request): Response { - TODO() + private fun drawAndRegisterCourseMembers(request: Request): Response { + TODO( + "requestからcourseidを取得" + + "courseIdからcourseTakingApplicationリストを取得" + + "抽選する" + + "結果を返す" + ) + /*requestからcourseIdを取得*/ + + /*courseIdからcourseTakingApplicationリストを取得*/ + + /*抽選する*/ + + /*結果を返す*/ } - private fun updateCourseCapacity(request: Request): Response { + private fun addCourseCapacity(request: Request): Response { TODO() + /*requestから追加するcapacityを取得*/ + + /**/ + + /*responseを返す*/ } private fun registerCourseMembers(request: Request): Response { TODO() + /*requestからcourseIdを取得*/ + + /*対応するcourseに対して登録する*/ + + /*responseを返す*/ } + data class JsonData(val raw: String) { + fun toOKResponse(): Response { + return Response(OK).body(raw).header("Content-Type", APPLICATION_JSON.toHeaderValue()) + } + } - data class JsonData(val raw:String) fun convertApplicationListToJson(list: List): JsonData { /*TODO: serialize list*/ return JsonData("nothing") @@ -73,6 +143,4 @@ class CourseTaking(val hub: CourseTakingHub): HttpHandler { Response(Status.OK).body(data.raw) - } -