mirror of
https://github.com/dalbodeule/sh0rt.kr-pdns.git
synced 2025-06-08 18:58:20 +00:00
add powerdns client codes.
This commit is contained in:
parent
07aa50cd3a
commit
3dd8fc69c1
@ -31,6 +31,8 @@ dependencies {
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect")
|
||||
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2")
|
||||
|
||||
implementation("com.google.code.gson:gson:2.11.0")
|
||||
|
||||
implementation("io.github.cdimascio:dotenv-kotlin:6.4.1")
|
||||
|
||||
runtimeOnly("org.mariadb.jdbc:mariadb-java-client")
|
||||
|
7
docker_build.sh
Executable file
7
docker_build.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 현재 날짜와 시간을 YYMMDD(AM/PM)HHMM 형식으로 설정
|
||||
current_time=$(date +'%y%m%d%p%H%M')
|
||||
|
||||
# Docker 이미지 빌드 명령 실행
|
||||
docker build --no-cache -t dalbodeule/dnsapi:$current_time -t dalbodeule/dnsapi:latest .
|
@ -3,6 +3,10 @@ package space.mori.dnsapi
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.runApplication
|
||||
import io.github.cdimascio.dotenv.dotenv
|
||||
import java.time.OffsetDateTime
|
||||
import java.time.ZoneOffset
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.*
|
||||
|
||||
@SpringBootApplication
|
||||
class DnsapiApplication
|
||||
@ -13,7 +17,9 @@ fun main(args: Array<String>) {
|
||||
"DB_PORT" to dotenv["DB_PORT"],
|
||||
"DB_NAME" to dotenv["DB_NAME"],
|
||||
"DB_USER" to dotenv["DB_USER"],
|
||||
"DB_PASSWORD" to dotenv["DB_PASSWORD"]
|
||||
"DB_PASSWORD" to dotenv["DB_PASSWORD"],
|
||||
"PDNS_API_KEY" to dotenv["PDNS_API_KEY"],
|
||||
"PDNS_API_URL" to dotenv["PDNS_API_URL"],
|
||||
)
|
||||
|
||||
runApplication<DnsapiApplication>(*args) {
|
||||
@ -24,3 +30,8 @@ fun main(args: Array<String>) {
|
||||
val dotenv = dotenv {
|
||||
ignoreIfMissing = true
|
||||
}
|
||||
|
||||
fun Date.getISOFormat(): String {
|
||||
val offsetDateTime = OffsetDateTime.ofInstant(this.toInstant(), ZoneOffset.UTC)
|
||||
return offsetDateTime.format(DateTimeFormatter.ISO_DATE_TIME)
|
||||
}
|
82
src/main/kotlin/space/mori/dnsapi/PowerDNSAPIClient.kt
Normal file
82
src/main/kotlin/space/mori/dnsapi/PowerDNSAPIClient.kt
Normal file
@ -0,0 +1,82 @@
|
||||
package space.mori.dnsapi
|
||||
|
||||
import com.google.gson.Gson
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.http.*
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.web.client.RestTemplate
|
||||
import space.mori.dnsapi.dto.RecordRequestDTO
|
||||
|
||||
@Service
|
||||
class PowerDNSApiClient {
|
||||
@Value("\${pdns.api.url}")
|
||||
private lateinit var apiUrl: String
|
||||
|
||||
@Value("\${pdns.api.key}")
|
||||
private lateinit var apiKey: String
|
||||
|
||||
private val restTemplate = RestTemplate()
|
||||
private val gson = Gson()
|
||||
|
||||
private fun createHeaders(): HttpHeaders {
|
||||
val headers = HttpHeaders()
|
||||
headers.set("X-API-Key", apiKey)
|
||||
headers.contentType = MediaType.APPLICATION_JSON
|
||||
return headers
|
||||
}
|
||||
|
||||
fun createDomain(name: String): ResponseEntity<String> {
|
||||
val url = "$apiUrl/servers/localhost/zones"
|
||||
val headers = createHeaders()
|
||||
val domainRequest = DomainRequest("$name.", "Master", arrayOf(), arrayOf())
|
||||
val body = gson.toJson(domainRequest)
|
||||
val entity = HttpEntity(body, headers)
|
||||
return restTemplate.exchange(url, HttpMethod.POST, entity, String::class.java)
|
||||
}
|
||||
|
||||
fun createRecord(domainName: String, recordRequest: RecordRequestDTO): ResponseEntity<String> {
|
||||
val url = "$apiUrl/servers/localhost/zones/$domainName."
|
||||
val headers = createHeaders()
|
||||
val record = RecordRequest(
|
||||
name = "${recordRequest.name}.$domainName.",
|
||||
type = recordRequest.type,
|
||||
ttl = recordRequest.ttl,
|
||||
changetype = "REPLACE",
|
||||
records = arrayOf(RecordContent(recordRequest.content, false))
|
||||
)
|
||||
val body = gson.toJson(RecordRequestWrapper(arrayOf(record)))
|
||||
val entity = HttpEntity(body, headers)
|
||||
return restTemplate.exchange(url, HttpMethod.PATCH, entity, String::class.java)
|
||||
}
|
||||
|
||||
fun deleteDomain(name: String): ResponseEntity<String> {
|
||||
val url = "$apiUrl/servers/localhost/zones/$name."
|
||||
val headers = createHeaders()
|
||||
val entity = HttpEntity<String>(headers)
|
||||
return restTemplate.exchange(url, HttpMethod.DELETE, entity, String::class.java)
|
||||
}
|
||||
|
||||
private data class DomainRequest(
|
||||
val name: String,
|
||||
val kind: String,
|
||||
val masters: Array<String>,
|
||||
val nameservers: Array<String>
|
||||
)
|
||||
|
||||
private data class RecordRequestWrapper(
|
||||
val rrsets: Array<RecordRequest>
|
||||
)
|
||||
|
||||
private data class RecordRequest(
|
||||
val name: String,
|
||||
val type: String,
|
||||
val ttl: Int,
|
||||
val changetype: String,
|
||||
val records: Array<RecordContent>
|
||||
)
|
||||
|
||||
private data class RecordContent(
|
||||
val content: String,
|
||||
val disabled: Boolean
|
||||
)
|
||||
}
|
@ -8,7 +8,6 @@ import io.swagger.v3.oas.annotations.media.Schema
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.web.ErrorResponse
|
||||
import org.springframework.web.bind.annotation.*
|
||||
import space.mori.dnsapi.db.Domain
|
||||
import space.mori.dnsapi.dto.DomainResponseDTO
|
||||
@ -68,5 +67,5 @@ class DomainController {
|
||||
domainService!!.deleteDomain(cfid!!)
|
||||
}
|
||||
|
||||
private fun Domain.toDTO() = DomainResponseDTO(cfid = cfid!!, domainName = domainName!!)
|
||||
private fun Domain.toDTO() = DomainResponseDTO(id = cfid, name = name)
|
||||
}
|
||||
|
@ -7,20 +7,23 @@ import io.swagger.v3.oas.annotations.media.Schema
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable_.id
|
||||
import org.springframework.web.bind.annotation.*
|
||||
import space.mori.dnsapi.service.RecordService
|
||||
import space.mori.dnsapi.db.Record
|
||||
import space.mori.dnsapi.db.Domain
|
||||
import space.mori.dnsapi.db.Record as DomainRecord
|
||||
import space.mori.dnsapi.dto.RecordRequestDTO
|
||||
import space.mori.dnsapi.dto.RecordResponseDTO
|
||||
import space.mori.dnsapi.getISOFormat
|
||||
import space.mori.dnsapi.service.RecordService
|
||||
import java.util.*
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/record")
|
||||
class RecordController {
|
||||
@RequestMapping("/zones")
|
||||
class RecordController(
|
||||
@Autowired
|
||||
private val recordService: RecordService? = null
|
||||
|
||||
@GetMapping
|
||||
private val recordService: RecordService,
|
||||
) {
|
||||
@GetMapping("{zone_id}/dns_records")
|
||||
@Operation(summary = "Get all records", tags=["record"])
|
||||
@ApiResponses(value = [
|
||||
ApiResponse(responseCode = "200", description = "Return All Records",
|
||||
@ -28,11 +31,11 @@ class RecordController {
|
||||
ApiResponse(responseCode = "400", description = "Bad request",
|
||||
content = [Content(schema = Schema(implementation = Void::class))]),
|
||||
])
|
||||
fun allRecords(@PathVariable cfid: String?): List<RecordResponseDTO?> {
|
||||
return recordService!!.getAllRecords(cfid!!).map{ it?.toDTO() }
|
||||
fun allRecords(@PathVariable zone_id: String): List<RecordResponseDTO> {
|
||||
return recordService.getRecordsByDomain(zone_id)?.map{ it } ?: listOf()
|
||||
}
|
||||
|
||||
@GetMapping("/{cfid}")
|
||||
@GetMapping("{zone_id}/dns_records/{dns_record_id}")
|
||||
@Operation(summary = "Get Record by ID", tags=["record"])
|
||||
@ApiResponses(value = [
|
||||
ApiResponse(responseCode = "200", description = "Return Record",
|
||||
@ -40,11 +43,11 @@ class RecordController {
|
||||
ApiResponse(responseCode = "400", description = "Bad request",
|
||||
content = [Content(schema = Schema(implementation = Void::class))])
|
||||
])
|
||||
fun getRecordByCfid(@PathVariable cfid: String?): Optional<RecordResponseDTO> {
|
||||
return recordService!!.getRecordById(cfid!!).map { it.toDTO() }
|
||||
fun getRecordByCfid(@PathVariable zone_id: String, @PathVariable dns_record_id: String): RecordResponseDTO {
|
||||
return recordService.getRecord(zone_id, dns_record_id)
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@PostMapping("{zone_id}/dns_records")
|
||||
@Operation(summary = "Add Record by ID", tags=["record"])
|
||||
@ApiResponses(value = [
|
||||
ApiResponse(responseCode = "200", description = "Return Record",
|
||||
@ -52,11 +55,11 @@ class RecordController {
|
||||
ApiResponse(responseCode = "400", description = "Bad request",
|
||||
content = [Content(schema = Schema(implementation = Void::class))]),
|
||||
])
|
||||
fun createRecord(@RequestBody record: RecordRequestDTO): RecordResponseDTO {
|
||||
return recordService!!.createRecord(record).toDTO()
|
||||
fun createRecord(@PathVariable zone_id: String, @RequestBody record: RecordRequestDTO): RecordResponseDTO {
|
||||
return recordService.createRecord(zone_id, record)
|
||||
}
|
||||
|
||||
@DeleteMapping("/{cfid}")
|
||||
@DeleteMapping("{zone_id}/dns_records/{dns_record_id}")
|
||||
@Operation(summary = "Remove Record by ID", tags=["record"])
|
||||
@ApiResponses(value = [
|
||||
ApiResponse(responseCode = "200", description = "Return Record",
|
||||
@ -64,19 +67,33 @@ class RecordController {
|
||||
ApiResponse(responseCode = "400", description = "Bad request",
|
||||
content = [Content(schema = Schema(implementation = Void::class))]),
|
||||
])
|
||||
fun deleteRecord(@PathVariable cfid: String?) {
|
||||
recordService!!.deleteRecord(cfid!!)
|
||||
fun deleteRecord(@PathVariable zone_id: String, @PathVariable dns_record_id: String) {
|
||||
recordService.deleteRecord(zone_id, dns_record_id)
|
||||
}
|
||||
|
||||
private fun Record.toDTO() = RecordResponseDTO(
|
||||
cfid = cfid!!,
|
||||
name = name!!,
|
||||
type = type!!,
|
||||
content = content!!,
|
||||
prio = prio!!,
|
||||
ttl = ttl!!,
|
||||
changeDate = changeDate!!,
|
||||
auth = auth,
|
||||
disabled = disabled
|
||||
@PatchMapping("{zone_id}/dns_records/{dns_record_id}")
|
||||
@Operation(summary = "Update Record by ID", tags=["record"])
|
||||
@ApiResponses(value = [
|
||||
ApiResponse(responseCode = "200", description = "Return Record",
|
||||
content = [Content(schema = Schema(implementation = RecordResponseDTO::class))]),
|
||||
ApiResponse(responseCode = "400", description = "Bad request",
|
||||
content = [Content(schema = Schema(implementation = Void::class))]),
|
||||
])
|
||||
fun updateRecord(@PathVariable zone_id: String, @PathVariable dns_record_id: String, @RequestBody record: RecordRequestDTO): RecordResponseDTO {
|
||||
return recordService.updateRecord(zone_id, dns_record_id, record)
|
||||
}
|
||||
|
||||
private fun DomainRecord.toDTO() = RecordResponseDTO(
|
||||
id = cfid,
|
||||
type = type,
|
||||
name = name,
|
||||
content = content,
|
||||
zoneId = domain.cfid,
|
||||
zoneName = domain.name,
|
||||
priority = prio,
|
||||
ttl = ttl,
|
||||
createdOn = createdOn.getISOFormat(),
|
||||
modifiedOn = modifiedOn.getISOFormat(),
|
||||
comment = comment
|
||||
)
|
||||
}
|
@ -7,37 +7,17 @@ import java.util.*
|
||||
|
||||
@Entity
|
||||
@Table(name = "domains")
|
||||
class Domain {
|
||||
data class Domain(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private val id: Long? = null
|
||||
var id: Long? = null,
|
||||
|
||||
@Column(nullable = false, length = 255)
|
||||
val domainName: String? = null
|
||||
@Column(nullable = false, unique = true)
|
||||
var name: String,
|
||||
|
||||
@Column(nullable = true, length = 128)
|
||||
val master: String? = null
|
||||
|
||||
@Column(nullable = true, name = "last_check")
|
||||
val lastCheck: Int? = null
|
||||
|
||||
@Column(nullable = false, length = 6)
|
||||
val type: String? = null
|
||||
|
||||
@Column(nullable = true, name = "notified_serial")
|
||||
val notifiedSerial: Int? = null
|
||||
|
||||
@Column(nullable = false, length = 128)
|
||||
val account: String? = null
|
||||
|
||||
@Column(unique = true, nullable = false, length = 32)
|
||||
var cfid: String? = null
|
||||
|
||||
@OneToMany(mappedBy = "domain", cascade = [CascadeType.ALL], fetch = FetchType.LAZY)
|
||||
private val records: Set<Record>? = null
|
||||
|
||||
@PrePersist
|
||||
protected fun onCreate() {
|
||||
this.cfid = UUID.randomUUID().toString().replace("-", "")
|
||||
} // Getters and setters
|
||||
@Column(nullable = false, unique = true)
|
||||
var cfid: String = UUID.randomUUID().toString().replace("-", "")
|
||||
) {
|
||||
@OneToMany(mappedBy = "domain", cascade = [CascadeType.ALL], orphanRemoval = true)
|
||||
var records: List<Record> = mutableListOf()
|
||||
}
|
@ -6,68 +6,28 @@ import java.util.*
|
||||
|
||||
@Entity
|
||||
@Table(name = "records")
|
||||
class Record {
|
||||
data class Record(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private val id: Long? = null
|
||||
var id: Long? = null,
|
||||
|
||||
@ManyToOne
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "domain_id", nullable = false)
|
||||
var domain: Domain? = null
|
||||
var domain: Domain,
|
||||
|
||||
@Column(nullable = false, length = 255)
|
||||
var name: String? = null
|
||||
var name: String,
|
||||
var type: String,
|
||||
var content: String,
|
||||
var ttl: Int,
|
||||
var prio: Int,
|
||||
var disabled: Boolean,
|
||||
var auth: Boolean,
|
||||
|
||||
@Column(nullable = false, length = 10)
|
||||
var type: String? = null
|
||||
var createdOn: Date,
|
||||
var modifiedOn: Date,
|
||||
|
||||
@Column(nullable = false, length = 64000)
|
||||
var content: String? = null
|
||||
var comment: String,
|
||||
|
||||
@Column(nullable = true)
|
||||
var ttl: Int?
|
||||
|
||||
@Column(nullable = true)
|
||||
var prio: Int?
|
||||
|
||||
@Column(nullable = true)
|
||||
var changeDate: Int?
|
||||
|
||||
var disabled: Boolean = false
|
||||
var auth: Boolean = true
|
||||
|
||||
@Column(unique = true, nullable = false, length = 32)
|
||||
var cfid: String? = null
|
||||
|
||||
@Column(nullable = true, length = 64)
|
||||
var comment: String? = null
|
||||
|
||||
@PrePersist
|
||||
private fun onCreate() {
|
||||
this.cfid = UUID.randomUUID().toString().replace("-", "")
|
||||
} // Getters and setters
|
||||
|
||||
constructor(
|
||||
name: String,
|
||||
type: String,
|
||||
content: String,
|
||||
changeDate: Int?,
|
||||
disabled: Boolean,
|
||||
domain: Domain,
|
||||
comment: String?,
|
||||
auth: Boolean = true,
|
||||
ttl: Int? = 300,
|
||||
prio: Int? = 0,
|
||||
) {
|
||||
this.name = name
|
||||
this.type = type
|
||||
this.content = content
|
||||
this.ttl = ttl
|
||||
this.prio = prio
|
||||
this.changeDate = changeDate
|
||||
this.disabled = disabled
|
||||
this.auth = auth
|
||||
this.domain = domain
|
||||
this.comment = comment
|
||||
}
|
||||
}
|
||||
@Column(nullable = false, unique = true)
|
||||
var cfid: String = UUID.randomUUID().toString().replace("-", "")
|
||||
)
|
@ -12,8 +12,11 @@ interface RecordRepository : JpaRepository<Record?, Long?> {
|
||||
fun findByCfid(cfid: String): Optional<Record>
|
||||
|
||||
@Transactional
|
||||
fun deleteByCfid(cfid: String)
|
||||
fun findByDomainIdAndCfid(domainId: Long, cfid: String): Optional<Record>
|
||||
|
||||
@Query("SELECT r FROM Record r WHERE r.domain.cfid = :domainCfid")
|
||||
fun findByDomainCfid(@Param("domainCfid") cfid: String): List<Record>
|
||||
@Transactional
|
||||
fun deleteByCfid(cfid: String): Int
|
||||
|
||||
@Transactional
|
||||
fun deleteByDomainIdAndCfid(domain_id: Long, cfid: String): Int
|
||||
}
|
@ -5,5 +5,5 @@ import io.swagger.v3.oas.annotations.media.Schema
|
||||
@Schema(description = "Request DTO for Domain")
|
||||
data class DomainRequestDTO(
|
||||
@Schema(description = "Domain name(TLD)", example = "example.com")
|
||||
val domainName: String
|
||||
val name: String
|
||||
)
|
@ -5,8 +5,8 @@ import io.swagger.v3.oas.annotations.media.Schema
|
||||
@Schema(description = "Response DTO for Domain")
|
||||
data class DomainResponseDTO(
|
||||
@Schema(description = "Domain CFID", example = "123e4567e89b12d3a456426655440000")
|
||||
val cfid: String,
|
||||
val id: String,
|
||||
|
||||
@Schema(description = "Domain name(TLD)", example = "example.com")
|
||||
val domainName: String
|
||||
val name: String
|
||||
)
|
@ -4,20 +4,23 @@ import io.swagger.v3.oas.annotations.media.Schema
|
||||
|
||||
@Schema(description = "Request DTO for Record")
|
||||
data class RecordRequestDTO(
|
||||
@Schema(description = "Host name", example = "www")
|
||||
val host: String,
|
||||
|
||||
@Schema(description = "Record type", example = "A")
|
||||
val type: String,
|
||||
|
||||
@Schema(description = "Host name", example = "www.example.com.")
|
||||
val name: String,
|
||||
|
||||
@Schema(description = "Record data", example = "192.0.2.1")
|
||||
val data: String,
|
||||
val content: String,
|
||||
|
||||
@Schema(description = "TTL (Time to Live)", example = "3600")
|
||||
val ttl: Int,
|
||||
val ttl: Int = 300,
|
||||
|
||||
@Schema(description = "Domain CFID", example = "123e4567e89b12d3a456426655440000")
|
||||
val cfid: String,
|
||||
@Schema(description = "Priority", example = "0")
|
||||
val priority: Int? = null,
|
||||
|
||||
@Schema(description = "Proxied: cloudflare api compatibility", example = "false")
|
||||
val proxied: Boolean = false,
|
||||
|
||||
@Schema(description = "comment", example="")
|
||||
val comment: String
|
||||
|
@ -5,30 +5,45 @@ import java.util.*
|
||||
|
||||
@Schema(description = "Response DTO for Record")
|
||||
data class RecordResponseDTO(
|
||||
@Schema(description = "Record CFID", example = "123e4567e89b12d3a456426655440001")
|
||||
val cfid: String,
|
||||
|
||||
@Schema(description = "Host name", example = "www.domain.tld")
|
||||
val name: String,
|
||||
@Schema(description = "Record ID", example = "123e4567e89b12d3a456426655440001")
|
||||
val id: String,
|
||||
|
||||
@Schema(description = "Record type", example = "A")
|
||||
val type: String,
|
||||
var type: String,
|
||||
|
||||
@Schema(description = "Record data", example = "192.0.2.1")
|
||||
val content: String,
|
||||
@Schema(description = "Record name", example = "test.example.com")
|
||||
var name: String,
|
||||
|
||||
@Schema(description = "TTL (Time to Live)", example = "3600")
|
||||
val ttl: Int,
|
||||
@Schema(description = "Record content", example = "1.1.1.1")
|
||||
var content: String,
|
||||
|
||||
@Schema(description = "TTL per second", example = "300s")
|
||||
val prio: Int,
|
||||
@Schema(description = "Zone(TLD) ID", example = "123e4567e89b12d3a456426655440001")
|
||||
val zoneId: String,
|
||||
|
||||
@Schema(description = "Changed date with Unix Timestamp")
|
||||
val changeDate: Int,
|
||||
@Schema(description = "Zone name(TLD)", example = "example.com")
|
||||
val zoneName: String,
|
||||
|
||||
@Schema(description = "is disabled?", example = "false")
|
||||
val disabled: Boolean,
|
||||
@Schema(description = "Record creation time", example = "2014-01-01T05:20:00.12345Z")
|
||||
val createdOn: String,
|
||||
|
||||
@Schema(description = "is authed", example = "true")
|
||||
val auth: Boolean,
|
||||
@Schema(description = "Record modification time", example = "2014-01-01T05:20:00.12345Z")
|
||||
val modifiedOn: String,
|
||||
|
||||
@Schema(description = "Record priority", example = "0")
|
||||
val priority: Int? = 0,
|
||||
|
||||
@Schema(description = "is proxyable: must false", example = "false")
|
||||
val proxiable: Boolean = false,
|
||||
|
||||
@Schema(description = "is proxied: must false", example = "false")
|
||||
val proxied: Boolean = false,
|
||||
|
||||
@Schema(description = "Record TTL", example = "300")
|
||||
val ttl: Int = 300,
|
||||
|
||||
@Schema(description = "Record is locked: must false", example = "false")
|
||||
val locked: Boolean = false,
|
||||
|
||||
@Schema(description = "Record comments", example = "")
|
||||
val comment: String? = null,
|
||||
)
|
@ -2,45 +2,160 @@ package space.mori.dnsapi.service
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
import space.mori.dnsapi.PowerDNSApiClient
|
||||
import space.mori.dnsapi.db.DomainRepository
|
||||
import space.mori.dnsapi.db.RecordRepository
|
||||
import space.mori.dnsapi.db.Record as DomainRecord
|
||||
import space.mori.dnsapi.db.RecordRepository
|
||||
import space.mori.dnsapi.dto.DomainRequestDTO
|
||||
import space.mori.dnsapi.dto.RecordRequestDTO
|
||||
import space.mori.dnsapi.dto.RecordResponseDTO
|
||||
import space.mori.dnsapi.getISOFormat
|
||||
import java.util.*
|
||||
|
||||
|
||||
@Service
|
||||
class RecordService {
|
||||
class RecordService(
|
||||
@Autowired
|
||||
private lateinit var domainRepository: DomainRepository
|
||||
private val powerDNSApiClient: PowerDNSApiClient,
|
||||
@Autowired
|
||||
private val recordRepository: RecordRepository? = null
|
||||
private val domainRepository: DomainRepository,
|
||||
@Autowired
|
||||
private val recordRepository: RecordRepository
|
||||
) {
|
||||
fun createRecord(domain_id: String, recordRequest: RecordRequestDTO): RecordResponseDTO {
|
||||
val domain = domainRepository.findByCfid(domain_id)
|
||||
if(domain.isEmpty) throw RuntimeException("Failed to find domain in API: $domain_id")
|
||||
|
||||
fun getAllRecords(cfid: String): List<DomainRecord?> {
|
||||
return recordRepository!!.findByDomainCfid(cfid)
|
||||
}
|
||||
|
||||
fun getRecordById(cfid: String): Optional<DomainRecord> {
|
||||
return recordRepository!!.findByCfid(cfid)
|
||||
}
|
||||
|
||||
fun createRecord(record: RecordRequestDTO): DomainRecord {
|
||||
val domain = domainRepository.findByCfid(record.cfid)
|
||||
.orElseThrow { IllegalArgumentException("Invalid domain CFID") }
|
||||
val r = DomainRecord(
|
||||
name = record.host,
|
||||
type = record.type,
|
||||
content = record.data,
|
||||
ttl = record.ttl,
|
||||
domain = domain,
|
||||
comment = record.comment,
|
||||
changeDate = java.util.Date().time.toInt(),
|
||||
disabled = false
|
||||
val response = powerDNSApiClient.createRecord(domain.get().name, recordRequest)
|
||||
if (!response.statusCode.is2xxSuccessful) {
|
||||
throw RuntimeException("Failed to create record in PowerDNS: ${response.body}")
|
||||
}
|
||||
val record = DomainRecord(
|
||||
domain = domain.get(),
|
||||
name = recordRequest.name,
|
||||
type = recordRequest.type,
|
||||
content = recordRequest.content,
|
||||
ttl = recordRequest.ttl,
|
||||
prio = recordRequest.priority ?: 0,
|
||||
disabled = false,
|
||||
auth = true,
|
||||
createdOn = Date(),
|
||||
modifiedOn = Date(),
|
||||
comment = recordRequest.comment,
|
||||
)
|
||||
|
||||
return RecordResponseDTO(
|
||||
id = record.cfid,
|
||||
type = record.type,
|
||||
name = record.name,
|
||||
content = record.content,
|
||||
proxiable = false,
|
||||
proxied = false,
|
||||
ttl = record.ttl,
|
||||
locked = false,
|
||||
zoneId = record.cfid,
|
||||
zoneName = domain.get().name,
|
||||
createdOn = record.createdOn.getISOFormat(),
|
||||
modifiedOn = record.modifiedOn.getISOFormat(),
|
||||
priority = record.prio,
|
||||
comment = record.comment
|
||||
)
|
||||
return recordRepository!!.save(r)
|
||||
}
|
||||
|
||||
fun deleteRecord(cfid: String) {
|
||||
recordRepository!!.deleteByCfid(cfid)
|
||||
fun getRecord(domain_id: String, record_id: String): RecordResponseDTO {
|
||||
val domain = domainRepository.findByCfid(domain_id)
|
||||
if(domain.isEmpty) throw RuntimeException("Failed to find domain in API: $domain_id")
|
||||
|
||||
val record = domain.get().records.find { it.cfid == record_id }
|
||||
if(record == null) throw RuntimeException("Failed to find record in API: $record_id")
|
||||
|
||||
return RecordResponseDTO(
|
||||
id = record.cfid,
|
||||
type = record.type,
|
||||
name = record.name,
|
||||
content = record.content,
|
||||
ttl = record.ttl,
|
||||
zoneId = record.domain.cfid,
|
||||
zoneName = record.domain.name,
|
||||
createdOn = record.createdOn.getISOFormat(),
|
||||
modifiedOn = record.modifiedOn.getISOFormat(),
|
||||
comment = record.comment,
|
||||
)
|
||||
}
|
||||
|
||||
fun getRecordsByDomain(domain_id: String): List<RecordResponseDTO>? {
|
||||
val domain = domainRepository.findByCfid(domain_id).orElseThrow { RuntimeException("Failed to find domain in API: $domain_id") }
|
||||
return domain?.records?.map { RecordResponseDTO(
|
||||
id = it.cfid,
|
||||
type = it.type,
|
||||
name = it.name,
|
||||
content = it.content,
|
||||
zoneId = it.domain.cfid,
|
||||
zoneName = it.domain.name,
|
||||
priority = it.prio,
|
||||
ttl = it.ttl,
|
||||
createdOn = it.createdOn.getISOFormat(),
|
||||
modifiedOn = it.modifiedOn.getISOFormat(),
|
||||
comment = it.comment,
|
||||
)}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
fun updateRecord(domainId: String, cfid: String, updatedRecord: RecordRequestDTO): RecordResponseDTO {
|
||||
// 도메인 조회
|
||||
val domain = domainRepository.findByCfid(domainId)
|
||||
.orElseThrow { RuntimeException("Domain not found") }
|
||||
|
||||
// 레코드 조회
|
||||
val record = recordRepository.findByDomainIdAndCfid(domain.id!!, cfid)
|
||||
.orElseThrow { RuntimeException("Record not found") }
|
||||
|
||||
// 레코드 업데이트
|
||||
record.name = updatedRecord.name
|
||||
record.type = updatedRecord.type
|
||||
record.content = updatedRecord.content
|
||||
record.ttl = updatedRecord.ttl
|
||||
record.prio = updatedRecord.priority ?: 0
|
||||
record.comment = updatedRecord.comment
|
||||
record.modifiedOn = Date()
|
||||
|
||||
val response = powerDNSApiClient.createRecord(domain!!.name, updatedRecord)
|
||||
if (!response.statusCode.is2xxSuccessful) {
|
||||
throw RuntimeException("Failed to update record in PowerDNS: ${response.body}")
|
||||
}
|
||||
|
||||
// 저장
|
||||
val savedRecord = recordRepository.save(record)
|
||||
return RecordResponseDTO(
|
||||
id = savedRecord.cfid,
|
||||
type = savedRecord.type,
|
||||
name = savedRecord.name,
|
||||
content = savedRecord.content,
|
||||
proxiable = true,
|
||||
proxied = false,
|
||||
ttl = savedRecord.ttl,
|
||||
locked = false,
|
||||
zoneId = domain.cfid,
|
||||
zoneName = domain.name,
|
||||
createdOn = savedRecord.createdOn.getISOFormat(),
|
||||
modifiedOn = savedRecord.modifiedOn.getISOFormat(),
|
||||
priority = savedRecord.prio
|
||||
)
|
||||
}
|
||||
|
||||
fun deleteRecord(domain_id: String, record_id: String) {
|
||||
val domain = domainRepository.findByCfid(domain_id).orElseThrow { RuntimeException("Failed to find domain in API: $domain_id") }
|
||||
|
||||
val deletedCount = recordRepository.deleteByDomainIdAndCfid(domain.id!!, record_id)
|
||||
|
||||
if(deletedCount == 0) throw RuntimeException("Failed to find record in API: $record_id")
|
||||
}
|
||||
|
||||
fun deleteDomain(name: String) {
|
||||
val response = powerDNSApiClient.deleteDomain(name)
|
||||
if (!response.statusCode.is2xxSuccessful) {
|
||||
throw RuntimeException("Failed to delete domain in PowerDNS: ${response.body}")
|
||||
}
|
||||
}
|
||||
}
|
@ -12,3 +12,5 @@ springdoc.api-docs.path=/api-docs
|
||||
springdoc.default-consumes-media-type= application/json
|
||||
springdoc.default-produces-media-type= application/json
|
||||
springdoc.version= '@project.version@'
|
||||
pdns.api.key=${PDNS_API_KEY}
|
||||
pdns.api.url=${PDNS_API_URL}
|
Loading…
x
Reference in New Issue
Block a user