167e4358da3f67a45d4e68c126d17a2229a02eca
[ccsdk/cds.git] / ms / blueprintsprocessor / modules / inbounds / designer-api / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / designer / api / BlueprintModelController.kt
1 /*
2  * Copyright © 2019 Bell Canada Intellectual Property.
3  * Modifications Copyright © 2019 IBM.
4  * Modifications Copyright © 2019 Orange.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 package org.onap.ccsdk.cds.blueprintsprocessor.designer.api
20
21 import io.swagger.annotations.ApiOperation
22 import io.swagger.annotations.Api
23 import io.swagger.annotations.ApiParam
24 import io.swagger.annotations.ApiResponse
25 import io.swagger.annotations.ApiResponses
26 import org.jetbrains.annotations.NotNull
27 import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.domain.BlueprintModelSearch
28 import org.onap.ccsdk.cds.blueprintsprocessor.designer.api.handler.BluePrintModelHandler
29 import org.onap.ccsdk.cds.blueprintsprocessor.designer.api.utils.BlueprintSortByOption
30 import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.mdcWebCoroutineScope
31 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
32 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonString
33 import org.springframework.core.io.Resource
34 import org.springframework.data.domain.Page
35 import org.springframework.data.domain.PageRequest
36 import org.springframework.data.domain.Sort
37 import org.springframework.http.HttpStatus
38 import org.springframework.http.MediaType
39 import org.springframework.http.ResponseEntity
40 import org.springframework.http.codec.multipart.FilePart
41 import org.springframework.security.access.prepost.PreAuthorize
42 import org.springframework.web.bind.annotation.DeleteMapping
43 import org.springframework.web.bind.annotation.GetMapping
44 import org.springframework.web.bind.annotation.PathVariable
45 import org.springframework.web.bind.annotation.PostMapping
46 import org.springframework.web.bind.annotation.RequestBody
47 import org.springframework.web.bind.annotation.RequestMapping
48 import org.springframework.web.bind.annotation.RequestParam
49 import org.springframework.web.bind.annotation.RequestPart
50 import org.springframework.web.bind.annotation.ResponseBody
51 import org.springframework.web.bind.annotation.RestController
52
53 /**
54  * BlueprintModelController Purpose: Handle controllerBlueprint API request
55  *
56  * @author Vinal Patel
57  * @version 1.0
58  */
59 @RestController
60 @RequestMapping("/api/v1/blueprint-model")
61 @Api(
62     value = "Blueprint Model Catalog API",
63     description = "Manages all blueprint models which are available in CDS"
64 )
65 open class BlueprintModelController(private val bluePrintModelHandler: BluePrintModelHandler) {
66
67     @PostMapping(
68         path = arrayOf("/bootstrap"), produces = arrayOf(MediaType.APPLICATION_JSON_VALUE),
69         consumes = arrayOf(MediaType.APPLICATION_JSON_VALUE)
70     )
71     @ApiOperation(
72         value = "Bootstrap CDS",
73         notes = "Loads all Model Types, Resource Dictionaries and Blueprint Models which are included in CDS by default. " +
74             "Before starting to work with CDS, bootstrap should be called to load all the basic models that each orginization might support. " +
75             "Parameter values can be set as `false`  to skip loading e.g. the Resource Dictionaries but this is not recommended."
76     )
77     @ApiResponses(
78         ApiResponse(code = 200, message = "OK"),
79         ApiResponse(code = 500, message = "Internal Server Error")
80     )
81     @ResponseBody
82     @Throws(BluePrintException::class)
83     @PreAuthorize("hasRole('USER')")
84     suspend fun bootstrap(
85         @ApiParam(required = true, value = "Specifies which elements to load")
86         @RequestBody bootstrapRequest: BootstrapRequest
87     ): Unit = mdcWebCoroutineScope {
88         bluePrintModelHandler.bootstrapBlueprint(bootstrapRequest)
89     }
90
91     @PostMapping(produces = [MediaType.APPLICATION_JSON_VALUE], consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
92     @ApiOperation(
93         value = "Save a Blueprint Model",
94         notes = "Saves a blueprint model by the given CBA zip file input. There is no validation of the attached CBA happening when this API is called."
95     )
96     @ApiResponses(
97         ApiResponse(code = 200, message = "OK"),
98         ApiResponse(code = 500, message = "Internal Server Error")
99     )
100     @ResponseBody
101     @Throws(BluePrintException::class)
102     @PreAuthorize("hasRole('USER')")
103     suspend fun saveBlueprint(
104         @ApiParam(name = "file", value = "CBA file to be uploaded (example: cba.zip)", required = true)
105         @RequestPart("file") filePart: FilePart
106     ): BlueprintModelSearch = mdcWebCoroutineScope {
107         bluePrintModelHandler.saveBlueprintModel(filePart)
108     }
109
110     @GetMapping(produces = [MediaType.APPLICATION_JSON_VALUE])
111     @ApiOperation(
112         value = "List all Blueprint Models",
113         notes = "Lists all meta-data of blueprint models which are saved in CDS."
114     )
115     @ApiResponses(
116         ApiResponse(code = 200, message = "OK"),
117         ApiResponse(code = 500, message = "Internal Server Error")
118     )
119     @ResponseBody
120     @PreAuthorize("hasRole('USER')")
121     fun allBlueprintModel(): List<BlueprintModelSearch> {
122         return this.bluePrintModelHandler.allBlueprintModel()
123     }
124
125     @GetMapping("/paged", produces = [MediaType.APPLICATION_JSON_VALUE])
126     @ApiOperation(
127         value = "Get Blueprints ordered",
128         notes = "Lists all blueprint models which are saved in CDS in an ordered mode.",
129         nickname = "BlueprintModelController_allBlueprintModelPaged_GET.org.onap.ccsdk.cds.blueprintsprocessor.designer.api"
130     )
131     @ResponseBody
132     @PreAuthorize("hasRole('USER')")
133     fun allBlueprintModel(
134         @ApiParam(value = "Maximum number of returned blueprint models") @RequestParam(defaultValue = "20") limit: Int,
135         @ApiParam(value = "Offset") @RequestParam(defaultValue = "0") offset: Int,
136         @ApiParam(value = "Order of returned blueprint models") @RequestParam(defaultValue = "DATE") sort: BlueprintSortByOption,
137         @ApiParam(value = "Ascend or descend ordering") @RequestParam(defaultValue = "ASC") sortType: String
138     ): Page<BlueprintModelSearch> {
139         val pageRequest = PageRequest.of(
140             offset, limit,
141             Sort.Direction.fromString(sortType), sort.columnName
142         )
143         return this.bluePrintModelHandler.allBlueprintModel(pageRequest)
144     }
145
146     @GetMapping("meta-data/{keyword}", produces = [MediaType.APPLICATION_JSON_VALUE])
147     @ApiOperation(
148         value = "Search for Blueprints by a Keyword",
149         notes = "Lists all blueprint models by a matching keyword in any of the meta-data of the blueprint models. " +
150             "Blueprint models are just returned if a whole keyword is matching, not just parts of it. Not case-sensitive. " +
151             "Used by CDS UI."
152     )
153     @ResponseBody
154     @PreAuthorize("hasRole('USER')")
155     suspend fun allBlueprintModelMetaData(
156         @NotNull
157         @ApiParam(value = "Keyword to search for in blueprint model meta-data", required = true, example = "pnf_netconf")
158         @PathVariable(value = "keyword") keyWord: String
159     ): List<BlueprintModelSearch> =
160         mdcWebCoroutineScope {
161             bluePrintModelHandler.searchBluePrintModelsByKeyWord(keyWord)
162         }
163
164     @GetMapping("/paged/meta-data/{keyword}", produces = [MediaType.APPLICATION_JSON_VALUE])
165     @ApiOperation(
166         value = "Search for Blueprints by a Keyword in an ordered mode",
167         notes = "Lists all blueprint models by a matching keyword in any of the meta-data of the blueprint models in an ordered mode. " +
168             "Blueprint models are just returned if a whole keyword is matching, not just parts of it. Not case-sensitive. " +
169             "Used by CDS UI."
170     )
171     @ResponseBody
172     @PreAuthorize("hasRole('USER')")
173     fun allBlueprintModelMetaDataPaged(
174         @ApiParam(value = "Keyword to search for in blueprint model meta-data", required = true, example = "pnf_netconf")
175         @NotNull @PathVariable(value = "keyword") keyWord: String,
176         @ApiParam(value = "Maximum number of returned blueprint models") @RequestParam(defaultValue = "20") limit: Int,
177         @ApiParam(value = "Offset") @RequestParam(defaultValue = "0") offset: Int,
178         @ApiParam(value = "Order of returned blueprint models") @RequestParam(defaultValue = "DATE") sort: BlueprintSortByOption,
179         @ApiParam(value = "Ascend or descend ordering") @RequestParam(defaultValue = "ASC") sortType: String
180     ): Page<BlueprintModelSearch> {
181         val pageRequest = PageRequest.of(
182             offset, limit,
183             Sort.Direction.fromString(sortType), sort.columnName
184         )
185         return this.bluePrintModelHandler.searchBluePrintModelsByKeyWordPaged(keyWord, pageRequest)
186     }
187
188     @DeleteMapping("/{id}")
189     @ApiOperation(
190         value = "Delete a Blueprint Model by ID",
191         notes = "Delete a blueprint model by its ID. ID is the internally created ID of blueprint, not the name of blueprint."
192     )
193     @ApiResponses(
194         ApiResponse(code = 200, message = "OK"),
195         ApiResponse(code = 404, message = "RESOURCE_NOT_FOUND")
196     )
197     @Throws(BluePrintException::class)
198     @PreAuthorize("hasRole('USER')")
199     suspend fun deleteBlueprint(
200         @ApiParam(value = "ID of the blueprint model to delete", required = true, example = "67ec1f96-ab55-4b81-aff9-23ee0ed1d7a4")
201         @PathVariable(value = "id") id: String
202     ) = mdcWebCoroutineScope {
203         bluePrintModelHandler.deleteBlueprintModel(id)
204     }
205
206     @GetMapping("/by-name/{name}/version/{version}", produces = [MediaType.APPLICATION_JSON_VALUE])
207     @ApiOperation(
208         value = "Get a Blueprint Model by Name and Version",
209         notes = "Get Meta-Data of a Blueprint Model by its name and version."
210     )
211     @ApiResponses(
212         ApiResponse(code = 200, message = "OK"),
213         ApiResponse(code = 404, message = "Not Found")
214     )
215     @ResponseBody
216     @Throws(BluePrintException::class)
217     @PreAuthorize("hasRole('USER')")
218     suspend fun getBlueprintByNameAndVersion(
219         @ApiParam(value = "Name of the blueprint model", required = true, example = "pnf_netconf") @PathVariable(value = "name") name: String,
220         @ApiParam(value = "Version of the blueprint model", required = true, example = "1.0.0") @PathVariable(value = "version") version: String
221     ): ResponseEntity<BlueprintModelSearch> = mdcWebCoroutineScope {
222         val bluePrintModel: BlueprintModelSearch? =
223             bluePrintModelHandler.getBlueprintModelSearchByNameAndVersion(name, version)
224         if (bluePrintModel != null)
225             ResponseEntity(bluePrintModel, HttpStatus.OK)
226         else
227             ResponseEntity(HttpStatus.NO_CONTENT)
228     }
229
230     @GetMapping("/download/by-name/{name}/version/{version}", produces = [MediaType.APPLICATION_JSON_VALUE])
231     @ApiOperation(
232         value = "Download a Blueprint Model",
233         notes = "Gets the CBA of a blueprint model by its name and version. Response can be saved to a file to download the CBA."
234     )
235     @ApiResponses(
236         ApiResponse(code = 200, message = "OK"),
237         ApiResponse(code = 404, message = "Not Found")
238     )
239     @ResponseBody
240     @Throws(BluePrintException::class)
241     @PreAuthorize("hasRole('USER')")
242     suspend fun downloadBlueprintByNameAndVersion(
243         @ApiParam(value = "Name of the blueprint model", required = true, example = "pnf_netconf") @PathVariable(value = "name") name: String,
244         @ApiParam(value = "Version of the blueprint model", required = true, example = "1.0.0") @PathVariable(value = "version") version: String
245     ): ResponseEntity<Resource> = mdcWebCoroutineScope {
246         bluePrintModelHandler.downloadBlueprintModelFileByNameAndVersion(name, version)
247     }
248
249     @GetMapping("/{id}", produces = [MediaType.APPLICATION_JSON_VALUE])
250     @ApiOperation(
251         value = "Get a Blueprint Model by ID",
252         notes = "Get meta-data of a blueprint model by its internally created ID."
253     )
254     @ApiResponses(
255         ApiResponse(code = 200, message = "OK"),
256         ApiResponse(code = 404, message = "Not Found")
257     )
258     @ResponseBody
259     @Throws(BluePrintException::class)
260     @PreAuthorize("hasRole('USER')")
261     suspend fun getBlueprintModel(
262         @ApiParam(value = "ID of the blueprint model to search for", required = true, example = "67ec1f96-ab55-4b81-aff9-23ee0ed1d7a4")
263         @PathVariable(value = "id") id: String
264     ): BlueprintModelSearch = mdcWebCoroutineScope {
265         bluePrintModelHandler.getBlueprintModelSearch(id)
266     }
267
268     @GetMapping("/download/{id}", produces = [MediaType.APPLICATION_JSON_VALUE])
269     @ApiOperation(
270         value = "Download a Blueprint Model by ID",
271         notes = "Gets the CBA of a blueprint model by its ID. Response can be saved to a file to download the CBA."
272     )
273     @ApiResponses(
274         ApiResponse(code = 200, message = "OK"),
275         ApiResponse(code = 404, message = "Not Found")
276     )
277     @ResponseBody
278     @Throws(BluePrintException::class)
279     @PreAuthorize("hasRole('USER')")
280     suspend fun downloadBluePrint(
281         @ApiParam(value = "ID of the blueprint model to download", required = true, example = "67ec1f96-ab55-4b81-aff9-23ee0ed1d7a4")
282         @PathVariable(value = "id") id: String
283     ): ResponseEntity<Resource> =
284         mdcWebCoroutineScope {
285             bluePrintModelHandler.downloadBlueprintModelFile(id)
286         }
287
288     @PostMapping(
289         "/enrich", produces = [MediaType.APPLICATION_JSON_VALUE],
290         consumes = [
291             MediaType
292                 .MULTIPART_FORM_DATA_VALUE
293         ]
294     )
295     @ApiOperation(
296         value = "Enrich a Blueprint Model",
297         notes = "Enriches the attached CBA and returns the enriched CBA zip file in the response. " +
298             "The enrichment process will complete the package by providing all the definition of types used."
299     )
300     @ResponseBody
301     @Throws(BluePrintException::class)
302     @PreAuthorize("hasRole('USER')")
303     suspend fun enrichBlueprint(
304         @ApiParam(name = "file", value = "CBA zip file to be uploaded (example: cba_unenriched.zip)", required = true)
305         @RequestPart("file") file: FilePart
306     ): ResponseEntity<Resource> = mdcWebCoroutineScope {
307         bluePrintModelHandler.enrichBlueprint(file)
308     }
309
310     @PostMapping(
311         "/enrichandpublish", produces = [MediaType.APPLICATION_JSON_VALUE],
312         consumes = [
313             MediaType
314                 .MULTIPART_FORM_DATA_VALUE
315         ]
316     )
317     @ApiOperation(
318         value = "Enrich and publish a Blueprint Model",
319         notes = "Enriches the attached CBA, validates it and saves it in CDS if validation was successful."
320     )
321     @ApiResponses(
322         ApiResponse(code = 200, message = "OK"),
323         ApiResponse(code = 503, message = "Service Unavailable")
324     )
325     @ResponseBody
326     @Throws(BluePrintException::class)
327     @PreAuthorize("hasRole('USER')")
328     suspend fun enrichAndPubishlueprint(
329         @ApiParam(name = "file", value = "Unenriched CBA zip file to be uploaded (example: cba_unenriched.zip)", required = true)
330         @RequestPart("file") file: FilePart
331     ): BlueprintModelSearch = mdcWebCoroutineScope {
332         bluePrintModelHandler.enrichAndPublishBlueprint(file)
333     }
334
335     @PostMapping("/publish", produces = [MediaType.APPLICATION_JSON_VALUE], consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
336     @ApiOperation(
337         value = "Publish a Blueprint Model",
338         notes = "Validates the attached CBA file and saves it in CDS if validation was successful. CBA needs to be already enriched."
339     )
340     @ResponseBody
341     @Throws(BluePrintException::class)
342     @PreAuthorize("hasRole('USER')")
343     suspend fun publishBlueprint(
344         @ApiParam(name = "file", value = "Enriched CBA zip file to be uploaded (example: cba_enriched.zip)", required = true)
345         @RequestPart("file") file: FilePart
346     ): BlueprintModelSearch = mdcWebCoroutineScope {
347         bluePrintModelHandler.publishBlueprint(file)
348     }
349
350     @GetMapping("/search/{tags}", produces = [MediaType.APPLICATION_JSON_VALUE])
351     @ApiOperation(
352         value = "Search for a Blueprint by Tag",
353         notes = "Searches for all blueprint models which contain the specified input parameter in their tags. " +
354             "Blueprint models which contain just parts of the searched word in their tags are also returned."
355     )
356     @ResponseBody
357     @PreAuthorize("hasRole('USER')")
358     suspend fun searchBlueprintModels(
359         @ApiParam(value = "Tag to search for", example = "test", required = true)
360         @PathVariable(value = "tags") tags: String
361     ): List<BlueprintModelSearch> =
362         mdcWebCoroutineScope {
363             bluePrintModelHandler.searchBlueprintModels(tags)
364         }
365
366     @DeleteMapping("/name/{name}/version/{version}")
367     @ApiOperation(
368         value = "Delete a Blueprint Model by Name",
369         notes = "Deletes a blueprint model identified by its name and version from CDS.",
370         // to avoid duplicate operation IDs
371         nickname = "BlueprintModelController_deleteBlueprintByName_DELETE.org.onap.ccsdk.cds.blueprintsprocessor.designer.api",
372         produces = MediaType.APPLICATION_JSON_VALUE
373     )
374     @PreAuthorize("hasRole('USER')")
375     suspend fun deleteBlueprint(
376         @ApiParam(value = "Name of the blueprint model", required = true, example = "pnf_netconf")
377         @PathVariable(value = "name") name: String,
378         @ApiParam(value = "Version of the blueprint model", required = true, example = "1.0.0")
379         @PathVariable(value = "version") version: String
380     ) = mdcWebCoroutineScope {
381         bluePrintModelHandler.deleteBlueprintModel(name, version)
382     }
383
384     @PostMapping(
385         path = arrayOf("/workflow-spec"),
386         produces = arrayOf(
387             MediaType
388                 .APPLICATION_JSON_VALUE
389         ),
390         consumes = arrayOf(MediaType.APPLICATION_JSON_VALUE)
391     )
392     @ApiOperation(
393         value = "Get Workflow Specification",
394         notes = "Get the workflow of a blueprint identified by Blueprint and workflow name. " +
395             "Inputs, outputs and data types of workflow is returned."
396     )
397     @ResponseBody
398     @Throws(BluePrintException::class)
399     @PreAuthorize("hasRole('USER')")
400     suspend fun workflowSpec(@RequestBody workFlowSpecReq: WorkFlowSpecRequest):
401         ResponseEntity<String> = mdcWebCoroutineScope {
402             var json = bluePrintModelHandler.prepareWorkFlowSpec(workFlowSpecReq)
403                 .asJsonString()
404             ResponseEntity(json, HttpStatus.OK)
405         }
406
407     @GetMapping(
408         path = arrayOf(
409             "/workflows/blueprint-name/{name}/version/{version}"
410         ),
411         produces = arrayOf(MediaType.APPLICATION_JSON_VALUE)
412     )
413     @ApiOperation(
414         value = "Get Workflows of a Blueprint",
415         notes = "Get all available workflows of a Blueprint identified by its name and version."
416     )
417     @ResponseBody
418     @Throws(BluePrintException::class)
419     @PreAuthorize("hasRole('USER')")
420     suspend fun getWorkflowList(
421         @ApiParam(value = "Name of the blueprint model", example = "pnf_netconf", required = true)
422         @PathVariable(value = "name") name: String,
423         @ApiParam(value = "Version of the blueprint model", example = "1.0.0", required = true)
424         @PathVariable(value = "version") version: String
425     ): ResponseEntity<String> = mdcWebCoroutineScope {
426         var json = bluePrintModelHandler.getWorkflowNames(name, version)
427             .asJsonString()
428         ResponseEntity(json, HttpStatus.OK)
429     }
430 }