Skip to content

Commit

Permalink
feat(bpdm): post endpoint to upload business partner data using csv file
Browse files Browse the repository at this point in the history
feat(bpdm): refactored validate and mapping with new test class

feat(bpdm): updated chart version and provide dependency to parent pom
  • Loading branch information
SujitMBRDI committed Jun 20, 2024
1 parent 0eabfc5 commit f5f06b2
Show file tree
Hide file tree
Showing 31 changed files with 1,282 additions and 52 deletions.
98 changes: 52 additions & 46 deletions DEPENDENCIES

Large diffs are not rendered by default.

12 changes: 10 additions & 2 deletions bpdm-common-test/src/main/resources/keycloak/CX-Central.json
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,14 @@
"clientRole" : true,
"containerId" : "0562ecfa-f17b-4d32-86cc-061f7da34b6b",
"attributes" : { }
}, {
"id" : "e3ca0b50-95c7-43d5-baf6-359d87fc272a",
"name" : "upload_input_partner",
"description" : "Upload access to business partner input data",
"composite" : false,
"clientRole" : true,
"containerId" : "0562ecfa-f17b-4d32-86cc-061f7da34b6b",
"attributes" : {}
} ],
"account-console" : [ ],
"EDC-GATE-OUTPUT-CONSUMER" : [ ],
Expand Down Expand Up @@ -551,7 +559,7 @@
"attributes" : { },
"realmRoles" : [ ],
"clientRoles" : {
"BPDM-GATE" : [ "write_sharing_state", "read_output_partner", "read_input_changelog", "read_stats", "read_output_changelog", "write_input_partner", "read_sharing_state", "read_input_partner" ]
"BPDM-GATE" : [ "write_sharing_state", "read_output_partner", "read_input_changelog", "read_stats", "read_output_changelog", "write_input_partner", "read_sharing_state", "read_input_partner", "upload_input_partner" ]
},
"subGroups" : [ ]
}, {
Expand All @@ -571,7 +579,7 @@
"attributes" : { },
"realmRoles" : [ ],
"clientRoles" : {
"BPDM-GATE" : [ "write_sharing_state", "read_input_changelog", "read_stats", "write_input_partner", "read_sharing_state", "read_input_partner" ]
"BPDM-GATE" : [ "write_sharing_state", "read_input_changelog", "read_stats", "write_input_partner", "read_sharing_state", "read_input_partner", "upload_input_partner" ]
},
"subGroups" : [ ]
}, {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*******************************************************************************
* Copyright (c) 2021,2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
******************************************************************************/

package org.eclipse.tractusx.bpdm.gate.api

import io.swagger.v3.oas.annotations.Operation
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.eclipse.tractusx.bpdm.gate.api.GateBusinessPartnerApi.Companion.BUSINESS_PARTNER_PATH
import org.eclipse.tractusx.bpdm.gate.api.model.response.BusinessPartnerInputDto
import org.eclipse.tractusx.bpdm.gate.api.model.response.PartnerUploadErrorResponse
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestPart
import org.springframework.web.multipart.MultipartFile

@RequestMapping(BUSINESS_PARTNER_PATH, produces = [MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE])
interface GatePartnerUploadApi {

companion object{
const val BUSINESS_PARTNER_PATH = ApiCommons.BASE_PATH
}

@Operation(
summary = "Create or update business partners from uploaded CSV file",
description = "Create or update generic business partners. " +
"Updates instead of creating a new business partner if an already existing external ID is used. " +
"The same external ID may not occur more than once in a single request. " +
"For file upload request, the maximum number of business partners in file limited to \${bpdm.api.upsert-limit} entries.",
)
@ApiResponses(
value = [
ApiResponse(responseCode = "200", description = "Business partners were successfully updated or created"),
ApiResponse(responseCode = "400", description = "On malformed Business partner upload request",
content = [Content(
mediaType = "application/json",
schema = Schema(implementation = PartnerUploadErrorResponse::class)
)]),
]
)
@PostMapping("/input/partner-upload-process", consumes = ["multipart/form-data"])
fun uploadPartnerCsvFile(
@RequestPart("file") file: MultipartFile
): ResponseEntity<Collection<BusinessPartnerInputDto>>

}
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,6 @@ interface GateClient {
val sharingState: SharingStateApiClient

val stats: StatsApiClient

val partnerUpload: PartnerUploadApiClient
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class GateClientImpl(

override val stats by lazy { createClient<StatsApiClient>() }

override val partnerUpload by lazy { createClient<PartnerUploadApiClient>() }

private inline fun <reified T> createClient() =
httpServiceProxyFactory.createClient(T::class.java)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*******************************************************************************
* Copyright (c) 2021,2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
******************************************************************************/

package org.eclipse.tractusx.bpdm.gate.api.client

import org.eclipse.tractusx.bpdm.gate.api.GatePartnerUploadApi
import org.eclipse.tractusx.bpdm.gate.api.model.response.BusinessPartnerInputDto
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.RequestPart
import org.springframework.web.multipart.MultipartFile
import org.springframework.web.service.annotation.HttpExchange
import org.springframework.web.service.annotation.PostExchange

@HttpExchange(GatePartnerUploadApi.BUSINESS_PARTNER_PATH)
interface PartnerUploadApiClient : GatePartnerUploadApi {

@PostExchange(
url = "/input/partner-upload-process",
contentType = MediaType.MULTIPART_FORM_DATA_VALUE,
accept = ["application/json"]
)
override fun uploadPartnerCsvFile(
@RequestPart("file") file: MultipartFile
): ResponseEntity<Collection<BusinessPartnerInputDto>>

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*******************************************************************************
* Copyright (c) 2021,2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
******************************************************************************/

package org.eclipse.tractusx.bpdm.gate.api.model.response

import io.swagger.v3.oas.annotations.media.Schema
import org.springframework.http.HttpStatus
import java.time.Instant

@Schema(description = "Error response for invalid partner upload")
class PartnerUploadErrorResponse(
@Schema(description = "Timestamp of the error occurrence")
val timestamp: Instant,
@Schema(description = "HTTP status of the error response")
val status: HttpStatus,
@Schema(description = "List of error messages")
val error: List<String>,
@Schema(description = "Request path where the error occurred")
val path: String
)
4 changes: 4 additions & 0 deletions bpdm-gate/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@
<groupId>org.eclipse.tractusx</groupId>
<artifactId>bpdm-orchestrator-api</artifactId>
</dependency>
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ data class PermissionConfigProperties(
val readOutputChangelog: String = "read_output_changelog",
val readSharingState: String = "read_sharing_state",
val writeSharingState: String = "write_sharing_state",
val readStats: String = "read_stats"
val readStats: String = "read_stats",
val uploadInputPartner: String = "upload_input_partner"
) {
companion object {
const val PREFIX = "bpdm.security.permissions"
Expand All @@ -49,5 +50,6 @@ data class PermissionConfigProperties(
const val READ_SHARING_STATE = "@$BEAN_QUALIFIER.getReadSharingState()"
const val WRITE_SHARING_STATE = "@$BEAN_QUALIFIER.getWriteSharingState()"
const val READ_STATS = "@$BEAN_QUALIFIER.getReadStats()"
const val UPLOAD_INPUT_PARTNER = "@$BEAN_QUALIFIER.getUploadInputPartner()"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*******************************************************************************
* Copyright (c) 2021,2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
******************************************************************************/

package org.eclipse.tractusx.bpdm.gate.controller

import org.eclipse.tractusx.bpdm.gate.api.GatePartnerUploadApi
import org.eclipse.tractusx.bpdm.gate.api.model.response.BusinessPartnerInputDto
import org.eclipse.tractusx.bpdm.gate.config.ApiConfigProperties
import org.eclipse.tractusx.bpdm.gate.config.PermissionConfigProperties
import org.eclipse.tractusx.bpdm.gate.service.BusinessPartnerService
import org.eclipse.tractusx.bpdm.gate.service.PartnerUploadService
import org.eclipse.tractusx.bpdm.gate.util.getCurrentUserBpn
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.multipart.MultipartFile

@RestController
class PartnerUploadController(
val businessPartnerService: BusinessPartnerService,
val apiConfigProperties: ApiConfigProperties,
val partnerUploadService: PartnerUploadService
) : GatePartnerUploadApi {

@PreAuthorize("hasAuthority(${PermissionConfigProperties.UPLOAD_INPUT_PARTNER})")
override fun uploadPartnerCsvFile(
file: MultipartFile
): ResponseEntity<Collection<BusinessPartnerInputDto>> {
return when {
file.isEmpty -> ResponseEntity(HttpStatus.BAD_REQUEST)
!file.contentType.equals("text/csv", ignoreCase = true) -> ResponseEntity(HttpStatus.BAD_REQUEST)
else -> partnerUploadService.processFile(file, getCurrentUserBpn())
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*******************************************************************************
* Copyright (c) 2021,2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
******************************************************************************/

package org.eclipse.tractusx.bpdm.gate.exception

class BpdmInvalidPartnerUploadException(
val errors: List<String>
) : RuntimeException()
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,25 @@
package org.eclipse.tractusx.bpdm.gate.exception

import org.eclipse.tractusx.bpdm.common.exception.BpdmExceptionHandler
import org.eclipse.tractusx.bpdm.gate.api.model.response.PartnerUploadErrorResponse
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.context.request.WebRequest
import java.time.Instant

@ControllerAdvice
class GateExceptionHandler : BpdmExceptionHandler()
class GateExceptionHandler : BpdmExceptionHandler() {

@ExceptionHandler(BpdmInvalidPartnerUploadException::class)
fun handleInvalidPartnerUploadException(ex:BpdmInvalidPartnerUploadException, request: WebRequest): ResponseEntity<PartnerUploadErrorResponse> {
val errorResponse = PartnerUploadErrorResponse(
timestamp = Instant.now(),
status = HttpStatus.BAD_REQUEST,
error = ex.errors,
path = request.getDescription(false)
)
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse)
}
}
Loading

0 comments on commit f5f06b2

Please sign in to comment.