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

feat(server): project import export external url #1205

Merged
merged 14 commits into from
Oct 30, 2024
Merged
103 changes: 92 additions & 11 deletions server/e2e/gql_import_export_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package e2e

import (
"fmt"
"net/http"
"os"
"testing"

"github.com/gavv/httpexpect/v2"
"github.com/reearth/reearth/server/internal/app/config"
"github.com/stretchr/testify/assert"
)

// export REEARTH_DB=mongodb://localhost
// go test -v -run TestCallExportProject ./e2e/...

func TestCallExportProject(t *testing.T) {
Expand All @@ -18,21 +23,91 @@ func TestCallExportProject(t *testing.T) {
},
}, true, baseSeeder)

pID := createProject(e, "test")
pID := createProjectWithExternalImage(e, "test")

_, _, sID := createScene(e, pID)

createStory(e, sID, "test", 0)
_, _, storyID := createStory(e, sID, "test", 0)

_, _, pageID := createPage(e, sID, storyID, "test", true)

_, _, _ = createBlock(e, sID, storyID, pageID, "reearth", "imageStoryBlock", nil)
_, _, _ = createBlock(e, sID, storyID, pageID, "reearth", "imageStoryBlock", nil)
_, _, _ = createBlock(e, sID, storyID, pageID, "reearth", "imageStoryBlock", nil)

_, res := fetchSceneForStories(e, sID)

blocks := res.Object().Value("data").Object().
Value("node").Object().
Value("stories").Array().First().Object().
Value("pages").Array().First().Object().
Value("blocks").Array().Iter()

propID1 := blocks[0].Object().Value("propertyId").Raw().(string)
propID2 := blocks[1].Object().Value("propertyId").Raw().(string)
propID3 := blocks[2].Object().Value("propertyId").Raw().(string)

_, res = updatePropertyValue(e, propID1, "default", "", "src", "http://localhost:8080/assets/01jbbhhtq2jq7mx39dhyq1cfr2.png", "URL")
res.Path("$.data.updatePropertyValue.propertyField.value").Equal("http://localhost:8080/assets/01jbbhhtq2jq7mx39dhyq1cfr2.png")

_, res = updatePropertyValue(e, propID2, "default", wID.String(), "src", "https://test.com/project.jpg", "URL")
res.Path("$.data.updatePropertyValue.propertyField.value").Equal("https://test.com/project.jpg")

_, res = updatePropertyValue(e, propID3, "default", wID.String(), "src", "https://api.visualizer.test.reearth.dev/assets/01jbbhhtq2jq7mx39dhyq1cfr2.png", "URL")
res.Path("$.data.updatePropertyValue.propertyField.value").Equal("https://api.visualizer.test.reearth.dev/assets/01jbbhhtq2jq7mx39dhyq1cfr2.png")

fileName := exporProject(t, e, pID)

defer func() {
err := os.Remove(fileName)
assert.Nil(t, err)
}()
hexaforce marked this conversation as resolved.
Show resolved Hide resolved

}
hexaforce marked this conversation as resolved.
Show resolved Hide resolved

func createProjectWithExternalImage(e *httpexpect.Expect, name string) string {
requestBody := GraphQLRequest{
OperationName: "CreateProject",
Query: `mutation CreateProject($teamId: ID!, $visualizer: Visualizer!, $name: String!, $description: String!, $imageUrl: URL, $coreSupport: Boolean) {
createProject( input: {teamId: $teamId, visualizer: $visualizer, name: $name, description: $description, imageUrl: $imageUrl, coreSupport: $coreSupport} ) {
project {
id
__typename
}
__typename
}
}`,
Variables: map[string]any{
"name": name,
"description": "abc",
"imageUrl": "https://test.com/project.jpg",
"teamId": wID.String(),
"visualizer": "CESIUM",
"coreSupport": true,
},
}

res := e.POST("/api/graphql").
WithHeader("Origin", "https://example.com").
WithHeader("X-Reearth-Debug-User", uID.String()).
WithHeader("Content-Type", "application/json").
WithJSON(requestBody).
Expect().
Status(http.StatusOK).
JSON()

return res.Path("$.data.createProject.project.id").Raw().(string)
}
hexaforce marked this conversation as resolved.
Show resolved Hide resolved

