Renaming Files having BluePrint to have Blueprint
[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",
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. " +
95             "There is no validation of the attached CBA happening when this API is called.",
96         response = BlueprintModelSearch::class
97     )
98     @ApiResponses(
99         ApiResponse(code = 200, message = "OK"),
100         ApiResponse(code = 500, message = "Internal Server Error")
101     )
102     @ResponseBody
103     @Throws(BlueprintException::class)
104     @PreAuthorize("hasRole('USER')")
105     suspend fun saveBlueprint(
106         @ApiParam(name = "file", value = "CBA file to be uploaded (example: cba.zip)", required = true)
107         @RequestPart("file") filePart: FilePart
108     ): BlueprintModelSearch = mdcWebCoroutineScope {
109         bluePrintModelHandler.saveBlueprintModel(filePart)
110     }
111
112     @GetMapping(produces = [MediaType.APPLICATION_JSON_VALUE])
113     @ApiOperation(
114         value = "List all Blueprint Models",
115         notes = "Lists all meta-data of blueprint models which are saved in CDS."
116     )
117     @ApiResponses(
118         ApiResponse(code = 200, message = "OK"),
119         ApiResponse(code = 500, message = "Internal Server Error")
120     )
121     @ResponseBody
122     @PreAuthorize("hasRole('USER')")
123     fun allBlueprintModel(): List<BlueprintModelSearch> {
124         return this.bluePrintModelHandler.allBlueprintModel()
125     }
126
127     @GetMapping("/paged", produces = [MediaType.APPLICATION_JSON_VALUE])
128     @ApiOperation(
129         value = "Get Blueprints ordered",
130         notes = "Lists all blueprint models which are saved in CDS in an ordered mode.",
131         nickname = "BlueprintModelController_allBlueprintModelPaged_GET.org.onap.ccsdk.cds.blueprintsprocessor.designer.api"
132     )
133     @ResponseBody
134     @PreAuthorize("hasRole('USER')")
135     fun allBlueprintModel(
136         @ApiParam(value = "Maximum number of returned blueprint models") @RequestParam(defaultValue = "20") limit: Int,
137         @ApiParam(value = "Offset") @RequestParam(defaultValue = "0") offset: Int,
138         @ApiParam(value = "Order of returned blueprint models") @RequestParam(defaultValue = "DATE") sort: BlueprintSortByOption,
139         @ApiParam(value = "Ascend or descend ordering") @RequestParam(defaultValue = "ASC") sortType: String
140     ): Page<BlueprintModelSearch> {
141         val pageRequest = PageRequest.of(
142             offset, limit,
143             Sort.Direction.fromString(sortType), sort.columnName
144         )
145         return this.bluePrintModelHandler.allBlueprintModel(pageRequest)
146     }
147
148     @GetMapping("meta-data/{keyword}", produces = [MediaType.APPLICATION_JSON_VALUE])
149     @ApiOperation(
150         value = "Search for Blueprints by a Keyword",
151         notes = "Lists all blueprint models by a matching keyword in any of the meta-data of the blueprint models. " +
152             "Blueprint models are just returned if a whole keyword is matching, not just parts of it. Not case-sensitive. " +
153             "Used by CDS UI.",
154         responseContainer = "List",
155         response = BlueprintModelSearch::class
156     )
157     @ResponseBody
158     @PreAuthorize("hasRole('USER')")
159     suspend fun allBlueprintModelMetaData(
160         @NotNull
161         @ApiParam(value = "Keyword to search for in blueprint model meta-data", required = true, example = "pnf_netconf")
162         @PathVariable(value = "keyword") keyWord: String
163     ): List<BlueprintModelSearch> =
164         mdcWebCoroutineScope {
165             bluePrintModelHandler.searchBlueprintModelsByKeyWord(keyWord)
166         }
167
168     @GetMapping("/paged/meta-data/{keyword}", produces = [MediaType.APPLICATION_JSON_VALUE])
169     @ApiOperation(
170         value = "Search for Blueprints by a Keyword in an ordered mode",
171         notes = "Lists all blueprint models by a matching keyword in any of the meta-data of the blueprint models in an ordered mode. " +
172             "Blueprint models are just returned if a whole keyword is matching, not just parts of it. Not case-sensitive. " +
173             "Used by CDS UI."
174     )
175     @ResponseBody
176     @PreAuthorize("hasRole('USER')")
177     fun allBlueprintModelMetaDataPaged(
178         @ApiParam(value = "Keyword to search for in blueprint model meta-data", required = true, example = "pnf_netconf")
179         @NotNull @PathVariable(value = "keyword") keyWord: String,
180         @ApiParam(value = "Maximum number of returned blueprint models") @RequestParam(defaultValue = "20") limit: Int,
181         @ApiParam(value = "Offset") @RequestParam(defaultValue = "0") offset: Int,
182         @ApiParam(value = "Order of returned blueprint models") @RequestParam(defaultValue = "DATE") sort: BlueprintSortByOption,
183         @ApiParam(value = "Ascend or descend ordering") @RequestParam(defaultValue = "ASC") sortType: String
184     ): Page<BlueprintModelSearch> {
185         val pageRequest = PageRequest.of(
186             offset, limit,
187             Sort.Direction.fromString(sortType), sort.columnName
188         )
189         return this.bluePrintModelHandler.searchBlueprintModelsByKeyWordPaged(keyWord, pageRequest)
190     }
191
192     @DeleteMapping("/{id}")
193     @ApiOperation(
194         value = "Delete a Blueprint Model by ID",
195         notes = "Delete a blueprint model by its ID. ID is the internally created ID of blueprint, not the name of blueprint."
196     )
197     @ApiResponses(
198         ApiResponse(code = 200, message = "OK"),
199         ApiResponse(code = 404, message = "RESOURCE_NOT_FOUND")
200     )
201     @Throws(BlueprintException::class)
202     @PreAuthorize("hasRole('USER')")
203     suspend fun deleteBlueprint(
204         @ApiParam(value = "ID of the blueprint model to delete", required = true, example = "67ec1f96-ab55-4b81-aff9-23ee0ed1d7a4")
205         @PathVariable(value = "id") id: String
206     ) = mdcWebCoroutineScope {
207         bluePrintModelHandler.deleteBlueprintModel(id)
208     }
209
210     @GetMapping("/by-name/{name}/version/{version}", produces = [MediaType.APPLICATION_JSON_VALUE])
211     @ApiOperation(
212         value = "Get a Blueprint Model by Name and Version",
213         notes = "Get Meta-Data of a Blueprint Model by its name and version.",
214         response = BlueprintModelSearch::class
215     )
216     @ApiResponses(
217         ApiResponse(code = 200, message = "OK"),
218         ApiResponse(code = 404, message = "Not Found")
219     )
220     @ResponseBody
221     @Throws(BlueprintException::class)
222     @PreAuthorize("hasRole('USER')")
223     suspend fun getBlueprintByNameAndVersion(
224         @ApiParam(value = "Name of the blueprint model", required = true, example = "pnf_netconf") @PathVariable(value = "name") name: String,
225         @ApiParam(value = "Version of the blueprint model", required = true, example = "1.0.0") @PathVariable(value = "version") version: String
226     ): ResponseEntity<BlueprintModelSearch> = mdcWebCoroutineScope {
227         val bluePrintModel: BlueprintModelSearch? =
228             bluePrintModelHandler.getBlueprintModelSearchByNameAndVersion(name, version)
229         if (bluePrintModel != null)
230             ResponseEntity(bluePrintModel, HttpStatus.OK)
231         else
232             ResponseEntity(HttpStatus.NO_CONTENT)
233     }
234
235     @GetMapping("/download/by-name/{name}/version/{version}", produces = [MediaType.APPLICATION_JSON_VALUE])
236     @ApiOperation(
237         value = "Download a Blueprint Model",
238         notes = "Gets the CBA of a blueprint model by its name and version. Response can be saved to a file to download the CBA."
239     )
240     @ApiResponses(
241         ApiResponse(code = 200, message = "OK"),
242         ApiResponse(code = 404, message = "Not Found")
243     )
244     @ResponseBody
245     @Throws(BlueprintException::class)
246     @PreAuthorize("hasRole('USER')")
247     suspend fun downloadBlueprintByNameAndVersion(
248         @ApiParam(value = "Name of the blueprint model", required = true, example = "pnf_netconf") @PathVariable(value = "name") name: String,
249         @ApiParam(value = "Version of the blueprint model", required = true, example = "1.0.0") @PathVariable(value = "version") version: String
250     ): ResponseEntity<Resource> = mdcWebCoroutineScope {
251         bluePrintModelHandler.downloadBlueprintModelFileByNameAndVersion(name, version)
252     }
253
254     @GetMapping("/{id}", produces = [MediaType.APPLICATION_JSON_VALUE])
255     @ApiOperation(
256         value = "Get a Blueprint Model by ID",
257         notes = "Get meta-data of a blueprint model by its internally created ID.",
258         response = BlueprintModelSearch::class
259     )
260     @ApiResponses(
261         ApiResponse(code = 200, message = "OK"),
262         ApiResponse(code = 404, message = "Not Found")
263     )
264     @ResponseBody
265     @Throws(BlueprintException::class)
266     @PreAuthorize("hasRole('USER')")
267     suspend fun getBlueprintModel(
268         @ApiParam(value = "ID of the blueprint model to search for", required = true, example = "67ec1f96-ab55-4b81-aff9-23ee0ed1d7a4")
269         @PathVariable(value = "id") id: String
270     ): BlueprintModelSearch = mdcWebCoroutineScope {
271         bluePrintModelHandler.getBlueprintModelSearch(id)
272     }
273
274     @GetMapping("/download/{id}", produces = [MediaType.APPLICATION_JSON_VALUE])
275     @ApiOperation(
276         value = "Download a Blueprint Model by ID",
277         notes = "Gets the CBA of a blueprint model by its ID. Response can be saved to a file to download the CBA."
278     )
279     @ApiResponses(
280         ApiResponse(code = 200, message = "OK"),
281         ApiResponse(code = 404, message = "Not Found")
282     )
283     @ResponseBody
284     @Throws(BlueprintException::class)
285     @PreAuthorize("hasRole('USER')")
286     suspend fun downloadBlueprint(
287         @ApiParam(value = "ID of the blueprint model to download", required = true, example = "67ec1f96-ab55-4b81-aff9-23ee0ed1d7a4")
288         @PathVariable(value = "id") id: String
289     ): ResponseEntity<Resource> =
290         mdcWebCoroutineScope {
291             bluePrintModelHandler.downloadBlueprintModelFile(id)
292         }
293
294     @PostMapping(
295         "/enrich", produces = [MediaType.APPLICATION_JSON_VALUE],
296         consumes = [
297             MediaType
298                 .MULTIPART_FORM_DATA_VALUE
299         ]
300     )
301     @ApiOperation(
302         value = "Enrich a Blueprint Model",
303         notes = "Enriches the attached CBA and returns the enriched CBA zip file in the response. " +
304             "The enrichment process will complete the package by providing all the definition of types used."
305     )
306     @ResponseBody
307     @Throws(BlueprintException::class)
308     @PreAuthorize("hasRole('USER')")
309     suspend fun enrichBlueprint(
310         @ApiParam(name = "file", value = "CBA zip file to be uploaded (example: cba_unenriched.zip)", required = true)
311         @RequestPart("file") file: FilePart
312     ): ResponseEntity<Resource> = mdcWebCoroutineScope {
313         bluePrintModelHandler.enrichBlueprint(file)
314     }
315
316     @PostMapping(
317         "/enrichandpublish", produces = [MediaType.APPLICATION_JSON_VALUE],
318         consumes = [
319             MediaType
320                 .MULTIPART_FORM_DATA_VALUE
321         ]
322     )
323     @ApiOperation(
324         value = "Enrich and publish a Blueprint Model",
325         notes = "Enriches the attached CBA, validates it and saves it in CDS if validation was successful.",
326         response = BlueprintModelSearch::class
327     )
328     @ApiResponses(
329         ApiResponse(code = 200, message = "OK"),
330         ApiResponse(code = 503, message = "Service Unavailable")
331     )
332     @ResponseBody
333     @Throws(BlueprintException::class)
334     @PreAuthorize("hasRole('USER')")
335     suspend fun enrichAndPubishlueprint(
336         @ApiParam(name = "file", value = "Unenriched CBA zip file to be uploaded (example: cba_unenriched.zip)", required = true)
337         @RequestPart("file") file: FilePart
338     ): BlueprintModelSearch = mdcWebCoroutineScope {
339         bluePrintModelHandler.enrichAndPublishBlueprint(file)
340     }
341
342     @PostMapping("/publish", produces = [MediaType.APPLICATION_JSON_VALUE], consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
343     @ApiOperation(
344         value = "Publish a Blueprint Model",
345         notes = "Validates the attached CBA file and saves it in CDS if validation was successful. CBA needs to be already enriched.",
346         response = BlueprintModelSearch::class
347     )
348     @ResponseBody
349     @Throws(BlueprintException::class)
350     @PreAuthorize("hasRole('USER')")
351     suspend fun publishBlueprint(
352         @ApiParam(name = "file", value = "Enriched CBA zip file to be uploaded (example: cba_enriched.zip)", required = true)
353         @RequestPart("file") file: FilePart
354     ): BlueprintModelSearch = mdcWebCoroutineScope {
355         bluePrintModelHandler.publishBlueprint(file)
356     }
357
358     @GetMapping("/search/{tags}", produces = [MediaType.APPLICATION_JSON_VALUE])
359     @ApiOperation(
360         value = "Search for a Blueprint by Tag",
361         notes = "Searches for all blueprint models which contain the specified input parameter in their tags. " +
362             "Blueprint models which contain just parts of the searched word in their tags are also returned.",
363         responseContainer = "List",
364         response = BlueprintModelSearch::class
365     )
366     @ResponseBody
367     @PreAuthorize("hasRole('USER')")
368     suspend fun searchBlueprintModels(
369         @ApiParam(value = "Tag to search for", example = "test", required = true)
370         @PathVariable(value = "tags") tags: String
371     ): List<BlueprintModelSearch> =
372         mdcWebCoroutineScope {
373             bluePrintModelHandler.searchBlueprintModels(tags)
374         }
375
376     @DeleteMapping("/name/{name}/version/{version}")
377     @ApiOperation(
378         value = "Delete a Blueprint Model by Name",
379         notes = "Deletes a blueprint model identified by its name and version from CDS.",
380         // to avoid duplicate operation IDs
381         nickname = "BlueprintModelController_deleteBlueprintByName_DELETE.org.onap.ccsdk.cds.blueprintsprocessor.designer.api",
382         produces = MediaType.APPLICATION_JSON_VALUE
383     )
384     @PreAuthorize("hasRole('USER')")
385     suspend fun deleteBlueprint(
386         @ApiParam(value = "Name of the blueprint model", required = true, example = "pnf_netconf")
387         @PathVariable(value = "name") name: String,
388         @ApiParam(value = "Version of the blueprint model", required = true, example = "1.0.0")
389         @PathVariable(value = "version") version: String
390     ) = mdcWebCoroutineScope {
391         bluePrintModelHandler.deleteBlueprintModel(name, version)
392     }
393
394     @PostMapping(
395         path = arrayOf("/workflow-spec"),
396         produces = arrayOf(
397             MediaType
398                 .APPLICATION_JSON_VALUE
399         ),
400         consumes = arrayOf(MediaType.APPLICATION_JSON_VALUE)
401     )
402     @ApiOperation(
403         value = "Get Workflow Specification",
404         notes = "Get the workflow of a blueprint identified by Blueprint and workflow name. " +
405             "Inputs, outputs and data types of workflow is returned."
406     )
407     @ResponseBody
408     @Throws(BlueprintException::class)
409     @PreAuthorize("hasRole('USER')")
410     suspend fun workflowSpec(
411         @ApiParam(required = true, value = "Blueprint and workflow identification")
412         @RequestBody workFlowSpecReq: WorkFlowSpecRequest
413     ):
414         ResponseEntity<String> = mdcWebCoroutineScope {
415             var json = bluePrintModelHandler.prepareWorkFlowSpec(workFlowSpecReq)
416                 .asJsonString()
417             ResponseEntity(json, HttpStatus.OK)
418         }
419
420     @GetMapping(
421         path = arrayOf(
422             "/workflows/blueprint-name/{name}/version/{version}"
423         ),
424         produces = arrayOf(MediaType.APPLICATION_JSON_VALUE)
425     )
426     @ApiOperation(
427         value = "Get Workflows of a Blueprint",
428         notes = "Get all available workflows of a Blueprint identified by its name and version."
429     )
430     @ResponseBody
431     @Throws(BlueprintException::class)
432     @PreAuthorize("hasRole('USER')")
433     suspend fun getWorkflowList(
434         @ApiParam(value = "Name of the blueprint model", example = "pnf_netconf", required = true)
435         @PathVariable(value = "name") name: String,
436         @ApiParam(value = "Version of the blueprint model", example = "1.0.0", required = true)
437         @PathVariable(value = "version") version: String
438     ): ResponseEntity<String> = mdcWebCoroutineScope {
439         var json = bluePrintModelHandler.getWorkflowNames(name, version)
440             .asJsonString()
441         ResponseEntity(json, HttpStatus.OK)
442     }
443 }