From 7aae77c88b43303d1d0f47976a60a2c1024c8e61 Mon Sep 17 00:00:00 2001 From: Ewan Cahen Date: Tue, 27 Feb 2024 10:34:37 +0100 Subject: [PATCH] feat: add simple CodeMeta overview page --- codemeta/Dockerfile | 2 ++ codemeta/main.go | 64 +++++++++++++++++++--------------------- codemeta/overview.go | 35 ++++++++++++++++++++++ codemeta/overview.gohtml | 24 +++++++++++++++ codemeta/utils.go | 35 ++++++++++++++++++++++ docker-compose.yml | 2 +- 6 files changed, 127 insertions(+), 35 deletions(-) create mode 100644 codemeta/overview.go create mode 100644 codemeta/overview.gohtml create mode 100644 codemeta/utils.go diff --git a/codemeta/Dockerfile b/codemeta/Dockerfile index 897570610..db768391d 100644 --- a/codemeta/Dockerfile +++ b/codemeta/Dockerfile @@ -11,6 +11,8 @@ COPY **.go . RUN go build -v -o /usr/local/bin/app +COPY **.gohtml . + RUN useradd user USER user diff --git a/codemeta/main.go b/codemeta/main.go index 3206a29de..cb82d796e 100644 --- a/codemeta/main.go +++ b/codemeta/main.go @@ -3,14 +3,12 @@ // // SPDX-License-Identifier: Apache-2.0 -// https://research-software-directory.org/api/v1/software?slug=eq.rsd-ng&select=brand_name,concept_doi,short_statement,contributor(family_names,given_names,affiliation,role,orcid),license_for_software(license),repository_url(url) - package main import ( + "bytes" "encoding/json" "fmt" - "io" "log" "net/http" "os" @@ -81,15 +79,37 @@ func main() { postgrestUrl = "http://backend:3500" } - http.HandleFunc("GET /", func(writer http.ResponseWriter, request *http.Request) { - http.Redirect(writer, request, "/v3/", http.StatusMovedPermanently) + http.HandleFunc("GET /{other}/", func(writer http.ResponseWriter, request *http.Request) { + http.Redirect(writer, request, "/", http.StatusMovedPermanently) }) - http.HandleFunc("GET /v3/", func(writer http.ResponseWriter, request *http.Request) { - writer.WriteHeader(http.StatusBadRequest) - _, err := writer.Write([]byte("Please provide a slug")) + http.HandleFunc("GET /", func(writer http.ResponseWriter, request *http.Request) { + urlUnformatted := "%v/software?select=slug,brand_name,short_statement&order=brand_name" + url := fmt.Sprintf(urlUnformatted, postgrestUrl) + bodyBytes, err := GetAndReadBody(url) if err != nil { - log.Print("Couldn't write response: ", err) + log.Print("Unknown error when downloading software overview: ", err) + writer.WriteHeader(http.StatusInternalServerError) + _, err := writer.Write([]byte("Server error")) + if err != nil { + log.Print("Couldn't write response: ", err) + } + return + } + + byteBuffer := &bytes.Buffer{} + err = GenerateOverview(bodyBytes, byteBuffer) + if err != nil { + writer.WriteHeader(http.StatusInternalServerError) + _, err := writer.Write([]byte("Unknown error when generating software overview, please provide a slug")) + if err != nil { + log.Print("Couldn't write response: ", err) + } + } + + _, err = byteBuffer.WriteTo(writer) + if err != nil { + log.Print("Couldn't write response after generating the overview: ", err) } }) @@ -129,7 +149,7 @@ func main() { urlUnformatted := "%v/software?slug=eq.%v&select=brand_name,concept_doi,short_statement,contributor(family_names,given_names,affiliation,role,orcid,email_address),keyword(value),license_for_software(license),repository_url(url)" url := fmt.Sprintf(urlUnformatted, postgrestUrl, slug) - resp, err := http.Get(url) + bytes, err := GetAndReadBody(url) if err != nil { log.Print("Unknown error when downloading data for slug "+slug+": ", err) writer.WriteHeader(http.StatusInternalServerError) @@ -140,30 +160,6 @@ func main() { return } - var bytes []byte - defer func(Body io.ReadCloser) { - err := Body.Close() - if err != nil { - log.Print("Unknown error when closing response body for slug "+slug+": ", err) - writer.WriteHeader(http.StatusInternalServerError) - _, err := writer.Write([]byte("Server error")) - if err != nil { - log.Print("Couldn't write response: ", err) - } - return - } - }(resp.Body) - bytes, err = io.ReadAll(resp.Body) - if err != nil { - log.Print("Unknown error for reading response body for slug "+slug+": ", err) - writer.WriteHeader(http.StatusInternalServerError) - _, err := writer.Write([]byte("Server error")) - if err != nil { - log.Print("Couldn't write response: ", err) - } - return - } - jsonBytes, err := convertRsdToCodeMeta(bytes) if err != nil { log.Print("Unknown error for slug "+slug+": ", err) diff --git a/codemeta/overview.go b/codemeta/overview.go new file mode 100644 index 000000000..39c1ca3ea --- /dev/null +++ b/codemeta/overview.go @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: 2024 Ewan Cahen (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2024 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "encoding/json" + "html/template" + "io" +) + +type SoftwareBasicData struct { + Slug string `json:"slug"` + BrandName string `json:"brand_name"` + ShortStatement string `json:"short_statement"` +} + +var tmpl = template.Must(template.ParseFiles("overview.gohtml")) + +func GenerateOverview(bytes []byte, writer io.Writer) error { + var software []SoftwareBasicData + err := json.Unmarshal(bytes, &software) + if err != nil { + return err + } + + err = tmpl.Execute(writer, software) + if err != nil { + return err + } + + return nil +} diff --git a/codemeta/overview.gohtml b/codemeta/overview.gohtml new file mode 100644 index 000000000..9b881cd6a --- /dev/null +++ b/codemeta/overview.gohtml @@ -0,0 +1,24 @@ + + + + + CodeMeta overview + + + +

+ CodeMeta overview +

+
+ This page gives a succinct overview of all software pages that export to CodeMeta. + Warning: this feature is still in development, so the generated CodeMeta data might still + change. + +
+
{{range .}} + {{end}} +
+ + diff --git a/codemeta/utils.go b/codemeta/utils.go new file mode 100644 index 000000000..fb4f820cc --- /dev/null +++ b/codemeta/utils.go @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: 2024 Ewan Cahen (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2024 Netherlands eScience Center +// +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "errors" + "io" + "log" + "net/http" +) + +func GetAndReadBody(url string) (body []byte, err error) { + resp, err := http.Get(url) + if err != nil { + return nil, err + } + + defer func(Body io.ReadCloser) { + closeErr := Body.Close() + if closeErr != nil { + log.Printf("Unknown error when closing response body for URL %v overview with error: %v", url, closeErr) + err = errors.Join(closeErr, err) + } + }(resp.Body) + + body, err = io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + return body, err +} diff --git a/docker-compose.yml b/docker-compose.yml index fd2c35a28..2afcbef9f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -178,7 +178,7 @@ services: codemeta: build: ./codemeta - image: rsd/codemeta:v1.0.0 + image: rsd/codemeta:v1.1.0 expose: - "8000" environment: