add domain service, auth service

This commit is contained in:
dalbodeule 2024-06-05 23:15:29 +09:00
parent 3dd8fc69c1
commit d99606436d
No known key found for this signature in database
GPG Key ID: EFA860D069C9FA65
18 changed files with 299 additions and 112 deletions

View File

@ -24,7 +24,7 @@ repositories {
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
// implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")

View File

@ -10,6 +10,7 @@ MARIADB_USER=pdns
MARIADB_PASSWORD=
PDNS_API_KEY=
PDNS_API_URL=
PDNS_WEBSERVER_KEY=
PDNS_VERSION_STRING=
MASTER_PDNS_IP=

View File

@ -3,6 +3,8 @@ package space.mori.dnsapi
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import io.github.cdimascio.dotenv.dotenv
import org.springframework.security.core.context.SecurityContextHolder
import space.mori.dnsapi.db.User
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter

View File

@ -0,0 +1,42 @@
package space.mori.dnsapi
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.http.SessionCreationPolicy
import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import space.mori.dnsapi.filter.UserFilter
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Autowired
private val service: UserFilter? = null
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
return http
.csrf{ it.disable() }
.cors{ it.disable() }
.sessionManagement {
it.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
}
.authorizeHttpRequests {
it.requestMatchers("/zones/**").authenticated()
it.requestMatchers(
"/swagger-ui.html",
"/swagger-ui/**",
"/api-docs/**",
"/v3/api-docs/**",
"/v2/api-docs/**",
"/swagger-resources/**",
"/webjars/**"
).permitAll()
}
.addFilterBefore(service, UsernamePasswordAuthenticationFilter::class.java)
.build()
}
}

View File

@ -3,23 +3,28 @@ package space.mori.dnsapi
import io.swagger.v3.oas.models.Components
import io.swagger.v3.oas.models.OpenAPI
import io.swagger.v3.oas.models.info.Info
import io.swagger.v3.oas.models.security.SecurityRequirement
import io.swagger.v3.oas.models.security.SecurityScheme
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@Configuration
class SwaggerConfig {
private val securitySchemeName = "api token"
@Bean
fun openAPI(): OpenAPI {
return OpenAPI()
.components(Components())
.info(apiInfo())
}
private fun apiInfo(): Info {
return Info()
.title("Spring Boot REST API Specifications")
.description("Specification")
.version("1.0.0")
.info(Info().title("Cloudflare compatible PowerDNS API Server").version("v1.0.0"))
.addSecurityItem(SecurityRequirement().addList(securitySchemeName))
.components(Components()
.addSecuritySchemes(securitySchemeName,
SecurityScheme()
.name(securitySchemeName)
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
)
)
}
}

View File

