more optional validations

This commit is contained in:
gowthaman.b
2023-11-11 13:10:25 +05:30
parent ea14212337
commit 31388bae59
9 changed files with 441 additions and 68 deletions

View File

@@ -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
}
}