func exporProject(t *testing.T, e *httpexpect.Expect, p string) string {
requestBody := GraphQLRequest{
OperationName: "ExportProject",
Query: "mutation ExportProject($projectId: ID!) { exportProject(input: {projectId: $projectId}) { projectDataPath __typename } }",
Variables: map[string]any{
"projectId": pID,
"projectId": p,
},
}

e.POST("/api/graphql").
r := e.POST("/api/graphql").
WithHeader("Origin", "https://example.com").
WithHeader("authorization", "Bearer test").
WithHeader("X-Reearth-Debug-User", uID.String()).
Expand All @@ -41,14 +116,20 @@ func TestCallExportProject(t *testing.T) {
Expect().
Status(http.StatusOK).
JSON().
Object().
Object()
fmt.Println(r)
downloadPath := r.
Value("data").Object().
Value("exportProject").Object().
Value("projectDataPath").String().Raw()

// downloadResponse := e.GET(fmt.Sprintf("http://localhost:8080%s", projectDataPath)).
// Expect().
// Status(http.StatusOK).
// Body()
// fmt.Println(downloadResponse)
downloadResponse := e.GET(fmt.Sprintf("http://localhost:8080%s", downloadPath)).
Expect().
Status(http.StatusOK).
Body().Raw()

fileName := "project_data.zip"
err := os.WriteFile(fileName, []byte(downloadResponse), os.ModePerm)
assert.Nil(t, err)
return fileName
}
24 changes: 19 additions & 5 deletions server/internal/adapter/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ import (
type ContextKey string

const (
contextUser ContextKey = "user"
contextOperator ContextKey = "operator"
ContextAuthInfo ContextKey = "authinfo"
contextUsecases ContextKey = "usecases"
contextMockAuth ContextKey = "mockauth"
contextUser ContextKey = "user"
contextOperator ContextKey = "operator"
ContextAuthInfo ContextKey = "authinfo"
contextUsecases ContextKey = "usecases"
contextMockAuth ContextKey = "mockauth"
contextCurrentHost ContextKey = "currenthost"
)

var defaultLang = language.English
Expand Down Expand Up @@ -49,6 +50,10 @@ func AttachMockAuth(ctx context.Context, mockAuth bool) context.Context {
return context.WithValue(ctx, contextMockAuth, mockAuth)
}

func AttachCurrentHost(ctx context.Context, currentHost string) context.Context {
return context.WithValue(ctx, contextCurrentHost, currentHost)
}

func User(ctx context.Context) *user.User {
if v := ctx.Value(contextUser); v != nil {
if u, ok := v.(*user.User); ok {
Expand Down Expand Up @@ -122,3 +127,12 @@ func IsMockAuth(ctx context.Context) bool {
}
return false
}

func CurrentHost(ctx context.Context) string {
if v := ctx.Value(contextCurrentHost); v != nil {
if currentHost, ok := v.(string); ok {
return currentHost
}
}
return ""
}
2 changes: 2 additions & 0 deletions server/internal/app/auth_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ func attachOpMiddleware(cfg *ServerConfig) echo.MiddlewareFunc {
log.Debugfc(ctx, "auth: op: %#v", op)
}

ctx = adapter.AttachCurrentHost(ctx, cfg.Config.Host)

c.SetRequest(req.WithContext(ctx))
return next(c)
}
Expand Down
36 changes: 34 additions & 2 deletions server/internal/usecase/interactor/nlslayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ package interactor
import (
"context"
"errors"
"fmt"
"net/url"
"strings"

"github.com/reearth/reearth/server/internal/adapter"
"github.com/reearth/reearth/server/internal/usecase"
"github.com/reearth/reearth/server/internal/usecase/interfaces"
"github.com/reearth/reearth/server/internal/usecase/repo"
Expand All @@ -17,6 +21,7 @@ import (
"github.com/reearth/reearth/server/pkg/scene/builder"
"github.com/reearth/reearthx/account/accountusecase/accountrepo"
"github.com/reearth/reearthx/idx"
"github.com/reearth/reearthx/log"
"github.com/reearth/reearthx/rerror"
"github.com/reearth/reearthx/usecasex"
)
Expand Down Expand Up @@ -854,6 +859,33 @@ func (i *NLSLayer) ImportNLSLayers(ctx context.Context, sceneID idx.ID[id.Scene]
nlayerIDs = append(nlayerIDs, newNLSLayerID)
replaceNLSLayerIDs[nlsLayerJSON.ID] = newNLSLayerID

if nlsLayerJSON.Config != nil {
config := *nlsLayerJSON.Config
if data, ok := config["data"].(map[string]interface{}); ok {
if u, ok := data["url"].(string); ok {
urlVal, err := url.Parse(u)
if err != nil {
log.Infofc(ctx, "invalid url: %v\n", err.Error())
return nil, nil, err
}
if urlVal.Host == "localhost:8080" || strings.HasSuffix(urlVal.Host, ".reearth.dev") || strings.HasSuffix(urlVal.Host, ".reearth.io") {
currentHost := adapter.CurrentHost(ctx)
currentHost = strings.TrimPrefix(currentHost, "https://")
currentHost = strings.TrimPrefix(currentHost, "http://")
urlVal.Host = currentHost
if currentHost == "localhost:8080" {
urlVal.Scheme = "http"
} else {
urlVal.Scheme = "https"
}
fmt.Printf("==== currentHost %s \n", currentHost)
hexaforce marked this conversation as resolved.
Show resolved Hide resolved
data["url"] = urlVal.String()
}
hexaforce marked this conversation as resolved.
Show resolved Hide resolved
}
}

}

hexaforce marked this conversation as resolved.
Show resolved Hide resolved
nlBuilder := nlslayer.New().
ID(newNLSLayerID).
Simple().
Expand All @@ -871,7 +903,7 @@ func (i *NLSLayer) ImportNLSLayers(ctx context.Context, sceneID idx.ID[id.Scene]
if err != nil {
return nil, nil, err
}
prop, err = builder.AddItemFromPropertyJSON(prop, schema, nlsLayerJSON.Infobox.Property)
prop, err = builder.AddItemFromPropertyJSON(ctx, prop, schema, nlsLayerJSON.Infobox.Property)
if err != nil {
return nil, nil, err
}
Expand All @@ -888,7 +920,7 @@ func (i *NLSLayer) ImportNLSLayers(ctx context.Context, sceneID idx.ID[id.Scene]
if err != nil {
return nil, nil, err
}
propB, err = builder.AddItemFromPropertyJSON(propB, schemaB, b.Property)
propB, err = builder.AddItemFromPropertyJSON(ctx, propB, schemaB, b.Property)
if err != nil {
return nil, nil, err
}
Expand Down
4 changes: 3 additions & 1 deletion server/internal/usecase/interactor/nlslayer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"testing"

"github.com/reearth/reearth/server/internal/adapter"
"github.com/reearth/reearth/server/internal/adapter/gql/gqlmodel"
"github.com/reearth/reearth/server/internal/infrastructure/memory"
"github.com/reearth/reearth/server/internal/usecase"
Expand Down Expand Up @@ -264,6 +265,7 @@ func TestDeleteGeoJSONFeature(t *testing.T) {
// go test -v -run TestImportNLSLayers ./internal/usecase/interactor/...
func TestImportNLSLayers(t *testing.T) {
ctx := context.Background()
ctx = adapter.AttachCurrentHost(ctx, "https://xxxx.reearth.dev")

db := memory.New()
ifl := NewNLSLayer(db)
Expand Down Expand Up @@ -323,7 +325,7 @@ func TestImportNLSLayers(t *testing.T) {
"lngColumn": "lng"
},
"type": "csv",
"url": "http://localhost:8080/assets/01j7g9gpba44e0nxwc727nax0q.csv"
"url": "https://xxxx.reearth.dev/assets/01j7g9gpba44e0nxwc727nax0q.csv"
hexaforce marked this conversation as resolved.
Show resolved Hide resolved
}
},
"title": "japan_architecture (2).csv",
Expand Down
3 changes: 1 addition & 2 deletions server/internal/usecase/interactor/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,7 @@ func (i *Plugin) ExportPlugins(ctx context.Context, sce *scene.Scene, zipWriter
return nil, nil, err
}

_, err = io.Copy(zipEntry, stream)
if err != nil {
if _, err = io.Copy(zipEntry, stream); err != nil {
_ = stream.Close()
return nil, nil, err
}
Expand Down
12 changes: 12 additions & 0 deletions server/internal/usecase/interactor/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strings"
"time"

"github.com/reearth/reearth/server/internal/adapter"
"github.com/reearth/reearth/server/internal/adapter/gql/gqlmodel"
jsonmodel "github.com/reearth/reearth/server/internal/adapter/gql/gqlmodel"
"github.com/reearth/reearth/server/internal/usecase"
Expand Down Expand Up @@ -616,6 +617,17 @@ func (i *Project) ImportProject(ctx context.Context, teamID string, projectData
}

if p.ImageURL != nil {
if p.ImageURL.Host == "localhost:8080" || strings.HasSuffix(p.ImageURL.Host, ".reearth.dev") || strings.HasSuffix(p.ImageURL.Host, ".reearth.io") {
currentHost := adapter.CurrentHost(ctx)
hexaforce marked this conversation as resolved.
Show resolved Hide resolved
currentHost = strings.TrimPrefix(currentHost, "https://")
currentHost = strings.TrimPrefix(currentHost, "http://")
hexaforce marked this conversation as resolved.
Show resolved Hide resolved
if currentHost == "localhost:8080" {
p.ImageURL.Scheme = "http"
} else {
p.ImageURL.Scheme = "https"
}
p.ImageURL.Host = currentHost
}
hexaforce marked this conversation as resolved.
Show resolved Hide resolved
hexaforce marked this conversation as resolved.
Show resolved Hide resolved
prjBuilder = prjBuilder.ImageURL(p.ImageURL)
}

Expand Down
6 changes: 4 additions & 2 deletions server/internal/usecase/interactor/project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net/url"
"testing"

"github.com/reearth/reearth/server/internal/adapter"
"github.com/reearth/reearth/server/internal/adapter/gql/gqlmodel"
"github.com/reearth/reearth/server/internal/infrastructure/fs"
"github.com/reearth/reearth/server/internal/infrastructure/memory"
Expand Down Expand Up @@ -149,6 +150,7 @@ func TestProject_Create(t *testing.T) {
func TestImportProject(t *testing.T) {

ctx := context.Background()
ctx = adapter.AttachCurrentHost(ctx, "https://xxxx.reearth.dev")

db := memory.New()
ifp := NewProject(db, &gateway.Container{
Expand Down Expand Up @@ -232,10 +234,10 @@ func TestImportProject(t *testing.T) {
"publicImage": "",
"publicNoIndex": false,
"imageUrl": {
"Scheme": "http",
"Scheme": "https",
"Opaque": "",
"User": null,
"Host": "localhost:8080",
"Host": "xxxx.reearth.dev",
hexaforce marked this conversation as resolved.
Show resolved Hide resolved
"Path": "/assets/01j7g9d988ct8hajjxfsb6e1n6.jpeg",
"RawPath": "",
"OmitHost": false,
Expand Down
Loading
Loading