From 3e92de160992292c18589f05261e2295a9c54d2b Mon Sep 17 00:00:00 2001 From: Raymond Yang Date: Mon, 26 Jun 2023 13:52:28 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=A6=E4=BD=9CCRUD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pcredive/database/dto/MemberDto.kt | 40 +++++++ .../pcredive/database/dto/MemberRecordDto.kt | 49 ++++++++ .../pcredive/database/model/Member.kt | 18 +++ .../pcredive/database/model/MemberRecord.kt | 26 +++++ .../pcredive/database/model/RecordData.kt | 9 ++ .../database/model/UpdateMemberRecord.kt | 16 +++ .../database/service/MemberRecordService.kt | 53 +++++++++ .../database/service/MemberService.kt | 52 +++++++++ .../pcredive/plugins/MemberRecordRouting.kt | 108 +++++++++++++++++- .../pcredive/plugins/MemberRouting.kt | 69 ++++++++++- .../pcredive/plugins/Serialization.kt | 6 +- src/main/resources/application.conf | 2 +- .../com/ray650128/pcredive/ApplicationTest.kt | 5 +- 13 files changed, 446 insertions(+), 7 deletions(-) create mode 100644 src/main/kotlin/com/ray650128/pcredive/database/dto/MemberDto.kt create mode 100644 src/main/kotlin/com/ray650128/pcredive/database/dto/MemberRecordDto.kt create mode 100644 src/main/kotlin/com/ray650128/pcredive/database/model/Member.kt create mode 100644 src/main/kotlin/com/ray650128/pcredive/database/model/MemberRecord.kt create mode 100644 src/main/kotlin/com/ray650128/pcredive/database/model/RecordData.kt create mode 100644 src/main/kotlin/com/ray650128/pcredive/database/model/UpdateMemberRecord.kt create mode 100644 src/main/kotlin/com/ray650128/pcredive/database/service/MemberRecordService.kt create mode 100644 src/main/kotlin/com/ray650128/pcredive/database/service/MemberService.kt diff --git a/src/main/kotlin/com/ray650128/pcredive/database/dto/MemberDto.kt b/src/main/kotlin/com/ray650128/pcredive/database/dto/MemberDto.kt new file mode 100644 index 0000000..c4d1a01 --- /dev/null +++ b/src/main/kotlin/com/ray650128/pcredive/database/dto/MemberDto.kt @@ -0,0 +1,40 @@ +package com.ray650128.pcredive.database.dto + +import com.ray650128.pcredive.database.model.Member +import kotlinx.serialization.Serializable + +@Serializable +data class MemberDto( + var _id: String? = null, + var playerName: String, + var nickName: String, + var discordID: String, + var uid: String, + var leave: Boolean = false, + var createAt: Long? = null, + var updatedAt: Long? = null +) + +fun Member.toDto(): MemberDto { + return MemberDto( + _id = this._id.toString(), + playerName = this.playerName, + nickName = this.nickName, + discordID = this.discordID, + uid = this.uid, + leave = this.leave, + createAt = this.createAt, + updatedAt = this.updatedAt + ) +} + +fun MemberDto.toMember(): Member = + Member( + playerName = this.playerName, + nickName = this.nickName, + discordID = this.discordID, + uid = this.uid, + leave = this.leave, + createAt = this.createAt, + updatedAt = this.updatedAt + ) \ No newline at end of file diff --git a/src/main/kotlin/com/ray650128/pcredive/database/dto/MemberRecordDto.kt b/src/main/kotlin/com/ray650128/pcredive/database/dto/MemberRecordDto.kt new file mode 100644 index 0000000..fc3ebe1 --- /dev/null +++ b/src/main/kotlin/com/ray650128/pcredive/database/dto/MemberRecordDto.kt @@ -0,0 +1,49 @@ +package com.ray650128.pcredive.database.dto + +import com.ray650128.pcredive.database.model.Member +import com.ray650128.pcredive.database.model.MemberRecord +import com.ray650128.pcredive.database.model.Record +import com.ray650128.pcredive.database.service.MemberService +import kotlinx.serialization.Serializable + +@Serializable +data class MemberRecordDto( + var _id: String? = null, + var member: Member? = null, + var record1: Record, + var record1c: Record, + var record2: Record, + var record2c: Record, + var record3: Record, + var record3c: Record, + var createdAt: Long?, + var updatedAt: Long? +) + +fun MemberRecord.toDto(): MemberRecordDto { + return MemberRecordDto( + _id = this._id.toString(), + member = MemberService.findById(this.memberId.toString()), + record1 = this.record1, + record1c = this.record1c, + record2 = this.record2, + record2c = this.record2c, + record3 = this.record3, + record3c = this.record3c, + createdAt = this.createdAt, + updatedAt = this.updatedAt + ) +} + +fun MemberRecordDto.toMemberRecord(): MemberRecord = + MemberRecord( + memberId = this.member?._id, + record1 = this.record1, + record1c = this.record1c, + record2 = this.record2, + record2c = this.record2c, + record3 = this.record3, + record3c = this.record3c, + createdAt = this.createdAt, + updatedAt = this.updatedAt + ) \ No newline at end of file diff --git a/src/main/kotlin/com/ray650128/pcredive/database/model/Member.kt b/src/main/kotlin/com/ray650128/pcredive/database/model/Member.kt new file mode 100644 index 0000000..c6ed645 --- /dev/null +++ b/src/main/kotlin/com/ray650128/pcredive/database/model/Member.kt @@ -0,0 +1,18 @@ +package com.ray650128.pcredive.database.model + +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import org.litote.kmongo.Id +import org.litote.kmongo.newId + +@Serializable +data class Member( + @Contextual var _id: Id = newId(), + var playerName: String, + var nickName: String, + var discordID: String, + var uid: String, + var leave: Boolean = false, + var createAt: Long? = null, + var updatedAt: Long? = null +) diff --git a/src/main/kotlin/com/ray650128/pcredive/database/model/MemberRecord.kt b/src/main/kotlin/com/ray650128/pcredive/database/model/MemberRecord.kt new file mode 100644 index 0000000..42c5aa0 --- /dev/null +++ b/src/main/kotlin/com/ray650128/pcredive/database/model/MemberRecord.kt @@ -0,0 +1,26 @@ +package com.ray650128.pcredive.database.model + +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import org.litote.kmongo.Id +import org.litote.kmongo.newId + +@Serializable +data class MemberRecord( + @Contextual var _id: Id = newId(), + @Contextual var memberId: Id? = null, + var record1: Record = Record("未出"), + var record1c: Record = Record("未出"), + var record2: Record = Record("未出"), + var record2c: Record = Record("未出"), + var record3: Record = Record("未出"), + var record3c: Record = Record("未出"), + var createdAt: Long? = null, + var updatedAt: Long? = null +) + +@Serializable +data class Record( + var boss: String, + var damage: Int? = null +) diff --git a/src/main/kotlin/com/ray650128/pcredive/database/model/RecordData.kt b/src/main/kotlin/com/ray650128/pcredive/database/model/RecordData.kt new file mode 100644 index 0000000..b1df965 --- /dev/null +++ b/src/main/kotlin/com/ray650128/pcredive/database/model/RecordData.kt @@ -0,0 +1,9 @@ +package com.ray650128.pcredive.database.model + +import kotlinx.serialization.Serializable + +@Serializable +data class RecordData( + val member: Member, + var record: MemberRecord +) diff --git a/src/main/kotlin/com/ray650128/pcredive/database/model/UpdateMemberRecord.kt b/src/main/kotlin/com/ray650128/pcredive/database/model/UpdateMemberRecord.kt new file mode 100644 index 0000000..cad08be --- /dev/null +++ b/src/main/kotlin/com/ray650128/pcredive/database/model/UpdateMemberRecord.kt @@ -0,0 +1,16 @@ +package com.ray650128.pcredive.database.model + +import kotlinx.serialization.Serializable + +@Serializable +data class UpdateMemberRecord( + var memberId: String, + var record1: Record = Record("未出"), + var record1c: Record = Record("未出"), + var record2: Record = Record("未出"), + var record2c: Record = Record("未出"), + var record3: Record = Record("未出"), + var record3c: Record = Record("未出"), + var createdAt: Long? = null, + var updatedAt: Long? = null +) diff --git a/src/main/kotlin/com/ray650128/pcredive/database/service/MemberRecordService.kt b/src/main/kotlin/com/ray650128/pcredive/database/service/MemberRecordService.kt new file mode 100644 index 0000000..4cbaa1e --- /dev/null +++ b/src/main/kotlin/com/ray650128/pcredive/database/service/MemberRecordService.kt @@ -0,0 +1,53 @@ +package com.ray650128.pcredive.database.service + +import com.ray650128.pcredive.database.model.Member +import com.ray650128.pcredive.database.model.MemberRecord +import org.bson.types.ObjectId +import org.litote.kmongo.* +import org.litote.kmongo.id.toId + +object MemberRecordService { + private val client = KMongo.createClient("mongodb://ray650128:Zx650128!@www.ray650128.com:27017") + private val database = client.getDatabase("pc_re_dive_clan_battle") + private val recordCollection = database.getCollection() + + fun create(record: MemberRecord): Id { + recordCollection.insertOne(record) + return record._id + } + + fun findById(id: String): MemberRecord? { + val bsonId: Id = ObjectId(id).toId() + return recordCollection.findOne(MemberRecord::_id eq bsonId) + } + + fun findByTimeBetween(start: Long, end: Long): List { + return recordCollection.find(MemberRecord::createdAt gte start, MemberRecord::createdAt lt end).toList() + } + + fun findByOwnerId(id: String): List { + val bsonId: Id = ObjectId(id).toId() + return recordCollection.find(MemberRecord::memberId eq bsonId).toList() + } + + fun updateById(id: String, request: MemberRecord): Boolean = + findById(id)?.let { record -> + val updateResult = recordCollection.replaceOne( + record.copy( + record1 = request.record1, + record1c = request.record1c, + record2 = request.record2, + record2c = request.record2c, + record3 = request.record3, + record3c = request.record3c, + updatedAt = System.currentTimeMillis() + ) + ) + updateResult.modifiedCount == 1L + } ?: false + + fun deleteById(id: String): Boolean { + val deleteResult = recordCollection.deleteOneById(ObjectId(id)) + return deleteResult.deletedCount == 1L + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/ray650128/pcredive/database/service/MemberService.kt b/src/main/kotlin/com/ray650128/pcredive/database/service/MemberService.kt new file mode 100644 index 0000000..944ee4e --- /dev/null +++ b/src/main/kotlin/com/ray650128/pcredive/database/service/MemberService.kt @@ -0,0 +1,52 @@ +package com.ray650128.pcredive.database.service + +import com.ray650128.pcredive.database.model.Member +import org.bson.types.ObjectId +import org.litote.kmongo.* +import org.litote.kmongo.id.toId + +object MemberService { + private val client = KMongo.createClient("mongodb://ray650128:Zx650128!@www.ray650128.com:27017") + private val database = client.getDatabase("pc_re_dive_clan_battle") + private val memberCollection = database.getCollection() + + fun create(member: Member): Id { + memberCollection.insertOne(member) + return member._id + } + + //fun findAll(): List = memberCollection.find().toList() + + fun findAll(isLeave: Boolean? = null): List { + return if (isLeave == null) { + memberCollection.find().toList() + } else { + memberCollection.find(Member::leave eq isLeave).toList() + } + } + + fun findById(id: String): Member? { + val bsonId: Id = ObjectId(id).toId() + return memberCollection.findOne(Member::_id eq bsonId) + } + + fun updateById(id: String, request: Member): Boolean = + findById(id)?.let { member -> + val updateResult = memberCollection.replaceOne( + member.copy( + playerName = request.playerName, + nickName = request.nickName, + discordID = request.discordID, + uid = request.uid, + leave = request.leave, + updatedAt = request.updatedAt + ) + ) + updateResult.modifiedCount == 1L + } ?: false + + fun deleteById(id: String): Boolean { + val deleteResult = memberCollection.deleteOneById(ObjectId(id)) + return deleteResult.deletedCount == 1L + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/ray650128/pcredive/plugins/MemberRecordRouting.kt b/src/main/kotlin/com/ray650128/pcredive/plugins/MemberRecordRouting.kt index 886ff8b..3a813ef 100644 --- a/src/main/kotlin/com/ray650128/pcredive/plugins/MemberRecordRouting.kt +++ b/src/main/kotlin/com/ray650128/pcredive/plugins/MemberRecordRouting.kt @@ -1,15 +1,119 @@ package com.ray650128.pcredive.plugins +import com.ray650128.pcredive.database.dto.toDto +import com.ray650128.pcredive.database.model.MemberRecord +import com.ray650128.pcredive.database.model.Record +import com.ray650128.pcredive.database.model.RecordData +import com.ray650128.pcredive.database.model.UpdateMemberRecord +import com.ray650128.pcredive.database.service.MemberRecordService +import com.ray650128.pcredive.database.service.MemberService +import io.ktor.http.* import io.ktor.serialization.kotlinx.json.* import io.ktor.server.plugins.contentnegotiation.* import io.ktor.server.response.* import io.ktor.server.application.* +import io.ktor.server.request.* import io.ktor.server.routing.* +import io.ktor.server.util.* +import kotlinx.coroutines.coroutineScope +import org.litote.kmongo.toId +import java.util.* fun Application.configureMemberRecordRouting() { routing { - get("/json/kotlinx-serialization") { - call.respond(mapOf("hello" to "world")) + route("/api") { + route("/record") { + get { + val calendar = Calendar.getInstance().apply { + timeInMillis = System.currentTimeMillis() - (5 * 60 * 60 * 1000) // 由於公連換日為每日早上5:00,因此減去時差 + } + val records = getData(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH)) + call.respond(HttpStatusCode.OK, records) + } + post("/{id}") { + val id = call.parameters.getOrFail("id") + val record = call.receive() + val member = MemberService.findById(id) ?: run { + call.respond(HttpStatusCode.NotFound) + return@post + } + record.apply { + memberId = member._id + createdAt = System.currentTimeMillis() + updatedAt = System.currentTimeMillis() + } + MemberRecordService.create(record).let { + call.respond(HttpStatusCode.OK, record) + } + } + get("/{year}/{month}/{day}") { + val year = call.parameters.getOrFail("year").toInt() + val month = call.parameters.getOrFail("month").toInt() - 1 + val day = call.parameters.getOrFail("day").toInt() + val records = getData(year, month, day) + call.respond(HttpStatusCode.OK, records) + } + get("/{id}") { + // Show an article with a specific id + val id = call.parameters.getOrFail("id") + val record = MemberRecordService.findById(id)?.toDto() ?: run { + call.respond(HttpStatusCode.NotFound) + return@get + } + call.respond(HttpStatusCode.OK, record) + } + put("/{id}") { + val id = call.parameters.getOrFail("id") + val record = call.receive() + val oldData = MemberRecordService.findById(id) ?: run { + call.respond(HttpStatusCode.NotFound) + return@put + } + oldData.apply { + record1 = record.record1 + record1c = record.record1c + record2 = record.record2 + record2c = record.record2c + record3 = record.record3 + record3c = record.record3c + createdAt = System.currentTimeMillis() + updatedAt = System.currentTimeMillis() + } + MemberRecordService.updateById(id, oldData) + call.respond(HttpStatusCode.OK, record) + } + } } } } + +fun getData(year: Int, month: Int, day: Int): List { + val calendar = Calendar.getInstance().apply { + set(Calendar.YEAR, year) + set(Calendar.MONTH, month) + set(Calendar.DAY_OF_MONTH, day) + } + val startTime = calendar.apply { + set(Calendar.HOUR_OF_DAY, 5) + set(Calendar.MINUTE, 0) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + }.timeInMillis + val endTime = startTime + 86399000L + // Show a list of articles + val records = ArrayList() + val memberList = MemberService.findAll() + memberList.forEach { member -> + records.add( + RecordData(member = member, MemberRecord()) + ) + } + val recordList = MemberRecordService.findByTimeBetween(startTime, endTime) + recordList.forEach { record -> + val player = MemberService.findById(record.memberId.toString()) + records.firstOrNull { it.member == player }?.let { playerRecord -> + playerRecord.record = record + } + } + return records +} diff --git a/src/main/kotlin/com/ray650128/pcredive/plugins/MemberRouting.kt b/src/main/kotlin/com/ray650128/pcredive/plugins/MemberRouting.kt index d70d27a..b31cf7c 100644 --- a/src/main/kotlin/com/ray650128/pcredive/plugins/MemberRouting.kt +++ b/src/main/kotlin/com/ray650128/pcredive/plugins/MemberRouting.kt @@ -1,15 +1,80 @@ package com.ray650128.pcredive.plugins +import com.ray650128.pcredive.database.dto.toDto +import com.ray650128.pcredive.database.model.Member +import com.ray650128.pcredive.database.service.MemberService +import io.ktor.http.* import io.ktor.serialization.kotlinx.json.* import io.ktor.server.plugins.contentnegotiation.* import io.ktor.server.response.* import io.ktor.server.application.* +import io.ktor.server.request.* import io.ktor.server.routing.* +import io.ktor.server.util.* +import kotlinx.coroutines.coroutineScope fun Application.configureMemberRouting() { routing { - get("/json/kotlinx-serialization") { - call.respond(mapOf("hello" to "world")) + route("/api") { + route("/member") { + get("/all") { + // 顯示所有登錄的成員資料 + coroutineScope { + val memberList = MemberService.findAll() + call.respond(HttpStatusCode.OK, memberList) + } + } + get("/{id}") { + val id = call.parameters.getOrFail("id") + val member = MemberService.findById(id) ?: run { + call.respond(HttpStatusCode.NotFound) + return@get + } + call.respond(HttpStatusCode.OK, member) + } + post("/new") { + // Save an article + val formParameters = call.receiveParameters() + val _playerName = formParameters.getOrFail("playerName") + val _nickName = formParameters.getOrFail("nickName") + val _discordID = formParameters.getOrFail("discordID") + val _uid = formParameters.getOrFail("uid") + val _createAt = System.currentTimeMillis() + val member = Member( + playerName = _playerName, + nickName = _nickName, + discordID = _discordID, + uid = _uid, + createAt = _createAt, + ) + MemberService.create(member).let { memberId -> + + call.respond(HttpStatusCode.OK, member) + } + } + put("/{id}") { + val id = call.parameters.getOrFail("id") + val formParameters = call.receiveParameters() + coroutineScope { + val _playerName = formParameters.getOrFail("playerName") + val _nickName = formParameters.getOrFail("nickName") + val _discordID = formParameters.getOrFail("discordID") + val _uid = formParameters.getOrFail("uid") + val _leave = (formParameters.getOrFail("leave") == "2") + val _updatedAt = System.currentTimeMillis() + val member = Member( + playerName = _playerName, + nickName = _nickName, + discordID = _discordID, + uid = _uid, + leave = _leave, + updatedAt = _updatedAt, + ) + MemberService.updateById(id, member) + call.respondRedirect("/memberList/$id") + } + } + } } } } diff --git a/src/main/kotlin/com/ray650128/pcredive/plugins/Serialization.kt b/src/main/kotlin/com/ray650128/pcredive/plugins/Serialization.kt index 8bbff14..21cd3ea 100644 --- a/src/main/kotlin/com/ray650128/pcredive/plugins/Serialization.kt +++ b/src/main/kotlin/com/ray650128/pcredive/plugins/Serialization.kt @@ -5,9 +5,13 @@ import io.ktor.server.plugins.contentnegotiation.* import io.ktor.server.response.* import io.ktor.server.application.* import io.ktor.server.routing.* +import kotlinx.serialization.json.Json +import org.litote.kmongo.id.serialization.IdKotlinXSerializationModule fun Application.configureSerialization() { install(ContentNegotiation) { - json() + json( + Json { serializersModule = IdKotlinXSerializationModule } + ) } } diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 41d12cc..b6765d4 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -1,6 +1,6 @@ ktor { deployment { - port = 8080 + port = 10001 port = ${?PORT} } application { diff --git a/src/test/kotlin/com/ray650128/pcredive/ApplicationTest.kt b/src/test/kotlin/com/ray650128/pcredive/ApplicationTest.kt index 28ca3f1..12917d1 100644 --- a/src/test/kotlin/com/ray650128/pcredive/ApplicationTest.kt +++ b/src/test/kotlin/com/ray650128/pcredive/ApplicationTest.kt @@ -11,7 +11,10 @@ class ApplicationTest { @Test fun testRoot() = testApplication { application { - configureRouting() + configureHTTP() + configureSerialization() + configureMemberRouting() + configureMemberRecordRouting() } client.get("/").apply { assertEquals(HttpStatusCode.OK, status)