diff --git a/server/e2e/gql_storytelling_test.go b/server/e2e/gql_storytelling_test.go index dc8661cdd3..163345e453 100644 --- a/server/e2e/gql_storytelling_test.go +++ b/server/e2e/gql_storytelling_test.go @@ -7,6 +7,7 @@ import ( "github.com/gavv/httpexpect/v2" "github.com/reearth/reearth/server/internal/app/config" "github.com/reearth/reearth/server/pkg/id" + "github.com/samber/lo" ) func createProject(e *httpexpect.Expect) string { @@ -92,6 +93,9 @@ func fetchSceneForStories(e *httpexpect.Expect, sId string) (GraphQLRequest, *ht swipeableLayers { id } + blocks { + id + } } } __typename @@ -545,6 +549,147 @@ func removeLayerToPage(e *httpexpect.Expect, sId, storyId, pageId, layerId strin return requestBody, res, layerId } +func createBlock(e *httpexpect.Expect, sId, storyId, pageId, pluginId, extensionId string, idx *int) (GraphQLRequest, *httpexpect.Value, string) { + requestBody := GraphQLRequest{ + OperationName: "CreateStoryBlock", + Query: `mutation CreateStoryBlock($storyId: ID!, $pageId: ID!, $pluginId: ID!, $extensionId: ID!, $index: Int) { + createStoryBlock( input: {storyId: $storyId, pageId: $pageId, pluginId: $pluginId, extensionId: $extensionId, index: $index} ) { + story { + id + pages { + id + } + } + page { + id + title + swipeable + blocks { + id + } + } + block { + id + } + } + }`, + Variables: map[string]any{ + "sceneId": sId, + "storyId": storyId, + "pageId": pageId, + "pluginId": pluginId, + "extensionId": extensionId, + "index": idx, + }, + } + + 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() + + res.Object(). + Value("data").Object(). + Value("createStoryBlock").Object(). + Value("page").Object(). + Value("blocks").Array().NotEmpty() + + return requestBody, res, res.Path("$.data.createStoryBlock.block.id").Raw().(string) +} + +func removeBlock(e *httpexpect.Expect, storyId, pageId, blockId string) (GraphQLRequest, *httpexpect.Value, string) { + requestBody := GraphQLRequest{ + OperationName: "RemoveStoryBlock", + Query: `mutation RemoveStoryBlock($storyId: ID!, $pageId: ID!, $blockId: ID!) { + removeStoryBlock( input: {storyId: $storyId, pageId: $pageId, blockId: $blockId} ) { + story { + id + pages { + id + } + } + page { + id + title + swipeable + blocks { + id + } + } + blockId + } + }`, + Variables: map[string]any{ + "storyId": storyId, + "pageId": pageId, + "blockId": blockId, + }, + } + + 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() + + res.Object(). + Path("$.data.removeStoryBlock.page.blocks[:].id").Array().NotContains(blockId) + + return requestBody, res, res.Path("$.data.removeStoryBlock.blockId").Raw().(string) +} + +func moveBlock(e *httpexpect.Expect, storyId, pageId, blockId string, index int) (GraphQLRequest, *httpexpect.Value, string) { + requestBody := GraphQLRequest{ + OperationName: "MoveStoryBlock", + Query: `mutation MoveStoryBlock($storyId: ID!, $pageId: ID!, $blockId: ID!, $index: Int!) { + moveStoryBlock( input: {storyId: $storyId, pageId: $pageId, blockId: $blockId, index: $index} ) { + story { + id + pages { + id + } + } + page { + id + title + swipeable + blocks { + id + } + } + blockId + } + }`, + Variables: map[string]any{ + "storyId": storyId, + "pageId": pageId, + "blockId": blockId, + "index": index, + }, + } + + 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() + + res.Object(). + Path("$.data.moveStoryBlock.page.blocks[:].id").Array().Contains(blockId) + + return requestBody, res, res.Path("$.data.moveStoryBlock.blockId").Raw().(string) +} + func TestStoryCRUD(t *testing.T) { e := StartServer(t, &config.Config{ Origins: []string{"https://example.com"}, @@ -713,3 +858,52 @@ func TestStoryPageLayersCRUD(t *testing.T) { res.Object(). Path("$.data.node.stories[0].pages[0].layers").Equal([]any{}) } + +func TestStoryPageBlocksCRUD(t *testing.T) { + e := StartServer(t, &config.Config{ + Origins: []string{"https://example.com"}, + AuthSrv: config.AuthSrvConfig{ + Disabled: true, + }, + }, true, baseSeeder) + + pId := createProject(e) + + _, _, sId := createScene(e, pId) + + _, _, storyId := createStory(e, sId, "test", 0) + + _, _, pageId := createPage(e, sId, storyId, "test", true) + + _, res := fetchSceneForStories(e, sId) + res.Object(). + Path("$.data.node.stories[0].pages[0].blocks").Equal([]any{}) + + _, _, blockId1 := createBlock(e, sId, storyId, pageId, "reearth", "storyBlock", nil) + _, _, blockId2 := createBlock(e, sId, storyId, pageId, "reearth", "storyBlock", nil) + + _, res = fetchSceneForStories(e, sId) + res.Object(). + Path("$.data.node.stories[0].pages[0].blocks[:].id").Equal([]string{blockId1, blockId2}) + + _, _, _ = moveBlock(e, storyId, pageId, blockId1, 1) + + _, res = fetchSceneForStories(e, sId) + res.Object(). + Path("$.data.node.stories[0].pages[0].blocks[:].id").Equal([]string{blockId2, blockId1}) + + _, _, blockId3 := createBlock(e, sId, storyId, pageId, "reearth", "storyBlock", lo.ToPtr(1)) + + _, res = fetchSceneForStories(e, sId) + res.Object(). + Path("$.data.node.stories[0].pages[0].blocks[:].id").Equal([]string{blockId2, blockId3, blockId1}) + + removeBlock(e, storyId, pageId, blockId1) + removeBlock(e, storyId, pageId, blockId2) + removeBlock(e, storyId, pageId, blockId3) + + _, res = fetchSceneForStories(e, sId) + res.Object(). + Path("$.data.node.stories[0].pages[0].blocks").Equal([]any{}) + +} diff --git a/server/gql/storytelling.graphql b/server/gql/storytelling.graphql index 15f50fe384..d5cd4b4421 100644 --- a/server/gql/storytelling.graphql +++ b/server/gql/storytelling.graphql @@ -31,17 +31,13 @@ type StoryPage implements Node { type StoryBlock implements Node { id: ID! - propertyId: ID! pluginId: ID! - extensionId: ID! - linkedDatasetId: ID - pageId: ID! - page: StoryPage! - property: Property plugin: Plugin + extensionId: ID! extension: PluginExtension - sceneId: ID! - scene: Scene + propertyId: ID! + property: Property + linkedDatasetId: ID } # InputType @@ -184,9 +180,9 @@ type CreateStoryBlockPayload { } type MoveStoryBlockPayload { - block: StoryBlock! page: StoryPage! story: Story! + blockId: ID! index: Int! } diff --git a/server/internal/adapter/gql/generated.go b/server/internal/adapter/gql/generated.go index bb5e7d5f71..cd5dc1d54f 100644 --- a/server/internal/adapter/gql/generated.go +++ b/server/internal/adapter/gql/generated.go @@ -514,10 +514,10 @@ type ComplexityRoot struct { } MoveStoryBlockPayload struct { - Block func(childComplexity int) int - Index func(childComplexity int) int - Page func(childComplexity int) int - Story func(childComplexity int) int + BlockID func(childComplexity int) int + Index func(childComplexity int) int + Page func(childComplexity int) int + Story func(childComplexity int) int } MoveStoryPagePayload struct { @@ -977,14 +977,10 @@ type ComplexityRoot struct { ExtensionID func(childComplexity int) int ID func(childComplexity int) int LinkedDatasetID func(childComplexity int) int - Page func(childComplexity int) int - PageID func(childComplexity int) int Plugin func(childComplexity int) int PluginID func(childComplexity int) int Property func(childComplexity int) int PropertyID func(childComplexity int) int - Scene func(childComplexity int) int - SceneID func(childComplexity int) int } StoryPage struct { @@ -1471,10 +1467,9 @@ type StoryResolver interface { Scene(ctx context.Context, obj *gqlmodel.Story) (*gqlmodel.Scene, error) } type StoryBlockResolver interface { - Property(ctx context.Context, obj *gqlmodel.StoryBlock) (*gqlmodel.Property, error) Plugin(ctx context.Context, obj *gqlmodel.StoryBlock) (*gqlmodel.Plugin, error) - Scene(ctx context.Context, obj *gqlmodel.StoryBlock) (*gqlmodel.Scene, error) + Property(ctx context.Context, obj *gqlmodel.StoryBlock) (*gqlmodel.Property, error) } type StoryPageResolver interface { Layers(ctx context.Context, obj *gqlmodel.StoryPage) ([]gqlmodel.Layer, error) @@ -3318,12 +3313,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.MoveLayerPayload.ToParentLayer(childComplexity), true - case "MoveStoryBlockPayload.block": - if e.complexity.MoveStoryBlockPayload.Block == nil { + case "MoveStoryBlockPayload.blockId": + if e.complexity.MoveStoryBlockPayload.BlockID == nil { break } - return e.complexity.MoveStoryBlockPayload.Block(childComplexity), true + return e.complexity.MoveStoryBlockPayload.BlockID(childComplexity), true case "MoveStoryBlockPayload.index": if e.complexity.MoveStoryBlockPayload.Index == nil { @@ -6166,20 +6161,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.StoryBlock.LinkedDatasetID(childComplexity), true - case "StoryBlock.page": - if e.complexity.StoryBlock.Page == nil { - break - } - - return e.complexity.StoryBlock.Page(childComplexity), true - - case "StoryBlock.pageId": - if e.complexity.StoryBlock.PageID == nil { - break - } - - return e.complexity.StoryBlock.PageID(childComplexity), true - case "StoryBlock.plugin": if e.complexity.StoryBlock.Plugin == nil { break @@ -6208,20 +6189,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.StoryBlock.PropertyID(childComplexity), true - case "StoryBlock.scene": - if e.complexity.StoryBlock.Scene == nil { - break - } - - return e.complexity.StoryBlock.Scene(childComplexity), true - - case "StoryBlock.sceneId": - if e.complexity.StoryBlock.SceneID == nil { - break - } - - return e.complexity.StoryBlock.SceneID(childComplexity), true - case "StoryPage.blocks": if e.complexity.StoryPage.Blocks == nil { break @@ -8406,17 +8373,13 @@ type StoryPage implements Node { type StoryBlock implements Node { id: ID! - propertyId: ID! pluginId: ID! - extensionId: ID! - linkedDatasetId: ID - pageId: ID! - page: StoryPage! - property: Property plugin: Plugin + extensionId: ID! extension: PluginExtension - sceneId: ID! - scene: Scene + propertyId: ID! + property: Property + linkedDatasetId: ID } # InputType @@ -8559,9 +8522,9 @@ type CreateStoryBlockPayload { } type MoveStoryBlockPayload { - block: StoryBlock! page: StoryPage! story: Story! + blockId: ID! index: Int! } @@ -13439,28 +13402,20 @@ func (ec *executionContext) fieldContext_CreateStoryBlockPayload_block(ctx conte switch field.Name { case "id": return ec.fieldContext_StoryBlock_id(ctx, field) - case "propertyId": - return ec.fieldContext_StoryBlock_propertyId(ctx, field) case "pluginId": return ec.fieldContext_StoryBlock_pluginId(ctx, field) - case "extensionId": - return ec.fieldContext_StoryBlock_extensionId(ctx, field) - case "linkedDatasetId": - return ec.fieldContext_StoryBlock_linkedDatasetId(ctx, field) - case "pageId": - return ec.fieldContext_StoryBlock_pageId(ctx, field) - case "page": - return ec.fieldContext_StoryBlock_page(ctx, field) - case "property": - return ec.fieldContext_StoryBlock_property(ctx, field) case "plugin": return ec.fieldContext_StoryBlock_plugin(ctx, field) + case "extensionId": + return ec.fieldContext_StoryBlock_extensionId(ctx, field) case "extension": return ec.fieldContext_StoryBlock_extension(ctx, field) - case "sceneId": - return ec.fieldContext_StoryBlock_sceneId(ctx, field) - case "scene": - return ec.fieldContext_StoryBlock_scene(ctx, field) + case "propertyId": + return ec.fieldContext_StoryBlock_propertyId(ctx, field) + case "property": + return ec.fieldContext_StoryBlock_property(ctx, field) + case "linkedDatasetId": + return ec.fieldContext_StoryBlock_linkedDatasetId(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type StoryBlock", field.Name) }, @@ -24637,8 +24592,8 @@ func (ec *executionContext) fieldContext_MoveLayerPayload_index(ctx context.Cont return fc, nil } -func (ec *executionContext) _MoveStoryBlockPayload_block(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.MoveStoryBlockPayload) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_MoveStoryBlockPayload_block(ctx, field) +func (ec *executionContext) _MoveStoryBlockPayload_page(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.MoveStoryBlockPayload) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_MoveStoryBlockPayload_page(ctx, field) if err != nil { return graphql.Null } @@ -24651,7 +24606,7 @@ func (ec *executionContext) _MoveStoryBlockPayload_block(ctx context.Context, fi }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.Block, nil + return obj.Page, nil }) if err != nil { ec.Error(ctx, err) @@ -24663,12 +24618,12 @@ func (ec *executionContext) _MoveStoryBlockPayload_block(ctx context.Context, fi } return graphql.Null } - res := resTmp.(*gqlmodel.StoryBlock) + res := resTmp.(*gqlmodel.StoryPage) fc.Result = res - return ec.marshalNStoryBlock2ᚖgithubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐStoryBlock(ctx, field.Selections, res) + return ec.marshalNStoryPage2ᚖgithubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐStoryPage(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_MoveStoryBlockPayload_block(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_MoveStoryBlockPayload_page(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "MoveStoryBlockPayload", Field: field, @@ -24677,38 +24632,198 @@ func (ec *executionContext) fieldContext_MoveStoryBlockPayload_block(ctx context Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": - return ec.fieldContext_StoryBlock_id(ctx, field) + return ec.fieldContext_StoryPage_id(ctx, field) + case "title": + return ec.fieldContext_StoryPage_title(ctx, field) + case "blocks": + return ec.fieldContext_StoryPage_blocks(ctx, field) + case "swipeable": + return ec.fieldContext_StoryPage_swipeable(ctx, field) + case "layersIds": + return ec.fieldContext_StoryPage_layersIds(ctx, field) + case "layers": + return ec.fieldContext_StoryPage_layers(ctx, field) + case "swipeableLayersIds": + return ec.fieldContext_StoryPage_swipeableLayersIds(ctx, field) + case "swipeableLayers": + return ec.fieldContext_StoryPage_swipeableLayers(ctx, field) case "propertyId": - return ec.fieldContext_StoryBlock_propertyId(ctx, field) - case "pluginId": - return ec.fieldContext_StoryBlock_pluginId(ctx, field) - case "extensionId": - return ec.fieldContext_StoryBlock_extensionId(ctx, field) - case "linkedDatasetId": - return ec.fieldContext_StoryBlock_linkedDatasetId(ctx, field) - case "pageId": - return ec.fieldContext_StoryBlock_pageId(ctx, field) - case "page": - return ec.fieldContext_StoryBlock_page(ctx, field) + return ec.fieldContext_StoryPage_propertyId(ctx, field) case "property": - return ec.fieldContext_StoryBlock_property(ctx, field) - case "plugin": - return ec.fieldContext_StoryBlock_plugin(ctx, field) - case "extension": - return ec.fieldContext_StoryBlock_extension(ctx, field) + return ec.fieldContext_StoryPage_property(ctx, field) + case "createdAt": + return ec.fieldContext_StoryPage_createdAt(ctx, field) case "sceneId": - return ec.fieldContext_StoryBlock_sceneId(ctx, field) + return ec.fieldContext_StoryPage_sceneId(ctx, field) case "scene": - return ec.fieldContext_StoryBlock_scene(ctx, field) + return ec.fieldContext_StoryPage_scene(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type StoryBlock", field.Name) + return nil, fmt.Errorf("no field named %q was found under type StoryPage", field.Name) }, } return fc, nil } -func (ec *executionContext) _MoveStoryBlockPayload_page(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.MoveStoryBlockPayload) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_MoveStoryBlockPayload_page(ctx, field) +func (ec *executionContext) _MoveStoryBlockPayload_story(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.MoveStoryBlockPayload) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_MoveStoryBlockPayload_story(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Story, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*gqlmodel.Story) + fc.Result = res + return ec.marshalNStory2ᚖgithubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐStory(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_MoveStoryBlockPayload_story(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "MoveStoryBlockPayload", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Story_id(ctx, field) + case "title": + return ec.fieldContext_Story_title(ctx, field) + case "alias": + return ec.fieldContext_Story_alias(ctx, field) + case "propertyId": + return ec.fieldContext_Story_propertyId(ctx, field) + case "property": + return ec.fieldContext_Story_property(ctx, field) + case "pages": + return ec.fieldContext_Story_pages(ctx, field) + case "publishmentStatus": + return ec.fieldContext_Story_publishmentStatus(ctx, field) + case "createdAt": + return ec.fieldContext_Story_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_Story_updatedAt(ctx, field) + case "publishedAt": + return ec.fieldContext_Story_publishedAt(ctx, field) + case "sceneId": + return ec.fieldContext_Story_sceneId(ctx, field) + case "scene": + return ec.fieldContext_Story_scene(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Story", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _MoveStoryBlockPayload_blockId(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.MoveStoryBlockPayload) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_MoveStoryBlockPayload_blockId(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.BlockID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(gqlmodel.ID) + fc.Result = res + return ec.marshalNID2githubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐID(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_MoveStoryBlockPayload_blockId(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "MoveStoryBlockPayload", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _MoveStoryBlockPayload_index(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.MoveStoryBlockPayload) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_MoveStoryBlockPayload_index(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Index, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_MoveStoryBlockPayload_index(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "MoveStoryBlockPayload", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Int does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _MoveStoryPagePayload_page(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.MoveStoryPagePayload) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_MoveStoryPagePayload_page(ctx, field) if err != nil { return graphql.Null } @@ -24738,195 +24853,9 @@ func (ec *executionContext) _MoveStoryBlockPayload_page(ctx context.Context, fie return ec.marshalNStoryPage2ᚖgithubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐStoryPage(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_MoveStoryBlockPayload_page(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_MoveStoryPagePayload_page(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "MoveStoryBlockPayload", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_StoryPage_id(ctx, field) - case "title": - return ec.fieldContext_StoryPage_title(ctx, field) - case "blocks": - return ec.fieldContext_StoryPage_blocks(ctx, field) - case "swipeable": - return ec.fieldContext_StoryPage_swipeable(ctx, field) - case "layersIds": - return ec.fieldContext_StoryPage_layersIds(ctx, field) - case "layers": - return ec.fieldContext_StoryPage_layers(ctx, field) - case "swipeableLayersIds": - return ec.fieldContext_StoryPage_swipeableLayersIds(ctx, field) - case "swipeableLayers": - return ec.fieldContext_StoryPage_swipeableLayers(ctx, field) - case "propertyId": - return ec.fieldContext_StoryPage_propertyId(ctx, field) - case "property": - return ec.fieldContext_StoryPage_property(ctx, field) - case "createdAt": - return ec.fieldContext_StoryPage_createdAt(ctx, field) - case "sceneId": - return ec.fieldContext_StoryPage_sceneId(ctx, field) - case "scene": - return ec.fieldContext_StoryPage_scene(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type StoryPage", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _MoveStoryBlockPayload_story(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.MoveStoryBlockPayload) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_MoveStoryBlockPayload_story(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Story, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*gqlmodel.Story) - fc.Result = res - return ec.marshalNStory2ᚖgithubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐStory(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_MoveStoryBlockPayload_story(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "MoveStoryBlockPayload", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_Story_id(ctx, field) - case "title": - return ec.fieldContext_Story_title(ctx, field) - case "alias": - return ec.fieldContext_Story_alias(ctx, field) - case "propertyId": - return ec.fieldContext_Story_propertyId(ctx, field) - case "property": - return ec.fieldContext_Story_property(ctx, field) - case "pages": - return ec.fieldContext_Story_pages(ctx, field) - case "publishmentStatus": - return ec.fieldContext_Story_publishmentStatus(ctx, field) - case "createdAt": - return ec.fieldContext_Story_createdAt(ctx, field) - case "updatedAt": - return ec.fieldContext_Story_updatedAt(ctx, field) - case "publishedAt": - return ec.fieldContext_Story_publishedAt(ctx, field) - case "sceneId": - return ec.fieldContext_Story_sceneId(ctx, field) - case "scene": - return ec.fieldContext_Story_scene(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Story", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _MoveStoryBlockPayload_index(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.MoveStoryBlockPayload) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_MoveStoryBlockPayload_index(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Index, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(int) - fc.Result = res - return ec.marshalNInt2int(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_MoveStoryBlockPayload_index(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "MoveStoryBlockPayload", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _MoveStoryPagePayload_page(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.MoveStoryPagePayload) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_MoveStoryPagePayload_page(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Page, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*gqlmodel.StoryPage) - fc.Result = res - return ec.marshalNStoryPage2ᚖgithubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐStoryPage(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_MoveStoryPagePayload_page(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "MoveStoryPagePayload", + Object: "MoveStoryPagePayload", Field: field, IsMethod: false, IsResolver: false, @@ -28487,12 +28416,12 @@ func (ec *executionContext) fieldContext_Mutation_moveStoryBlock(ctx context.Con IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { - case "block": - return ec.fieldContext_MoveStoryBlockPayload_block(ctx, field) case "page": return ec.fieldContext_MoveStoryBlockPayload_page(ctx, field) case "story": return ec.fieldContext_MoveStoryBlockPayload_story(ctx, field) + case "blockId": + return ec.fieldContext_MoveStoryBlockPayload_blockId(ctx, field) case "index": return ec.fieldContext_MoveStoryBlockPayload_index(ctx, field) } @@ -42328,8 +42257,8 @@ func (ec *executionContext) fieldContext_StoryBlock_id(ctx context.Context, fiel return fc, nil } -func (ec *executionContext) _StoryBlock_propertyId(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.StoryBlock) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_StoryBlock_propertyId(ctx, field) +func (ec *executionContext) _StoryBlock_pluginId(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.StoryBlock) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_StoryBlock_pluginId(ctx, field) if err != nil { return graphql.Null } @@ -42342,7 +42271,7 @@ func (ec *executionContext) _StoryBlock_propertyId(ctx context.Context, field gr }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.PropertyID, nil + return obj.PluginID, nil }) if err != nil { ec.Error(ctx, err) @@ -42359,7 +42288,7 @@ func (ec *executionContext) _StoryBlock_propertyId(ctx context.Context, field gr return ec.marshalNID2githubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐID(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_StoryBlock_propertyId(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_StoryBlock_pluginId(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StoryBlock", Field: field, @@ -42372,8 +42301,8 @@ func (ec *executionContext) fieldContext_StoryBlock_propertyId(ctx context.Conte return fc, nil } -func (ec *executionContext) _StoryBlock_pluginId(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.StoryBlock) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_StoryBlock_pluginId(ctx, field) +func (ec *executionContext) _StoryBlock_plugin(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.StoryBlock) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_StoryBlock_plugin(ctx, field) if err != nil { return graphql.Null } @@ -42386,31 +42315,62 @@ func (ec *executionContext) _StoryBlock_pluginId(ctx context.Context, field grap }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.PluginID, nil + return ec.resolvers.StoryBlock().Plugin(rctx, obj) }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } return graphql.Null } - res := resTmp.(gqlmodel.ID) + res := resTmp.(*gqlmodel.Plugin) fc.Result = res - return ec.marshalNID2githubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐID(ctx, field.Selections, res) + return ec.marshalOPlugin2ᚖgithubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐPlugin(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_StoryBlock_pluginId(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_StoryBlock_plugin(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StoryBlock", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ID does not have child fields") + switch field.Name { + case "id": + return ec.fieldContext_Plugin_id(ctx, field) + case "sceneId": + return ec.fieldContext_Plugin_sceneId(ctx, field) + case "name": + return ec.fieldContext_Plugin_name(ctx, field) + case "version": + return ec.fieldContext_Plugin_version(ctx, field) + case "description": + return ec.fieldContext_Plugin_description(ctx, field) + case "author": + return ec.fieldContext_Plugin_author(ctx, field) + case "repositoryUrl": + return ec.fieldContext_Plugin_repositoryUrl(ctx, field) + case "propertySchemaId": + return ec.fieldContext_Plugin_propertySchemaId(ctx, field) + case "extensions": + return ec.fieldContext_Plugin_extensions(ctx, field) + case "scenePlugin": + return ec.fieldContext_Plugin_scenePlugin(ctx, field) + case "allTranslatedDescription": + return ec.fieldContext_Plugin_allTranslatedDescription(ctx, field) + case "allTranslatedName": + return ec.fieldContext_Plugin_allTranslatedName(ctx, field) + case "scene": + return ec.fieldContext_Plugin_scene(ctx, field) + case "translatedName": + return ec.fieldContext_Plugin_translatedName(ctx, field) + case "translatedDescription": + return ec.fieldContext_Plugin_translatedDescription(ctx, field) + case "propertySchema": + return ec.fieldContext_Plugin_propertySchema(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Plugin", field.Name) }, } return fc, nil @@ -42460,8 +42420,8 @@ func (ec *executionContext) fieldContext_StoryBlock_extensionId(ctx context.Cont return fc, nil } -func (ec *executionContext) _StoryBlock_linkedDatasetId(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.StoryBlock) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_StoryBlock_linkedDatasetId(ctx, field) +func (ec *executionContext) _StoryBlock_extension(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.StoryBlock) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_StoryBlock_extension(ctx, field) if err != nil { return graphql.Null } @@ -42474,7 +42434,7 @@ func (ec *executionContext) _StoryBlock_linkedDatasetId(ctx context.Context, fie }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.LinkedDatasetID, nil + return obj.Extension, nil }) if err != nil { ec.Error(ctx, err) @@ -42483,26 +42443,62 @@ func (ec *executionContext) _StoryBlock_linkedDatasetId(ctx context.Context, fie if resTmp == nil { return graphql.Null } - res := resTmp.(*gqlmodel.ID) + res := resTmp.(*gqlmodel.PluginExtension) fc.Result = res - return ec.marshalOID2ᚖgithubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐID(ctx, field.Selections, res) + return ec.marshalOPluginExtension2ᚖgithubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐPluginExtension(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_StoryBlock_linkedDatasetId(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_StoryBlock_extension(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StoryBlock", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ID does not have child fields") + switch field.Name { + case "extensionId": + return ec.fieldContext_PluginExtension_extensionId(ctx, field) + case "pluginId": + return ec.fieldContext_PluginExtension_pluginId(ctx, field) + case "type": + return ec.fieldContext_PluginExtension_type(ctx, field) + case "name": + return ec.fieldContext_PluginExtension_name(ctx, field) + case "description": + return ec.fieldContext_PluginExtension_description(ctx, field) + case "icon": + return ec.fieldContext_PluginExtension_icon(ctx, field) + case "singleOnly": + return ec.fieldContext_PluginExtension_singleOnly(ctx, field) + case "widgetLayout": + return ec.fieldContext_PluginExtension_widgetLayout(ctx, field) + case "visualizer": + return ec.fieldContext_PluginExtension_visualizer(ctx, field) + case "propertySchemaId": + return ec.fieldContext_PluginExtension_propertySchemaId(ctx, field) + case "allTranslatedName": + return ec.fieldContext_PluginExtension_allTranslatedName(ctx, field) + case "allTranslatedDescription": + return ec.fieldContext_PluginExtension_allTranslatedDescription(ctx, field) + case "plugin": + return ec.fieldContext_PluginExtension_plugin(ctx, field) + case "sceneWidget": + return ec.fieldContext_PluginExtension_sceneWidget(ctx, field) + case "propertySchema": + return ec.fieldContext_PluginExtension_propertySchema(ctx, field) + case "translatedName": + return ec.fieldContext_PluginExtension_translatedName(ctx, field) + case "translatedDescription": + return ec.fieldContext_PluginExtension_translatedDescription(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type PluginExtension", field.Name) }, } return fc, nil } -func (ec *executionContext) _StoryBlock_pageId(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.StoryBlock) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_StoryBlock_pageId(ctx, field) +func (ec *executionContext) _StoryBlock_propertyId(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.StoryBlock) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_StoryBlock_propertyId(ctx, field) if err != nil { return graphql.Null } @@ -42515,7 +42511,7 @@ func (ec *executionContext) _StoryBlock_pageId(ctx context.Context, field graphq }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.PageID, nil + return obj.PropertyID, nil }) if err != nil { ec.Error(ctx, err) @@ -42532,7 +42528,7 @@ func (ec *executionContext) _StoryBlock_pageId(ctx context.Context, field graphq return ec.marshalNID2githubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐID(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_StoryBlock_pageId(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_StoryBlock_propertyId(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StoryBlock", Field: field, @@ -42545,78 +42541,6 @@ func (ec *executionContext) fieldContext_StoryBlock_pageId(ctx context.Context, return fc, nil } -func (ec *executionContext) _StoryBlock_page(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.StoryBlock) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_StoryBlock_page(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Page, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*gqlmodel.StoryPage) - fc.Result = res - return ec.marshalNStoryPage2ᚖgithubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐStoryPage(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_StoryBlock_page(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "StoryBlock", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_StoryPage_id(ctx, field) - case "title": - return ec.fieldContext_StoryPage_title(ctx, field) - case "blocks": - return ec.fieldContext_StoryPage_blocks(ctx, field) - case "swipeable": - return ec.fieldContext_StoryPage_swipeable(ctx, field) - case "layersIds": - return ec.fieldContext_StoryPage_layersIds(ctx, field) - case "layers": - return ec.fieldContext_StoryPage_layers(ctx, field) - case "swipeableLayersIds": - return ec.fieldContext_StoryPage_swipeableLayersIds(ctx, field) - case "swipeableLayers": - return ec.fieldContext_StoryPage_swipeableLayers(ctx, field) - case "propertyId": - return ec.fieldContext_StoryPage_propertyId(ctx, field) - case "property": - return ec.fieldContext_StoryPage_property(ctx, field) - case "createdAt": - return ec.fieldContext_StoryPage_createdAt(ctx, field) - case "sceneId": - return ec.fieldContext_StoryPage_sceneId(ctx, field) - case "scene": - return ec.fieldContext_StoryPage_scene(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type StoryPage", field.Name) - }, - } - return fc, nil -} - func (ec *executionContext) _StoryBlock_property(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.StoryBlock) (ret graphql.Marshaler) { fc, err := ec.fieldContext_StoryBlock_property(ctx, field) if err != nil { @@ -42672,160 +42596,8 @@ func (ec *executionContext) fieldContext_StoryBlock_property(ctx context.Context return fc, nil } -func (ec *executionContext) _StoryBlock_plugin(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.StoryBlock) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_StoryBlock_plugin(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.StoryBlock().Plugin(rctx, obj) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*gqlmodel.Plugin) - fc.Result = res - return ec.marshalOPlugin2ᚖgithubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐPlugin(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_StoryBlock_plugin(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "StoryBlock", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_Plugin_id(ctx, field) - case "sceneId": - return ec.fieldContext_Plugin_sceneId(ctx, field) - case "name": - return ec.fieldContext_Plugin_name(ctx, field) - case "version": - return ec.fieldContext_Plugin_version(ctx, field) - case "description": - return ec.fieldContext_Plugin_description(ctx, field) - case "author": - return ec.fieldContext_Plugin_author(ctx, field) - case "repositoryUrl": - return ec.fieldContext_Plugin_repositoryUrl(ctx, field) - case "propertySchemaId": - return ec.fieldContext_Plugin_propertySchemaId(ctx, field) - case "extensions": - return ec.fieldContext_Plugin_extensions(ctx, field) - case "scenePlugin": - return ec.fieldContext_Plugin_scenePlugin(ctx, field) - case "allTranslatedDescription": - return ec.fieldContext_Plugin_allTranslatedDescription(ctx, field) - case "allTranslatedName": - return ec.fieldContext_Plugin_allTranslatedName(ctx, field) - case "scene": - return ec.fieldContext_Plugin_scene(ctx, field) - case "translatedName": - return ec.fieldContext_Plugin_translatedName(ctx, field) - case "translatedDescription": - return ec.fieldContext_Plugin_translatedDescription(ctx, field) - case "propertySchema": - return ec.fieldContext_Plugin_propertySchema(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Plugin", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _StoryBlock_extension(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.StoryBlock) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_StoryBlock_extension(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Extension, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*gqlmodel.PluginExtension) - fc.Result = res - return ec.marshalOPluginExtension2ᚖgithubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐPluginExtension(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_StoryBlock_extension(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "StoryBlock", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "extensionId": - return ec.fieldContext_PluginExtension_extensionId(ctx, field) - case "pluginId": - return ec.fieldContext_PluginExtension_pluginId(ctx, field) - case "type": - return ec.fieldContext_PluginExtension_type(ctx, field) - case "name": - return ec.fieldContext_PluginExtension_name(ctx, field) - case "description": - return ec.fieldContext_PluginExtension_description(ctx, field) - case "icon": - return ec.fieldContext_PluginExtension_icon(ctx, field) - case "singleOnly": - return ec.fieldContext_PluginExtension_singleOnly(ctx, field) - case "widgetLayout": - return ec.fieldContext_PluginExtension_widgetLayout(ctx, field) - case "visualizer": - return ec.fieldContext_PluginExtension_visualizer(ctx, field) - case "propertySchemaId": - return ec.fieldContext_PluginExtension_propertySchemaId(ctx, field) - case "allTranslatedName": - return ec.fieldContext_PluginExtension_allTranslatedName(ctx, field) - case "allTranslatedDescription": - return ec.fieldContext_PluginExtension_allTranslatedDescription(ctx, field) - case "plugin": - return ec.fieldContext_PluginExtension_plugin(ctx, field) - case "sceneWidget": - return ec.fieldContext_PluginExtension_sceneWidget(ctx, field) - case "propertySchema": - return ec.fieldContext_PluginExtension_propertySchema(ctx, field) - case "translatedName": - return ec.fieldContext_PluginExtension_translatedName(ctx, field) - case "translatedDescription": - return ec.fieldContext_PluginExtension_translatedDescription(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type PluginExtension", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _StoryBlock_sceneId(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.StoryBlock) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_StoryBlock_sceneId(ctx, field) +func (ec *executionContext) _StoryBlock_linkedDatasetId(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.StoryBlock) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_StoryBlock_linkedDatasetId(ctx, field) if err != nil { return graphql.Null } @@ -42838,24 +42610,21 @@ func (ec *executionContext) _StoryBlock_sceneId(ctx context.Context, field graph }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.SceneID, nil + return obj.LinkedDatasetID, nil }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } return graphql.Null } - res := resTmp.(gqlmodel.ID) + res := resTmp.(*gqlmodel.ID) fc.Result = res - return ec.marshalNID2githubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐID(ctx, field.Selections, res) + return ec.marshalOID2ᚖgithubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐID(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_StoryBlock_sceneId(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_StoryBlock_linkedDatasetId(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "StoryBlock", Field: field, @@ -42868,87 +42637,6 @@ func (ec *executionContext) fieldContext_StoryBlock_sceneId(ctx context.Context, return fc, nil } -func (ec *executionContext) _StoryBlock_scene(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.StoryBlock) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_StoryBlock_scene(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.StoryBlock().Scene(rctx, obj) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*gqlmodel.Scene) - fc.Result = res - return ec.marshalOScene2ᚖgithubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐScene(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_StoryBlock_scene(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "StoryBlock", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_Scene_id(ctx, field) - case "projectId": - return ec.fieldContext_Scene_projectId(ctx, field) - case "teamId": - return ec.fieldContext_Scene_teamId(ctx, field) - case "propertyId": - return ec.fieldContext_Scene_propertyId(ctx, field) - case "createdAt": - return ec.fieldContext_Scene_createdAt(ctx, field) - case "updatedAt": - return ec.fieldContext_Scene_updatedAt(ctx, field) - case "rootLayerId": - return ec.fieldContext_Scene_rootLayerId(ctx, field) - case "widgets": - return ec.fieldContext_Scene_widgets(ctx, field) - case "plugins": - return ec.fieldContext_Scene_plugins(ctx, field) - case "widgetAlignSystem": - return ec.fieldContext_Scene_widgetAlignSystem(ctx, field) - case "project": - return ec.fieldContext_Scene_project(ctx, field) - case "team": - return ec.fieldContext_Scene_team(ctx, field) - case "property": - return ec.fieldContext_Scene_property(ctx, field) - case "rootLayer": - return ec.fieldContext_Scene_rootLayer(ctx, field) - case "stories": - return ec.fieldContext_Scene_stories(ctx, field) - case "datasetSchemas": - return ec.fieldContext_Scene_datasetSchemas(ctx, field) - case "tagIds": - return ec.fieldContext_Scene_tagIds(ctx, field) - case "tags": - return ec.fieldContext_Scene_tags(ctx, field) - case "clusters": - return ec.fieldContext_Scene_clusters(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Scene", field.Name) - }, - } - return fc, nil -} - func (ec *executionContext) _StoryPage_id(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.StoryPage) (ret graphql.Marshaler) { fc, err := ec.fieldContext_StoryPage_id(ctx, field) if err != nil { @@ -43078,28 +42766,20 @@ func (ec *executionContext) fieldContext_StoryPage_blocks(ctx context.Context, f switch field.Name { case "id": return ec.fieldContext_StoryBlock_id(ctx, field) - case "propertyId": - return ec.fieldContext_StoryBlock_propertyId(ctx, field) case "pluginId": return ec.fieldContext_StoryBlock_pluginId(ctx, field) - case "extensionId": - return ec.fieldContext_StoryBlock_extensionId(ctx, field) - case "linkedDatasetId": - return ec.fieldContext_StoryBlock_linkedDatasetId(ctx, field) - case "pageId": - return ec.fieldContext_StoryBlock_pageId(ctx, field) - case "page": - return ec.fieldContext_StoryBlock_page(ctx, field) - case "property": - return ec.fieldContext_StoryBlock_property(ctx, field) case "plugin": return ec.fieldContext_StoryBlock_plugin(ctx, field) + case "extensionId": + return ec.fieldContext_StoryBlock_extensionId(ctx, field) case "extension": return ec.fieldContext_StoryBlock_extension(ctx, field) - case "sceneId": - return ec.fieldContext_StoryBlock_sceneId(ctx, field) - case "scene": - return ec.fieldContext_StoryBlock_scene(ctx, field) + case "propertyId": + return ec.fieldContext_StoryBlock_propertyId(ctx, field) + case "property": + return ec.fieldContext_StoryBlock_property(ctx, field) + case "linkedDatasetId": + return ec.fieldContext_StoryBlock_linkedDatasetId(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type StoryBlock", field.Name) }, @@ -57782,23 +57462,23 @@ func (ec *executionContext) _MoveStoryBlockPayload(ctx context.Context, sel ast. switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("MoveStoryBlockPayload") - case "block": + case "page": - out.Values[i] = ec._MoveStoryBlockPayload_block(ctx, field, obj) + out.Values[i] = ec._MoveStoryBlockPayload_page(ctx, field, obj) if out.Values[i] == graphql.Null { invalids++ } - case "page": + case "story": - out.Values[i] = ec._MoveStoryBlockPayload_page(ctx, field, obj) + out.Values[i] = ec._MoveStoryBlockPayload_story(ctx, field, obj) if out.Values[i] == graphql.Null { invalids++ } - case "story": + case "blockId": - out.Values[i] = ec._MoveStoryBlockPayload_story(ctx, field, obj) + out.Values[i] = ec._MoveStoryBlockPayload_blockId(ctx, field, obj) if out.Values[i] == graphql.Null { invalids++ @@ -61579,13 +61259,6 @@ func (ec *executionContext) _StoryBlock(ctx context.Context, sel ast.SelectionSe out.Values[i] = ec._StoryBlock_id(ctx, field, obj) - if out.Values[i] == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - case "propertyId": - - out.Values[i] = ec._StoryBlock_propertyId(ctx, field, obj) - if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } @@ -61596,48 +61269,6 @@ func (ec *executionContext) _StoryBlock(ctx context.Context, sel ast.SelectionSe if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } - case "extensionId": - - out.Values[i] = ec._StoryBlock_extensionId(ctx, field, obj) - - if out.Values[i] == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - case "linkedDatasetId": - - out.Values[i] = ec._StoryBlock_linkedDatasetId(ctx, field, obj) - - case "pageId": - - out.Values[i] = ec._StoryBlock_pageId(ctx, field, obj) - - if out.Values[i] == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - case "page": - - out.Values[i] = ec._StoryBlock_page(ctx, field, obj) - - if out.Values[i] == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - case "property": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._StoryBlock_property(ctx, field, obj) - return res - } - - out.Concurrently(i, func() graphql.Marshaler { - return innerFunc(ctx) - - }) case "plugin": field := field @@ -61655,18 +61286,25 @@ func (ec *executionContext) _StoryBlock(ctx context.Context, sel ast.SelectionSe return innerFunc(ctx) }) + case "extensionId": + + out.Values[i] = ec._StoryBlock_extensionId(ctx, field, obj) + + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } case "extension": out.Values[i] = ec._StoryBlock_extension(ctx, field, obj) - case "sceneId": + case "propertyId": - out.Values[i] = ec._StoryBlock_sceneId(ctx, field, obj) + out.Values[i] = ec._StoryBlock_propertyId(ctx, field, obj) if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } - case "scene": + case "property": field := field innerFunc := func(ctx context.Context) (res graphql.Marshaler) { @@ -61675,7 +61313,7 @@ func (ec *executionContext) _StoryBlock(ctx context.Context, sel ast.SelectionSe ec.Error(ctx, ec.Recover(ctx, r)) } }() - res = ec._StoryBlock_scene(ctx, field, obj) + res = ec._StoryBlock_property(ctx, field, obj) return res } @@ -61683,6 +61321,10 @@ func (ec *executionContext) _StoryBlock(ctx context.Context, sel ast.SelectionSe return innerFunc(ctx) }) + case "linkedDatasetId": + + out.Values[i] = ec._StoryBlock_linkedDatasetId(ctx, field, obj) + default: panic("unknown field " + strconv.Quote(field.Name)) } diff --git a/server/internal/adapter/gql/gqlmodel/convert_storytelling.go b/server/internal/adapter/gql/gqlmodel/convert_storytelling.go index 18e2a7d196..0b8e0962d2 100644 --- a/server/internal/adapter/gql/gqlmodel/convert_storytelling.go +++ b/server/internal/adapter/gql/gqlmodel/convert_storytelling.go @@ -6,6 +6,9 @@ import ( ) func ToStory(s *storytelling.Story) *Story { + if s == nil { + return nil + } return &Story{ ID: IDFrom(s.Id()), Title: s.Title(), @@ -20,53 +23,61 @@ func ToStory(s *storytelling.Story) *Story { } } -func ToStories(ss storytelling.StoryList) []*Story { - return lo.Map(ss, func(s *storytelling.Story, _ int) *Story { +func ToStories(sl storytelling.StoryList) []*Story { + return lo.Map(sl, func(s *storytelling.Story, _ int) *Story { return ToStory(s) }) } -func ToPage(s *storytelling.Page) *StoryPage { +func ToPage(p *storytelling.Page) *StoryPage { + if p == nil { + return nil + } return &StoryPage{ - ID: IDFrom(s.Id()), - Title: s.Title(), - Blocks: ToBlocks(s.Blocks()), - Swipeable: s.Swipeable(), - LayersIds: IDFromList(s.Layers()), + ID: IDFrom(p.Id()), + Title: p.Title(), + Blocks: ToBlocks(p.Blocks()), + Swipeable: p.Swipeable(), + LayersIds: IDFromList(p.Layers()), Layers: nil, - SwipeableLayersIds: IDFromList(s.SwipeableLayers()), + SwipeableLayersIds: IDFromList(p.SwipeableLayers()), SwipeableLayers: nil, - PropertyID: IDFrom(s.Property()), + PropertyID: IDFrom(p.Property()), Property: nil, - CreatedAt: s.Id().Timestamp(), + CreatedAt: p.Id().Timestamp(), } } -func ToPages(ss *storytelling.PageList) []*StoryPage { - if ss == nil { - return nil +func ToPages(pl *storytelling.PageList) []*StoryPage { + if pl == nil || len(pl.Pages()) == 0 { + return []*StoryPage{} } - return lo.Map(ss.Pages(), func(s *storytelling.Page, _ int) *StoryPage { + return lo.Map(pl.Pages(), func(s *storytelling.Page, _ int) *StoryPage { return ToPage(s) }) } -func ToBlock(s *storytelling.Block) *StoryBlock { +func ToBlock(b *storytelling.Block) *StoryBlock { + if b == nil { + return nil + } return &StoryBlock{ - ID: IDFrom(s.ID()), - PropertyID: "", - PluginID: "", - ExtensionID: "", - LinkedDatasetID: nil, - Page: nil, + ID: IDFrom(b.ID()), + PropertyID: IDFrom(b.Property()), Property: nil, + PluginID: IDFromPluginID(b.Plugin()), Plugin: nil, + ExtensionID: IDFromString(b.Extension()), Extension: nil, + LinkedDatasetID: nil, } } -func ToBlocks(ss storytelling.BlockList) []*StoryBlock { - return lo.Map(ss, func(s *storytelling.Block, _ int) *StoryBlock { +func ToBlocks(bl storytelling.BlockList) []*StoryBlock { + if len(bl) == 0 { + return []*StoryBlock{} + } + return lo.Map(bl, func(s *storytelling.Block, _ int) *StoryBlock { return ToBlock(s) }) } diff --git a/server/internal/adapter/gql/gqlmodel/models_gen.go b/server/internal/adapter/gql/gqlmodel/models_gen.go index 0c58ba499e..2c57f54cbf 100644 --- a/server/internal/adapter/gql/gqlmodel/models_gen.go +++ b/server/internal/adapter/gql/gqlmodel/models_gen.go @@ -710,10 +710,10 @@ type MoveStoryBlockInput struct { } type MoveStoryBlockPayload struct { - Block *StoryBlock `json:"block"` - Page *StoryPage `json:"page"` - Story *Story `json:"story"` - Index int `json:"index"` + Page *StoryPage `json:"page"` + Story *Story `json:"story"` + BlockID ID `json:"blockId"` + Index int `json:"index"` } type MoveStoryInput struct { @@ -1195,17 +1195,13 @@ func (Story) IsNode() {} type StoryBlock struct { ID ID `json:"id"` - PropertyID ID `json:"propertyId"` PluginID ID `json:"pluginId"` - ExtensionID ID `json:"extensionId"` - LinkedDatasetID *ID `json:"linkedDatasetId"` - PageID ID `json:"pageId"` - Page *StoryPage `json:"page"` - Property *Property `json:"property"` Plugin *Plugin `json:"plugin"` + ExtensionID ID `json:"extensionId"` Extension *PluginExtension `json:"extension"` - SceneID ID `json:"sceneId"` - Scene *Scene `json:"scene"` + PropertyID ID `json:"propertyId"` + Property *Property `json:"property"` + LinkedDatasetID *ID `json:"linkedDatasetId"` } func (StoryBlock) IsNode() {} diff --git a/server/internal/adapter/gql/gqlmodel/scalar_id.go b/server/internal/adapter/gql/gqlmodel/scalar_id.go index 9e2e42a818..0a85f87994 100644 --- a/server/internal/adapter/gql/gqlmodel/scalar_id.go +++ b/server/internal/adapter/gql/gqlmodel/scalar_id.go @@ -109,6 +109,10 @@ func IDFromRef[T idx.Type](i *idx.ID[T]) *ID { return (*ID)(i.StringRef()) } +func IDFromString[T idx.Type](i idx.StringID[T]) ID { + return (ID)(i) +} + func IDFromStringRef[T idx.Type](i *idx.StringID[T]) *ID { return (*ID)(i) } diff --git a/server/internal/adapter/gql/resolver_Storytelling.go b/server/internal/adapter/gql/resolver_Storytelling.go index ea606b1d91..0a28b9576d 100644 --- a/server/internal/adapter/gql/resolver_Storytelling.go +++ b/server/internal/adapter/gql/resolver_Storytelling.go @@ -79,17 +79,6 @@ func (s storyBlockResolver) Property(ctx context.Context, obj *gqlmodel.StoryBlo return dataloaders(ctx).Property.Load(obj.PropertyID) } -func (s storyBlockResolver) Scene(ctx context.Context, obj *gqlmodel.StoryBlock) (*gqlmodel.Scene, error) { - scene, err := loaders(ctx).Scene.Fetch(ctx, []gqlmodel.ID{obj.SceneID}) - if len(err) > 0 && err[0] != nil { - return nil, err[0] - } - if len(scene) == 0 { - return nil, rerror.ErrNotFound - } - return scene[0], nil -} - func (s storyBlockResolver) Plugin(ctx context.Context, obj *gqlmodel.StoryBlock) (*gqlmodel.Plugin, error) { return dataloaders(ctx).Plugin.Load(obj.PluginID) } diff --git a/server/internal/adapter/gql/resolver_mutation_storytelling.go b/server/internal/adapter/gql/resolver_mutation_storytelling.go index 9b9fda56a1..3c9e66578e 100644 --- a/server/internal/adapter/gql/resolver_mutation_storytelling.go +++ b/server/internal/adapter/gql/resolver_mutation_storytelling.go @@ -2,6 +2,7 @@ package gql import ( "context" + "errors" "github.com/reearth/reearth/server/internal/adapter/gql/gqlmodel" "github.com/reearth/reearth/server/internal/usecase/interfaces" @@ -302,13 +303,80 @@ func (r *mutationResolver) RemovePageLayer(ctx context.Context, input gqlmodel.P } func (r *mutationResolver) CreateStoryBlock(ctx context.Context, input gqlmodel.CreateStoryBlockInput) (*gqlmodel.CreateStoryBlockPayload, error) { - return nil, ErrNotImplemented + sId, pId, err := gqlmodel.ToID2[id.Story, id.Page](input.StoryID, input.PageID) + if err != nil { + return nil, err + } + + pid, err := gqlmodel.ToPluginID(input.PluginID) + if err != nil { + return nil, err + } + + story, page, block, idx, err := usecases(ctx).StoryTelling.CreateBlock(ctx, interfaces.CreateBlockParam{ + StoryID: sId, + PageID: pId, + PluginID: pid, + ExtensionID: id.PluginExtensionID(input.ExtensionID), + Index: input.Index, + }, getOperator(ctx)) + if err != nil { + return nil, err + } + + return &gqlmodel.CreateStoryBlockPayload{ + Block: gqlmodel.ToBlock(block), + Page: gqlmodel.ToPage(page), + Story: gqlmodel.ToStory(story), + Index: idx, + }, nil } func (r *mutationResolver) MoveStoryBlock(ctx context.Context, input gqlmodel.MoveStoryBlockInput) (*gqlmodel.MoveStoryBlockPayload, error) { - return nil, ErrNotImplemented + sId, pId, bId, err := gqlmodel.ToID3[id.Story, id.Page, id.Block](input.StoryID, input.PageID, input.BlockID) + if err != nil { + return nil, err + } + + story, page, blockId, idx, err := usecases(ctx).StoryTelling.MoveBlock(ctx, interfaces.MoveBlockParam{ + StoryID: sId, + PageID: pId, + BlockID: bId, + Index: input.Index, + }, getOperator(ctx)) + if err != nil { + return nil, err + } + + return &gqlmodel.MoveStoryBlockPayload{ + Story: gqlmodel.ToStory(story), + Page: gqlmodel.ToPage(page), + BlockID: gqlmodel.IDFrom(*blockId), + Index: idx, + }, nil } func (r *mutationResolver) RemoveStoryBlock(ctx context.Context, input gqlmodel.RemoveStoryBlockInput) (*gqlmodel.RemoveStoryBlockPayload, error) { - return nil, ErrNotImplemented + sId, pId, bId, err := gqlmodel.ToID3[id.Story, id.Page, id.Block](input.StoryID, input.PageID, input.BlockID) + if err != nil { + return nil, err + } + + story, page, removedBlockId, err := usecases(ctx).StoryTelling.RemoveBlock(ctx, interfaces.RemoveBlockParam{ + StoryID: sId, + PageID: pId, + BlockID: bId, + }, getOperator(ctx)) + if err != nil { + return nil, err + } + if removedBlockId == nil { + return nil, errors.New("block not found") + } + + return &gqlmodel.RemoveStoryBlockPayload{ + BlockID: gqlmodel.IDFrom(*removedBlockId), + Page: gqlmodel.ToPage(page), + Story: gqlmodel.ToStory(story), + }, nil } diff --git a/server/internal/infrastructure/mongo/mongodoc/storytelling.go b/server/internal/infrastructure/mongo/mongodoc/storytelling.go index 04b85fa5e3..c939564061 100644 --- a/server/internal/infrastructure/mongo/mongodoc/storytelling.go +++ b/server/internal/infrastructure/mongo/mongodoc/storytelling.go @@ -3,6 +3,7 @@ package mongodoc import ( "time" + "github.com/pkg/errors" "github.com/reearth/reearth/server/pkg/id" "github.com/reearth/reearth/server/pkg/storytelling" "github.com/samber/lo" @@ -64,6 +65,23 @@ func NewStorytelling(s *storytelling.Story) (*StorytellingDocument, string) { }, sId } +func NewStorytellings(sl *storytelling.StoryList) ([]any, []string) { + if sl == nil { + return nil, nil + } + + sdl := lo.Map(*sl, func(s *storytelling.Story, _ int) any { + sd, _ := NewStorytelling(s) + return sd + }) + + ids := lo.Map(*sl, func(s *storytelling.Story, _ int) string { + return s.Id().String() + }) + + return sdl, ids +} + func newPage(p storytelling.Page) PageDocument { return PageDocument{ Id: p.Id().String(), @@ -72,7 +90,7 @@ func newPage(p storytelling.Page) PageDocument { Swipeable: p.Swipeable(), Layers: p.Layers().Strings(), SwipeLayers: p.SwipeableLayers().Strings(), - Blocks: nil, + Blocks: newBlocks(p.Blocks()), } } @@ -88,21 +106,25 @@ func newPages(pl *storytelling.PageList) []PageDocument { }) } -func NewStorytellings(sl *storytelling.StoryList) ([]any, []string) { - if sl == nil { - return nil, nil +func newBlocks(blocks storytelling.BlockList) []BlockDocument { + if blocks == nil { + return nil } - - sdl := lo.Map(*sl, func(s *storytelling.Story, _ int) any { - sd, _ := NewStorytelling(s) - return sd - }) - - ids := lo.Map(*sl, func(s *storytelling.Story, _ int) string { - return s.Id().String() + return lo.Map(blocks, func(b *storytelling.Block, _ int) BlockDocument { + if b == nil { + return BlockDocument{} + } + return newBlock(*b) }) +} - return sdl, ids +func newBlock(b storytelling.Block) BlockDocument { + return BlockDocument{ + Id: b.ID().String(), + Plugin: b.Plugin().String(), + Extension: b.Extension().String(), + Property: b.Property().String(), + } } func (d *StorytellingDocument) Model() (*storytelling.Story, error) { @@ -167,6 +189,18 @@ func (d *PageDocument) Model() (*storytelling.Page, error) { return nil, err } + blocks := lo.Map(d.Blocks, func(b BlockDocument, _ int) *storytelling.Block { + page, err2 := b.Model() + if err2 != nil { + err = err2 + return nil + } + return page + }) + if err != nil { + return nil, err + } + p, err := storytelling.NewPage(). ID(pId). Property(property). @@ -174,7 +208,7 @@ func (d *PageDocument) Model() (*storytelling.Page, error) { Layers(lIds). Swipeable(d.Swipeable). SwipeableLayers(slIds). - Blocks(nil). + Blocks(blocks). Build() if err != nil { return nil, err @@ -182,3 +216,34 @@ func (d *PageDocument) Model() (*storytelling.Page, error) { return p, nil } + +func (d BlockDocument) Model() (*storytelling.Block, error) { + bId, err := id.BlockIDFrom(d.Id) + if err != nil { + return nil, err + } + property, err := id.PropertyIDFrom(d.Property) + if err != nil { + return nil, err + } + plugin, err := id.PluginIDFrom(d.Plugin) + if err != nil { + return nil, err + } + extension := id.PluginExtensionIDFromRef(&d.Extension) + if extension == nil { + return nil, errors.New("invalid extension") + } + + b, err := storytelling.NewBlock(). + ID(bId). + Property(property). + Plugin(plugin). + Extension(*extension). + Build() + if err != nil { + return nil, err + } + + return b, nil +} diff --git a/server/internal/usecase/interactor/storytelling.go b/server/internal/usecase/interactor/storytelling.go index 1137919716..a46bd726b8 100644 --- a/server/internal/usecase/interactor/storytelling.go +++ b/server/internal/usecase/interactor/storytelling.go @@ -2,14 +2,17 @@ package interactor import ( "context" + "errors" "github.com/reearth/reearth/server/internal/usecase" "github.com/reearth/reearth/server/internal/usecase/interfaces" "github.com/reearth/reearth/server/internal/usecase/repo" "github.com/reearth/reearth/server/pkg/builtin" "github.com/reearth/reearth/server/pkg/id" + "github.com/reearth/reearth/server/pkg/plugin" "github.com/reearth/reearth/server/pkg/property" "github.com/reearth/reearth/server/pkg/storytelling" + "github.com/reearth/reearthx/rerror" "github.com/reearth/reearthx/usecasex" "github.com/samber/lo" ) @@ -17,12 +20,16 @@ import ( type Storytelling struct { common storytellingRepo repo.Storytelling + pluginRepo repo.Plugin + propertyRepo repo.Property transaction usecasex.Transaction } func NewStorytelling(r *repo.Container) interfaces.Storytelling { return &Storytelling{ storytellingRepo: r.Storytelling, + pluginRepo: r.Plugin, + propertyRepo: r.Property, transaction: r.Transaction, } } @@ -35,7 +42,7 @@ func (i *Storytelling) FetchByScene(ctx context.Context, sid id.SceneID, _ *usec return i.storytellingRepo.FindByScene(ctx, sid) } -func (i *Storytelling) Create(ctx context.Context, inp interfaces.CreateStoryInput, operator *usecase.Operator) (*storytelling.Story, error) { +func (i *Storytelling) Create(ctx context.Context, inp interfaces.CreateStoryInput, op *usecase.Operator) (*storytelling.Story, error) { tx, err := i.transaction.Begin(ctx) if err != nil { return nil, err @@ -48,7 +55,7 @@ func (i *Storytelling) Create(ctx context.Context, inp interfaces.CreateStoryInp } }() - if err := i.CanWriteScene(inp.SceneID, operator); err != nil { + if err := i.CanWriteScene(inp.SceneID, op); err != nil { return nil, interfaces.ErrOperationDenied } @@ -80,7 +87,7 @@ func (i *Storytelling) Create(ctx context.Context, inp interfaces.CreateStoryInp return story, nil } -func (i *Storytelling) Update(ctx context.Context, inp interfaces.UpdateStoryInput, operator *usecase.Operator) (*storytelling.Story, error) { +func (i *Storytelling) Update(ctx context.Context, inp interfaces.UpdateStoryInput, op *usecase.Operator) (*storytelling.Story, error) { tx, err := i.transaction.Begin(ctx) if err != nil { return nil, err @@ -97,7 +104,7 @@ func (i *Storytelling) Update(ctx context.Context, inp interfaces.UpdateStoryInp if err != nil { return nil, err } - if err := i.CanWriteScene(story.Scene(), operator); err != nil { + if err := i.CanWriteScene(story.Scene(), op); err != nil { return nil, err } @@ -115,7 +122,7 @@ func (i *Storytelling) Update(ctx context.Context, inp interfaces.UpdateStoryInp return story, nil } -func (i *Storytelling) Remove(ctx context.Context, inp interfaces.RemoveStoryInput, operator *usecase.Operator) (*id.StoryID, error) { +func (i *Storytelling) Remove(ctx context.Context, inp interfaces.RemoveStoryInput, op *usecase.Operator) (*id.StoryID, error) { tx, err := i.transaction.Begin(ctx) if err != nil { return nil, err @@ -132,7 +139,7 @@ func (i *Storytelling) Remove(ctx context.Context, inp interfaces.RemoveStoryInp if err != nil { return nil, err } - if err := i.CanWriteScene(story.Scene(), operator); err != nil { + if err := i.CanWriteScene(story.Scene(), op); err != nil { return nil, err } @@ -145,12 +152,11 @@ func (i *Storytelling) Remove(ctx context.Context, inp interfaces.RemoveStoryInp return &inp.StoryID, nil } -func (i *Storytelling) Move(ctx context.Context, inp interfaces.MoveStoryInput, operator *usecase.Operator) (*id.StoryID, int, error) { - // TODO implement me - panic("implement me") +func (i *Storytelling) Move(_ context.Context, _ interfaces.MoveStoryInput, _ *usecase.Operator) (*id.StoryID, int, error) { + return nil, 0, rerror.ErrNotImplemented } -func (i *Storytelling) CreatePage(ctx context.Context, inp interfaces.CreatePageParam, operator *usecase.Operator) (*storytelling.Story, *storytelling.Page, error) { +func (i *Storytelling) CreatePage(ctx context.Context, inp interfaces.CreatePageParam, op *usecase.Operator) (*storytelling.Story, *storytelling.Page, error) { tx, err := i.transaction.Begin(ctx) if err != nil { return nil, nil, err @@ -163,7 +169,7 @@ func (i *Storytelling) CreatePage(ctx context.Context, inp interfaces.CreatePage } }() - if err := i.CanWriteScene(inp.SceneID, operator); err != nil { + if err := i.CanWriteScene(inp.SceneID, op); err != nil { return nil, nil, interfaces.ErrOperationDenied } @@ -213,7 +219,7 @@ func (i *Storytelling) CreatePage(ctx context.Context, inp interfaces.CreatePage return story, page, nil } -func (i *Storytelling) UpdatePage(ctx context.Context, inp interfaces.UpdatePageParam, operator *usecase.Operator) (*storytelling.Story, *storytelling.Page, error) { +func (i *Storytelling) UpdatePage(ctx context.Context, inp interfaces.UpdatePageParam, op *usecase.Operator) (*storytelling.Story, *storytelling.Page, error) { tx, err := i.transaction.Begin(ctx) if err != nil { return nil, nil, err @@ -226,7 +232,7 @@ func (i *Storytelling) UpdatePage(ctx context.Context, inp interfaces.UpdatePage } }() - if err := i.CanWriteScene(inp.SceneID, operator); err != nil { + if err := i.CanWriteScene(inp.SceneID, op); err != nil { return nil, nil, interfaces.ErrOperationDenied } @@ -266,7 +272,7 @@ func (i *Storytelling) UpdatePage(ctx context.Context, inp interfaces.UpdatePage return story, page, nil } -func (i *Storytelling) RemovePage(ctx context.Context, inp interfaces.RemovePageParam, operator *usecase.Operator) (*storytelling.Story, *id.PageID, error) { +func (i *Storytelling) RemovePage(ctx context.Context, inp interfaces.RemovePageParam, op *usecase.Operator) (*storytelling.Story, *id.PageID, error) { tx, err := i.transaction.Begin(ctx) if err != nil { return nil, nil, err @@ -279,7 +285,7 @@ func (i *Storytelling) RemovePage(ctx context.Context, inp interfaces.RemovePage } }() - if err := i.CanWriteScene(inp.SceneID, operator); err != nil { + if err := i.CanWriteScene(inp.SceneID, op); err != nil { return nil, nil, interfaces.ErrOperationDenied } @@ -303,7 +309,7 @@ func (i *Storytelling) RemovePage(ctx context.Context, inp interfaces.RemovePage return story, page.Id().Ref(), nil } -func (i *Storytelling) MovePage(ctx context.Context, inp interfaces.MovePageParam, operator *usecase.Operator) (*storytelling.Story, *storytelling.Page, int, error) { +func (i *Storytelling) MovePage(ctx context.Context, inp interfaces.MovePageParam, op *usecase.Operator) (*storytelling.Story, *storytelling.Page, int, error) { tx, err := i.transaction.Begin(ctx) if err != nil { return nil, nil, 0, err @@ -321,7 +327,7 @@ func (i *Storytelling) MovePage(ctx context.Context, inp interfaces.MovePagePara return nil, nil, 0, err } - if err := i.CanWriteScene(story.Scene(), operator); err != nil { + if err := i.CanWriteScene(story.Scene(), op); err != nil { return nil, nil, 0, interfaces.ErrOperationDenied } @@ -340,7 +346,7 @@ func (i *Storytelling) MovePage(ctx context.Context, inp interfaces.MovePagePara return story, page, inp.Index, nil } -func (i *Storytelling) DuplicatePage(ctx context.Context, inp interfaces.DuplicatePageParam, operator *usecase.Operator) (*storytelling.Story, *storytelling.Page, error) { +func (i *Storytelling) DuplicatePage(ctx context.Context, inp interfaces.DuplicatePageParam, op *usecase.Operator) (*storytelling.Story, *storytelling.Page, error) { tx, err := i.transaction.Begin(ctx) if err != nil { return nil, nil, err @@ -358,7 +364,7 @@ func (i *Storytelling) DuplicatePage(ctx context.Context, inp interfaces.Duplica return nil, nil, err } - if err := i.CanWriteScene(story.Scene(), operator); err != nil { + if err := i.CanWriteScene(story.Scene(), op); err != nil { return nil, nil, interfaces.ErrOperationDenied } @@ -378,7 +384,7 @@ func (i *Storytelling) DuplicatePage(ctx context.Context, inp interfaces.Duplica return story, dupPage, nil } -func (i *Storytelling) AddPageLayer(ctx context.Context, inp interfaces.PageLayerParam, operator *usecase.Operator) (*storytelling.Story, *storytelling.Page, error) { +func (i *Storytelling) AddPageLayer(ctx context.Context, inp interfaces.PageLayerParam, op *usecase.Operator) (*storytelling.Story, *storytelling.Page, error) { tx, err := i.transaction.Begin(ctx) if err != nil { return nil, nil, err @@ -396,7 +402,7 @@ func (i *Storytelling) AddPageLayer(ctx context.Context, inp interfaces.PageLaye return nil, nil, err } - if err := i.CanWriteScene(story.Scene(), operator); err != nil { + if err := i.CanWriteScene(story.Scene(), op); err != nil { return nil, nil, interfaces.ErrOperationDenied } @@ -423,7 +429,7 @@ func (i *Storytelling) AddPageLayer(ctx context.Context, inp interfaces.PageLaye return story, page, nil } -func (i *Storytelling) RemovePageLayer(ctx context.Context, inp interfaces.PageLayerParam, operator *usecase.Operator) (*storytelling.Story, *storytelling.Page, error) { +func (i *Storytelling) RemovePageLayer(ctx context.Context, inp interfaces.PageLayerParam, op *usecase.Operator) (*storytelling.Story, *storytelling.Page, error) { tx, err := i.transaction.Begin(ctx) if err != nil { return nil, nil, err @@ -441,7 +447,7 @@ func (i *Storytelling) RemovePageLayer(ctx context.Context, inp interfaces.PageL return nil, nil, err } - if err := i.CanWriteScene(story.Scene(), operator); err != nil { + if err := i.CanWriteScene(story.Scene(), op); err != nil { return nil, nil, interfaces.ErrOperationDenied } @@ -468,17 +474,182 @@ func (i *Storytelling) RemovePageLayer(ctx context.Context, inp interfaces.PageL return story, page, nil } -func (i *Storytelling) CreateBlock(ctx context.Context, param interfaces.CreateBlockParam, operator *usecase.Operator) (*storytelling.Page, *storytelling.Block, error) { - // TODO implement me - panic("implement me") +func (i *Storytelling) CreateBlock(ctx context.Context, inp interfaces.CreateBlockParam, op *usecase.Operator) (*storytelling.Story, *storytelling.Page, *storytelling.Block, int, error) { + tx, err := i.transaction.Begin(ctx) + if err != nil { + return nil, nil, nil, -1, err + } + + ctx = tx.Context() + defer func() { + if err2 := tx.End(ctx); err == nil && err2 != nil { + err = err2 + } + }() + + story, err := i.storytellingRepo.FindByID(ctx, inp.StoryID) + if err != nil { + return nil, nil, nil, -1, err + } + if err := i.CanWriteScene(story.Scene(), op); err != nil { + return nil, nil, nil, -1, err + } + + _, extension, err := i.getPlugin(ctx, &inp.PluginID, &inp.ExtensionID) + if err != nil { + return nil, nil, nil, -1, err + } + if extension.Type() != plugin.ExtensionTypeStoryBlock { + return nil, nil, nil, -1, interfaces.ErrExtensionTypeMustBeStoryBlock + } + + prop, err := property.New().NewID().Schema(extension.Schema()).Scene(story.Scene()).Build() + if err != nil { + return nil, nil, nil, -1, err + } + + block, err := storytelling.NewBlock(). + NewID(). + Plugin(inp.PluginID). + Extension(inp.ExtensionID). + Property(prop.ID()). + Build() + if err != nil { + return nil, nil, nil, -1, err + } + + index := -1 + if inp.Index != nil { + index = *inp.Index + } + + page := story.Pages().Page(inp.PageID) + if page == nil { + return nil, nil, nil, -1, interfaces.ErrPageNotFound + } + + page.AddBlock(block, index) + + err = i.propertyRepo.Save(ctx, prop) + if err != nil { + return nil, nil, nil, -1, err + } + + err = i.storytellingRepo.Save(ctx, *story) + if err != nil { + return nil, nil, nil, -1, err + } + + tx.Commit() + return story, page, block, 1, err } -func (i *Storytelling) RemoveBlock(ctx context.Context, param interfaces.RemoveBlockParam, operator *usecase.Operator) (*storytelling.Page, *id.BlockID, error) { - // TODO implement me - panic("implement me") +func (i *Storytelling) RemoveBlock(ctx context.Context, inp interfaces.RemoveBlockParam, op *usecase.Operator) (*storytelling.Story, *storytelling.Page, *id.BlockID, error) { + tx, err := i.transaction.Begin(ctx) + if err != nil { + return nil, nil, nil, err + } + + ctx = tx.Context() + defer func() { + if err2 := tx.End(ctx); err == nil && err2 != nil { + err = err2 + } + }() + + story, err := i.storytellingRepo.FindByID(ctx, inp.StoryID) + if err != nil { + return nil, nil, nil, err + } + if err := i.CanWriteScene(story.Scene(), op); err != nil { + return nil, nil, nil, err + } + + page := story.Pages().Page(inp.PageID) + if page == nil { + return nil, nil, nil, interfaces.ErrPageNotFound + } + + block := page.Block(inp.BlockID) + if block == nil { + return nil, nil, nil, interfaces.ErrBlockNotFound + } + + page.RemoveBlock(inp.BlockID) + err = i.storytellingRepo.Save(ctx, *story) + if err != nil { + return nil, nil, nil, err + } + + if err := i.propertyRepo.Remove(ctx, block.Property()); err != nil { + return nil, nil, nil, err + } + + tx.Commit() + return story, page, &inp.BlockID, nil +} + +func (i *Storytelling) MoveBlock(ctx context.Context, inp interfaces.MoveBlockParam, op *usecase.Operator) (*storytelling.Story, *storytelling.Page, *id.BlockID, int, error) { + tx, err := i.transaction.Begin(ctx) + if err != nil { + return nil, nil, nil, inp.Index, err + } + + ctx = tx.Context() + defer func() { + if err2 := tx.End(ctx); err == nil && err2 != nil { + err = err2 + } + }() + + story, err := i.storytellingRepo.FindByID(ctx, inp.StoryID) + if err != nil { + return nil, nil, nil, inp.Index, err + } + if err := i.CanWriteScene(story.Scene(), op); err != nil { + return nil, nil, nil, inp.Index, err + } + + page := story.Pages().Page(inp.PageID) + if page == nil { + return nil, nil, nil, inp.Index, interfaces.ErrPageNotFound + } + + if block := page.Block(inp.BlockID); block == nil { + return nil, nil, nil, inp.Index, interfaces.ErrBlockNotFound + } + + page.MoveBlock(inp.BlockID, inp.Index) + err = i.storytellingRepo.Save(ctx, *story) + if err != nil { + return nil, nil, nil, inp.Index, err + } + + tx.Commit() + return story, page, &inp.BlockID, inp.Index, nil } -func (i *Storytelling) MoveBlock(ctx context.Context, param interfaces.MoveBlockParam, operator *usecase.Operator) (*storytelling.Page, *id.BlockID, int, error) { - // TODO implement me - panic("implement me") +func (i *Storytelling) getPlugin(ctx context.Context, pId *id.PluginID, eId *id.PluginExtensionID) (*plugin.Plugin, *plugin.Extension, error) { + if pId == nil { + return nil, nil, nil + } + + plg, err := i.pluginRepo.FindByID(ctx, *pId) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return nil, nil, interfaces.ErrPluginNotFound + } + return nil, nil, err + } + + if eId == nil { + return plg, nil, nil + } + + extension := plg.Extension(*eId) + if extension == nil { + return nil, nil, interfaces.ErrExtensionNotFound + } + + return plg, extension, nil } diff --git a/server/internal/usecase/interfaces/story.go b/server/internal/usecase/interfaces/story.go index aef5bd27a0..1743847e80 100644 --- a/server/internal/usecase/interfaces/story.go +++ b/server/internal/usecase/interfaces/story.go @@ -2,6 +2,7 @@ package interfaces import ( "context" + "errors" "github.com/reearth/reearth/server/internal/usecase" "github.com/reearth/reearth/server/pkg/id" @@ -93,7 +94,7 @@ type MoveBlockParam struct { StoryID id.StoryID PageID id.PageID BlockID id.BlockID - Index *int + Index int } type RemoveBlockParam struct { @@ -103,8 +104,10 @@ type RemoveBlockParam struct { } var ( - ErrPageNotFound error = rerror.NewE(i18n.T("page not found")) - ErrPageSwipeableMismatch error = rerror.NewE(i18n.T("page swipeable mismatch")) + ErrPageNotFound error = rerror.NewE(i18n.T("page not found")) + ErrBlockNotFound error = rerror.NewE(i18n.T("block not found")) + ErrPageSwipeableMismatch error = rerror.NewE(i18n.T("page swipeable mismatch")) + ErrExtensionTypeMustBeStoryBlock error = errors.New("extension type must be storyBlock") ) type Storytelling interface { @@ -124,7 +127,7 @@ type Storytelling interface { AddPageLayer(context.Context, PageLayerParam, *usecase.Operator) (*storytelling.Story, *storytelling.Page, error) RemovePageLayer(context.Context, PageLayerParam, *usecase.Operator) (*storytelling.Story, *storytelling.Page, error) - CreateBlock(context.Context, CreateBlockParam, *usecase.Operator) (*storytelling.Page, *storytelling.Block, error) - RemoveBlock(context.Context, RemoveBlockParam, *usecase.Operator) (*storytelling.Page, *id.BlockID, error) - MoveBlock(context.Context, MoveBlockParam, *usecase.Operator) (*storytelling.Page, *id.BlockID, int, error) + CreateBlock(context.Context, CreateBlockParam, *usecase.Operator) (*storytelling.Story, *storytelling.Page, *storytelling.Block, int, error) + RemoveBlock(context.Context, RemoveBlockParam, *usecase.Operator) (*storytelling.Story, *storytelling.Page, *id.BlockID, error) + MoveBlock(context.Context, MoveBlockParam, *usecase.Operator) (*storytelling.Story, *storytelling.Page, *id.BlockID, int, error) } diff --git a/server/pkg/builtin/manifest.yml b/server/pkg/builtin/manifest.yml index 86a01fc90b..65ba0134fd 100644 --- a/server/pkg/builtin/manifest.yml +++ b/server/pkg/builtin/manifest.yml @@ -2026,6 +2026,18 @@ extensions: name: Page type: storyPage description: Storytelling Page + schema: + groups: + - id: default + title: Basic + fields: + - id: title + type: string + title: Title + - id: storyBlock + name: Block + type: storyBlock + description: Storytelling Block schema: groups: - id: default diff --git a/server/pkg/storytelling/block_builder.go b/server/pkg/storytelling/block_builder.go new file mode 100644 index 0000000000..2ce4451678 --- /dev/null +++ b/server/pkg/storytelling/block_builder.go @@ -0,0 +1,49 @@ +package storytelling + +type BlockBuilder struct { + block *Block +} + +func NewBlock() *BlockBuilder { + return &BlockBuilder{block: &Block{}} +} + +func (b *BlockBuilder) Build() (*Block, error) { + if b.block.id.IsNil() || string(b.block.extension) == "" || b.block.property.IsNil() || b.block.plugin.IsNil() { + return nil, ErrInvalidID + } + return b.block, nil +} + +func (b *BlockBuilder) MustBuild() *Block { + i, err := b.Build() + if err != nil { + panic(err) + } + return i +} + +func (b *BlockBuilder) ID(id BlockID) *BlockBuilder { + b.block.id = id + return b +} + +func (b *BlockBuilder) NewID() *BlockBuilder { + b.block.id = NewBlockID() + return b +} + +func (b *BlockBuilder) Plugin(plugin PluginID) *BlockBuilder { + b.block.plugin = plugin + return b +} + +func (b *BlockBuilder) Extension(extension PluginExtensionID) *BlockBuilder { + b.block.extension = extension + return b +} + +func (b *BlockBuilder) Property(p PropertyID) *BlockBuilder { + b.block.property = p + return b +} diff --git a/server/pkg/storytelling/block_builder_test.go b/server/pkg/storytelling/block_builder_test.go new file mode 100644 index 0000000000..01aadd6e0b --- /dev/null +++ b/server/pkg/storytelling/block_builder_test.go @@ -0,0 +1,50 @@ +package storytelling + +import ( + "testing" + + "github.com/reearth/reearth/server/pkg/id" + "github.com/stretchr/testify/assert" +) + +func TestBlockBuilder(t *testing.T) { + + b := NewBlock() + assert.Equal(t, &BlockBuilder{block: &Block{}}, b) + + assert.PanicsWithError(t, ErrInvalidID.Error(), func() { + b.MustBuild() + }) + + b = b.NewID() + assert.False(t, b.block.id.IsEmpty()) + + blockID := NewBlockID() + b = b.ID(blockID) + assert.Equal(t, blockID, b.block.id) + + pluginID, _ := id.NewPluginID("plugin", "1.0.0", nil) + b = b.Plugin(pluginID) + assert.Equal(t, pluginID, b.block.plugin) + + extensionId := id.PluginExtensionID("extension") + b = b.Extension(extensionId) + assert.Equal(t, extensionId, b.block.extension) + + propertyID := NewPropertyID() + b = b.Property(propertyID) + assert.Equal(t, propertyID, b.block.property) + + p, err := b.Build() + assert.NoError(t, err) + assert.Equal(t, &Block{ + id: blockID, + property: propertyID, + plugin: pluginID, + extension: extensionId, + }, p) + + assert.NotPanics(t, func() { + b.MustBuild() + }) +}