Open-sourced generic, dynamic POC, RESTful alerting API
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
import org.springframework.boot.gradle.tasks.bundling.BootJar
|
||||
|
||||
plugins {
|
||||
id("io.swagger.core.v3.swagger-gradle-plugin") version "2.1.9"
|
||||
kotlin("plugin.jpa") version "1.5.10"
|
||||
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
sourceCompatibility = "1.8"
|
||||
targetCompatibility = "1.8"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
"implementation"(project(":persistence"))
|
||||
"implementation"(project(":amqp"))
|
||||
|
||||
implementation("org.springframework.boot:spring-boot-starter-aop")
|
||||
implementation("org.springframework.boot:spring-boot-starter-web")
|
||||
implementation("org.springframework.boot:spring-boot-starter-tomcat")
|
||||
implementation("javax.validation:validation-api")
|
||||
}
|
||||
|
||||
tasks.getByName<BootJar>("bootJar") {
|
||||
enabled = true
|
||||
mainClass.set("com.poc.alerting.api.AlertingApi")
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.poc.alerting.api;
|
||||
|
||||
import java.beans.FeatureDescriptor;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
|
||||
public final class PropertyCopier {
|
||||
private PropertyCopier() {
|
||||
}
|
||||
|
||||
public static void copyNonNullProperties(final Object source, final Object target, final List<String> ignoredProperties) {
|
||||
BeanUtils.copyProperties(source, target, getNullPropertyNames(source, ignoredProperties));
|
||||
}
|
||||
|
||||
private static String[] getNullPropertyNames(final Object source, final List<String> ignoredProperties) {
|
||||
final BeanWrapper wrappedSource = new BeanWrapperImpl(source);
|
||||
return Stream.of(wrappedSource.getPropertyDescriptors())
|
||||
.map(FeatureDescriptor::getName)
|
||||
.filter(propertyName -> wrappedSource.getPropertyValue(propertyName) == null || (ignoredProperties != null && ignoredProperties.contains(propertyName)))
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.poc.alerting.api
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.runApplication
|
||||
|
||||
@SpringBootApplication(scanBasePackages = ["com.poc.alerting"])
|
||||
open class AlertingApi
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
runApplication<AlertingApi>(*args)
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.poc.alerting.api.controller
|
||||
|
||||
import com.poc.alerting.amqp.AlertingAmqpMessage.Add
|
||||
import com.poc.alerting.amqp.AlertingAmqpMessage.Delete
|
||||
import com.poc.alerting.amqp.AlertingAmqpMessage.Pause
|
||||
import com.poc.alerting.amqp.AlertingAmqpMessage.Resume
|
||||
import com.poc.alerting.amqp.AlertingAmqpMessage.Update
|
||||
import com.poc.alerting.amqp.RabbitSender
|
||||
import com.poc.alerting.api.PropertyCopier
|
||||
import com.poc.alerting.persistence.dto.Alert
|
||||
import com.poc.alerting.persistence.repositories.AccountRepository
|
||||
import com.poc.alerting.persistence.repositories.AlertRepository
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.validation.annotation.Validated
|
||||
import org.springframework.web.bind.annotation.DeleteMapping
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PatchMapping
|
||||
import org.springframework.web.bind.annotation.PathVariable
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.bind.annotation.RequestParam
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import javax.validation.Valid
|
||||
|
||||
@RestController
|
||||
@Validated
|
||||
open class AlertController @Autowired constructor(
|
||||
private val accountRepository: AccountRepository,
|
||||
private val alertRepository: AlertRepository,
|
||||
private val rabbitSender: RabbitSender
|
||||
) {
|
||||
@PostMapping("/accounts/{account_id}/alerts")
|
||||
open fun addAlert(@PathVariable("account_id") accountId: String,
|
||||
@RequestBody body: @Valid Alert
|
||||
): ResponseEntity<Alert> {
|
||||
val account = accountRepository.findByExtId(accountId)
|
||||
body.account = account
|
||||
val alert = alertRepository.save(body).also {
|
||||
rabbitSender.send(Add(body.frequency, body.extId, accountId))
|
||||
}
|
||||
|
||||
return ResponseEntity(alert, HttpStatus.CREATED)
|
||||
}
|
||||
|
||||
@DeleteMapping("/accounts/{account_id}/alerts/{alert_id}")
|
||||
open fun deleteAlert(@PathVariable("account_id") accountId: String,
|
||||
@PathVariable("alert_id") alertId: String
|
||||
): ResponseEntity<Void> {
|
||||
rabbitSender.send(Delete(alertId, accountId))
|
||||
return ResponseEntity(HttpStatus.OK)
|
||||
}
|
||||
|
||||
@GetMapping("/accounts/{account_id}/alerts/{alert_id}")
|
||||
open fun getAlertById(
|
||||
@PathVariable("account_id") accountId: String,
|
||||
@PathVariable("alert_id") alertId: String,
|
||||
@RequestParam(value = "include_recipients", required = false, defaultValue = "false") includeRecipients: @Valid Boolean?
|
||||
): ResponseEntity<Alert> {
|
||||
return ResponseEntity.ok(alertRepository.findByExtIdAndAccount_ExtId(alertId, accountId))
|
||||
}
|
||||
|
||||
@GetMapping("/accounts/{account_id}/alerts")
|
||||
open fun getListOfAlerts(
|
||||
@PathVariable("account_id") accountId: String,
|
||||
@RequestParam(value = "include_recipients", required = false, defaultValue = "false") includeRecipients: @Valid Boolean?
|
||||
): ResponseEntity<List<Alert>> {
|
||||
return ResponseEntity.ok(alertRepository.findAllByAccount_ExtId(accountId))
|
||||
}
|
||||
|
||||
@PatchMapping("/accounts/{account_id}/alerts/{alert_id}")
|
||||
open fun updateAlert(
|
||||
@PathVariable("account_id") accountId: String,
|
||||
@PathVariable("alert_id") alertId: String,
|
||||
@RequestBody body: @Valid Alert
|
||||
): ResponseEntity<Alert> {
|
||||
val existingAlert = alertRepository.findByExtIdAndAccount_ExtId(alertId, accountId)
|
||||
|
||||
rabbitSender.send(Update(body.frequency, alertId, accountId))
|
||||
|
||||
body.enabled.let {
|
||||
if (body.enabled.isNotBlank() && body.enabled.toBoolean() != existingAlert.enabled.toBoolean()) {
|
||||
if (body.enabled.toBoolean()) {
|
||||
rabbitSender.send(Resume(alertId, accountId))
|
||||
} else {
|
||||
rabbitSender.send(Pause(alertId, accountId))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PropertyCopier.copyNonNullProperties(body, existingAlert, null)
|
||||
return ResponseEntity.ok(alertRepository.save(existingAlert))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.poc.alerting.api.controller
|
||||
|
||||
import com.poc.alerting.api.PropertyCopier
|
||||
import com.poc.alerting.persistence.dto.Recipient
|
||||
import com.poc.alerting.persistence.repositories.RecipientRepository
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.validation.annotation.Validated
|
||||
import org.springframework.web.bind.annotation.DeleteMapping
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PatchMapping
|
||||
import org.springframework.web.bind.annotation.PathVariable
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import javax.validation.Valid
|
||||
|
||||
@RestController
|
||||
@Validated
|
||||
open class RecipientController @Autowired constructor(
|
||||
private val recipientRepository: RecipientRepository
|
||||
) {
|
||||
@PostMapping("/accounts/{account_id}/alerts/{alert_id}/recipients")
|
||||
open fun addRecipient(@PathVariable("account_id") accountId: String,
|
||||
@PathVariable("alert_id") alertId: String,
|
||||
@RequestBody body: @Valid MutableList<Recipient>
|
||||
): ResponseEntity<Iterable<Recipient>> {
|
||||
return ResponseEntity(recipientRepository.saveAll(body), HttpStatus.CREATED)
|
||||
}
|
||||
|
||||
@DeleteMapping("/accounts/{account_id}/alerts/{alert_id}/recipients/{recipient_id}")
|
||||
open fun deleteRecipient(
|
||||
@PathVariable("account_id") accountId: String,
|
||||
@PathVariable("alert_id") alertId: String,
|
||||
@PathVariable("recipient_id") recipientId: String
|
||||
): ResponseEntity<Void> {
|
||||
recipientRepository.delete(recipientRepository.findByExtIdAndAlert_ExtIdAndAccount_ExtId(recipientId, alertId, accountId))
|
||||
return ResponseEntity(HttpStatus.OK)
|
||||
}
|
||||
|
||||
@GetMapping("/accounts/{account_id}/recipients")
|
||||
open fun getAllRecipients(
|
||||
@PathVariable("account_id") accountId: String
|
||||
): ResponseEntity<List<Recipient>> {
|
||||
return ResponseEntity.ok(recipientRepository.findAllByAccount_ExtId(accountId))
|
||||
}
|
||||
|
||||
@GetMapping("/accounts/{account_id}/alerts/{alert_id}/recipients/{recipient_id}")
|
||||
open fun getRecipient(
|
||||
@PathVariable("account_id") accountId: String,
|
||||
@PathVariable("alert_id") alertId: String,
|
||||
@PathVariable("recipient_id") recipientId: String
|
||||
): ResponseEntity<Recipient> {
|
||||
return ResponseEntity.ok(recipientRepository.findByExtIdAndAlert_ExtIdAndAccount_ExtId(recipientId, alertId, accountId))
|
||||
}
|
||||
|
||||
@GetMapping("/accounts/{account_id}/alerts/{alert_id}/recipients")
|
||||
open fun getRecipientList(
|
||||
@PathVariable("account_id") accountId: String,
|
||||
@PathVariable("alert_id") alertId: String
|
||||
): ResponseEntity<List<Recipient>> {
|
||||
return ResponseEntity.ok(recipientRepository.findAllByAlert_ExtIdAndAccount_ExtId(alertId, accountId))
|
||||
}
|
||||
|
||||
@PatchMapping("/accounts/{account_id}/alerts/{alert_id}/recipients/{recipient_id}")
|
||||
open fun updateRecipient(
|
||||
@PathVariable("account_id") accountId: String,
|
||||
@PathVariable("alert_id") alertId: String,
|
||||
@PathVariable("recipient_id") recipientId: String,
|
||||
@RequestBody body: @Valid Recipient
|
||||
): ResponseEntity<Recipient> {
|
||||
val existingRecipient = recipientRepository.findByExtIdAndAlert_ExtIdAndAccount_ExtId(recipientId, alertId, accountId)
|
||||
PropertyCopier.copyNonNullProperties(body, existingRecipient, null)
|
||||
return ResponseEntity.ok(recipientRepository.save(existingRecipient))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
server:
|
||||
servlet:
|
||||
contextPath: "/poc/alerting/v1"
|
||||
port: 8080
|
||||
spring:
|
||||
jackson:
|
||||
time-zone: UTC
|
||||
default-property-inclusion: non_null
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
show-sql: true
|
||||
datasource:
|
||||
url: "jdbc:h2:tcp://localhost:9091/mem:alerting"
|
||||
username: "defaultUser"
|
||||
password: "secret"
|
||||
application:
|
||||
name: AlertingApi
|
||||
main:
|
||||
allow-bean-definition-overriding: true
|
||||
profiles:
|
||||
active: "api"
|
||||
Reference in New Issue
Block a user