add plant integ

This commit is contained in:
gowthaman.b 2024-03-20 14:01:22 +05:30
parent fc361e3133
commit ce1f5f9b04
6 changed files with 122 additions and 191 deletions

View File

@ -18,6 +18,8 @@ app:
client: rmc client: rmc
scripts: scripts:
path: /Users/gowthaman.b/IdeaProjects/rmc_modules_api/src/main/resources/scripts path: /Users/gowthaman.b/IdeaProjects/rmc_modules_api/src/main/resources/scripts
integration:
rmc: https://www.readymixerp.com
security: security:
enforce_role_restriction: 'true' enforce_role_restriction: 'true'
private_key: |- private_key: |-

View File

@ -9,6 +9,7 @@ import com.restapi.domain.DataNotFoundException
import com.restapi.domain.ReminderLog import com.restapi.domain.ReminderLog
import com.restapi.domain.Session.currentTenant import com.restapi.domain.Session.currentTenant
import com.restapi.domain.Session.currentUser import com.restapi.domain.Session.currentUser
import com.restapi.domain.Session.currentUserPlants
import com.restapi.domain.Session.objectMapper import com.restapi.domain.Session.objectMapper
import com.restapi.domain.Session.setAuthorizedUser import com.restapi.domain.Session.setAuthorizedUser
import com.restapi.domain.Session.signPayload import com.restapi.domain.Session.signPayload
@ -43,15 +44,13 @@ fun main(args: Array<String>) {
//ratelimit based on IP Only //ratelimit based on IP Only
RateLimitUtil.keyFunction = { ctx -> ctx.header("X-Forwarded-For")?.split(",")?.get(0) ?: ctx.ip() } RateLimitUtil.keyFunction = { ctx -> ctx.header("X-Forwarded-For")?.split(",")?.get(0) ?: ctx.ip() }
Javalin Javalin.create { cfg ->
.create { cfg ->
cfg.http.generateEtags = true cfg.http.generateEtags = true
if (appConfig.corsEnabled()) { if (appConfig.corsEnabled()) {
cfg.plugins.enableCors { container -> cfg.plugins.enableCors { container ->
container.add { container.add {
it.allowHost( it.allowHost(
"http://localhost:5173", "http://localhost:5173", *appConfig.corsHosts().toTypedArray()
*appConfig.corsHosts().toTypedArray()
) )
} }
} }
@ -60,8 +59,7 @@ fun main(args: Array<String>) {
cfg.compression.gzipOnly() cfg.compression.gzipOnly()
cfg.jsonMapper(JavalinJackson(objectMapper)) cfg.jsonMapper(JavalinJackson(objectMapper))
cfg.accessManager(AppAccessManager()) cfg.accessManager(AppAccessManager())
} }.routes {
.routes {
path("/auth") { path("/auth") {
get("/endpoint", Auth::endPoint) get("/endpoint", Auth::endPoint)
@ -73,9 +71,7 @@ fun main(args: Array<String>) {
before("/api/*") { ctx -> before("/api/*") { ctx ->
NaiveRateLimit.requestPerTimeUnit( NaiveRateLimit.requestPerTimeUnit(
ctx, ctx, appConfig.rateLimit().getOrDefault(30), TimeUnit.MINUTES
appConfig.rateLimit().getOrDefault(30),
TimeUnit.MINUTES
) )
val authToken = ctx.getAuthHeader() ?: throw UnauthorizedResponse() val authToken = ctx.getAuthHeader() ?: throw UnauthorizedResponse()
@ -106,6 +102,9 @@ fun main(args: Array<String>) {
} }
path("/api") { path("/api") {
get("/plants") {
it.json(currentUserPlants())
}
post("/audit/{action}") { post("/audit/{action}") {
logger.warn("User ${currentUser()} of tenant ${currentTenant()} has performed ${it.pathParam("action")} @ ${LocalDateTime.now()}") logger.warn("User ${currentUser()} of tenant ${currentTenant()} has performed ${it.pathParam("action")} @ ${LocalDateTime.now()}")
it.json(mapOf("status" to true)) it.json(mapOf("status" to true))
@ -117,14 +116,10 @@ fun main(args: Array<String>) {
post("/batch", VendorCtrl::createBatch, Roles(Role.Explicit("ROLE_VENDOR_CREATE"))) post("/batch", VendorCtrl::createBatch, Roles(Role.Explicit("ROLE_VENDOR_CREATE")))
get("/{id}", VendorCtrl::get, Roles(Role.Explicit("ROLE_VENDOR_VIEW", "ROLE_VENDOR_CREATE"))) get("/{id}", VendorCtrl::get, Roles(Role.Explicit("ROLE_VENDOR_VIEW", "ROLE_VENDOR_CREATE")))
post( post(
"/getAll", "/getAll", VendorCtrl::getAll, Roles(Role.Explicit("ROLE_VENDOR_VIEW", "ROLE_VENDOR_CREATE"))
VendorCtrl::getAll,
Roles(Role.Explicit("ROLE_VENDOR_VIEW", "ROLE_VENDOR_CREATE"))
) )
get( get(
"quotes/{id}", "quotes/{id}", VendorCtrl::getQuotes, Roles(Role.Explicit("ROLE_QUOTE_VIEW", "ROLE_QUOTE_CREATE", "ROLE_VENDOR_VIEW"))
VendorCtrl::getQuotes,
Roles(Role.Explicit("ROLE_QUOTE_VIEW", "ROLE_QUOTE_CREATE", "ROLE_VENDOR_VIEW"))
) )
get("pos/{id}", VendorCtrl::getPos, Roles(Role.Explicit("ROLE_PO_VIEW", "ROLE_PO_CREATE`"))) get("pos/{id}", VendorCtrl::getPos, Roles(Role.Explicit("ROLE_PO_VIEW", "ROLE_PO_CREATE`")))
put("/rate/{id}/{rating}", VendorCtrl::rate, Roles(Role.Explicit("ROLE_VENDOR_CREATE"))) put("/rate/{id}/{rating}", VendorCtrl::rate, Roles(Role.Explicit("ROLE_VENDOR_CREATE")))
@ -134,59 +129,43 @@ fun main(args: Array<String>) {
post("", IncomingInventoryCtrl::create, Roles(Role.Explicit("ROLE_INVENTORY_CREATE"))) post("", IncomingInventoryCtrl::create, Roles(Role.Explicit("ROLE_INVENTORY_CREATE")))
get("/next", IncomingInventoryCtrl::getNextNum, Roles(Role.Explicit("ROLE_INVENTORY_CREATE"))) get("/next", IncomingInventoryCtrl::getNextNum, Roles(Role.Explicit("ROLE_INVENTORY_CREATE")))
get( get(
"/{id}", "/{id}", IncomingInventoryCtrl::get, Roles(Role.Explicit("ROLE_INVENTORY_VIEW", "ROLE_INVENTORY_CREATE"))
IncomingInventoryCtrl::get,
Roles(Role.Explicit("ROLE_INVENTORY_VIEW", "ROLE_INVENTORY_CREATE"))
) )
put("/{id}", IncomingInventoryCtrl::update, Roles(Role.Explicit("ROLE_INVENTORY_CREATE"))) put("/{id}", IncomingInventoryCtrl::update, Roles(Role.Explicit("ROLE_INVENTORY_CREATE")))
post( post(
"/getAll", "/getAll", IncomingInventoryCtrl::getAll, Roles(Role.Explicit("ROLE_INVENTORY_CREATE", "ROLE_INVENTORY_VIEW"))
IncomingInventoryCtrl::getAll,
Roles(Role.Explicit("ROLE_INVENTORY_CREATE", "ROLE_INVENTORY_VIEW"))
) )
} }
path("/outgoing") { path("/outgoing") {
post("", OutgoingInventoryCtrl::create, Roles(Role.Explicit("ROLE_INVENTORY_CREATE"))) post("", OutgoingInventoryCtrl::create, Roles(Role.Explicit("ROLE_INVENTORY_CREATE")))
get("/next", OutgoingInventoryCtrl::getNextNum, Roles(Role.Explicit("ROLE_INVENTORY_CREATE"))) get("/next", OutgoingInventoryCtrl::getNextNum, Roles(Role.Explicit("ROLE_INVENTORY_CREATE")))
get( get(
"/{id}", "/{id}", OutgoingInventoryCtrl::get, Roles(Role.Explicit("ROLE_INVENTORY_VIEW", "ROLE_INVENTORY_CREATE"))
OutgoingInventoryCtrl::get,
Roles(Role.Explicit("ROLE_INVENTORY_VIEW", "ROLE_INVENTORY_CREATE"))
) )
put("/{id}", OutgoingInventoryCtrl::update, Roles(Role.Explicit("ROLE_INVENTORY_CREATE"))) put("/{id}", OutgoingInventoryCtrl::update, Roles(Role.Explicit("ROLE_INVENTORY_CREATE")))
post( post(
"/getAll", "/getAll", OutgoingInventoryCtrl::getAll, Roles(Role.Explicit("ROLE_INVENTORY_CREATE", "ROLE_INVENTORY_VIEW"))
OutgoingInventoryCtrl::getAll,
Roles(Role.Explicit("ROLE_INVENTORY_CREATE", "ROLE_INVENTORY_VIEW"))
) )
} }
path("/invoice") { path("/invoice") {
post("", InvoiceCtrl::create, Roles(Role.Explicit("ROLE_INVOICE_CREATE"))) post("", InvoiceCtrl::create, Roles(Role.Explicit("ROLE_INVOICE_CREATE")))
get("/next", InvoiceCtrl::getNextNum, Roles(Role.Explicit("ROLE_INVOICE_CREATE"))) get("/next", InvoiceCtrl::getNextNum, Roles(Role.Explicit("ROLE_INVOICE_CREATE")))
get( get(
"/{id}", "/{id}", InvoiceCtrl::get, Roles(Role.Explicit("ROLE_INVOICE_VIEW", "ROLE_INVOICE_CREATE"))
InvoiceCtrl::get,
Roles(Role.Explicit("ROLE_INVOICE_VIEW", "ROLE_INVOICE_CREATE"))
) )
put("/{id}", InvoiceCtrl::update, Roles(Role.Explicit("ROLE_INVOICE_CREATE"))) put("/{id}", InvoiceCtrl::update, Roles(Role.Explicit("ROLE_INVOICE_CREATE")))
post( post(
"/getAll", "/getAll", InvoiceCtrl::getAll, Roles(Role.Explicit("ROLE_INVOICE_CREATE", "ROLE_INVOICE_VIEW"))
InvoiceCtrl::getAll,
Roles(Role.Explicit("ROLE_INVOICE_CREATE", "ROLE_INVOICE_VIEW"))
) )
} }
path("/payment") { path("/payment") {
post("", PaymentCtrl::create, Roles(Role.Explicit("ROLE_PAYMENT_CREATE"))) post("", PaymentCtrl::create, Roles(Role.Explicit("ROLE_PAYMENT_CREATE")))
get( get(
"/{id}", "/{id}", PaymentCtrl::get, Roles(Role.Explicit("ROLE_PAYMENT_VIEW", "ROLE_PAYMENT_CREATE"))
PaymentCtrl::get,
Roles(Role.Explicit("ROLE_PAYMENT_VIEW", "ROLE_PAYMENT_CREATE"))
) )
put("/{id}", PaymentCtrl::update, Roles(Role.Explicit("ROLE_PAYMENT_CREATE"))) put("/{id}", PaymentCtrl::update, Roles(Role.Explicit("ROLE_PAYMENT_CREATE")))
post( post(
"/getAll", "/getAll", PaymentCtrl::getAll, Roles(Role.Explicit("ROLE_PAYMENT_CREATE", "ROLE_PAYMENT_VIEW"))
PaymentCtrl::getAll,
Roles(Role.Explicit("ROLE_PAYMENT_CREATE", "ROLE_PAYMENT_VIEW"))
) )
delete("/{id}", PaymentCtrl::delete, Roles(Role.Explicit("ROLE_PAYMENT_CREATE"))) delete("/{id}", PaymentCtrl::delete, Roles(Role.Explicit("ROLE_PAYMENT_CREATE")))
} }
@ -194,88 +173,62 @@ fun main(args: Array<String>) {
post("", FleetCtrl::create, Roles(Role.Explicit("ROLE_FLEET_CREATE"))) post("", FleetCtrl::create, Roles(Role.Explicit("ROLE_FLEET_CREATE")))
get( get(
"/{id}", "/{id}", FleetCtrl::get, Roles(Role.Explicit("ROLE_FLEET_VIEW", "ROLE_FLEET_CREATE"))
FleetCtrl::get,
Roles(Role.Explicit("ROLE_FLEET_VIEW", "ROLE_FLEET_CREATE"))
) )
put("/{id}", FleetCtrl::update, Roles(Role.Explicit("ROLE_FLEET_CREATE"))) put("/{id}", FleetCtrl::update, Roles(Role.Explicit("ROLE_FLEET_CREATE")))
post( post(
"/getAll", "/getAll", FleetCtrl::getAll, Roles(Role.Explicit("ROLE_FLEET_CREATE", "ROLE_FLEET_VIEW"))
FleetCtrl::getAll,
Roles(Role.Explicit("ROLE_FLEET_CREATE", "ROLE_FLEET_VIEW"))
) )
delete("/{id}", FleetCtrl::delete, Roles(Role.Explicit("ROLE_FLEET_CREATE"))) delete("/{id}", FleetCtrl::delete, Roles(Role.Explicit("ROLE_FLEET_CREATE")))
} }
path("/renewal") { path("/renewal") {
post("", RenewalCtrl::create, Roles(Role.Explicit("ROLE_FLEET_CREATE"))) post("", RenewalCtrl::create, Roles(Role.Explicit("ROLE_FLEET_CREATE")))
get( get(
"/{id}", "/{id}", RenewalCtrl::get, Roles(Role.Explicit("ROLE_FLEET_VIEW", "ROLE_FLEET_CREATE"))
RenewalCtrl::get,
Roles(Role.Explicit("ROLE_FLEET_VIEW", "ROLE_FLEET_CREATE"))
) )
put("/{id}", RenewalCtrl::update, Roles(Role.Explicit("ROLE_FLEET_CREATE"))) put("/{id}", RenewalCtrl::update, Roles(Role.Explicit("ROLE_FLEET_CREATE")))
post( post(
"/getAll", "/getAll", RenewalCtrl::getAll, Roles(Role.Explicit("ROLE_FLEET_CREATE", "ROLE_FLEET_VIEW"))
RenewalCtrl::getAll,
Roles(Role.Explicit("ROLE_FLEET_CREATE", "ROLE_FLEET_VIEW"))
) )
delete("/{id}", RenewalCtrl::delete, Roles(Role.Explicit("ROLE_FLEET_CREATE"))) delete("/{id}", RenewalCtrl::delete, Roles(Role.Explicit("ROLE_FLEET_CREATE")))
} }
path("/reminder") { path("/reminder") {
post("", ReminderCtrl::create, Roles(Role.Explicit("ROLE_REMINDER_CREATE"))) post("", ReminderCtrl::create, Roles(Role.Explicit("ROLE_REMINDER_CREATE")))
get( get(
"/{id}", "/{id}", ReminderCtrl::get, Roles(Role.Explicit("ROLE_REMINDER_VIEW", "ROLE_REMINDER_CREATE"))
ReminderCtrl::get,
Roles(Role.Explicit("ROLE_REMINDER_VIEW", "ROLE_REMINDER_CREATE"))
) )
put("/{id}", ReminderCtrl::update, Roles(Role.Explicit("ROLE_REMINDER_CREATE"))) put("/{id}", ReminderCtrl::update, Roles(Role.Explicit("ROLE_REMINDER_CREATE")))
post( post(
"/getAll", "/getAll", ReminderLogCtrl::getAll, Roles(Role.Explicit("ROLE_REMINDER_CREATE", "ROLE_REMINDER_VIEW"))
ReminderLogCtrl::getAll,
Roles(Role.Explicit("ROLE_REMINDER_CREATE", "ROLE_REMINDER_VIEW"))
) )
post( post(
"/done", "/done", ReminderLogCtrl::done, Roles(Role.Explicit("ROLE_REMAINDER_CREATE"))
ReminderLogCtrl::done,
Roles(Role.Explicit("ROLE_REMAINDER_CREATE"))
) )
get( get(
"/getAll/{id}", "/getAll/{id}", ReminderCtrl::getAllByFleetId, Roles(Role.Explicit("ROLE_REMINDER_CREATE", "ROLE_REMINDER_VIEW"))
ReminderCtrl::getAllByFleetId,
Roles(Role.Explicit("ROLE_REMINDER_CREATE", "ROLE_REMINDER_VIEW"))
) )
delete( delete(
"/{id}", "/{id}", ReminderCtrl::delete, Roles(Role.Explicit("ROLE_REMINDER_CREATE"))
ReminderCtrl::delete,
Roles(Role.Explicit("ROLE_REMINDER_CREATE"))
) )
} }
path("/vehicle") { path("/vehicle") {
post("", VehicleCtrl::create, Roles(Role.Explicit("ROLE_FLEET_CREATE"))) post("", VehicleCtrl::create, Roles(Role.Explicit("ROLE_FLEET_CREATE")))
get( get(
"/{id}", "/{id}", VehicleCtrl::get, Roles(Role.Explicit("ROLE_FLEET_VIEW", "ROLE_FLEET_CREATE"))
VehicleCtrl::get,
Roles(Role.Explicit("ROLE_FLEET_VIEW", "ROLE_FLEET_CREATE"))
) )
put("/{id}", VehicleCtrl::update, Roles(Role.Explicit("ROLE_FLEET_CREATE"))) put("/{id}", VehicleCtrl::update, Roles(Role.Explicit("ROLE_FLEET_CREATE")))
post( post(
"/getAll", "/getAll", VehicleCtrl::getAll, Roles(Role.Explicit("ROLE_FLEET_CREATE", "ROLE_FLEET_VIEW"))
VehicleCtrl::getAll,
Roles(Role.Explicit("ROLE_FLEET_CREATE", "ROLE_FLEET_VIEW"))
) )
} }
path("/fleetType") { path("/fleetType") {
post("", FleetTypeCtrl::create, Roles(Role.Explicit("ROLE_FLEET_CREATE"))) post("", FleetTypeCtrl::create, Roles(Role.Explicit("ROLE_FLEET_CREATE")))
get( get(
"/{id}", "/{id}", FleetTypeCtrl::get, Roles(Role.Explicit("ROLE_FLEET_VIEW", "ROLE_FLEET_CREATE"))
FleetTypeCtrl::get,
Roles(Role.Explicit("ROLE_FLEET_VIEW", "ROLE_FLEET_CREATE"))
) )
put("/{id}", FleetTypeCtrl::update, Roles(Role.Explicit("ROLE_FLEET_CREATE"))) put("/{id}", FleetTypeCtrl::update, Roles(Role.Explicit("ROLE_FLEET_CREATE")))
post( post(
"/getAll", "/getAll", FleetTypeCtrl::getAll, Roles(Role.Explicit("ROLE_FLEET_CREATE", "ROLE_FLEET_VIEW"))
FleetTypeCtrl::getAll,
Roles(Role.Explicit("ROLE_FLEET_CREATE", "ROLE_FLEET_VIEW"))
) )
} }
path("/po") { path("/po") {
@ -283,14 +236,10 @@ fun main(args: Array<String>) {
post("", PurchaseOrderCtrl::create, Roles(Role.Explicit("ROLE_PO_CREATE"))) post("", PurchaseOrderCtrl::create, Roles(Role.Explicit("ROLE_PO_CREATE")))
post("/batch", PurchaseOrderCtrl::createBatch, Roles(Role.Explicit("ROLE_PO_CREATE"))) post("/batch", PurchaseOrderCtrl::createBatch, Roles(Role.Explicit("ROLE_PO_CREATE")))
post( post(
"/getAll", "/getAll", PurchaseOrderCtrl::getAll, Roles(Role.Explicit("ROLE_PO_CREATE", "ROLE_PO_VIEW", "ROLE_VENDOR_CREATE"))
PurchaseOrderCtrl::getAll,
Roles(Role.Explicit("ROLE_PO_CREATE", "ROLE_PO_VIEW", "ROLE_VENDOR_CREATE"))
) )
get( get(
"/{id}", "/{id}", PurchaseOrderCtrl::get, Roles(Role.Explicit("ROLE_PO_CREATE", "ROLE_PO_VIEW", "ROLE_QUOTE_CREATE"))
PurchaseOrderCtrl::get,
Roles(Role.Explicit("ROLE_PO_CREATE", "ROLE_PO_VIEW", "ROLE_QUOTE_CREATE"))
) )
put("/{id}", PurchaseOrderCtrl::update, Roles(Role.Explicit("ROLE_PO_CREATE"))) put("/{id}", PurchaseOrderCtrl::update, Roles(Role.Explicit("ROLE_PO_CREATE")))
put("/approve/{id}", PurchaseOrderCtrl::approve, Roles(Role.Explicit())) put("/approve/{id}", PurchaseOrderCtrl::approve, Roles(Role.Explicit()))
@ -302,9 +251,7 @@ fun main(args: Array<String>) {
post("", QuotationCtrl::create, Roles(Role.Explicit("ROLE_QUOTE_CREATE"))) post("", QuotationCtrl::create, Roles(Role.Explicit("ROLE_QUOTE_CREATE")))
post("/batch", QuotationCtrl::createBatch, Roles(Role.Explicit("ROLE_QUOTE_CREATE"))) post("/batch", QuotationCtrl::createBatch, Roles(Role.Explicit("ROLE_QUOTE_CREATE")))
post( post(
"/getAll", "/getAll", QuotationCtrl::getAll, Roles(Role.Explicit("ROLE_QUOTE_CREATE", "ROLE_QUOTE_VIEW"))
QuotationCtrl::getAll,
Roles(Role.Explicit("ROLE_QUOTE_CREATE", "ROLE_QUOTE_VIEW"))
) )
get("/{id}", QuotationCtrl::get, Roles(Role.Explicit("ROLE_QUOTE_VIEW", "ROLE_QUOTE_CREATE"))) get("/{id}", QuotationCtrl::get, Roles(Role.Explicit("ROLE_QUOTE_VIEW", "ROLE_QUOTE_CREATE")))
put("/{id}", QuotationCtrl::update, Roles(Role.Explicit("ROLE_QUOTE_CREATE"))) put("/{id}", QuotationCtrl::update, Roles(Role.Explicit("ROLE_QUOTE_CREATE")))
@ -322,33 +269,23 @@ fun main(args: Array<String>) {
post("", DocumentCtrl::create, Roles(Role.Explicit("ROLE_DOC_CREATE"))) post("", DocumentCtrl::create, Roles(Role.Explicit("ROLE_DOC_CREATE")))
//why type and refid are clubbed ?? //why type and refid are clubbed ??
get( get(
"/{type}/{refId}", "/{type}/{refId}", DocumentCtrl::getWithRefId, Roles(Role.Explicit("ROLE_DOC_VIEW", "ROLE_PRODUCT_CREATE"))
DocumentCtrl::getWithRefId,
Roles(Role.Explicit("ROLE_DOC_VIEW", "ROLE_PRODUCT_CREATE"))
) )
get("/{id}", DocumentCtrl::get, Roles(Role.Explicit("ROLE_DOC_VIEW", "ROLE_PRODUCT_CREATE"))) get("/{id}", DocumentCtrl::get, Roles(Role.Explicit("ROLE_DOC_VIEW", "ROLE_PRODUCT_CREATE")))
get( get(
"/print/{id}", "/print/{id}", DocumentCtrl::print, Roles(Role.Explicit("ROLE_DOC_CREATE", "ROLE_DOC_VIEW"))
DocumentCtrl::print,
Roles(Role.Explicit("ROLE_DOC_CREATE", "ROLE_DOC_VIEW"))
) )
delete("/{id}", DocumentCtrl::delete, Roles(Role.Explicit("ROLE_DOC_CREATE"))) delete("/{id}", DocumentCtrl::delete, Roles(Role.Explicit("ROLE_DOC_CREATE")))
} }
path("/reqForQuote") { path("/reqForQuote") {
post( post(
"", "", RequestForQuote::create, Roles(Role.Explicit("ROLE_QUOTE_CREATE", "ROLE_PO_CREATE", "ROLE_RFQ_CREATE"))
RequestForQuote::create,
Roles(Role.Explicit("ROLE_QUOTE_CREATE", "ROLE_PO_CREATE", "ROLE_RFQ_CREATE"))
) )
get( get(
"/{id}", "/{id}", RequestForQuote::get, Roles(Role.Explicit("ROLE_RFQ_CREATE", "ROLE_RFQ_VIEW", "ROLE_QUOTE_VIEW", "ROLE_PO_VIEW"))
RequestForQuote::get,
Roles(Role.Explicit("ROLE_RFQ_CREATE", "ROLE_RFQ_VIEW", "ROLE_QUOTE_VIEW", "ROLE_PO_VIEW"))
) )
put( put(
"/{id}", "/{id}", RequestForQuote::update, Roles(Role.Explicit("ROLE_QUOTE_CREATE", "ROLE_PO_CREATE", "ROLE_RFQ_CREATE"))
RequestForQuote::update,
Roles(Role.Explicit("ROLE_QUOTE_CREATE", "ROLE_PO_CREATE", "ROLE_RFQ_CREATE"))
) )
} }
} }
@ -368,18 +305,11 @@ fun main(args: Array<String>) {
patch("/{entity}/{id}", Entities::patch, Roles(adminRole, updateRole)) patch("/{entity}/{id}", Entities::patch, Roles(adminRole, updateRole))
delete("/{entity}/{id}", Entities::delete, Roles(adminRole, Role.Standard(Action.DELETE))) delete("/{entity}/{id}", Entities::delete, Roles(adminRole, Role.Standard(Action.DELETE)))
} }
} }.exception(DuplicateKeyException::class.java, Exceptions.dupKeyExceptionHandler).exception(DataIntegrityException::class.java, Exceptions.dataIntegrityException)
.exception(DuplicateKeyException::class.java, Exceptions.dupKeyExceptionHandler) .exception(DataNotFoundException::class.java, Exceptions.dataNotFoundException).exception(IllegalArgumentException::class.java, Exceptions.illegalArgumentException)
.exception(DataIntegrityException::class.java, Exceptions.dataIntegrityException) .exception(JsonMappingException::class.java, Exceptions.jsonMappingException).exception(InvalidJwtException::class.java, Exceptions.invalidJwtException)
.exception(DataNotFoundException::class.java, Exceptions.dataNotFoundException)
.exception(IllegalArgumentException::class.java, Exceptions.illegalArgumentException)
.exception(JsonMappingException::class.java, Exceptions.jsonMappingException)
.exception(InvalidJwtException::class.java, Exceptions.invalidJwtException)
.start(appConfig.portNumber()) .start(appConfig.portNumber())
} }
private fun Context.getAuthHeader() = header("Authorization") private fun Context.getAuthHeader() = header("Authorization")?.replace("Bearer ", "")?.replace("Bearer: ", "")?.trim()
?.replace("Bearer ", "")
?.replace("Bearer: ", "")
?.trim()

View File

@ -58,6 +58,10 @@ interface AppConfig {
@Key("app.iam.client_secret") @Key("app.iam.client_secret")
fun iamClientSecret(): Optional<String> fun iamClientSecret(): Optional<String>
@Key("app.integration.rmc")
@Default("https://www.readymixerp.com")
fun integrationRmc(): String
@Key("app.cache.redis_uri") @Key("app.cache.redis_uri")
fun redisUri(): Optional<String> fun redisUri(): Optional<String>

View File

@ -2,6 +2,7 @@ package com.restapi.config
import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.readValue
import com.restapi.config.AppConfig.Companion.appConfig import com.restapi.config.AppConfig.Companion.appConfig
import com.restapi.domain.Plant
import com.restapi.domain.Session import com.restapi.domain.Session
import com.restapi.domain.Session.objectMapper import com.restapi.domain.Session.objectMapper
import io.javalin.http.BadRequestResponse import io.javalin.http.BadRequestResponse
@ -9,6 +10,9 @@ import io.javalin.http.ContentType
import io.javalin.http.Context import io.javalin.http.Context
import io.javalin.http.UnauthorizedResponse import io.javalin.http.UnauthorizedResponse
import io.javalin.security.RouteRole import io.javalin.security.RouteRole
import org.apache.http.client.methods.HttpGet
import org.apache.http.impl.client.HttpClients
import org.apache.http.util.EntityUtils
import org.jose4j.jwk.HttpsJwks import org.jose4j.jwk.HttpsJwks
import org.jose4j.jwt.consumer.JwtConsumerBuilder import org.jose4j.jwt.consumer.JwtConsumerBuilder
import org.jose4j.keys.resolvers.HttpsJwksVerificationKeyResolver import org.jose4j.keys.resolvers.HttpsJwksVerificationKeyResolver
@ -43,13 +47,10 @@ object Auth {
fun getAuthEndpoint(): AuthEndpoint { fun getAuthEndpoint(): AuthEndpoint {
return authCache.computeIfAbsent("AUTH") { return authCache.computeIfAbsent("AUTH") {
val wellKnown = val wellKnown = "${appConfig.iamUrl()}/realms/${appConfig.iamRealm()}/.well-known/openid-configuration"
"${appConfig.iamUrl()}/realms/${appConfig.iamRealm()}/.well-known/openid-configuration"
val client = HttpClient.newHttpClient() val client = HttpClient.newHttpClient()
val req = HttpRequest.newBuilder() val req = HttpRequest.newBuilder().uri(URI.create(wellKnown)).GET().build()
.uri(URI.create(wellKnown))
.GET().build()
objectMapper.readValue<AuthEndpoint>( objectMapper.readValue<AuthEndpoint>(
client.send(req, HttpResponse.BodyHandlers.ofString()).body() client.send(req, HttpResponse.BodyHandlers.ofString()).body()
@ -58,19 +59,11 @@ object Auth {
} }
private val jwtConsumer = JwtConsumerBuilder() private val jwtConsumer = JwtConsumerBuilder().setRequireExpirationTime().setAllowedClockSkewInSeconds(30).setRequireSubject().setExpectedAudience("account")
.setRequireExpirationTime() .setExpectedIssuer(getAuthEndpoint().issuer).setVerificationKeyResolver(HttpsJwksVerificationKeyResolver(HttpsJwks(getAuthEndpoint().jwksUri))).build()
.setAllowedClockSkewInSeconds(30)
.setRequireSubject()
.setExpectedAudience("account")
.setExpectedIssuer(getAuthEndpoint().issuer)
.setVerificationKeyResolver(HttpsJwksVerificationKeyResolver(HttpsJwks(getAuthEndpoint().jwksUri)))
.build()
private val jwtConsumerSkipValidate = JwtConsumerBuilder() private val jwtConsumerSkipValidate =
.setSkipAllValidators() JwtConsumerBuilder().setSkipAllValidators().setVerificationKeyResolver(HttpsJwksVerificationKeyResolver(HttpsJwks(getAuthEndpoint().jwksUri))).build()
.setVerificationKeyResolver(HttpsJwksVerificationKeyResolver(HttpsJwks(getAuthEndpoint().jwksUri)))
.build()
fun validateAuthToken(authToken: String, skipValidate: Boolean = false): AuthUser { fun validateAuthToken(authToken: String, skipValidate: Boolean = false): AuthUser {
@ -78,14 +71,29 @@ object Auth {
val jwtClaims = if (skipValidate) jwtConsumerSkipValidate.process(authToken) else jwtConsumer.process(authToken) val jwtClaims = if (skipValidate) jwtConsumerSkipValidate.process(authToken) else jwtConsumer.process(authToken)
val userId = jwtClaims.jwtClaims.claimsMap["preferred_username"] as String val userId = jwtClaims.jwtClaims.claimsMap["preferred_username"] as String
val tenant = jwtClaims.jwtClaims.claimsMap["tenant"] as String val tenant = jwtClaims.jwtClaims.claimsMap["tenant"] as String
val plantIds = jwtClaims.jwtClaims.claimsMap["plantIds"] as List<String>
val roles = ((jwtClaims.jwtClaims.claimsMap["realm_access"] as Map<String, Any>)["roles"]) as List<String> val roles = ((jwtClaims.jwtClaims.claimsMap["realm_access"] as Map<String, Any>)["roles"]) as List<String>
val date = Date(jwtClaims.jwtClaims.expirationTime.valueInMillis) val date = Date(jwtClaims.jwtClaims.expirationTime.valueInMillis)
HttpClients.createDefault().use { h ->
//sync plant's from rmc to here, just name and id
for (plantId in plantIds) {
val existing = Session.database.find(Plant::class.java).where().eq("plantId", plantId).findOne()
if (existing == null) {
h.execute(HttpGet("${appConfig.integrationRmc()}/plant?id=${plantId}")).use { r ->
if (r.statusLine.statusCode == 200) {
Session.database.save(Plant().apply {
this.plantId = plantId
this.plantName = EntityUtils.toString(r.entity)
})
}
}
}
}
}
return AuthUser( return AuthUser(
userName = userId, userName = userId, tenant = tenant, roles = roles, token = authToken, expiry = LocalDateTime.from(date.toInstant().atZone(ZoneId.systemDefault())), plantIds = plantIds
tenant = tenant,
roles = roles,
token = authToken,
expiry = LocalDateTime.from(date.toInstant().atZone(ZoneId.systemDefault()))
) )
} }
@ -100,8 +108,7 @@ object Auth {
fun init(ctx: Context) { fun init(ctx: Context) {
val endpoint = getAuthEndpoint().authorizationEndpoint val endpoint = getAuthEndpoint().authorizationEndpoint
val redirectUrl = val redirectUrl = "$endpoint?response_type=code&client_id=${appConfig.iamClient()}&redirect_uri=${appConfig.iamClientRedirectUri()}&scope=profile&state=1234zyx"
"$endpoint?response_type=code&client_id=${appConfig.iamClient()}&redirect_uri=${appConfig.iamClientRedirectUri()}&scope=profile&state=1234zyx"
ctx.redirect(redirectUrl) ctx.redirect(redirectUrl)
} }
@ -112,9 +119,7 @@ object Auth {
val ep = getAuthEndpoint().tokenEndpoint val ep = getAuthEndpoint().tokenEndpoint
val httpClient = HttpClient.newHttpClient() val httpClient = HttpClient.newHttpClient()
val req = HttpRequest.newBuilder() val req = HttpRequest.newBuilder().uri(URI.create(ep)).POST(
.uri(URI.create(ep))
.POST(
HttpRequest.BodyPublishers.ofString( HttpRequest.BodyPublishers.ofString(
getFormDataAsString( getFormDataAsString(
mapOf( mapOf(
@ -125,9 +130,7 @@ object Auth {
) )
) )
) )
) ).header("Content-Type", "application/x-www-form-urlencoded").build()
.header("Content-Type", "application/x-www-form-urlencoded")
.build()
val message = httpClient.send(req, HttpResponse.BodyHandlers.ofString()).body() val message = httpClient.send(req, HttpResponse.BodyHandlers.ofString()).body()
val atResponse = objectMapper.readValue<AuthTokenResponse>(message) val atResponse = objectMapper.readValue<AuthTokenResponse>(message)
@ -135,8 +138,7 @@ object Auth {
//keep track of this for renewal when asked by client //keep track of this for renewal when asked by client
Session.redis.lpush( Session.redis.lpush(
"$AUTH_TOKEN${parsed.userName}", "$AUTH_TOKEN${parsed.userName}", objectMapper.writeValueAsString(
objectMapper.writeValueAsString(
atResponse.copy( atResponse.copy(
createdAt = LocalDateTime.now() createdAt = LocalDateTime.now()
) )
@ -147,10 +149,7 @@ object Auth {
fun refreshToken(ctx: Context) { fun refreshToken(ctx: Context) {
//refresh authToken //refresh authToken
val authToken = ctx.header("Authorization") val authToken = ctx.header("Authorization")?.replace("Bearer ", "")?.replace("Bearer: ", "")?.trim() ?: throw UnauthorizedResponse()
?.replace("Bearer ", "")
?.replace("Bearer: ", "")
?.trim() ?: throw UnauthorizedResponse()
val authUser = validateAuthToken(authToken, skipValidate = true) val authUser = validateAuthToken(authToken, skipValidate = true)
val client = ctx.queryParam("client") ?: throw BadRequestResponse("client not sent") val client = ctx.queryParam("client") ?: throw BadRequestResponse("client not sent")
@ -159,10 +158,7 @@ object Auth {
val key = "$AUTH_TOKEN${authUser.userName}" val key = "$AUTH_TOKEN${authUser.userName}"
val found = Session.redis.llen(key) val found = Session.redis.llen(key)
logger.warn("for user ${authUser.userName}, found from redis, $key => $found entries") logger.warn("for user ${authUser.userName}, found from redis, $key => $found entries")
val foundOldAt = (0..found) val foundOldAt = (0..found).mapNotNull { Session.redis.lindex(key, it) }.map { objectMapper.readValue<AuthTokenResponse>(it) }.firstOrNull { it.accessToken == authToken }
.mapNotNull { Session.redis.lindex(key, it) }
.map { objectMapper.readValue<AuthTokenResponse>(it) }
.firstOrNull { it.accessToken == authToken }
?: throw BadRequestResponse("authToken not found in cache") ?: throw BadRequestResponse("authToken not found in cache")
val createdAt = foundOldAt.createdAt ?: throw BadRequestResponse("created at is missing") val createdAt = foundOldAt.createdAt ?: throw BadRequestResponse("created at is missing")
@ -177,9 +173,7 @@ object Auth {
logger.warn("We can refresh the token for ${authUser.userName}, expires = $expiresAt, refresh Till = $rtExpiresAt") logger.warn("We can refresh the token for ${authUser.userName}, expires = $expiresAt, refresh Till = $rtExpiresAt")
val ep = getAuthEndpoint().tokenEndpoint val ep = getAuthEndpoint().tokenEndpoint
val httpClient = HttpClient.newHttpClient() val httpClient = HttpClient.newHttpClient()
val req = HttpRequest.newBuilder() val req = HttpRequest.newBuilder().uri(URI.create(ep)).POST(
.uri(URI.create(ep))
.POST(
HttpRequest.BodyPublishers.ofString( HttpRequest.BodyPublishers.ofString(
getFormDataAsString( getFormDataAsString(
mapOf( mapOf(
@ -190,16 +184,13 @@ object Auth {
) )
) )
) )
) ).header("Content-Type", "application/x-www-form-urlencoded").build()
.header("Content-Type", "application/x-www-form-urlencoded")
.build()
val message = httpClient.send(req, HttpResponse.BodyHandlers.ofString()).body() val message = httpClient.send(req, HttpResponse.BodyHandlers.ofString()).body()
val atResponse = objectMapper.readValue<AuthTokenResponse>(message) val atResponse = objectMapper.readValue<AuthTokenResponse>(message)
val parsed = validateAuthToken(atResponse.accessToken) val parsed = validateAuthToken(atResponse.accessToken)
Session.redis.lpush( Session.redis.lpush(
"AUTH_TOKEN_${parsed.userName}", "AUTH_TOKEN_${parsed.userName}", objectMapper.writeValueAsString(
objectMapper.writeValueAsString(
atResponse.copy(createdAt = LocalDateTime.now()) atResponse.copy(createdAt = LocalDateTime.now())
) )
) )
@ -221,11 +212,7 @@ object Auth {
} }
data class AuthUser( data class AuthUser(
val userName: String, val userName: String, val tenant: String, val roles: List<String>, val token: String, val expiry: LocalDateTime, val plantIds: List<String>
val tenant: String,
val roles: List<String>,
val token: String,
val expiry: LocalDateTime
) )
enum class Action { enum class Action {

View File

@ -39,7 +39,7 @@ object Session {
private val logger = LoggerFactory.getLogger("session") private val logger = LoggerFactory.getLogger("session")
private val currentUser = object : ThreadLocal<AuthUser>() { private val currentUser = object : ThreadLocal<AuthUser>() {
override fun initialValue(): AuthUser { override fun initialValue(): AuthUser {
return AuthUser("", "", emptyList(), "", LocalDateTime.now()) return AuthUser("", "", emptyList(), "", LocalDateTime.now(), emptyList())
} }
} }
@ -182,6 +182,13 @@ object Session {
fun currentTenant() = currentUser.get().tenant fun currentTenant() = currentUser.get().tenant
fun currentRoles() = currentUser.get().roles fun currentRoles() = currentUser.get().roles
fun currentToken() = currentUser.get().token fun currentToken() = currentUser.get().token
fun currentUserPlants() = currentUser.get().plantIds.map {
Session.database.find(Plant::class.java)
.where()
.eq("plantId", it)
.findOne()
}.filterNotNull()
fun jwk() = keypair.toParams(JsonWebKey.OutputControlLevel.PUBLIC_ONLY) fun jwk() = keypair.toParams(JsonWebKey.OutputControlLevel.PUBLIC_ONLY)
fun Database.findDataModelByEntityAndUniqId(entity: String, uniqId: String): DataModel { fun Database.findDataModelByEntityAndUniqId(entity: String, uniqId: String): DataModel {

View File

@ -14,11 +14,7 @@ import javax.persistence.*
data class Comments(val text: String = "", val by: String = "", val at: LocalDateTime = LocalDateTime.now()) data class Comments(val text: String = "", val by: String = "", val at: LocalDateTime = LocalDateTime.now())
data class POProducts( data class POProducts(
val productId: String = "", val productId: String = "", val productName: String = "", val unitPrice: Double = 0.0, val quantity: Double = 0.0, val description: String = ""
val productName: String = "",
val unitPrice: Double = 0.0,
val quantity: Double = 0.0,
val description: String = ""
) )
@ -112,15 +108,13 @@ open class AuditLog : BaseTenantModel() {
@DbJsonB @DbJsonB
@Index( @Index(
definition = "create index audit_log_values_idx on audit_log using GIN (data)", definition = "create index audit_log_values_idx on audit_log using GIN (data)", platforms = [Platform.POSTGRES]
platforms = [Platform.POSTGRES]
) )
var data: Map<String, Any> = hashMapOf() var data: Map<String, Any> = hashMapOf()
@DbJsonB @DbJsonB
@Index( @Index(
definition = "create index audit_log_changes_idx on audit_log using GIN (changes)", definition = "create index audit_log_changes_idx on audit_log using GIN (changes)", platforms = [Platform.POSTGRES]
platforms = [Platform.POSTGRES]
) )
var changes: Map<String, Any> = hashMapOf() var changes: Map<String, Any> = hashMapOf()
} }
@ -636,3 +630,10 @@ open class ReminderLog : BaseTenantModel() {
@DbArray @DbArray
var documents: List<String>? = null var documents: List<String>? = null
} }
@Entity
@Index(name="plantid_idx", columnNames = ["plant_id"], unique = true)
open class Plant : BaseModel() {
var plantId: String = ""
var plantName: String = ""
}