@ -1,8 +1,6 @@
package space.mori.dnsapi.controller
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.Parameter
import io.swagger.v3.oas.annotations.media.ArraySchema
import io.swagger.v3.oas.annotations.media.Content
import io.swagger.v3.oas.annotations.media.Schema
import io.swagger.v3.oas.annotations.responses.ApiResponse
@ -10,61 +8,66 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.*
import space.mori.dnsapi.db.Domain
import space.mori.dnsapi.dto.ApiResponseDTO
import space.mori.dnsapi.dto.DeleteResponseWithId
import space.mori.dnsapi.dto.DomainRequestDTO
import space.mori.dnsapi.dto.DomainResponseDTO
import space.mori.dnsapi.filter.getCurrentUser
import space.mori.dnsapi.service.DomainService
import java.util.*
@RestController
@RequestMapping("/domain")
class DomainController {
@RequestMapping("/zones")
class DomainController(
@Autowired
private val domainService: DomainService? = null
@get:GetMapping
@get:Operation(summary = "Get all domains", tags = ["domain"])
@get:ApiResponse(responseCode = "200", description = "Returns all domains",
content = [Content(array = ArraySchema(schema = Schema(implementation = DomainResponseDTO::class)))])
val allDomains: List<DomainResponseDTO?>
get() = domainService!!.getAllDomains().map { it?.toDTO() }
private val domainService: DomainService
) {
@GetMapping
@Operation(summary = "Get all domains", tags = ["domain"])
@ApiResponses(value = [
ApiResponse(responseCode = "200", description = "Returns all domains", useReturnTypeSchema = true),
ApiResponse(responseCode = "404", description = "Returns not found",
content = [Content(schema = Schema(implementation = ApiResponseDTO::class))])
])
fun allDomains(): ApiResponseDTO<List<DomainResponseDTO?>> {
return ApiResponseDTO(result = domainService.getAllDomains().map { it.toDTO() })
}
@Operation(summary = "Get domain", tags = ["domain"])
@ApiResponses(value = [
ApiResponse(responseCode = "200", description = "Returns domain",
content = [Content(schema = Schema(implementation = DomainResponseDTO::class))]),
ApiResponse(responseCode = "200", description = "Returns domain", useReturnTypeSchema = true),
ApiResponse(responseCode = "404", description = "Returns not found",
content = [Content(schema = Schema(implementation = Void::class))])
content = [Content(schema = Schema(implementation = ApiResponseDTO::class))])
])
@GetMapping("/{cfid}")
fun getDomainByCfid(
@Parameter(description = "CFID", required = true)
@PathVariable cfid: String?
): Optional<DomainResponseDTO> {
return domainService!!.getDomainById(cfid!!).map { it.toDTO() }
): ApiResponseDTO<DomainResponseDTO> {
return ApiResponseDTO(result = domainService.getDomainById(cfid!!).toDTO())
}
@Operation(summary = "Create domain", tags = ["domain"])
@ApiResponses(value = [
ApiResponse(responseCode = "200", description = "Created domain",
content = [Content(schema = Schema(implementation = DomainResponseDTO::class))]),
ApiResponse(responseCode = "200", description = "Created domain", useReturnTypeSchema = true),
ApiResponse(responseCode = "400", description = "Bad request",
content = [Content(schema = Schema(implementation = Void::class))])
content = [Content(schema = Schema(implementation = ApiResponseDTO::class))])
])
@PostMapping
fun createDomain(@RequestBody domain: Domain?): DomainResponseDTO {
return domainService!!.createDomain(domain!!).toDTO()
fun createDomain(@RequestBody domain: DomainRequestDTO): ApiResponseDTO<DomainResponseDTO> {
return ApiResponseDTO(result = domainService.createDomain(domain).toDTO())
}
@Operation(summary = "Delete domain", tags = ["domain"])
@ApiResponses(value = [
ApiResponse(responseCode = "200", description = "Deleted domain",
content = [Content(schema = Schema(implementation = Void::class))]),
ApiResponse(responseCode = "200", description = "Deleted domain", useReturnTypeSchema = true),
ApiResponse(responseCode = "400", description = "Bad request",
content = [Content(schema = Schema(implementation = Void::class))])
content = [Content(schema = Schema(implementation = ApiResponseDTO::class))])
])
@DeleteMapping("/{cfid}")
fun deleteDomain(@PathVariable cfid: String?) {
domainService!!.deleteDomain(cfid!!)
@DeleteMapping("/{domain_id}")
fun deleteDomain(@PathVariable domain_id: String?): ApiResponseDTO<DeleteResponseWithId> {
domainService.deleteDomain(domain_id!!)
return ApiResponseDTO(result=DeleteResponseWithId(domain_id))
}
private fun Domain.toDTO() = DomainResponseDTO(id = cfid, name = name)

View File

@ -1,21 +1,16 @@
package space.mori.dnsapi.controller
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.media.ArraySchema
import io.swagger.v3.oas.annotations.media.Content
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.db.Domain
import space.mori.dnsapi.dto.*
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("/zones")
@ -26,61 +21,57 @@ class RecordController(
@GetMapping("{zone_id}/dns_records")
@Operation(summary = "Get all records", tags=["record"])
@ApiResponses(value = [
ApiResponse(responseCode = "200", description = "Return All Records",
content = [Content(array = ArraySchema(schema = Schema(implementation = RecordResponseDTO::class)))]),
ApiResponse(responseCode = "200", description = "Return All Records", useReturnTypeSchema = true),
ApiResponse(responseCode = "400", description = "Bad request",
content = [Content(schema = Schema(implementation = Void::class))]),
content = [Content(schema = Schema(implementation = ApiResponseDTO::class))]),
])
fun allRecords(@PathVariable zone_id: String): List<RecordResponseDTO> {
return recordService.getRecordsByDomain(zone_id)?.map{ it } ?: listOf()
fun allRecords(@PathVariable zone_id: String): ApiResponseDTO<List<RecordResponseDTO>> {
return ApiResponseDTO(result = recordService.getRecordsByDomain(zone_id)?.map{ it } ?: listOf())
}
@GetMapping("{zone_id}/dns_records/{dns_record_id}")
@Operation(summary = "Get Record by ID", tags=["record"])
@ApiResponses(value = [
ApiResponse(responseCode = "200", description = "Return Record",
content = [Content(schema = Schema(implementation = RecordResponseDTO::class))]),
ApiResponse(responseCode = "200", description = "Return Record", useReturnTypeSchema = true),
ApiResponse(responseCode = "400", description = "Bad request",
content = [Content(schema = Schema(implementation = Void::class))])
content = [Content(schema = Schema(implementation = ApiResponseDTO::class))]),
])
fun getRecordByCfid(@PathVariable zone_id: String, @PathVariable dns_record_id: String): RecordResponseDTO {
return recordService.getRecord(zone_id, dns_record_id)
fun getRecordByCfid(@PathVariable zone_id: String, @PathVariable dns_record_id: String): ApiResponseDTO<RecordResponseDTO> {
return ApiResponseDTO(result = recordService.getRecord(zone_id, dns_record_id))
}
@PostMapping("{zone_id}/dns_records")
@Operation(summary = "Add Record by ID", tags=["record"])
@ApiResponses(value = [
ApiResponse(responseCode = "200", description = "Return Record",
content = [Content(schema = Schema(implementation = RecordResponseDTO::class))]),
ApiResponse(responseCode = "200", description = "Return Record", useReturnTypeSchema = true),
ApiResponse(responseCode = "400", description = "Bad request",
content = [Content(schema = Schema(implementation = Void::class))]),
content = [Content(schema = Schema(implementation = ApiResponseDTO::class))]),
])
fun createRecord(@PathVariable zone_id: String, @RequestBody record: RecordRequestDTO): RecordResponseDTO {
return recordService.createRecord(zone_id, record)
fun createRecord(@PathVariable zone_id: String, @RequestBody record: RecordRequestDTO): ApiResponseDTO<RecordResponseDTO> {
return ApiResponseDTO(result = recordService.createRecord(zone_id, record))
}
@DeleteMapping("{zone_id}/dns_records/{dns_record_id}")
@Operation(summary = "Remove Record by ID", tags=["record"])
@ApiResponses(value = [
ApiResponse(responseCode = "200", description = "Return Record",
content = [Content(schema = Schema(implementation = Void::class))]),
ApiResponse(responseCode = "200", description = "Return Record", useReturnTypeSchema = true),
ApiResponse(responseCode = "400", description = "Bad request",
content = [Content(schema = Schema(implementation = Void::class))]),
content = [Content(schema = Schema(implementation = ApiResponseDTO::class))]),
])
fun deleteRecord(@PathVariable zone_id: String, @PathVariable dns_record_id: String) {
recordService.deleteRecord(zone_id, dns_record_id)
fun deleteRecord(@PathVariable zone_id: String, @PathVariable dns_record_id: String): ApiResponseDTO<DeleteResponseWithId> {
val record_id = recordService.deleteRecord(zone_id, dns_record_id)
return ApiResponseDTO(result = DeleteResponseWithId(record_id))
}
@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 = "200", description = "Return Record", useReturnTypeSchema = true),
ApiResponse(responseCode = "400", description = "Bad request",
content = [Content(schema = Schema(implementation = Void::class))]),
content = [Content(schema = Schema(implementation = ApiResponseDTO::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)
fun updateRecord(@PathVariable zone_id: String, @PathVariable dns_record_id: String, @RequestBody record: RecordRequestDTO): ApiResponseDTO<RecordResponseDTO> {
return ApiResponseDTO(result = recordService.updateRecord(zone_id, dns_record_id, record))
}
private fun DomainRecord.toDTO() = RecordResponseDTO(

View File

@ -1,6 +1,5 @@
package space.mori.dnsapi.db
import io.swagger.v3.oas.annotations.media.Schema
import jakarta.persistence.*
import java.util.*
@ -16,8 +15,14 @@ data class Domain(
var name: String,
@Column(nullable = false, unique = true)
var cfid: String = UUID.randomUUID().toString().replace("-", "")
) {
@OneToMany(mappedBy = "domain", cascade = [CascadeType.ALL], orphanRemoval = true)
var cfid: String = UUID.randomUUID().toString().replace("-", ""),
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
var user: User,
@OneToMany(mappedBy = "domain", cascade = [CascadeType.ALL], orphanRemoval = true, fetch = FetchType.LAZY)
var records: List<Record> = mutableListOf()
) {
override fun toString(): String = "Domain(id=$cfid, name='$name')"
}

View File

@ -10,5 +10,8 @@ interface DomainRepository : JpaRepository<Domain?, Long?> {
fun findByCfid(cfid: String): Optional<Domain>
@Transactional
fun deleteByCfid(cfid: String)
fun findAllByUser(user: User): List<Domain>
@Transactional
fun deleteByCfid(cfid: String): Int
}

View File

@ -2,8 +2,6 @@ package space.mori.dnsapi.db
import jakarta.transaction.Transactional
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.query.Param
import java.util.*

View File

@ -0,0 +1,22 @@
package space.mori.dnsapi.db
import jakarta.persistence.*
import org.springframework.security.core.context.SecurityContextHolder
@Entity
data class User(
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
val id: Long? = null,
@Column(nullable = false, unique = true, name = "api_key", length = 64)
val apiKey: String,
@Column(nullable = false, unique = false, length = 20)
val name: String,
@OneToMany(mappedBy = "user", cascade = [CascadeType.ALL], orphanRemoval = true, fetch = FetchType.EAGER)
val domains: List<Domain> = mutableListOf(),
) {
override fun toString(): String = "User(id=$id, name='$name')"
}

View File

@ -0,0 +1,7 @@
package space.mori.dnsapi.db
import org.springframework.data.jpa.repository.JpaRepository
interface UserRepository: JpaRepository<User, Long> {
fun findByApiKey(apiKey: String): User?
}

View File

@ -0,0 +1,17 @@
package space.mori.dnsapi.dto
data class ApiResponseDTO<T>(
val success: Boolean = true,
val errors: List<ErrorOrMessage> = listOf(),
val messages: List<ErrorOrMessage> = listOf(),
val result: T? = null
)
data class ErrorOrMessage(
val code: Int,
val message: String
)
data class DeleteResponseWithId(
val id: String
)

View File

@ -7,7 +7,7 @@ data class RecordRequestDTO(
@Schema(description = "Record type", example = "A")
val type: String,
@Schema(description = "Host name", example = "www.example.com.")
@Schema(description = "Host name", example = "www")
val name: String,
@Schema(description = "Record data", example = "192.0.2.1")

View File

@ -11,7 +11,7 @@ data class RecordResponseDTO(
@Schema(description = "Record type", example = "A")
var type: String,
@Schema(description = "Record name", example = "test.example.com")
@Schema(description = "Record name", example = "test")
var name: String,
@Schema(description = "Record content", example = "1.1.1.1")

View File

@ -0,0 +1,38 @@
package space.mori.dnsapi.filter
import jakarta.servlet.FilterChain
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpHeaders
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
import org.springframework.stereotype.Component
import org.springframework.web.filter.OncePerRequestFilter
import space.mori.dnsapi.db.User
import space.mori.dnsapi.db.UserRepository
@Component
class UserFilter(
@Autowired
private val userRepository: UserRepository
): OncePerRequestFilter() {
override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain) {
val apiKey = request.getHeader(HttpHeaders.AUTHORIZATION)
if(apiKey != null) {
val user = userRepository.findByApiKey(apiKey.replace("Bearer ", ""))
if(user != null) {
val authentication = UsernamePasswordAuthenticationToken(
user, null, emptyList()
)
authentication.details = WebAuthenticationDetailsSource().buildDetails(request)
SecurityContextHolder.getContext().authentication = authentication
}
}
chain.doFilter(request, response)
}
}
fun getCurrentUser(): User =
SecurityContextHolder.getContext().authentication.principal as User

View File

@ -2,29 +2,56 @@ package space.mori.dnsapi.service
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import space.mori.dnsapi.PowerDNSApiClient
import space.mori.dnsapi.db.Domain
import space.mori.dnsapi.db.DomainRepository
import space.mori.dnsapi.db.UserRepository
import space.mori.dnsapi.dto.DomainRequestDTO
import space.mori.dnsapi.filter.getCurrentUser
import java.util.*
@Service
class DomainService {
class DomainService(
@Autowired
private val domainRepository: DomainRepository? = null
private val userRepository: UserRepository,
@Autowired
private val domainRepository: DomainRepository,
@Autowired
private val powerDNSApiClient: PowerDNSApiClient
) {
fun getAllDomains(): List<Domain> {
val user = getCurrentUser()
val domain = domainRepository.findAllByUser(user)
if(domain.isEmpty()) throw RuntimeException("Unauthorized")
fun getAllDomains(): List<Domain?> {
return domainRepository!!.findAll()
return domain
}
fun getDomainById(cfid: String): Optional<Domain> {
return domainRepository!!.findByCfid(cfid)
fun getDomainById(domain_id: String): Domain {
val domain = domainRepository.findByCfid(domain_id).orElseThrow {
RuntimeException("Failed to find domain in API: $domain_id")
}
val user = getCurrentUser()
if(domain.user.id != user.id)
throw RuntimeException("Unauthorized to create record in API: $domain_id")
return domain
}
fun createDomain(domain: Domain): Domain {
return domainRepository!!.save<Domain>(domain)
fun createDomain(domain: DomainRequestDTO): Domain {
val user = getCurrentUser()
powerDNSApiClient.createDomain(domain.name)
val saved_domain = domainRepository.save(Domain(name=domain.name, user=user))
return saved_domain
}
fun deleteDomain(cfid: String) {
domainRepository!!.deleteByCfid(cfid)
fun deleteDomain(domain_id: String): String {
val count = domainRepository.deleteByCfid(domain_id)
if(count > 0) throw RuntimeException("Domain with CFID $domain_id not found")
return domain_id
}
}

View File

@ -7,9 +7,11 @@ import space.mori.dnsapi.PowerDNSApiClient
import space.mori.dnsapi.db.DomainRepository
import space.mori.dnsapi.db.Record as DomainRecord
import space.mori.dnsapi.db.RecordRepository
import space.mori.dnsapi.db.UserRepository
import space.mori.dnsapi.dto.DomainRequestDTO
import space.mori.dnsapi.dto.RecordRequestDTO
import space.mori.dnsapi.dto.RecordResponseDTO
import space.mori.dnsapi.filter.getCurrentUser
import space.mori.dnsapi.getISOFormat
import java.util.*
@ -21,18 +23,25 @@ class RecordService(
@Autowired
private val domainRepository: DomainRepository,
@Autowired
private val recordRepository: RecordRepository
private val recordRepository: RecordRepository,
@Autowired
private val userRepository: UserRepository,
) {
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")
val domain = domainRepository.findByCfid(domain_id).orElseThrow {
throw RuntimeException("Failed to find domain in API: $domain_id")
}
val response = powerDNSApiClient.createRecord(domain.get().name, recordRequest)
val user = getCurrentUser()
if(domain.user.id != user.id)
throw RuntimeException("Unauthorized to create record in API: $domain_id")
val response = powerDNSApiClient.createRecord(domain.name, recordRequest)
if (!response.statusCode.is2xxSuccessful) {
throw RuntimeException("Failed to create record in PowerDNS: ${response.body}")
}
val record = DomainRecord(
domain = domain.get(),
domain = domain,
name = recordRequest.name,
type = recordRequest.type,
content = recordRequest.content,
@ -55,7 +64,7 @@ class RecordService(
ttl = record.ttl,
locked = false,
zoneId = record.cfid,
zoneName = domain.get().name,
zoneName = domain.name,
createdOn = record.createdOn.getISOFormat(),
modifiedOn = record.modifiedOn.getISOFormat(),
priority = record.prio,
@ -64,10 +73,15 @@ class RecordService(
}
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 domain = domainRepository.findByCfid(domain_id).orElseThrow {
RuntimeException("Failed to find domain in API: $domain_id")
}
val record = domain.get().records.find { it.cfid == record_id }
val user = getCurrentUser()
if(domain.user.id != user.id)
throw RuntimeException("Unauthorized to get record in API: $domain_id")
val record = domain.records.find { it.cfid == record_id }
if(record == null) throw RuntimeException("Failed to find record in API: $record_id")
return RecordResponseDTO(
@ -85,7 +99,14 @@ class RecordService(
}
fun getRecordsByDomain(domain_id: String): List<RecordResponseDTO>? {
val domain = domainRepository.findByCfid(domain_id).orElseThrow { RuntimeException("Failed to find domain in API: $domain_id") }
val domain = domainRepository.findByCfid(domain_id).orElseThrow {
RuntimeException("Failed to find domain in API: $domain_id")
}
val user = getCurrentUser()
if(domain.user.id != user.id)
throw RuntimeException("Unauthorized to create record in API: $domain_id")
return domain?.records?.map { RecordResponseDTO(
id = it.cfid,
type = it.type,
@ -102,10 +123,15 @@ class RecordService(
}
@Transactional
fun updateRecord(domainId: String, cfid: String, updatedRecord: RecordRequestDTO): RecordResponseDTO {
fun updateRecord(domain_id: String, cfid: String, updatedRecord: RecordRequestDTO): RecordResponseDTO {
// 도메인 조회
val domain = domainRepository.findByCfid(domainId)
.orElseThrow { RuntimeException("Domain not found") }
val domain = domainRepository.findByCfid(domain_id).orElseThrow {
RuntimeException("Failed to find domain in API: $domain_id")
}
val user = getCurrentUser()
if(domain.user.id != user.id)
throw RuntimeException("Unauthorized to create record in API: $domain_id")
// 레코드 조회
val record = recordRepository.findByDomainIdAndCfid(domain.id!!, cfid)
@ -144,18 +170,18 @@ class RecordService(
)
}
fun deleteRecord(domain_id: String, record_id: String) {
val domain = domainRepository.findByCfid(domain_id).orElseThrow { RuntimeException("Failed to find domain in API: $domain_id") }
fun deleteRecord(domain_id: String, record_id: String): String {
val domain = domainRepository.findByCfid(domain_id).orElseThrow {
RuntimeException("Failed to find domain in API: $domain_id")
}
val user = getCurrentUser()
if(domain.user.id != user.id)
throw RuntimeException("Unauthorized to create record 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}")
}
else return record_id
}
}