Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f4c4c6906e | |||
| 0cf0f8c49b | |||
| f8a1328a03 | |||
| f677fdb162 | |||
| abd4c24c83 | |||
| 7c390aebdf | |||
| 7f0d0f4a87 | |||
| 8b20758404 | |||
| 0741d5846b |
@@ -3,6 +3,10 @@ FROM gradle:9.5.1-jdk25 AS builder
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
|
ENV GRADLE_OPTS="-Xmx1536m -XX:MaxMetaspaceSize=512m"
|
||||||
|
ENV NODE_OPTIONS="--max-old-space-size=1536"
|
||||||
|
|
||||||
RUN gradle clean shadowJar --no-daemon
|
RUN gradle clean shadowJar --no-daemon
|
||||||
|
|
||||||
# 運行階段
|
# 運行階段
|
||||||
|
|||||||
+2
-2
@@ -8,11 +8,11 @@ import java.time.Instant
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class MemberDto(
|
data class MemberDto(
|
||||||
var uid: String,
|
@SerialName("uid") var uid: String,
|
||||||
@SerialName("player_name") val playerName: String,
|
@SerialName("player_name") val playerName: String,
|
||||||
@SerialName("discord_name") val discordName: String,
|
@SerialName("discord_name") val discordName: String,
|
||||||
@SerialName("discord_id") val discordID: String,
|
@SerialName("discord_id") val discordID: String,
|
||||||
var leave: Boolean = false,
|
@SerialName("leave") var leave: Boolean,
|
||||||
@SerialName("created_at") var createAt: Long? = null,
|
@SerialName("created_at") var createAt: Long? = null,
|
||||||
@SerialName("updated_at") var updatedAt: Long? = null
|
@SerialName("updated_at") var updatedAt: Long? = null
|
||||||
) {
|
) {
|
||||||
|
|||||||
+46
-5
@@ -1,6 +1,9 @@
|
|||||||
package club.sakunadaisuki.pcrediveclanrecordbackend.database.service
|
package club.sakunadaisuki.pcrediveclanrecordbackend.database.service
|
||||||
|
|
||||||
import club.sakunadaisuki.pcrediveclanrecordbackend.database.dto.BattleRecordDto
|
import club.sakunadaisuki.pcrediveclanrecordbackend.database.dto.BattleRecordDto
|
||||||
|
import club.sakunadaisuki.pcrediveclanrecordbackend.database.dto.MemberDto
|
||||||
|
import club.sakunadaisuki.pcrediveclanrecordbackend.mapper.toEmptyBattleRecordDto
|
||||||
|
import club.sakunadaisuki.pcrediveclanrecordbackend.model.BattleRecord
|
||||||
import com.mongodb.client.MongoCollection
|
import com.mongodb.client.MongoCollection
|
||||||
import com.mongodb.client.MongoDatabase
|
import com.mongodb.client.MongoDatabase
|
||||||
import com.mongodb.client.model.Filters
|
import com.mongodb.client.model.Filters
|
||||||
@@ -8,28 +11,34 @@ import com.mongodb.client.model.Filters.and
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.bson.Document
|
import org.bson.Document
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.time.YearMonth
|
||||||
|
|
||||||
class BattleRecordService(private val database: MongoDatabase) {
|
class BattleRecordService(private val database: MongoDatabase) {
|
||||||
var collection: MongoCollection<Document>
|
var collection: MongoCollection<Document>
|
||||||
|
var memberCollection: MongoCollection<Document>
|
||||||
|
|
||||||
init {
|
init {
|
||||||
database.createCollection("battle_records")
|
database.createCollection("battle_records")
|
||||||
collection = database.getCollection("battle_records")
|
collection = database.getCollection("battle_records")
|
||||||
|
|
||||||
|
database.createCollection("member")
|
||||||
|
memberCollection = database.getCollection("member")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new car
|
// Create new battle record
|
||||||
suspend fun create(data: BattleRecordDto): BattleRecordDto = withContext(Dispatchers.IO) {
|
suspend fun create(data: BattleRecordDto): BattleRecordDto = withContext(Dispatchers.IO) {
|
||||||
val doc = data.toDocument()
|
val doc = data.toDocument()
|
||||||
collection.insertOne(doc)
|
collection.insertOne(doc)
|
||||||
doc.let(BattleRecordDto::fromDocument)
|
doc.let(BattleRecordDto::fromDocument)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read a car
|
// Read a battle record
|
||||||
suspend fun read(date: String): List<BattleRecordDto> = withContext(Dispatchers.IO) {
|
suspend fun read(date: String): List<BattleRecordDto> = withContext(Dispatchers.IO) {
|
||||||
collection.find(Filters.eq("date", date)).toList().map(BattleRecordDto::fromDocument)
|
collection.find(Filters.eq("date", date)).toList().map(BattleRecordDto::fromDocument)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read a car
|
// Read a battle record
|
||||||
suspend fun read(date: String, uid: String): BattleRecordDto? = withContext(Dispatchers.IO) {
|
suspend fun read(date: String, uid: String): BattleRecordDto? = withContext(Dispatchers.IO) {
|
||||||
val filter = and(
|
val filter = and(
|
||||||
Filters.eq("date", date),
|
Filters.eq("date", date),
|
||||||
@@ -38,7 +47,7 @@ class BattleRecordService(private val database: MongoDatabase) {
|
|||||||
collection.find(filter).first()?.let(BattleRecordDto::fromDocument)
|
collection.find(filter).first()?.let(BattleRecordDto::fromDocument)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update a car
|
// Update a battle record
|
||||||
suspend fun update(date: String, data: BattleRecordDto): BattleRecordDto? = withContext(Dispatchers.IO) {
|
suspend fun update(date: String, data: BattleRecordDto): BattleRecordDto? = withContext(Dispatchers.IO) {
|
||||||
val filter = and(
|
val filter = and(
|
||||||
Filters.eq("date", date),
|
Filters.eq("date", date),
|
||||||
@@ -48,7 +57,7 @@ class BattleRecordService(private val database: MongoDatabase) {
|
|||||||
collection.find(filter).first()?.let(BattleRecordDto::fromDocument)
|
collection.find(filter).first()?.let(BattleRecordDto::fromDocument)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete a car
|
// Delete a battle record
|
||||||
suspend fun delete(date: String, uid: String): Document? = withContext(Dispatchers.IO) {
|
suspend fun delete(date: String, uid: String): Document? = withContext(Dispatchers.IO) {
|
||||||
val filter = and(
|
val filter = and(
|
||||||
Filters.eq("date", date),
|
Filters.eq("date", date),
|
||||||
@@ -56,4 +65,36 @@ class BattleRecordService(private val database: MongoDatabase) {
|
|||||||
)
|
)
|
||||||
collection.findOneAndDelete(filter)
|
collection.findOneAndDelete(filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun createTable(date: String): List<BattleRecordDto> = withContext(Dispatchers.IO) {
|
||||||
|
val memberList = memberCollection.find(Filters.eq("leave", false)).toList().map(MemberDto::fromDocument)
|
||||||
|
val emptyBattleRecordList = memberList.map { it.toEmptyBattleRecordDto(date) }
|
||||||
|
collection.insertMany(emptyBattleRecordList.map { it.toDocument() })
|
||||||
|
collection.find(Filters.eq("date", date)).toList().map(BattleRecordDto::fromDocument)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun createTableMonth(date: String): List<List<BattleRecordDto>> = withContext(Dispatchers.IO) {
|
||||||
|
val memberList = memberCollection.find(Filters.eq("leave", false)).toList().map(MemberDto::fromDocument)
|
||||||
|
|
||||||
|
// 1. 指定年份與月份(例如:2026年8月)
|
||||||
|
val dateSplit = date.split("-").map { it.toInt() }
|
||||||
|
val yearMonth = YearMonth.of(dateSplit[0], dateSplit[1])
|
||||||
|
|
||||||
|
// 2. 取得該月最後一天的 LocalDate 物件
|
||||||
|
val lastDayOfMonth = yearMonth.atEndOfMonth()
|
||||||
|
|
||||||
|
// 3. 取得最後 5 天的日期列表(由舊到新排序)
|
||||||
|
val lastFiveDays: List<LocalDate> = (4 downTo 0).map { lastDayOfMonth.minusDays(it.toLong()) }
|
||||||
|
|
||||||
|
// 4. Temp list
|
||||||
|
val tables = mutableListOf<List<BattleRecordDto>>()
|
||||||
|
|
||||||
|
// 5. 寫入資料
|
||||||
|
lastFiveDays.forEach { date ->
|
||||||
|
val emptyBattleRecordList = memberList.map { it.toEmptyBattleRecordDto(date.toString()) }
|
||||||
|
tables.add(emptyBattleRecordList)
|
||||||
|
collection.insertMany(emptyBattleRecordList.map { it.toDocument() })
|
||||||
|
}
|
||||||
|
tables
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-1
@@ -38,7 +38,15 @@ class MemberService(private val database: MongoDatabase) {
|
|||||||
|
|
||||||
// Update a member
|
// Update a member
|
||||||
suspend fun update(uid: String, data: MemberDto): MemberDto? = withContext(Dispatchers.IO) {
|
suspend fun update(uid: String, data: MemberDto): MemberDto? = withContext(Dispatchers.IO) {
|
||||||
collection.findOneAndReplace(Filters.eq("uid", uid), data.toDocument())
|
collection.find(Filters.eq("uid", uid)).first()?.let(MemberDto::fromDocument)?.copy(
|
||||||
|
playerName = data.playerName,
|
||||||
|
discordName = data.discordName,
|
||||||
|
discordID = data.discordID,
|
||||||
|
leave = data.leave,
|
||||||
|
updatedAt = System.currentTimeMillis(),
|
||||||
|
)?.let {
|
||||||
|
collection.findOneAndReplace(Filters.eq("uid", uid), it.toDocument())
|
||||||
|
}
|
||||||
collection.find(Filters.eq("uid", uid)).first()?.let(MemberDto::fromDocument)
|
collection.find(Filters.eq("uid", uid)).first()?.let(MemberDto::fromDocument)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package club.sakunadaisuki.pcrediveclanrecordbackend.mapper
|
package club.sakunadaisuki.pcrediveclanrecordbackend.mapper
|
||||||
|
|
||||||
|
import club.sakunadaisuki.pcrediveclanrecordbackend.database.dto.BattleRecordDto
|
||||||
import club.sakunadaisuki.pcrediveclanrecordbackend.database.dto.MemberDto
|
import club.sakunadaisuki.pcrediveclanrecordbackend.database.dto.MemberDto
|
||||||
import club.sakunadaisuki.pcrediveclanrecordbackend.model.Member
|
import club.sakunadaisuki.pcrediveclanrecordbackend.model.Member
|
||||||
import club.sakunadaisuki.pcrediveclanrecordbackend.model.MemberRequest
|
import club.sakunadaisuki.pcrediveclanrecordbackend.model.MemberRequest
|
||||||
@@ -35,4 +36,15 @@ fun UpdateMemberRequest.toDto(uid: String): MemberDto {
|
|||||||
discordID = discordID,
|
discordID = discordID,
|
||||||
leave = leave,
|
leave = leave,
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun MemberDto.toEmptyBattleRecordDto(date: String): BattleRecordDto {
|
||||||
|
return BattleRecordDto(
|
||||||
|
date = date,
|
||||||
|
uid = uid,
|
||||||
|
playerName = playerName,
|
||||||
|
discordName = discordName,
|
||||||
|
discordID = discordID,
|
||||||
|
attackDetailList = emptyList(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
@@ -1,23 +1,26 @@
|
|||||||
package club.sakunadaisuki.pcrediveclanrecordbackend.model
|
package club.sakunadaisuki.pcrediveclanrecordbackend.model
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class BattleRecord(
|
data class BattleRecord(
|
||||||
val date: String, // yyyy-MM-dd
|
@SerialName("date") val date: String, // yyyy-MM-dd
|
||||||
var uid: String,
|
@SerialName("uid") var uid: String,
|
||||||
@SerialName("player_name") val playerName: String,
|
@SerialName("player_name") val playerName: String,
|
||||||
@SerialName("discord_name") val discordName: String,
|
@SerialName("discord_name") val discordName: String,
|
||||||
@SerialName("discord_id") val discordID: String,
|
@SerialName("discord_id") val discordID: String,
|
||||||
@SerialName("attack_detail_list") val attackDetailList: List<AttackDetail>
|
@SerialName("attack_detail_list") val attackDetailList: List<AttackDetail>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class AttackDetail(
|
data class AttackDetail(
|
||||||
@SerialName("boss_round") val bossRound: Int, // 周目
|
@SerialName("boss_round") val bossRound: Int, // 周目
|
||||||
@SerialName("boss_index") val bossIndex: Int, // 1~5 號王
|
@SerialName("boss_index") val bossIndex: Int, // 1~5 號王
|
||||||
val damage: Long, // 傷害
|
@SerialName("damage") val damage: Long, // 傷害
|
||||||
@SerialName("is_compensation") val isCompensation: Boolean = false, // true: 補償刀, false: 正刀
|
@SerialName("is_compensation") val isCompensation: Boolean, // true: 補償刀, false: 正刀
|
||||||
@SerialName("is_dropped") val isDropped: Boolean = false, // true: 掉刀, false: 沒掉刀
|
@SerialName("is_dropped") val isDropped: Boolean, // true: 掉刀, false: 沒掉刀
|
||||||
@SerialName("created_at") val createdAt: Long = Instant.now().toEpochMilli(),
|
@SerialName("created_at") val createdAt: Long = Instant.now().toEpochMilli(),
|
||||||
@SerialName("updated_at") val updatedAt: Long = Instant.now().toEpochMilli()
|
@SerialName("updated_at") val updatedAt: Long = Instant.now().toEpochMilli()
|
||||||
)
|
)
|
||||||
@@ -5,11 +5,11 @@ import kotlinx.serialization.Serializable
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Member(
|
data class Member(
|
||||||
var uid: String,
|
@SerialName("uid") var uid: String,
|
||||||
@SerialName("player_name") val playerName: String,
|
@SerialName("player_name") val playerName: String,
|
||||||
@SerialName("discord_name") val discordName: String,
|
@SerialName("discord_name") val discordName: String,
|
||||||
@SerialName("discord_id") val discordID: String,
|
@SerialName("discord_id") val discordID: String,
|
||||||
var leave: Boolean = false,
|
@SerialName("leave") var leave: Boolean,
|
||||||
@SerialName("created_at") var createAt: Long? = null,
|
@SerialName("created_at") var createAt: Long? = null,
|
||||||
@SerialName("updated_at") var updatedAt: Long? = null
|
@SerialName("updated_at") var updatedAt: Long? = null
|
||||||
)
|
)
|
||||||
+1
-1
@@ -8,5 +8,5 @@ data class UpdateMemberRequest(
|
|||||||
@SerialName("player_name") val playerName: String,
|
@SerialName("player_name") val playerName: String,
|
||||||
@SerialName("discord_name") val discordName: String,
|
@SerialName("discord_name") val discordName: String,
|
||||||
@SerialName("discord_id") val discordID: String,
|
@SerialName("discord_id") val discordID: String,
|
||||||
var leave: Boolean = false,
|
@SerialName("leave") var leave: Boolean,
|
||||||
)
|
)
|
||||||
@@ -10,6 +10,7 @@ fun Application.configureHttp() {
|
|||||||
install(CORS) {
|
install(CORS) {
|
||||||
allowHost("localhost:8080")
|
allowHost("localhost:8080")
|
||||||
allowHost("table.sakunadaisuki.club")
|
allowHost("table.sakunadaisuki.club")
|
||||||
|
allowHost("192.168.50.128:10002")
|
||||||
|
|
||||||
allowMethod(HttpMethod.Options)
|
allowMethod(HttpMethod.Options)
|
||||||
allowMethod(HttpMethod.Put)
|
allowMethod(HttpMethod.Put)
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ fun Application.configureMongo() {
|
|||||||
call.respond(HttpStatusCode.OK, member)
|
call.respond(HttpStatusCode.OK, member)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read member
|
// Read member
|
||||||
get("/member/{uid}") {
|
get("/member/{uid}") {
|
||||||
val uid = call.parameters["uid"] ?: throw IllegalArgumentException("No ID found")
|
val uid = call.parameters["uid"] ?: throw IllegalArgumentException("No ID found")
|
||||||
@@ -43,6 +44,7 @@ fun Application.configureMongo() {
|
|||||||
call.respond(HttpStatusCode.OK, member)
|
call.respond(HttpStatusCode.OK, member)
|
||||||
} ?: call.respond(HttpStatusCode.NotFound)
|
} ?: call.respond(HttpStatusCode.NotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create member
|
// Create member
|
||||||
post("/member") {
|
post("/member") {
|
||||||
val member = call.receive<MemberRequest>()
|
val member = call.receive<MemberRequest>()
|
||||||
@@ -54,14 +56,16 @@ fun Application.configureMongo() {
|
|||||||
call.respond(HttpStatusCode.Conflict)
|
call.respond(HttpStatusCode.Conflict)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update member
|
// Update member
|
||||||
put("/member/{uid}") {
|
put("/member/{uid}") {
|
||||||
val uid = call.parameters["uid"] ?: throw IllegalArgumentException("No ID found")
|
val uid = call.parameters["uid"] ?: throw IllegalArgumentException("No ID found")
|
||||||
val member = call.receive<UpdateMemberRequest>()
|
val member = call.receive<UpdateMemberRequest>()
|
||||||
memberService.update(uid, member.toDto(uid))?.let {
|
memberService.update(uid, member.toDto(uid))?.let { member ->
|
||||||
call.respond(HttpStatusCode.OK)
|
call.respond(HttpStatusCode.OK, member)
|
||||||
} ?: call.respond(HttpStatusCode.NotFound)
|
} ?: call.respond(HttpStatusCode.NotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete member
|
// Delete member
|
||||||
delete("/member/{uid}") {
|
delete("/member/{uid}") {
|
||||||
val uid = call.parameters["uid"] ?: throw IllegalArgumentException("No ID found")
|
val uid = call.parameters["uid"] ?: throw IllegalArgumentException("No ID found")
|
||||||
@@ -126,7 +130,24 @@ fun Application.configureMongo() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
post("/battle_record/create_table_day/{date}") {
|
||||||
|
val date = call.parameters["date"] ?: throw IllegalArgumentException("No date")
|
||||||
|
val exist = battleRecordService.read(date)
|
||||||
|
if (exist.isNotEmpty()) {
|
||||||
|
call.respond(HttpStatusCode.Conflict)
|
||||||
|
return@post
|
||||||
|
}
|
||||||
|
battleRecordService.createTable(date).let { battleRecord ->
|
||||||
|
call.respond(HttpStatusCode.OK, battleRecord)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post("/battle_record/create_table_month/{date}") {
|
||||||
|
val date = call.parameters["date"] ?: throw IllegalArgumentException("No date")
|
||||||
|
battleRecordService.createTableMonth(date).let { battleRecordList ->
|
||||||
|
call.respond(HttpStatusCode.OK, battleRecordList)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user