feat: As a developer I want to create new Projects

This commit is contained in:
Marcel Haag 2021-12-14 11:23:51 +01:00 committed by Knez Stipe
parent c7160d5340
commit d7d04ef3ef
8 changed files with 164 additions and 4 deletions

View File

@ -10,6 +10,9 @@
"item": [
{
"name": "getProjects",
"protocolProfileBehavior": {
"disableBodyPruning": true
},
"request": {
"auth": {
"type": "oauth2",
@ -38,6 +41,43 @@
},
"method": "GET",
"header": [],
"body": {
"mode": "raw",
"raw": "",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://localhost:8443/projects",
"protocol": "http",
"host": [
"localhost"
],
"port": "8443",
"path": [
"projects"
]
}
},
"response": []
},
{
"name": "saveProject",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"client\": \"Novatec\",\n \"title\": \"log4j Pentest\",\n \"tester\": \"Stipe\",\n \"createyBy\": \"10e06d7a-8dd0-4ecd-8963-056b45079c4f\"\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://localhost:8443/projects",
"protocol": "http",

View File

@ -39,10 +39,28 @@ include::{snippets}/getProjects/http-response.adoc[]
include::{snippets}/getProjects/response-fields.adoc[]
=== Save project
To save a project, call the POST request /projects
==== Request example
include::{snippets}/saveProject/http-request.adoc[]
==== Response example
include::{snippets}/saveProject/http-response.adoc[]
==== Response structure
include::{snippets}/saveProject/response-fields.adoc[]
== Change History
|===
|Date |Change
|2021-12-22
|Added POST endpoint to save Projects
|2021-02-14
|Added GET endpoint to receive Projects
|2021-02-12

View File

@ -37,3 +37,21 @@ fun ProjectOverview.toProjectOverviewResponseBody(): ResponseBody {
"projects" to projects
)
}
data class ProjectRequestBody(
val client: String,
val title: String,
val tester: String? = null,
val createdBy: String
)
fun ProjectRequestBody.toProject(): Project {
return Project(
id = UUID.randomUUID().toString(),
client = this.client,
title = this.title,
createdAt = Instant.now().toString(),
tester = this.tester,
createdBy = this.createdBy
)
}

View File

@ -14,7 +14,7 @@ import reactor.core.publisher.Mono
origins = [],
allowCredentials = "false",
allowedHeaders = ["*"],
methods = [RequestMethod.GET]
methods = [RequestMethod.GET, RequestMethod.POST]
)
@SuppressFBWarnings(BC_BAD_CAST_TO_ABSTRACT_COLLECTION)
class ProjectController(private val projectService: ProjectService) {
@ -23,12 +23,21 @@ class ProjectController(private val projectService: ProjectService) {
@GetMapping
fun getProjects(): Mono<ResponseEntity<List<ResponseBody>>> {
return projectService.getProjects().map {
it.map {
return projectService.getProjects().map { projectList ->
projectList.map {
it.toProjectResponseBody()
}
}.map {
ResponseEntity.ok(it)
}
}
@PostMapping
fun saveProject(
@RequestBody body: ProjectRequestBody
): Mono<ResponseEntity<ResponseBody>> {
return this.projectService.saveProject(body).map {
ResponseEntity.accepted().body(it.toProjectResponseBody())
}
}
}

View File

@ -23,4 +23,14 @@ class ProjectService(private val projectRepository: ProjectRepository) {
it.map { projectEntity -> projectEntity.toProject() }
}
}
fun saveProject(body: ProjectRequestBody): Mono<Project> {
val project = body.toProject()
val projectEntity = ProjectEntity(project)
return projectRepository.insert(projectEntity).map {
it.toProject()
}.doOnError {
logger.warn("Project could not be stored in Database. Thrown exception: ", it)
}
}
}

View File

@ -17,6 +17,7 @@ import org.springframework.restdocs.operation.preprocess.Preprocessors
import org.springframework.restdocs.payload.JsonFieldType
import org.springframework.restdocs.payload.PayloadDocumentation
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation
import reactor.core.publisher.Mono
@SuppressFBWarnings(
SIC_INNER_SHOULD_BE_STATIC,
@ -90,6 +91,43 @@ class ProjectControllerDocumentationTest : BaseDocumentationIntTest() {
)
}
@Nested
inner class SaveProject {
@Test
fun saveProject() {
webTestClient.post().uri("/projects")
.header("Authorization", "Bearer $tokenAdmin")
.body(Mono.just(project), ProjectRequestBody::class.java)
.exchange()
.expectStatus().isAccepted
.expectHeader().valueEquals("Application-Name", "SecurityC4PO")
.expectBody().json(Json.write(project))
.consumeWith(WebTestClientRestDocumentation.document("{methodName}",
Preprocessors.preprocessRequest(Preprocessors.prettyPrint(),
Preprocessors.modifyUris().removePort(),
Preprocessors.removeHeaders("Host", "Content-Length")),
Preprocessors.preprocessResponse(
Preprocessors.prettyPrint()
),
PayloadDocumentation.relaxedResponseFields(
PayloadDocumentation.fieldWithPath("id").type(JsonFieldType.STRING).description("The id of the requested project"),
PayloadDocumentation.fieldWithPath("client").type(JsonFieldType.STRING).description("The name of the client of the requested project"),
PayloadDocumentation.fieldWithPath("title").type(JsonFieldType.STRING).description("The title of the requested project"),
PayloadDocumentation.fieldWithPath("createdAt").type(JsonFieldType.STRING).description("The date where the project was created at"),
PayloadDocumentation.fieldWithPath("tester").type(JsonFieldType.STRING).description("The user that is assigned as a tester in the project"),
PayloadDocumentation.fieldWithPath("createdBy").type(JsonFieldType.STRING).description("The id of the user that created the project")
)
))
}
val project = ProjectRequestBody(
client = "Novatec",
title = "log4j Pentest",
tester = "Stipe",
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
)
}
private fun persistBasicTestScenario() {
// setup test data
val projectOne = Project(

View File

@ -15,6 +15,7 @@ import org.springframework.boot.web.server.LocalServerPort
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.query.Query
import org.springframework.test.web.reactive.server.WebTestClient
import reactor.core.publisher.Mono
import java.time.Duration
@SuppressFBWarnings(
@ -87,6 +88,33 @@ class ProjectControllerIntTest : BaseIntTest() {
)
}
@Nested
inner class SaveProject {
@Test
fun `save project successfully`() {
webTestClient.post().uri("/projects")
.header("Authorization", "Bearer $tokenAdmin")
.body(Mono.just(project), ProjectRequestBody::class.java)
.exchange()
.expectStatus().isAccepted
.expectHeader().valueEquals("Application-Name", "SecurityC4PO")
.expectBody().json(Json.write(project))
.jsonPath("$.client").isEqualTo("Novatec")
.jsonPath("$.title").isEqualTo("log4j Pentest")
.jsonPath("$.tester").isEqualTo("Stipe")
.jsonPath("$.createdBy").isEqualTo("f8aab31f-4925-4242-a6fa-f98135b4b032")
}
val project = Project(
id = "4f6567a8-76fd-487b-8602-f82d0ca4d1f9",
client = "Novatec",
title = "log4j Pentest",
createdAt = "2021-04-10T18:05:00Z",
tester = "Stipe",
createdBy = "f8aab31f-4925-4242-a6fa-f98135b4b032"
)
}
private fun persistBasicTestScenario() {
// setup test data
val projectOne = Project(

View File

@ -22,7 +22,6 @@ class ProjectServiceTest {
inner class GetProjects {
@Test
fun `happy path - getProjects successfully`() {
}
}