Adding Capif provider 82/10982/3
authorychacon <yennifer.chacon@est.tech>
Wed, 26 Apr 2023 07:11:45 +0000 (09:11 +0200)
committerychacon <yennifer.chacon@est.tech>
Wed, 10 May 2023 08:04:21 +0000 (10:04 +0200)
Issue-ID: NONRTRIC-861
Signed-off-by: ychacon <yennifer.chacon@est.tech>
Change-Id: If80624eccbbafd8c9ae9d14658a3bb5599fdec2f

24 files changed:
provider/Dockerfile [new file with mode: 0644]
provider/generate.sh [new file with mode: 0755]
provider/gogeneratorspecs/common/generator_settings.yaml [new file with mode: 0644]
provider/gogeneratorspecs/common29122/generator_settings.yaml [new file with mode: 0644]
provider/gogeneratorspecs/common29571/generator_settings.yaml [new file with mode: 0644]
provider/gogeneratorspecs/providermanagementapi/generator_settings_types.yaml [new file with mode: 0644]
provider/gogeneratorspecs/publishserviceapi/generator_settings_types.yaml [new file with mode: 0644]
provider/handler/common_handler.go [new file with mode: 0644]
provider/handler/getapi_handler.go [new file with mode: 0644]
provider/handler/home_handler.go [new file with mode: 0644]
provider/handler/publishapi_handler.go [new file with mode: 0644]
provider/handler/registration_handler.go [new file with mode: 0644]
provider/internal/gentools/commoncollector/commoncollector.go [new file with mode: 0644]
provider/internal/gentools/commoncollector/definitions.txt [new file with mode: 0644]
provider/internal/gentools/enumfixer/enumfixer.go [new file with mode: 0644]
provider/internal/gentools/specificationfixer/specificationfixer.go [new file with mode: 0644]
provider/main.go [new file with mode: 0644]
provider/view/base.html [new file with mode: 0644]
provider/view/css/style.css [new file with mode: 0644]
provider/view/getapi.html [new file with mode: 0644]
provider/view/home.html [new file with mode: 0644]
provider/view/js/script.js [new file with mode: 0644]
provider/view/publishapi.html [new file with mode: 0644]
provider/view/registration.html [new file with mode: 0644]

