more optional validations
This commit is contained in:
@@ -1,16 +1,23 @@
|
||||
package com.restapi.controllers
|
||||
|
||||
import com.restapi.domain.ApprovalStatus
|
||||
import com.restapi.domain.DataModel
|
||||
import com.restapi.domain.EntityModel
|
||||
import com.restapi.domain.Session
|
||||
import com.restapi.domain.Session.database
|
||||
import com.restapi.domain.Session.findByEntityAndId
|
||||
import com.restapi.integ.Scripting
|
||||
import io.ebean.CallableSql
|
||||
import io.ebean.RawSqlBuilder
|
||||
import io.javalin.http.BadRequestResponse
|
||||
import io.javalin.http.Context
|
||||
import io.javalin.http.NotFoundResponse
|
||||
import io.javalin.http.bodyAsClass
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import java.time.LocalTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
data class PatchValue(val key: String, val value: Any)
|
||||
data class Query(
|
||||
@@ -46,6 +53,14 @@ object Entities {
|
||||
fun approve(ctx: Context) {}
|
||||
fun reject(ctx: Context) {}
|
||||
|
||||
fun executeScript(ctx: Context) {
|
||||
val name = ctx.pathParam("name")
|
||||
val params = ctx.bodyAsClass<Map<String, Any>>()
|
||||
ctx.json(
|
||||
Scripting.execute(name, params)
|
||||
)
|
||||
}
|
||||
|
||||
fun executeStoredProcedure(ctx: Context) {
|
||||
val name = ctx.pathParam("name")
|
||||
val params = ctx.bodyAsClass<Map<String, Any>>()
|
||||
@@ -58,7 +73,12 @@ object Entities {
|
||||
cs.setParameter(index + 1, entry.value)
|
||||
}
|
||||
cs.setParameter(params.entries.size + 1, Session.currentTenant())
|
||||
database.execute(cs)
|
||||
val done = database.execute(cs)
|
||||
ctx.json(
|
||||
mapOf(
|
||||
"done" to done
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun sqlQueryRaw(ctx: Context) {
|
||||
@@ -77,7 +97,7 @@ object Entities {
|
||||
|
||||
}
|
||||
|
||||
fun sqlQueryId(ctx: Context) {
|
||||
fun sqlQueryById(ctx: Context) {
|
||||
val sql = ctx.bodyAsClass<Query>()
|
||||
val query = database.findByEntityAndId(ctx.pathParam("entity"), ctx.pathParam("id"))
|
||||
|
||||
@@ -104,16 +124,112 @@ object Entities {
|
||||
}
|
||||
|
||||
fun create(ctx: Context) {
|
||||
|
||||
val entity = ctx.pathParam("entity")
|
||||
val seqCreated = Session.creatSeq(entity)
|
||||
logger.debug("sequence created for $entity? = $seqCreated")
|
||||
database.save(
|
||||
ctx.bodyAsClass<DataModel>().apply {
|
||||
this.entityName = entity
|
||||
if (this.uniqueIdentifier.isEmpty()) {
|
||||
this.uniqueIdentifier = Session.nextUniqId(entity)
|
||||
}
|
||||
|
||||
|
||||
//may be approval flow is configured?
|
||||
val setupEntity = database.find(EntityModel::class.java)
|
||||
.where()
|
||||
.eq("name", entity)
|
||||
.findOne()
|
||||
|
||||
Session.creatSeq(entity)
|
||||
val dataModel = ctx.bodyAsClass<DataModel>().apply {
|
||||
this.entityName = entity
|
||||
if (this.uniqueIdentifier.isEmpty()) {
|
||||
this.uniqueIdentifier = Session.nextUniqId(entity)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
database.save(
|
||||
dataModel.apply {
|
||||
if (setupEntity != null) {
|
||||
|
||||
val allowedFields = setupEntity.allowedFields.map { it.lowercase() }
|
||||
if (allowedFields.isNotEmpty()) {
|
||||
|
||||
val moreFields =
|
||||
dataModel.data.keys.map { it.lowercase() }.filter { !allowedFields.contains(it) }
|
||||
|
||||
if (moreFields.isNotEmpty()) {
|
||||
logger.warn("Data Keys = ${dataModel.data.keys} is more than $allowedFields, extra fields = $moreFields")
|
||||
throw BadRequestResponse("data contains more fields than allowed")
|
||||
}
|
||||
|
||||
setupEntity.allowedFieldTypes.forEach { (key, expectedType) ->
|
||||
|
||||
val valueFromUser = dataModel.data[key] ?: return@forEach
|
||||
val isDate = expectedType.equals("date", ignoreCase = true)
|
||||
val isDateTime = expectedType.equals("datetime", ignoreCase = true)
|
||||
val isTime = expectedType.equals("time", ignoreCase = true)
|
||||
if (isDate || isDateTime || isTime) {
|
||||
//this should be a string of a particular format
|
||||
if (valueFromUser !is String) {
|
||||
throw BadRequestResponse("field $key, is of type ${valueFromUser.javaClass.simpleName} expected $expectedType")
|
||||
} else {
|
||||
val dtPattern = Regex("^\\d{4}-\\d{2}-\\d{2}$")
|
||||
val dtmPattern = Regex("^\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}$")
|
||||
val timePattern = Regex("^\\d{2}:\\d{2}$")
|
||||
|
||||
|
||||
if (isDate
|
||||
&& !dtPattern.matches(valueFromUser)
|
||||
&& !isValidDate(valueFromUser)
|
||||
) {
|
||||
throw BadRequestResponse("field $key, is of type ${valueFromUser.javaClass.simpleName} expected $expectedType")
|
||||
}
|
||||
|
||||
|
||||
if (isDateTime
|
||||
&& !dtmPattern.matches(valueFromUser)
|
||||
&& !isValidDateTime(valueFromUser)
|
||||
) {
|
||||
throw BadRequestResponse("field $key, is of type ${valueFromUser.javaClass.simpleName} expected $expectedType")
|
||||
}
|
||||
|
||||
if (isTime
|
||||
&& !timePattern.matches(valueFromUser)
|
||||
&& !isValidTime(valueFromUser)
|
||||
) {
|
||||
throw BadRequestResponse("field $key, is of type ${valueFromUser.javaClass.simpleName} expected $expectedType")
|
||||
}
|
||||
}
|
||||
}
|
||||
if (valueFromUser.javaClass.simpleName != expectedType) {
|
||||
throw BadRequestResponse("field $key, is of type ${valueFromUser.javaClass.simpleName} expected $expectedType")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (setupEntity.approvalLevels > 0) {
|
||||
|
||||
this.approvalStatus = ApprovalStatus.PENDING
|
||||
this.requiredApprovalLevels = setupEntity.approvalLevels
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun isValidDate(f: String) = try {
|
||||
LocalDate.parse(f, DateTimeFormatter.ofPattern("yyyy-MM-dd"))
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
|
||||
private fun isValidDateTime(f: String) = try {
|
||||
LocalDateTime.parse(f, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
|
||||
private fun isValidTime(f: String) = try {
|
||||
LocalTime.parse(f, DateTimeFormatter.ofPattern("HH:mm"))
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user