Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/rewrite links poc #462

Draft
wants to merge 4 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Dockerfile.local
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
FROM golang:1.22.6-bullseye as build
FROM golang:1.23-bullseye as build

ENV GOCACHE=/go/.go/cache GOPATH=/go/.go/path TZ=Europe/London

RUN GOBIN=/bin go install github.com/cespare/reflex@latest

RUN git config --global --add safe.directory /go

# Map between the working directories of dev and live
RUN ln -s /go /dp-dataset-api
WORKDIR /dp-dataset-api
155 changes: 128 additions & 27 deletions api/dataset.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,24 @@ import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
"time"

errs "github.com/ONSdigital/dp-dataset-api/apierrors"
"github.com/ONSdigital/dp-dataset-api/config"
"github.com/ONSdigital/dp-dataset-api/models"
dphttp "github.com/ONSdigital/dp-net/v2/http"
"github.com/ONSdigital/log.go/v2/log"
"github.com/gorilla/mux"
)

type contextKey string

const (
ctxPathPrefix contextKey = "pathPrefix"
)

var (
// errors that should return a 403 status
datasetsForbidden = map[error]bool{
Expand Down Expand Up @@ -79,11 +87,13 @@ func (api *DatasetAPI) getDatasets(w http.ResponseWriter, r *http.Request, limit
return nil, 0, err
}

if authorised {
return datasets, totalCount, nil
datasetsResponse, err := mapResultsAndRewriteLinks(ctx, datasets, authorised)
if err != nil {
log.Error(ctx, "Error mapping results and rewriting links", err)
return nil, 0, err
}

return mapResults(datasets), totalCount, nil
return datasetsResponse, totalCount, nil
}

func (api *DatasetAPI) getDataset(w http.ResponseWriter, r *http.Request) {
Expand All @@ -102,27 +112,11 @@ func (api *DatasetAPI) getDataset(w http.ResponseWriter, r *http.Request) {
authorised := api.authenticate(r, logData)

var b []byte
var datasetResponse interface{}

if !authorised {
// User is not authenticated and hence has only access to current sub document
if dataset.Current == nil {
log.Info(ctx, "getDataset endpoint: published dataset not found", logData)
return nil, errs.ErrDatasetNotFound
}
log.Info(ctx, "getDataset endpoint: caller not authorised returning dataset", logData)

dataset.Current.ID = dataset.ID
datasetResponse = dataset.Current
} else {
// User has valid authentication to get raw dataset document
if dataset == nil {
log.Info(ctx, "getDataset endpoint: published or unpublished dataset not found", logData)
return nil, errs.ErrDatasetNotFound
}
log.Info(ctx, "getDataset endpoint: caller authorised returning dataset current sub document", logData)

datasetResponse = dataset
datasetResponse, err := mapResultsAndRewriteLinks(ctx, []*models.DatasetUpdate{dataset}, authorised)
if err != nil {
log.Error(ctx, "Error mapping results and rewriting links", err)
return nil, err
}

b, err = json.Marshal(datasetResponse)
Expand Down Expand Up @@ -203,11 +197,11 @@ func (api *DatasetAPI) addDataset(w http.ResponseWriter, r *http.Request) {
}

dataset.Links.Editions = &models.LinkObject{
HRef: fmt.Sprintf("%s/datasets/%s/editions", api.host, datasetID),
HRef: fmt.Sprintf("/datasets/%s/editions", datasetID),
}

dataset.Links.Self = &models.LinkObject{
HRef: fmt.Sprintf("%s/datasets/%s", api.host, datasetID),
HRef: fmt.Sprintf("/datasets/%s", datasetID),
}

// Remove latest version from new dataset resource, this cannot be added at this point
Expand Down Expand Up @@ -499,16 +493,123 @@ func (api *DatasetAPI) deleteDataset(w http.ResponseWriter, r *http.Request) {
log.Info(ctx, "delete dataset", logData)
}

func mapResults(results []*models.DatasetUpdate) []*models.Dataset {
func mapResultsAndRewriteLinks(ctx context.Context, results []*models.DatasetUpdate, authorised bool) ([]*models.Dataset, error) {
items := []*models.Dataset{}
for _, item := range results {
if authorised && item.Current == nil && item.Next != nil {
item.Next.ID = item.ID
err := rewriteAllLinks(ctx, item.Next.Links)
if err != nil {
log.Error(ctx, "unable to rewrite 'next' links", err)
return nil, err
}
items = append(items, item.Next)
continue
}

if item.Current == nil {
continue
}

item.Current.ID = item.ID
err := rewriteAllLinks(ctx, item.Current.Links)
if err != nil {
log.Error(ctx, "unable to rewrite 'current' links", err)
return nil, err
}
items = append(items, item.Current)

if authorised && item.Next != nil {
item.Next.ID = item.ID
err := rewriteAllLinks(ctx, item.Next.Links)
if err != nil {
log.Error(ctx, "unable to rewrite 'next' links", err)
return nil, err
}
items = append(items, item.Next)
}
}

return items, nil

}

func rewriteAllLinks(ctx context.Context, oldLinks *models.DatasetLinks) error {
if oldLinks.AccessRights != nil && oldLinks.AccessRights.HRef != "" {
accessRights, err := URLBuild(ctx, oldLinks.AccessRights.HRef)
if err != nil {
log.Error(ctx, "error rewriting AccessRights link", err)
return err
}
oldLinks.AccessRights.HRef = accessRights
}
return items

if oldLinks.Editions != nil && oldLinks.Editions.HRef != "" {
editions, err := URLBuild(ctx, oldLinks.Editions.HRef)
if err != nil {
log.Error(ctx, "error rewriting Editions link", err)
return err
}
oldLinks.Editions.HRef = editions
}

if oldLinks.LatestVersion != nil && oldLinks.LatestVersion.HRef != "" {
latestVersion, err := URLBuild(ctx, oldLinks.LatestVersion.HRef)
if err != nil {
log.Error(ctx, "error rewriting LatestVersion link", err)
return err
}
oldLinks.LatestVersion.HRef = latestVersion
}

if oldLinks.Self != nil && oldLinks.Self.HRef != "" {
self, err := URLBuild(ctx, oldLinks.Self.HRef)
if err != nil {
log.Error(ctx, "error rewriting Self link", err)
return err
}
oldLinks.Self.HRef = self
}

if oldLinks.Taxonomy != nil && oldLinks.Taxonomy.HRef != "" {
taxonomy, err := URLBuild(ctx, oldLinks.Taxonomy.HRef)
if err != nil {
log.Error(ctx, "error rewriting Taxonomy link", err)
return err
}
oldLinks.Taxonomy.HRef = taxonomy
}

return nil
}

func URLBuild(ctx context.Context, oldURL string) (string, error) {
cfg, err := config.Get()
if err != nil {
log.Error(ctx, "unable to retrieve config", err)
return "", err
}

parsedURL, err := url.Parse(oldURL)
if err != nil {
return "", fmt.Errorf("error parsing old URL: %v", err)
}

parsedAPIDomainUrl, err := url.Parse(cfg.APIDomainUrl)
if err != nil {
return "", fmt.Errorf("error parsing old URL: %v", err)
}

fmt.Printf("\nOld URL: %s\n", parsedURL.String())

newUrl, err := url.JoinPath(parsedAPIDomainUrl.String(), parsedURL.Path)
if err != nil {
return "", fmt.Errorf("error joining paths: %v", err)
}

fmt.Printf("New URL: %s\n", newUrl)

return newUrl, nil
}

func handleDatasetAPIErr(ctx context.Context, err error, w http.ResponseWriter, data log.Data) {
Expand Down
2 changes: 2 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type Configuration struct {
CantabularExportStartTopic string `envconfig:"CANTABULAR_EXPORT_START"`
CodeListAPIURL string `envconfig:"CODE_LIST_API_URL"`
DatasetAPIURL string `envconfig:"DATASET_API_URL"`
APIDomainUrl string `envconfig:"API_DOMAIN_URL"`
WebsiteURL string `envconfig:"WEBSITE_URL"`
ZebedeeURL string `envconfig:"ZEBEDEE_URL"`
DownloadServiceSecretKey string `envconfig:"DOWNLOAD_SERVICE_SECRET_KEY" json:"-"`
Expand Down Expand Up @@ -83,6 +84,7 @@ func Get() (*Configuration, error) {
CantabularExportStartTopic: "cantabular-export-start",
CodeListAPIURL: "http://localhost:22400",
DatasetAPIURL: "http://localhost:22000",
APIDomainUrl: "https://api.beta.ons.gov.uk/v1",
WebsiteURL: "http://localhost:20000",
ZebedeeURL: "http://localhost:8082",
ServiceAuthToken: "FD0108EA-825D-411C-9B1D-41EF7727F465",
Expand Down