diff --git a/provider/Dockerfile b/provider/Dockerfile
new file mode 100644 (file)
index 0000000..bfadfb8
--- /dev/null
@@ -0,0 +1,38 @@
+#==================================================================================
+#   Copyright (C) 2023: Nordix Foundation
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://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.
+#
+#   This source code is part of the near-RT RIC (RAN Intelligent Controller)
+#   platform project (RICP).
+#==================================================================================
+
+##
+## Build
+##
+FROM nexus3.o-ran-sc.org:10001/golang:1.19.2-bullseye AS build
+WORKDIR /app
+COPY go.mod .
+COPY go.sum .
+RUN go mod download
+COPY . .
+RUN go build -o /capifprovider
+##
+## Deploy
+##
+FROM gcr.io/distroless/base-debian11
+WORKDIR /
+## Copy from "build" stage
+COPY --from=build /capifprovider .
+USER nonroot:nonroot
+ENTRYPOINT ["/capifprovider"]
diff --git a/provider/generate.sh b/provider/generate.sh
new file mode 100755 (executable)
index 0000000..36dfe59
--- /dev/null
@@ -0,0 +1,156 @@
+# -
+#   ========================LICENSE_START=================================
+#   O-RAN-SC
+#   %%
+#   Copyright (C) 2023: Nordix Foundation
+#   %%
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#        http://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.
+#   ========================LICENSE_END===================================
+#
+
+cwd=$(pwd)
+
+mkdir -p specs
+
+curl https://www.3gpp.org/ftp/Specs/archive/29_series/29.222/29222-h60.zip -o specs/apidef.zip
+curl https://www.3gpp.org/ftp/Specs/archive/29_series/29.122/29122-h70.zip -o specs/common29122apidef.zip
+curl https://www.3gpp.org/ftp/Specs/archive/29_series/29.508/29508-h80.zip -o specs/common29508apidef.zip
+curl https://www.3gpp.org/ftp/Specs/archive/29_series/29.510/29510-h70.zip -o specs/common29510apidef.zip
+curl https://www.3gpp.org/ftp/Specs/archive/29_series/29.512/29512-h80.zip -o specs/common29512apidef.zip
+curl https://www.3gpp.org/ftp/Specs/archive/29_series/29.514/29514-h60.zip -o specs/common29514apidef.zip
+curl https://www.3gpp.org/ftp/Specs/archive/29_series/29.517/29517-h70.zip -o specs/common29517apidef.zip
+curl https://www.3gpp.org/ftp/Specs/archive/29_series/29.518/29518-h70.zip -o specs/common29518apidef.zip
+curl https://www.3gpp.org/ftp/Specs/archive/29_series/29.522/29522-h70.zip -o specs/common29522apidef.zip
+curl https://www.3gpp.org/ftp/Specs/archive/29_series/29.523/29523-h80.zip -o specs/common29523apidef.zip
+curl https://www.3gpp.org/ftp/Specs/archive/29_series/29.554/29554-h40.zip -o specs/common29554apidef.zip
+curl https://www.3gpp.org/ftp/Specs/archive/29_series/29.571/29571-h70.zip -o specs/common29571apidef.zip
+curl https://www.3gpp.org/ftp/Specs/archive/29_series/29.572/29572-h60.zip -o specs/common29572apidef.zip
+
+cd specs/
+
+jar xvf apidef.zip
+jar xvf common29122apidef.zip
+jar xvf common29508apidef.zip
+jar xvf common29510apidef.zip
+jar xvf common29512apidef.zip
+jar xvf common29514apidef.zip
+jar xvf common29517apidef.zip
+jar xvf common29518apidef.zip
+jar xvf common29522apidef.zip
+jar xvf common29523apidef.zip
+jar xvf common29554apidef.zip
+jar xvf common29571apidef.zip
+jar xvf common29572apidef.zip
+
+# Remove types that are not used by CAPIF that have dependencies to other specifications.
+sed -e 'H;x;/^\(  *\)\n\1/{s/\n.*//;x;d;}' -e 's/.*//;x;/\CivicAddress/{s/^\( *\).*/ \1/;x;d;}' TS29571_CommonData.yaml >temp.yaml
+mv temp.yaml TS29571_CommonData.yaml
+sed -e 'H;x;/^\(  *\)\n\1/{s/\n.*//;x;d;}' -e 's/.*//;x;/\ExternalMbsServiceArea/{s/^\( *\).*/ \1/;x;d;}' TS29571_CommonData.yaml >temp.yaml
+mv temp.yaml TS29571_CommonData.yaml
+sed -e 'H;x;/^\(  *\)\n\1/{s/\n.*//;x;d;}' -e 's/.*//;x;/\GeographicArea/{s/^\( *\).*/ \1/;x;d;}' TS29571_CommonData.yaml >temp.yaml
+mv temp.yaml TS29571_CommonData.yaml
+sed -e 'H;x;/^\(  *\)\n\1/{s/\n.*//;x;d;}' -e 's/.*//;x;/\GeoServiceArea/{s/^\( *\).*/ \1/;x;d;}' TS29571_CommonData.yaml >temp.yaml
+mv temp.yaml TS29571_CommonData.yaml
+sed -e 'H;x;/^\(  *\)\n\1/{s/\n.*//;x;d;}' -e 's/.*//;x;/\MbsMediaComp/{s/^\( *\).*/ \1/;x;d;}' TS29571_CommonData.yaml >temp.yaml
+mv temp.yaml TS29571_CommonData.yaml
+sed -e 'H;x;/^\(  *\)\n\1/{s/\n.*//;x;d;}' -e 's/.*//;x;/\MbsMediaCompRm/{s/^\( *\).*/ \1/;x;d;}' TS29571_CommonData.yaml >temp.yaml
+mv temp.yaml TS29571_CommonData.yaml
+sed -e 'H;x;/^\(  *\)\n\1/{s/\n.*//;x;d;}' -e 's/.*//;x;/\MbsMediaInfo/{s/^\( *\).*/ \1/;x;d;}' TS29571_CommonData.yaml >temp.yaml
+mv temp.yaml TS29571_CommonData.yaml
+sed -e 'H;x;/^\(  *\)\n\1/{s/\n.*//;x;d;}' -e 's/.*//;x;/\MbsServiceInfo/{s/^\( *\).*/ \1/;x;d;}' TS29571_CommonData.yaml >temp.yaml
+mv temp.yaml TS29571_CommonData.yaml
+sed -e 'H;x;/^\(  *\)\n\1/{s/\n.*//;x;d;}' -e 's/.*//;x;/\MbsSession/{s/^\( *\).*/ \1/;x;d;}' TS29571_CommonData.yaml >temp.yaml
+mv temp.yaml TS29571_CommonData.yaml
+sed -e 'H;x;/^\(  *\)\n\1/{s/\n.*//;x;d;}' -e 's/.*//;x;/\SpatialValidityCond/{s/^\( *\).*/ \1/;x;d;}' TS29571_CommonData.yaml >temp.yaml
+mv temp.yaml TS29571_CommonData.yaml
+
+# Remove attributes that can not be generated easily.
+sed '/accessTokenError.*/,+3d' TS29571_CommonData.yaml >temp.yaml
+mv temp.yaml TS29571_CommonData.yaml
+sed '/accessTokenRequest.*/,+3d' TS29571_CommonData.yaml >temp.yaml
+mv temp.yaml TS29571_CommonData.yaml
+
+
+sed '/oneOf.*/,+2d' TS29222_CAPIF_Publish_Service_API.yaml >temp.yaml
+mv temp.yaml TS29222_CAPIF_Publish_Service_API.yaml
+
+# Replace references to external specs that are collected to the common spec by the commoncollector
+# <replacements_start>
+cat TS29122_CommonData.yaml | sed 's/TS29572_Nlmf_Location/CommonData/g' > temp.yaml
+mv temp.yaml TS29122_CommonData.yaml
+cat TS29122_CommonData.yaml | sed 's/TS29554_Npcf_BDTPolicyControl/CommonData/g' > temp.yaml
+mv temp.yaml TS29122_CommonData.yaml
+cat TS29122_CommonData.yaml | sed 's/TS29514_Npcf_PolicyAuthorization/CommonData/g' > temp.yaml
+mv temp.yaml TS29122_CommonData.yaml
+cat TS29571_CommonData.yaml | sed 's/TS29514_Npcf_PolicyAuthorization/CommonData/g' > temp.yaml
+mv temp.yaml TS29571_CommonData.yaml
+cat TS29571_CommonData.yaml | sed 's/TS29572_Nlmf_Location/CommonData/g' > temp.yaml
+mv temp.yaml TS29571_CommonData.yaml
+cat TS29222_CAPIF_Publish_Service_API.yaml | sed 's/TS29572_Nlmf_Location/CommonData/g' > temp.yaml
+mv temp.yaml TS29222_CAPIF_Publish_Service_API.yaml
+# <new_replacement>
+
+# This spec has references to itself that need to be removed
+cat TS29571_CommonData.yaml | sed 's/TS29571_CommonData.yaml//g' > temp.yaml
+mv temp.yaml TS29571_CommonData.yaml
+
+cd $cwd
+
+echo "Fixing enums"
+cd internal/gentools/enumfixer
+go build .
+./enumfixer -apidir=../../../specs
+
+cd $cwd
+echo "Gathering common references"
+cd internal/gentools/commoncollector
+go build .
+./commoncollector -apidir=../../../specs
+
+cd $cwd
+echo "Fixing misc in specifications"
+cd internal/gentools/specificationfixer
+go build .
+./specificationfixer -apidir=../../../specs
+
+cd $cwd
+
+go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@v1.10.1
+PATH=$PATH:~/go/bin
+
+echo "Generating TS29122_CommonData"
+mkdir -p internal/common29122
+oapi-codegen --config gogeneratorspecs/common29122/generator_settings.yaml specs/TS29122_CommonData.yaml
+
+echo "Generating aggregated CommonData"
+mkdir -p internal/common
+oapi-codegen --config gogeneratorspecs/common/generator_settings.yaml specs/CommonData.yaml
+
+echo "Generating TS29571_CommonData"
+mkdir -p internal/common29571
+oapi-codegen --config gogeneratorspecs/common29571/generator_settings.yaml specs/TS29571_CommonData.yaml
+
+
+echo "Generating TS29222_CAPIF_API_Provider_Management_API"
+mkdir -p internal/providermanagementapi
+oapi-codegen --config gogeneratorspecs/providermanagementapi/generator_settings_types.yaml specs/TS29222_CAPIF_API_Provider_Management_API.yaml
+
+echo "Generating TS29222_CAPIF_Publish_Service_API"
+mkdir -p internal/publishserviceapi
+oapi-codegen --config gogeneratorspecs/publishserviceapi/generator_settings_types.yaml specs/TS29222_CAPIF_Publish_Service_API.yaml
+
+echo "Cleanup"
+rm -rf specs
+
+echo "Generating mocks."
+go generate ./...
\ No newline at end of file
diff --git a/provider/gogeneratorspecs/common/generator_settings.yaml b/provider/gogeneratorspecs/common/generator_settings.yaml
new file mode 100644 (file)
index 0000000..af302a1
--- /dev/null
@@ -0,0 +1,29 @@
+# -
+#   ========================LICENSE_START=================================
+#   O-RAN-SC
+#   %%
+#   Copyright (C) 2022: Nordix Foundation
+#   %%
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#        http://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.
+#   ========================LICENSE_END===================================
+#
+
+output:
+  internal/common/common.gen.go
+package: common
+generate:
+  - types
+  - skip-prune
+  - spec
+import-mapping:
+  TS29571_CommonData.yaml: oransc.org/nonrtric/capifprov/internal/common29571
diff --git a/provider/gogeneratorspecs/common29122/generator_settings.yaml b/provider/gogeneratorspecs/common29122/generator_settings.yaml
new file mode 100644 (file)
index 0000000..69f77e2
--- /dev/null
@@ -0,0 +1,30 @@
+# -
+#   ========================LICENSE_START=================================
+#   O-RAN-SC
+#   %%
+#   Copyright (C) 2023: Nordix Foundation
+#   %%
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#        http://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.
+#   ========================LICENSE_END===================================
+#
+
+output:
+  internal/common29122/common29122.gen.go
+package: common29122
+generate:
+  - types
+  - skip-prune
+  - spec
+import-mapping:
+  TS29571_CommonData.yaml: oransc.org/nonrtric/capifprov/internal/common29571
+  CommonData.yaml: oransc.org/nonrtric/capifprov/internal/common
\ No newline at end of file
diff --git a/provider/gogeneratorspecs/common29571/generator_settings.yaml b/provider/gogeneratorspecs/common29571/generator_settings.yaml
new file mode 100644 (file)
index 0000000..c83b629
--- /dev/null
@@ -0,0 +1,27 @@
+# -
+#   ========================LICENSE_START=================================
+#   O-RAN-SC
+#   %%
+#   Copyright (C) 2023: Nordix Foundation
+#   %%
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#        http://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.
+#   ========================LICENSE_END===================================
+#
+
+output:
+  internal/common29571/common29571.gen.go
+package: common29571
+generate:
+  - types
+  - skip-prune
+  - spec
\ No newline at end of file
diff --git a/provider/gogeneratorspecs/providermanagementapi/generator_settings_types.yaml b/provider/gogeneratorspecs/providermanagementapi/generator_settings_types.yaml
new file mode 100644 (file)
index 0000000..fd9bd0a
--- /dev/null
@@ -0,0 +1,28 @@
+# -
+#   ========================LICENSE_START=================================
+#   O-RAN-SC
+#   %%
+#   Copyright (C) 2023: Nordix Foundation
+#   %%
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#        http://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.
+#   ========================LICENSE_END===================================
+#
+
+output:
+  internal/providermanagementapi/providermanagementapi-types.gen.go
+package: providermanagementapi
+generate:
+  - types
+import-mapping:
+  TS29122_CommonData.yaml: oransc.org/nonrtric/capifprov/internal/common29122
+  TS29571_CommonData.yaml: oransc.org/nonrtric/capifprov/internal/common29571
\ No newline at end of file
diff --git a/provider/gogeneratorspecs/publishserviceapi/generator_settings_types.yaml b/provider/gogeneratorspecs/publishserviceapi/generator_settings_types.yaml
new file mode 100644 (file)
index 0000000..1a5f416
--- /dev/null
@@ -0,0 +1,29 @@
+# -
+#   ========================LICENSE_START=================================
+#   O-RAN-SC
+#   %%
+#   Copyright (C) 2023: Nordix Foundation
+#   %%
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#        http://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.
+#   ========================LICENSE_END===================================
+#
+
+output:
+  internal/publishserviceapi/publishserviceapi-types.gen.go
+package: publishserviceapi
+generate:
+  - types
+import-mapping:
+  TS29122_CommonData.yaml:  oransc.org/nonrtric/capifprov/internal/common29122
+  TS29571_CommonData.yaml:  oransc.org/nonrtric/capifprov/internal/common29571
+  CommonData.yaml:  oransc.org/nonrtric/capifprov/internal/common
\ No newline at end of file
diff --git a/provider/handler/common_handler.go b/provider/handler/common_handler.go
new file mode 100644 (file)
index 0000000..73952ee
--- /dev/null
@@ -0,0 +1,81 @@
+// -
+//
+//     ========================LICENSE_START=================================
+//     O-RAN-SC
+//     %%
+//     Copyright (C) 2023: Nordix Foundation
+//     %%
+//     Licensed under the Apache License, Version 2.0 (the "License");
+//     you may not use this file except in compliance with the License.
+//     You may obtain a copy of the License at
+//
+//          http://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.
+//     ========================LICENSE_END===================================
+package handler
+
+import (
+       "bytes"
+       "encoding/json"
+       "fmt"
+       "io"
+       "net/http"
+)
+
+func makeRequest(method, url string, headers map[string]string, data interface{}) ([]byte, error) {
+       client := &http.Client{}
+
+       // Create a new HTTP request with the specified method and URL
+       req, err := http.NewRequest(method, url, nil)
+       if err != nil {
+               return nil, err
+       }
+
+       // Set any headers specified in the headers map
+       for k, v := range headers {
+               req.Header.Set(k, v)
+       }
+
+       // If there is data to send, marshal it to JSON and set it as the request body
+       if data != nil {
+               jsonBytes, err := json.Marshal(data)
+               if err != nil {
+                       return nil, err
+               }
+               req.Body = io.NopCloser(bytes.NewReader(jsonBytes))
+       }
+
+       // Send the request and get the response
+       if resp, err := client.Do(req); err == nil {
+               if isResponseSuccess(resp.StatusCode) {
+                       defer resp.Body.Close()
+
+                       // Read the response body
+                       respBody, err := io.ReadAll(resp.Body)
+                       if err != nil {
+                               return nil, err
+                       }
+                       return respBody, nil
+               } else {
+                       return nil, getRequestError(resp)
+               }
+       } else {
+               return nil, err
+       }
+}
+
+func isResponseSuccess(statusCode int) bool {
+       return statusCode >= http.StatusOK && statusCode <= 299
+}
+
+func getRequestError(response *http.Response) error {
+       defer response.Body.Close()
+       responseData, _ := io.ReadAll(response.Body)
+
+       return fmt.Errorf("message:  %v code: %v", string(responseData), response.StatusCode)
+}
diff --git a/provider/handler/getapi_handler.go b/provider/handler/getapi_handler.go
new file mode 100644 (file)
index 0000000..01c33e6
--- /dev/null
@@ -0,0 +1,80 @@
+// -
+//
+//     ========================LICENSE_START=================================
+//     O-RAN-SC
+//     %%
+//     Copyright (C) 2023: Nordix Foundation
+//     %%
+//     Licensed under the Apache License, Version 2.0 (the "License");
+//     you may not use this file except in compliance with the License.
+//     You may obtain a copy of the License at
+//
+//          http://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.
+//     ========================LICENSE_END===================================
+package handler
+
+import (
+       "encoding/json"
+       "fmt"
+       "net/http"
+
+       log "github.com/sirupsen/logrus"
+
+       "github.com/labstack/echo/v4"
+       "oransc.org/nonrtric/capifprov/internal/publishserviceapi"
+)
+
+func GetApiRequest(server string) echo.HandlerFunc {
+       return func(c echo.Context) error {
+
+               aefId := c.FormValue("apfId")
+               if aefId == "" {
+                       return c.Render(http.StatusOK, "getapi.html", map[string]interface{}{
+                               "isResponse": false,
+                               "isError":    false,
+                       })
+               }
+
+               //server format: http://localhost:8090
+               url := server + "/published-apis/v1/" + aefId + "/service-apis"
+               log.Infof("[Get API] to %v for aefId: %v", url, aefId)
+
+               headers := map[string]string{
+                       "Content-Type": "text/plain",
+               }
+               resp, err := makeRequest("GET", url, headers, nil)
+               if err != nil {
+                       log.Errorf("[Get API] %v", fmt.Sprintf("error: %v", err))
+                       return c.Render(http.StatusBadRequest, "getapi.html", map[string]interface{}{
+                               "response":   fmt.Sprintf("error: %v", err),
+                               "isError":    true,
+                               "isResponse": false,
+                       })
+               }
+               log.Infof("[Get API] Response from service: %+v error: %v\n", string(resp), err)
+
+               var resAPIs []publishserviceapi.ServiceAPIDescription
+               err = json.Unmarshal(resp, &resAPIs)
+               if err != nil {
+                       log.Error("[Get API] error unmarshaling parameter ServiceAPIDescription as JSON")
+                       return c.Render(http.StatusBadRequest, "getapi.html", map[string]interface{}{
+                               "isResponse": false,
+                               "isError":    true,
+                               "response":   "error unmarshaling parameter ServiceAPIDescription as JSON",
+                       })
+               }
+
+               bytes, _ := json.Marshal(resAPIs)
+               log.Infof("[Get API] There are %v ServiceAPIDescription objects available", len(resAPIs))
+               return c.Render(http.StatusOK, "getapi.html", map[string]interface{}{
+                       "isResponse": true,
+                       "response":   string(bytes),
+               })
+       }
+}
diff --git a/provider/handler/home_handler.go b/provider/handler/home_handler.go
new file mode 100644 (file)
index 0000000..619d624
--- /dev/null
@@ -0,0 +1,32 @@
+// -
+//
+//     ========================LICENSE_START=================================
+//     O-RAN-SC
+//     %%
+//     Copyright (C) 2023: Nordix Foundation
+//     %%
+//     Licensed under the Apache License, Version 2.0 (the "License");
+//     you may not use this file except in compliance with the License.
+//     You may obtain a copy of the License at
+//
+//          http://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.
+//     ========================LICENSE_END===================================
+package handler
+
+import (
+       "net/http"
+
+       "github.com/labstack/echo/v4"
+)
+
+func HomeHandler(c echo.Context) error {
+       return c.Render(http.StatusOK, "home.html", map[string]interface{}{
+               "name": "HOME",
+       })
+}
diff --git a/provider/handler/publishapi_handler.go b/provider/handler/publishapi_handler.go
new file mode 100644 (file)
index 0000000..99e6775
--- /dev/null
@@ -0,0 +1,98 @@
+// -
+//
+//     ========================LICENSE_START=================================
+//     O-RAN-SC
+//     %%
+//     Copyright (C) 2023: Nordix Foundation
+//     %%
+//     Licensed under the Apache License, Version 2.0 (the "License");
+//     you may not use this file except in compliance with the License.
+//     You may obtain a copy of the License at
+//
+//          http://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.
+//     ========================LICENSE_END===================================
+package handler
+
+import (
+       "encoding/json"
+       "fmt"
+       "net/http"
+
+       "github.com/labstack/echo/v4"
+       log "github.com/sirupsen/logrus"
+       "oransc.org/nonrtric/capifprov/internal/publishserviceapi"
+)
+
+func PublishapiHandler(c echo.Context) error {
+       return c.Render(http.StatusOK, "publishapi.html", map[string]interface{}{
+               "isError":    false,
+               "isResponse": false,
+       })
+}
+
+func PublishApiFormHandler(server string) echo.HandlerFunc {
+       return func(c echo.Context) error {
+
+               apfId := c.FormValue("apfId")
+               if apfId == "" {
+                       return c.Render(http.StatusBadRequest, "publishapi.html", map[string]interface{}{
+                               "isError":    true,
+                               "isResponse": false,
+                               "response":   "field apfId is needed",
+                       })
+               }
+
+               //server format: http://localhost:8090
+               url := server + "/published-apis/v1/" + apfId + "/service-apis"
+
+               log.Infof("[Publish API] url to capif core %v for aefId: %v", url, apfId)
+               var apiDescription publishserviceapi.ServiceAPIDescription
+
+               err := json.Unmarshal([]byte(c.FormValue("apiDescription")), &apiDescription)
+               if err != nil {
+                       log.Error("[Publish API] error unmarshaling parameter ServiceAPIDescription as JSON")
+                       return c.Render(http.StatusBadRequest, "publishapi.html", map[string]interface{}{
+                               "isResponse": false,
+                               "isError":    true,
+                               "response":   "error unmarshaling parameter ServiceAPIDescription as JSON",
+                       })
+               }
+
+               headers := map[string]string{
+                       "Content-Type": "application/json",
+               }
+               resp, err := makeRequest("POST", url, headers, apiDescription)
+               if err != nil {
+                       log.Errorf("[Publish API] %v", fmt.Sprintf("error: %v", err))
+                       return c.Render(http.StatusBadRequest, "publishapi.html", map[string]interface{}{
+                               "isResponse": false,
+                               "isError":    true,
+                               "response":   fmt.Sprintf("error: %v", err),
+                       })
+               }
+
+               var resAPI publishserviceapi.ServiceAPIDescription
+               err = json.Unmarshal(resp, &resAPI)
+               if err != nil {
+                       log.Error("[Publish API] error unmarshaling parameter ServiceAPIDescription as JSON")
+                       return c.Render(http.StatusBadRequest, "publishapi.html", map[string]interface{}{
+                               "isResponse": false,
+                               "isError":    true,
+                               "response":   "Error unmarshaling parameter ServiceAPIDescription as JSON",
+                       })
+               }
+
+               bytes, _ := json.Marshal(resAPI)
+               log.Infof("[Publish API] API %v with the id: %v has been register", resAPI.ApiName, *resAPI.ApiId)
+               return c.Render(http.StatusOK, "publishapi.html", map[string]interface{}{
+                       "isResponse": true,
+                       "response":   string(bytes),
+               })
+       }
+}
diff --git a/provider/handler/registration_handler.go b/provider/handler/registration_handler.go
new file mode 100644 (file)
index 0000000..0259999
--- /dev/null
@@ -0,0 +1,88 @@
+// -
+//
+//     ========================LICENSE_START=================================
+//     O-RAN-SC
+//     %%
+//     Copyright (C) 2023: Nordix Foundation
+//     %%
+//     Licensed under the Apache License, Version 2.0 (the "License");
+//     you may not use this file except in compliance with the License.
+//     You may obtain a copy of the License at
+//
+//          http://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.
+//     ========================LICENSE_END===================================
+package handler
+
+import (
+       "encoding/json"
+       "fmt"
+       "net/http"
+
+       "github.com/labstack/echo/v4"
+       log "github.com/sirupsen/logrus"
+       "oransc.org/nonrtric/capifprov/internal/providermanagementapi"
+)
+
+func RegistrationHandler(c echo.Context) error {
+       return c.Render(http.StatusOK, "registration.html", map[string]interface{}{
+               "isError":    false,
+               "isResponse": false,
+       })
+}
+
+func RegistrationFormHandler(server string) echo.HandlerFunc {
+       return func(c echo.Context) error {
+
+               url := server + "/api-provider-management/v1/registrations"
+               log.Infof("[Register provider] url to capif core %v\n", url)
+
+               var newProvider providermanagementapi.APIProviderEnrolmentDetails
+               err := json.Unmarshal([]byte(c.FormValue("enrolmentDetails")), &newProvider)
+               if err != nil {
+                       log.Error("[Register provider] error unmarshaling parameter enrolmentDetails as JSON")
+                       return c.Render(http.StatusBadRequest, "registration.html", map[string]interface{}{
+                               "isResponse": false,
+                               "isError":    true,
+                               "response":   "Error unmarshaling parameter enrolmentDetails as JSON",
+                       })
+               }
+
+               headers := map[string]string{
+                       "Content-Type": "application/json",
+               }
+               resp, err := makeRequest("POST", url, headers, newProvider)
+               if err != nil {
+                       log.Errorf("[Register provider] %v", fmt.Sprintf("error: %v", err))
+                       return c.Render(http.StatusBadRequest, "registration.html", map[string]interface{}{
+                               "isResponse": false,
+                               "isError":    true,
+                               "response":   fmt.Sprintf("error: %v", err),
+                       })
+               }
+
+               var resProvider providermanagementapi.APIProviderEnrolmentDetails
+               err = json.Unmarshal(resp, &resProvider)
+               if err != nil {
+                       log.Error("[Register provider] error unmarshaling parameter enrolmentDetails as JSON")
+                       return c.Render(http.StatusBadRequest, "registration.html", map[string]interface{}{
+                               "isResponse": false,
+                               "isError":    true,
+                               "response":   "error unmarshaling parameter enrolmentDetails as JSON",
+                       })
+               }
+
+               bytes, _ := json.Marshal(resProvider)
+               log.Infof("[Register provider] Api Provider domain %v has been register\n", resProvider.ApiProvDomId)
+               return c.Render(http.StatusOK, "registration.html", map[string]interface{}{
+                       "isResponse": true,
+                       "isError":    false,
+                       "response":   string(bytes),
+               })
+       }
+}
diff --git a/provider/internal/gentools/commoncollector/commoncollector.go b/provider/internal/gentools/commoncollector/commoncollector.go
new file mode 100644 (file)
index 0000000..ab85e0a
--- /dev/null
@@ -0,0 +1,119 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2022: Nordix Foundation
+//   %%
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//        http://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.
+//   ========================LICENSE_END===================================
+//
+
+package main
+
+import (
+       "bufio"
+       "flag"
+       "io/ioutil"
+       "log"
+       "os"
+       "strings"
+
+       "gopkg.in/yaml.v2"
+)
+
+var apiDir *string
+var common = map[interface{}]interface{}{
+       "openapi": "3.0.0",
+       "info": map[interface{}]interface{}{
+               "title":   "Common",
+               "version": "1.0.0",
+       },
+       "components": map[interface{}]interface{}{
+               "schemas": map[interface{}]interface{}{},
+       },
+}
+
+func main() {
+       apiDir = flag.String("apidir", "", "Directory containing API definitions to fix")
+       flag.Parse()
+
+       file, err := os.Open("definitions.txt")
+       if err != nil {
+               log.Fatalf("Error opening file: %v", err)
+       }
+       defer func(file *os.File) {
+               _ = file.Close()
+       }(file)
+
+       scanner := bufio.NewScanner(file)
+       components := common["components"]
+       cMap := components.(map[interface{}]interface{})
+       schemas := cMap["schemas"].(map[interface{}]interface{})
+       for scanner.Scan() {
+               name, data := getDependency(scanner.Text())
+               if name == "EthFlowDescription" {
+                       changeToLocalReference("fDir", "FlowDirection", data)
+               }
+               if name == "ReportingInformation" {
+                       changeToLocalReference("notifMethod", "NotificationMethod", data)
+               }
+               if name == "RelativeCartesianLocation" {
+                       properties := data["properties"].(map[interface{}]interface{})
+                       delete(properties, true)
+                       data["required"] = remove(data["required"].([]interface{}), 1)
+               }
+               schemas[name] = data
+       }
+
+       if err := scanner.Err(); err != nil {
+               log.Fatal(err)
+       }
+
+       modCommon, err := yaml.Marshal(common)
+       if err != nil {
+               log.Fatalf("Marshal: #%v ", err)
+       }
+       err = ioutil.WriteFile(*apiDir+"/"+"CommonData.yaml", modCommon, 0644)
+       if err != nil {
+               log.Fatalf("Error writing yamlFile. #%v ", err)
+       }
+}
+
+func changeToLocalReference(attrname, refName string, data map[interface{}]interface{}) {
+       properties := data["properties"].(map[interface{}]interface{})
+       ref := properties[attrname].(map[interface{}]interface{})
+       ref["$ref"] = "#/components/schemas/" + refName
+}
+
+func getDependency(s string) (string, map[interface{}]interface{}) {
+       info := strings.Split(s, "#")
+       yamlFile, err := ioutil.ReadFile(*apiDir + "/" + info[0])
+       if err != nil {
+               log.Fatalf("Error reading yamlFile. #%v ", err)
+       }
+       m := make(map[string]interface{})
+       err = yaml.Unmarshal(yamlFile, m)
+       if err != nil {
+               log.Fatalf("Unmarshal: %v", err)
+       }
+       components := m["components"]
+       cMap := components.(map[interface{}]interface{})
+       schemas := cMap["schemas"].(map[interface{}]interface{})
+       component := strings.Split(info[1], "/")
+       dep := schemas[component[3]].(map[interface{}]interface{})
+       return component[3], dep
+}
+
+func remove(slice []interface{}, s int) []interface{} {
+       return append(slice[:s], slice[s+1:]...)
+}
diff --git a/provider/internal/gentools/commoncollector/definitions.txt b/provider/internal/gentools/commoncollector/definitions.txt
new file mode 100644 (file)
index 0000000..a2f3f25
--- /dev/null
@@ -0,0 +1,38 @@
+TS29508_Nsmf_EventExposure.yaml#/components/schemas/NotificationMethod
+TS29510_Nnrf_NFManagement.yaml#/components/schemas/Ipv4AddressRange
+TS29512_Npcf_SMPolicyControl.yaml#/components/schemas/FlowDirection
+TS29514_Npcf_PolicyAuthorization.yaml#/components/schemas/ContentVersion
+TS29514_Npcf_PolicyAuthorization.yaml#/components/schemas/EthFlowDescription
+TS29514_Npcf_PolicyAuthorization.yaml#/components/schemas/FlowDescription
+TS29514_Npcf_PolicyAuthorization.yaml#/components/schemas/TscaiInputContainer
+TS29517_Naf_EventExposure.yaml#/components/schemas/AddrFqdn
+TS29518_Namf_EventExposure.yaml#/components/schemas/CommunicationFailure
+TS29522_TrafficInfluence.yaml#/components/schemas/AfResultInfo
+TS29522_TrafficInfluence.yaml#/components/schemas/AfResultStatus
+TS29523_Npcf_EventExposure.yaml#/components/schemas/ReportingInformation
+TS29554_Npcf_BDTPolicyControl.yaml#/components/schemas/NetworkAreaInfo
+TS29572_Nlmf_Location.yaml#/components/schemas/Altitude
+TS29572_Nlmf_Location.yaml#/components/schemas/Angle
+TS29572_Nlmf_Location.yaml#/components/schemas/CivicAddress
+TS29572_Nlmf_Location.yaml#/components/schemas/Confidence
+TS29572_Nlmf_Location.yaml#/components/schemas/EllipsoidArc
+TS29572_Nlmf_Location.yaml#/components/schemas/GADShape
+TS29572_Nlmf_Location.yaml#/components/schemas/GeographicArea
+TS29572_Nlmf_Location.yaml#/components/schemas/GeographicalCoordinates
+TS29572_Nlmf_Location.yaml#/components/schemas/InnerRadius
+TS29572_Nlmf_Location.yaml#/components/schemas/Local2dPointUncertaintyEllipse
+TS29572_Nlmf_Location.yaml#/components/schemas/Local3dPointUncertaintyEllipsoid
+TS29572_Nlmf_Location.yaml#/components/schemas/LocalOrigin
+TS29572_Nlmf_Location.yaml#/components/schemas/Orientation
+TS29572_Nlmf_Location.yaml#/components/schemas/Point
+TS29572_Nlmf_Location.yaml#/components/schemas/PointAltitude
+TS29572_Nlmf_Location.yaml#/components/schemas/PointAltitudeUncertainty
+TS29572_Nlmf_Location.yaml#/components/schemas/PointList
+TS29572_Nlmf_Location.yaml#/components/schemas/PointUncertaintyCircle
+TS29572_Nlmf_Location.yaml#/components/schemas/PointUncertaintyEllipse
+TS29572_Nlmf_Location.yaml#/components/schemas/Polygon
+TS29572_Nlmf_Location.yaml#/components/schemas/RelativeCartesianLocation
+TS29572_Nlmf_Location.yaml#/components/schemas/Uncertainty
+TS29572_Nlmf_Location.yaml#/components/schemas/UncertaintyEllipsoid
+TS29572_Nlmf_Location.yaml#/components/schemas/SupportedGADShapes
+TS29572_Nlmf_Location.yaml#/components/schemas/UncertaintyEllipse
\ No newline at end of file
diff --git a/provider/internal/gentools/enumfixer/enumfixer.go b/provider/internal/gentools/enumfixer/enumfixer.go
new file mode 100644 (file)
index 0000000..e722875
--- /dev/null
@@ -0,0 +1,117 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2022: Nordix Foundation
+//   %%
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//        http://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.
+//   ========================LICENSE_END===================================
+//
+
+package main
+
+import (
+       "flag"
+       "fmt"
+       "io/ioutil"
+       "log"
+       "os"
+       "path/filepath"
+       "reflect"
+       "strconv"
+       "strings"
+
+       "gopkg.in/yaml.v2"
+)
+
+type Enum struct {
+       Enum        []string `yaml:"enum"`
+       Type        string   `yaml:"type"`
+       Description string   `yaml:"description"`
+}
+
+func main() {
+       var apiDir = flag.String("apidir", "", "Directory containing API definitions to fix")
+       flag.Parse()
+       err := filepath.Walk(*apiDir, fixEnums)
+       if err != nil {
+               fmt.Println(err)
+       }
+}
+
+func fixEnums(path string, info os.FileInfo, _ error) error {
+       if !info.IsDir() && strings.HasSuffix(info.Name(), ".yaml") {
+               yamlFile, err := ioutil.ReadFile(path)
+               if err != nil {
+                       log.Printf("yamlFile. Get err   #%v ", err)
+               }
+               m := make(map[string]interface{})
+               err = yaml.Unmarshal(yamlFile, m)
+               if err != nil {
+                       log.Fatalf("Unmarshal: %v", err)
+               }
+               components := m["components"]
+               if components != nil {
+                       cMap := components.(map[interface{}]interface{})
+                       if _, ok := cMap["schemas"].(map[interface{}]interface{}); ok {
+                               schemas := cMap["schemas"].(map[interface{}]interface{})
+                               for typeName, typeDef := range schemas {
+                                       tDMap := typeDef.(map[interface{}]interface{})
+                                       anyOf, ok := tDMap["anyOf"]
+                                       if ok {
+                                               aOSlice := anyOf.([]interface{})
+                                               correctEnum := Enum{}
+                                               mapInterface := aOSlice[0].(map[interface{}]interface{})
+                                               enumInterface := mapInterface["enum"]
+                                               if enumInterface != nil {
+                                                       is := enumInterface.([]interface{})
+                                                       var enumVals []string
+                                                       for i := 0; i < len(is); i++ {
+                                                               if reflect.TypeOf(is[i]).Kind() == reflect.String {
+                                                                       enumVals = append(enumVals, is[i].(string))
+
+                                                               } else if reflect.TypeOf(is[1]).Kind() == reflect.Int {
+                                                                       enumVals = append(enumVals, strconv.Itoa(is[i].(int)))
+                                                               }
+                                                       }
+                                                       correctEnum.Enum = enumVals
+                                                       correctEnum.Type = "string"
+                                                       description := tDMap["description"]
+                                                       if description != nil {
+                                                               correctEnum.Description = description.(string)
+                                                       } else {
+                                                               if aOSlice[1] != nil {
+                                                                       mapInterface = aOSlice[1].(map[interface{}]interface{})
+                                                                       description := mapInterface["description"]
+                                                                       if description != nil {
+                                                                               correctEnum.Description = description.(string)
+                                                                       }
+                                                               }
+                                                       }
+                                                       schemas[typeName] = correctEnum
+                                               }
+                                       }
+                               }
+                               modM, err := yaml.Marshal(m)
+                               if err != nil {
+                                       log.Printf("yamlFile. Get err   #%v ", err)
+                               }
+                               err = ioutil.WriteFile(path, modM, 0644)
+                               if err != nil {
+                                       log.Printf("yamlFile. Get err   #%v ", err)
+                               }
+                       }
+               }
+       }
+       return nil
+}
diff --git a/provider/internal/gentools/specificationfixer/specificationfixer.go b/provider/internal/gentools/specificationfixer/specificationfixer.go
new file mode 100644 (file)
index 0000000..4257b65
--- /dev/null
@@ -0,0 +1,80 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2022: Nordix Foundation
+//   %%
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//        http://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.
+//   ========================LICENSE_END===================================
+//
+
+package main
+
+import (
+       "flag"
+       "io/ioutil"
+       "log"
+
+       "gopkg.in/yaml.v2"
+)
+
+var apiDir *string
+
+func main() {
+       apiDir = flag.String("apidir", "", "Directory containing API definitions to fix")
+       flag.Parse()
+
+       m := getData("TS29571_CommonData.yaml")
+       components := m["components"]
+       cMap := components.(map[interface{}]interface{})
+       schemas := cMap["schemas"].(map[interface{}]interface{})
+       snssaiExtensionData := schemas["SnssaiExtension"].(map[interface{}]interface{})
+       props := snssaiExtensionData["properties"].(map[interface{}]interface{})
+       wildcardSdData := props["wildcardSd"].(map[interface{}]interface{})
+       delete(wildcardSdData, "enum")
+
+       writeFile("TS29571_CommonData.yaml", m)
+
+       m = getData("TS29222_CAPIF_Security_API.yaml")
+       components = m["components"]
+       cMap = components.(map[interface{}]interface{})
+       schemas = cMap["schemas"].(map[interface{}]interface{})
+       accessTokenReq := schemas["AccessTokenReq"].(map[interface{}]interface{})
+       accessTokenReq["type"] = "object"
+
+       writeFile("TS29222_CAPIF_Security_API.yaml", m)
+}
+
+func getData(filename string) map[string]interface{} {
+       yamlFile, err := ioutil.ReadFile(*apiDir + "/" + filename)
+       if err != nil {
+               log.Fatalf("Error reading yamlFile. #%v ", err)
+       }
+       m := make(map[string]interface{})
+       err = yaml.Unmarshal(yamlFile, m)
+       if err != nil {
+               log.Fatalf("Unmarshal: %v", err)
+       }
+       return m
+}
+
+func writeFile(filename string, data map[string]interface{}) {
+       modCommon, err := yaml.Marshal(data)
+       if err != nil {
+               log.Fatalf("Marshal: #%v ", err)
+       }
+       err = ioutil.WriteFile(*apiDir+"/"+filename, modCommon, 0644)
+       if err != nil {
+               log.Fatalf("Error writing yamlFile. #%v ", err)
+       }
+}
diff --git a/provider/main.go b/provider/main.go
new file mode 100644 (file)
index 0000000..b7661ea
--- /dev/null
@@ -0,0 +1,89 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2023: Nordix Foundation
+//   %%
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//        http://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.
+//   ========================LICENSE_END===================================
+//
+
+package main
+
+import (
+       "errors"
+       "flag"
+       "fmt"
+       "html/template"
+       "io"
+
+       log "github.com/sirupsen/logrus"
+
+       "github.com/labstack/echo/v4"
+       "oransc.org/nonrtric/capifprov/handler"
+)
+
+type TemplateRegistry struct {
+       templates map[string]*template.Template
+}
+
+func (t *TemplateRegistry) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
+       tmpl, ok := t.templates[name]
+       if !ok {
+               err := errors.New("Template not found -> " + name)
+               return err
+       }
+       return tmpl.ExecuteTemplate(w, "base", data)
+}
+
+func main() {
+
+       // Echo instance
+       e := echo.New()
+       e.Static("/", "view")
+       var capifCoreUrl string
+       flag.StringVar(&capifCoreUrl, "capifCoreUrl", "http://localhost:8090", "Url for CAPIF core")
+       var logLevelStr = flag.String("loglevel", "Info", "Log level")
+       var port = flag.Int("port", 9090, "Port for CAPIF Provider")
+
+       flag.Parse()
+
+       if loglevel, err := log.ParseLevel(*logLevelStr); err == nil {
+               log.SetLevel(loglevel)
+       }
+
+       templates := make(map[string]*template.Template)
+       templates["home.html"] = template.Must(template.ParseFiles("view/home.html", "view/base.html"))
+       templates["registration.html"] = template.Must(template.ParseFiles("view/registration.html", "view/base.html"))
+       templates["publishapi.html"] = template.Must(template.ParseFiles("view/publishapi.html", "view/base.html"))
+       templates["getapi.html"] = template.Must(template.ParseFiles("view/getapi.html", "view/base.html"))
+
+       e.Renderer = &TemplateRegistry{
+               templates: templates,
+       }
+
+       // Route => handler
+       e.GET("/", handler.HomeHandler)
+       e.POST("/", handler.HomeHandler)
+
+       e.GET("/registration", handler.RegistrationHandler)
+       e.POST("/registration", handler.RegistrationFormHandler(capifCoreUrl))
+
+       e.GET("/publishapi", handler.PublishapiHandler)
+       e.POST("/publishapi", handler.PublishApiFormHandler(capifCoreUrl))
+
+       e.GET("/getapi", handler.GetApiRequest(capifCoreUrl))
+
+       // Start the web server
+       e.Logger.Fatal(e.Start(fmt.Sprintf("0.0.0.0:%d", *port)))
+}
diff --git a/provider/view/base.html b/provider/view/base.html
new file mode 100644 (file)
index 0000000..7d6d2b2
--- /dev/null
@@ -0,0 +1,53 @@
+<!--
+   ========================LICENSE_START=================================
+   O-RAN-SC
+   %%
+   Copyright (C) 2023: Nordix Foundation
+   %%
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+        http://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.
+   ========================LICENSE_END===================================
+-->
+{{define "base"}}
+  <!DOCTYPE html>
+  <html lang="en">
+    <head>
+        <!-- Required meta tags -->
+        <meta charset="utf-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1">
+
+        <!-- CSS -->
+        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
+        <link rel="stylesheet"  type="text/css" href="./css/style.css">
+        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
+        <script language="JavaScript" type="text/javascript" src="./js/script.js"></script>
+
+        <title>{{template "title" .}}</title>
+    </head>
+    <body>
+        <main>
+        <div class="container py-4">
+            <header class="d-flex flex-wrap justify-content-center py-3 mb-4 border-bottom text-dark">
+                <div class="col-4 text-center">
+                    <a class="text-body-emphasis mb-3 mb-md-0 me-md-auto link-body-emphasis text-decoration-none" href="/">
+                        <span class="fs-2">CAPIF API Provider Domain</span>
+                    </a>
+                  </div>
+            </header>
+            {{template "body" .}}
+        </div>
+        </main>
+        <!-- JS -->
+        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
+    </body>
+  </html>
+{{end}}
\ No newline at end of file
diff --git a/provider/view/css/style.css b/provider/view/css/style.css
new file mode 100644 (file)
index 0000000..1654f0c
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+   ========================LICENSE_START=================================
+   O-RAN-SC
+   %%
+   Copyright (C) 2023: Nordix Foundation
+   %%
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+        http://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.
+   ========================LICENSE_END===================================
+*/
+.callout {
+  padding: 20px;
+  margin: 20px 0;
+  border: 1px solid #eee;
+  border-left-width: 5px;
+  border-radius: 3px;
+}
+
+.bs-callout {
+  margin-top: -5px;
+}
+.callout-info {
+  border-left-color: #5bc0de;
+}
+
+.callout-info h4 {
+  color: #5bc0de;
+}
+
+.hiddenRow {
+  padding: 0 !important;
+}
\ No newline at end of file
diff --git a/provider/view/getapi.html b/provider/view/getapi.html
new file mode 100644 (file)
index 0000000..9ae04e3
--- /dev/null
@@ -0,0 +1,109 @@
+<!--
+   ========================LICENSE_START=================================
+   O-RAN-SC
+   %%
+   Copyright (C) 2023: Nordix Foundation
+   %%
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+        http://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.
+   ========================LICENSE_END===================================
+-->
+{{define "title"}}
+  CAPIF Provider | {{index . "name"}}
+{{end}}
+
+{{define "body"}}
+
+{{if .isResponse}}
+<div class="p-5 mb-4 bg-light rounded-3">
+    <div class="container-fluid py-5">
+      <h4 class="card-subtitle mb-3 text-body-secondary">Response from CAPIF core</h4>
+      <div class="callout callout-info">
+        <h5 class="card-subtitle mb-3 text-body-secondary">ServiceAPIDescription</h5>
+        <div id="response">
+        </div>
+      </div>
+
+      <div class="btns col-md-12 text-center">
+        <form action="/" method="GET">
+            <input class="btn btn-secondary" formaction="/" type="submit" value="Return to main page">
+          </form>
+      </div>
+    </div>
+  </div>
+  <script>
+    var htmlResponse = "{{.response}}"
+    const strData = JSON.parse(htmlResponse);
+    let out = "";
+    strData.forEach((api) => {
+        out += `
+          <h6>
+            ApiId:
+            <small id="ApiId" class="text-muted">${api.apiId}</small>
+          </h6>
+          <h6>
+            ApiName:
+            <small id="ApiName" class="text-muted">${api.apiName}</small>
+          </h6>
+          <h6>
+            Description:
+            <small id="Description" class="text-muted">${api.description}</small>
+          </h6>
+
+          <h6>AefProfiles:</h6>
+          <div id="responseTable" class="table-responsive">
+            <table class="table accordion">
+              <thead>
+                 <tr>
+                    <th scope="col">AefId</th>
+                    <th scope="col">AefLocation</th>
+                    <th scope="col">DomainName</th>
+                    <th scope="col">Protocol</th>
+                    <th scope="col">SecurityMethods</th>
+                 </tr>
+              </thead>
+              <tbody id="data-output">
+                 <!-- Prodcuts from javascript file in here. -->
+                 ${printAefProfiles(api.aefProfiles)}
+              </tbody>
+           </table>
+          </div>
+        `;
+
+        document.querySelector("#response").innerHTML = out;
+    });
+  </script>
+{{- else}}
+    <div class="p-5 mb-4 bg-light rounded-3">
+        <div class="container-fluid py-5">
+            {{if .isError}}
+                <div class="alert alert-danger" role="alert">
+                    {{.response}}
+                </div>
+            {{end}}
+            <h5 class="card-subtitle mb-3 text-body-secondary">API publishing functions> Get APIs</h5>
+            <form action="/getapi" method="GET">
+                <div class="mb-3">
+                    <label for="apfId" class="form-label">ApfId:</label>
+                    <input type="text" class="form-control" id="apfId" name="apfId" placeholder="apfId" required>
+                </div>
+                <div class="btns col-md-12 text-center">
+                    <input class="btn btn-primary" type="submit" value="Submit">
+                    <input class="btn btn-secondary" formaction="/" type="submit" value="Cancel" formnovalidate>
+                </div>
+            </form>
+        </div>
+    </div>
+{{- end}}
+{{end}}
+
+
diff --git a/provider/view/home.html b/provider/view/home.html
new file mode 100644 (file)
index 0000000..9d9ff55
--- /dev/null
@@ -0,0 +1,70 @@
+<!--
+   ========================LICENSE_START=================================
+   O-RAN-SC
+   %%
+   Copyright (C) 2023: Nordix Foundation
+   %%
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+        http://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.
+   ========================LICENSE_END===================================
+-->
+{{define "title"}}
+  CAPIF Provider
+{{end}}
+
+{{define "body"}}
+<div class="bd-example">
+<div class="accordion" id="accordionExample">
+    <div class="accordion-item">
+      <h2 class="accordion-header">
+        <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
+            API management function
+        </button>
+      </h2>
+      <div id="collapseOne" class="accordion-collapse collapse show" data-bs-parent="#accordionExample">
+        <div class="accordion-body">
+            <ul>
+                <li><a href="/registration">Registers a new API Provider domain with API provider domain functions profiles.</a></li>
+            </ul>
+        </div>
+      </div>
+    </div>
+    <div class="accordion-item">
+      <h2 class="accordion-header">
+        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
+            APF API publishing function
+        </button>
+      </h2>
+      <div id="collapseTwo" class="accordion-collapse collapse" data-bs-parent="#accordionExample">
+        <div class="accordion-body">
+            <ul>
+                <li><a href="/publishapi">Publish a new API</a></li>
+                <li><a href="/getapi">Retrieve all published APIs</a></li>
+            </ul>
+        </div>
+      </div>
+    </div>
+    <div class="accordion-item">
+      <h2 class="accordion-header">
+        <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
+            AEF API exposing function
+        </button>
+      </h2>
+      <div id="collapseThree" class="accordion-collapse collapse" data-bs-parent="#accordionExample">
+
+      </div>
+    </div>
+  </div>
+</div>
+{{end}}
+
+
diff --git a/provider/view/js/script.js b/provider/view/js/script.js
new file mode 100644 (file)
index 0000000..2b25652
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+   ========================LICENSE_START=================================
+   O-RAN-SC
+   %%
+   Copyright (C) 2023: Nordix Foundation
+   %%
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+        http://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.
+   ========================LICENSE_END===================================
+*/
+const isObject = (value) => typeof value === "object" && value !== null
+
+function checkValue(value){
+    return (isObject(value) ? value : "");
+}
+
+function printResources(resources) {
+    let res = Object.values(checkValue(resources));
+    let out = `<p class="lead">Resources:</p><ul>`;
+    res.forEach((r) => {
+        out += `<li>
+            <p>
+            <strong>CommType:</strong> ${r.commType}
+            <strong>CustOpName:</strong> ${r.custOpName}
+            <strong>ResourceName:</strong> ${r.resourceName}
+            <strong>Uri:</strong> ${r.uri}
+            <strong>Description:</strong> ${r.description}
+            <strong>Operations:</strong> ${Object.values(checkValue(r.operations))}
+            </p>
+            </li>`;
+    });
+    out += `</ul>`;
+    return out;
+}
+
+function printCustomOperations(custOperations) {
+    let operations = Object.values(checkValue(custOperations));
+    let out = `<p class="lead"> Custom Operations:</p><ul>`;
+    operations.forEach((o) => {
+        out += `<li>
+            <p>
+            <strong>CommType:</strong> ${o.commType}
+            <strong>CustOpName:</strong> ${o.custOpName}
+            <strong>Description:</strong> ${o.description}
+            <strong>Operations:</strong> ${Object.values(checkValue(o.operations))}
+            </p>
+            </li>`;
+    });
+    out += `</ul>`;
+    return out;
+}
+
+function printVersions(versions) {
+    let vers = Object.values(checkValue(versions));
+    let out = `<p class="lead">Versions:</p><ul>`;
+    vers.forEach((v) => {
+        out += `<li>
+            <p>
+            <strong>ApiVersion:</strong> ${v.apiVersion}
+            ${printCustomOperations(v.custOperations)}
+            ${printResources(v.resources)}
+            </p>
+            </li>`;
+    });
+    out += `</ul>`;
+    return out;
+}
+
+function printInterfaceDescription(description) {
+    let interfaceDescriptions = Object.values(checkValue(description));
+    let out = `<p class="lead">Interface Description:</p><ul>`;
+    interfaceDescriptions.forEach((d) => {
+        out += `<li>
+            <p>
+            <strong>Ipv4Addr:</strong> ${d.ipv4Addr}
+            <strong>Ipv6Addr:</strong> ${d.ipv6Addr}
+            <strong>Port:</strong> ${d.port}
+            <strong>SecurityMethods:</strong> ${Object.values(checkValue(d.securityMethods))}
+            </p>
+            </li>`;
+    });
+    out += `</ul>`;
+    return out;
+}
+
+function printAefProfiles(aefProfiles){
+    let out = "";
+    let index = 0;
+    aefProfiles.forEach((aef) => {
+      out += `
+         <tr data-bs-toggle="collapse"  data-bs-target="#r${index}">
+            <td>${aef.aefId}</td>
+            <td>${aef.aefLocation}</td>
+            <td>${aef.domainName}</td>
+            <td>${aef.protocol}</td>
+            <td>${Object.values(checkValue(aef.securityMethods))}</td>
+         </tr>
+         <tr class="collapse accordion-collapse" id="r${index}" data-bs-parent=".table">
+            <td colspan="5">
+                <div id="demo1">
+                    ${printInterfaceDescription(aef.interfaceDescriptions)}
+                    ${printVersions(aef.versions)}
+                </div>
+            </td>
+        </tr>
+      `;
+      index++;
+    });
+    return out;
+}
+
+
diff --git a/provider/view/publishapi.html b/provider/view/publishapi.html
new file mode 100644 (file)
index 0000000..3f71ed6
--- /dev/null
@@ -0,0 +1,111 @@
+<!--
+   ========================LICENSE_START=================================
+   O-RAN-SC
+   %%
+   Copyright (C) 2023: Nordix Foundation
+   %%
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+        http://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.
+   ========================LICENSE_END===================================
+-->
+{{define "title"}}
+  CAPIF Provider
+{{end}}
+
+{{define "body"}}
+  {{if .isResponse}}
+  <div class="p-5 mb-4 bg-light rounded-3">
+    <div class="container-fluid py-5">
+      <h4 class="card-subtitle mb-3 text-body-secondary">Response from CAPIF core</h4>
+      <div class="callout callout-info">
+        <h5 class="card-subtitle mb-3 text-body-secondary">ServiceAPIDescription</h5>
+        <div id="response">
+          <h6>
+            ApiId:
+            <small id="ApiId" class="text-muted"></small>
+          </h6>
+          <h6>
+            ApiName:
+            <small id="ApiName" class="text-muted"></small>
+          </h6>
+          <h6>
+            Description:
+            <small id="Description" class="text-muted"></small>
+          </h6>
+
+          <h6>AefProfiles:</h6>
+          <div id="responseTable" class="table-responsive">
+            <table class="table accordion">
+              <thead>
+                 <tr>
+                    <th scope="col">AefId</th>
+                    <th scope="col">AefLocation</th>
+                    <th scope="col">DomainName</th>
+                    <th scope="col">Protocol</th>
+                    <th scope="col">SecurityMethods</th>
+                 </tr>
+              </thead>
+              <tbody id="data-output">
+                 <!-- Prodcuts from javascript file in here. -->
+              </tbody>
+           </table>
+          </div>
+        </div>
+      </div>
+
+      <div class="btns col-md-12 text-center">
+        <form action="/" method="GET">
+            <input class="btn btn-secondary" formaction="/" type="submit" value="Return to main page">
+          </form>
+      </div>
+    </div>
+  </div>
+  <script>
+    var htmlResponse = "{{.response}}"
+    const strData = JSON.parse(htmlResponse);
+    document.getElementById("ApiId").innerHTML = strData.apiId;
+    document.getElementById("ApiName").innerHTML = strData.apiName;
+    document.getElementById("Description").innerHTML = strData.description;
+
+    let aefProfiles = Object.values(checkValue(strData.aefProfiles));
+    document.querySelector("#data-output").innerHTML = printAefProfiles(aefProfiles);
+  </script>
+  {{- else}}
+  <div class="p-5 mb-4 bg-light rounded-3">
+    <div class="container-fluid py-5">
+        {{if .isError}}
+            <div class="alert alert-danger" role="alert">
+                {{.response}}
+            </div>
+        {{end}}
+      <h5 class="card-subtitle mb-3 text-body-secondary">API publishing functions> Publish API</h5>
+      <form action="/publishapi" method="POST">
+        <div class="mb-3">
+          <label for="apfId" class="form-label">ApfId:</label>
+          <input type="text" class="form-control" id="apfId" name="apfId" placeholder="apfId" required>
+        </div>
+        <div class="mb-3">
+            <label for="apiDescription" class="form-label">ServiceAPIDescription:</label>
+            <textarea id="apiDescription"  class="form-control" name="apiDescription" rows="10" cols="60"></textarea>
+          </div>
+
+        <div class="btns col-md-12 text-center">
+            <input class="btn btn-primary" type="submit" value="Submit">
+            <input class="btn btn-secondary" formaction="/" type="submit" value="Cancel" formnovalidate>
+        </div>
+      </form>
+    </div>
+  </div>
+  {{- end}}
+{{end}}
+
+
diff --git a/provider/view/registration.html b/provider/view/registration.html
new file mode 100644 (file)
index 0000000..d0e381d
--- /dev/null
@@ -0,0 +1,119 @@
+<!--
+   ========================LICENSE_START=================================
+   O-RAN-SC
+   %%
+   Copyright (C) 2023: Nordix Foundation
+   %%
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+        http://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.
+   ========================LICENSE_END===================================
+-->
+{{define "title"}}
+  CAPIF Provider | {{index . "name"}}
+{{end}}
+
+{{define "body"}}
+{{if .isResponse}}
+  <div class="p-5 mb-4 bg-light rounded-3">
+    <div class="container-fluid py-5">
+      <h4 class="card-subtitle mb-3 text-body-secondary">Response from CAPIF core</h4>
+      <div class="callout callout-info">
+        <h5 class="card-subtitle mb-3 text-body-secondary">APIProviderEnrolmentDetails</h5>
+        <div id="response">
+          <h6>
+            ApiProvDomId:
+            <small id="ApiProvDomId" class="text-muted"></small>
+          </h6>
+          <h6>
+            ApiProvDomInfo:
+            <small id="ApiProvDomInfo" class="text-muted"></small>
+          </h6>
+          <h6>
+            RegSec:
+            <small id="RegSec" class="text-muted"></small>
+          </h6>
+          <h6>APIProviderFunctionDetails:</h6>
+
+          <div id="responseTable">
+            <table class="table table-striped">
+              <thead>
+                 <tr>
+                    <th scope="col">ApiProvFuncId</th>
+                    <th scope="col">ApiProvFuncInfo</th>
+                    <th scope="col">ApiProvFuncRole</th>
+                    <th scope="col">RegistrationInformation</th>
+                 </tr>
+              </thead>
+              <tbody id="data-output">
+                 <!-- Prodcuts from javascript file in here. -->
+              </tbody>
+           </table>
+          </div>
+        </div>
+      </div>
+
+      <div class="btns col-md-12 text-center">
+        <form action="/" method="GET">
+          <input class="btn btn-secondary" formaction="/" type="submit" value="Return to main page">
+        </form>
+      </div>
+    </div>
+  </div>
+  <script>
+
+    var htmlResponse = "{{.response}}"
+    const strData = JSON.parse(htmlResponse);
+    document.getElementById("ApiProvDomId").innerHTML = strData.apiProvDomId;
+    document.getElementById("ApiProvDomInfo").innerHTML = strData.apiProvDomInfo;
+    document.getElementById("RegSec").innerHTML = strData.regSec;
+
+    let functionsV = Object.values(strData.apiProvFuncs);
+    let out = "";
+    functionsV.forEach((f) => {
+      out += `
+         <tr>
+            <td>${f.apiProvFuncId}</td>
+            <td>${f.apiProvFuncInfo}</td>
+            <td>${f.apiProvFuncRole}</td>
+            <td>${Object.values(f.regInfo)}</td>
+         </tr>
+      `;
+    });
+
+    document.querySelector("#data-output").innerHTML = out;
+  </script>
+{{- else}}
+  <div class="p-5 mb-4 bg-light rounded-3">
+    <div class="container-fluid py-5">
+      {{if .isError}}
+        <div class="alert alert-danger" role="alert">
+          {{.response}}
+        </div>
+      {{end}}
+      <h5 class="card-subtitle mb-3 text-body-secondary">API management functions> Registrations</h5>
+      <form action="/registration" method="POST">
+        <div class="mb-3">
+          <label for="enrolmentDetails" class="form-label">APIProviderEnrolmentDetails:</label>
+          <textarea id="enrolmentDetails"  class="form-control" name="enrolmentDetails" rows="10" cols="60" required></textarea>
+        </div>
+
+        <div class="btns col-md-12 text-center">
+            <input class="btn btn-primary" type="submit" value="Submit">
+            <input class="btn btn-secondary" formaction="/" type="submit" value="Cancel" formnovalidate>
+        </div>
+      </form>
+    </div>
+  </div>
+{{- end}}
+{{end}}
+
+