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

chore(server): refactoring id property schema [VIZ-BE-574] #1455

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

hexaforce
Copy link
Contributor

@hexaforce hexaforce commented Feb 27, 2025

Overview

Refactoring ids

What I've done

This pull request unifies the Property and PropertySchema IDs to the ones in ./server/pkg/id/id.go.

I removed the parts that were redefining the ID from id.go.

type PropertyID
type PropertySchemaID
type PropertySchemaGroupID

What I haven't done

How I tested

Which point I want you to review particularly

Memo

Summary by CodeRabbit

  • New Features

    • Added a new command to clear caches, making routine maintenance easier.
    • Enhanced asset management so assets can now be associated with specific projects.
    • Introduced Google Analytics integration for stories via new settings, including GA enablement and tracking identifiers.
  • Improvements

    • Streamlined GraphQL queries and team asset filtering for better usability.
    • Simplified server initialization and error handling to boost overall stability and performance.

Copy link

coderabbitai bot commented Feb 27, 2025

Walkthrough

The pull request introduces extensive refactoring across multiple modules. A new Makefile target is added to clear caches. Many GraphQL schema definitions, resolver functions, test cases, and interactor methods have been updated—signatures changed, unused types and legacy fields removed, and error handling streamlined. In addition, files related to layer, dataset, and tag management in both in‑memory and MongoDB implementations have been removed or simplified, while asset, project, and storytelling logic now incorporate project filtering and Google Analytics parameters.

Changes

File(s) Change Summary
server/Makefile Added new target run-clear-cache and updated the .PHONY declaration.
server/e2e/* Updated numerous end-to-end tests (asset, project, scene, storytelling, user, ping, mock, seeder) with new function signatures, streamlined server initialization, and added tests for asset associations and CRUD operations.
server/gql/* and server/gqlgen.yml Updated GraphQL schema by adding projectId to Asset, GA fields (enableGa, trackingId) to Story, removing obsolete layer types, and reformatting queries/mutations; removed the rootLayer field from Scene.
server/internal/adapter/gql/* Removed outdated data loader generators and conversion files (e.g. convert_layer.go), updated conversion functions (adding ProjectID to assets, GA fields in stories), and modified resolvers (removing layer resolvers, adding UpdateAsset mutation, updating query methods for project filtering).
server/internal/app/* Simplified server startup by replacing detailed config calls with Server, ServerPingTest, and ServerMockTest; introduced AuthMiddlewareDummy and removed private export endpoints.
server/internal/infrastructure/fs/* Adjusted asset file URL construction and file removal validation to incorporate assetDir; corresponding test base URLs updated to root (/).
server/internal/infrastructure/memory/* Removed management for Dataset, DatasetSchema, Layer, and Tag; simplified property retrieval and tag functionalities.
server/internal/infrastructure/mongo/* Removed whole files for dataset, dataset_schema, layer, and tag management; updated asset filtering functions to support project‑based queries.
server/internal/usecase/interactor/* Refactored interactor methods: renamed functions (e.g. ExportProjectData, ImportProjectData), updated asset update and import methods to include project handling, removed legacy dataset/layer/tag operations, added new error variables in nlslayer, and streamlined plugin, scene, and storytelling operations.
server/internal/usecase/interfaces/* Updated interfaces by adding a ProjectID field to asset creation parameters, modifying project import/export signatures for type safety, and removing dataset, layer, and tag interfaces.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant AssetInteractor
    participant AssetRepo
    Client->>AssetInteractor: Update(assetID, newProjectID, operator)
    AssetInteractor->>AssetRepo: Retrieve asset by assetID
    AssetRepo-->>AssetInteractor: Asset data
    AssetInteractor->>AssetRepo: Save asset (with updated ProjectID)
    AssetRepo-->>AssetInteractor: Save confirmation
    AssetInteractor-->>Client: Return updated assetID and ProjectID
Loading
sequenceDiagram
    participant Client
    participant ProjectInteractor
    participant ProjectRepo
    participant FileGateway
    Client->>ProjectInteractor: ExportProjectData(projectID, zipWriter, operator)
    ProjectInteractor->>ProjectRepo: Fetch project details
    ProjectInteractor->>FileGateway: AddZipAsset(file, zipWriter, path)
    FileGateway-->>ProjectInteractor: Asset added to zip
    ProjectRepo-->>ProjectInteractor: Project data retrieved
    ProjectInteractor-->>Client: Return exported project data
Loading

Poem

I'm a hoppin’ rabbit, oh so spry,
Leaping through code with a joyful sigh.
Cache is cleared and tests are neat,
Layers and tags now skipped a beat.
With GA magic and projects in view,
I celebrate changes fresh and new!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

netlify bot commented Feb 27, 2025

Deploy Preview for reearth-web ready!

Name Link
🔨 Latest commit 2daf45d
🔍 Latest deploy log https://app.netlify.com/sites/reearth-web/deploys/67bfebf04874860008d7cf30
😎 Deploy Preview https://deploy-preview-1455--reearth-web.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (21)
server/go.mod (1)

131-131: Dependency Refactoring: Use of github.com/oklog/ulid as an Indirect Dependency

The dependency github.com/oklog/ulid v1.3.1 has been moved to the indirect block. Please ensure that:

  • It is not imported directly in your codebase.
  • This change does not break any dependency resolution or tooling that expects it as a direct dependency.
server/e2e/gql_user_test.go (1)

28-28: Unused parameter in baseSeederUser function

The function signature has been updated to accept a new gateway.File parameter, but this parameter is not used within the function implementation. This suggests that either:

  1. The parameter is intended for future functionality, or
  2. There's a missing implementation that should use this parameter

If the parameter is for future use, consider adding a comment explaining its purpose. If implementation is missing, ensure the parameter is properly utilized.

server/internal/adapter/gql/resolver_mutation_project.go (4)

10-10: Check new imports.

Imports for "net/url" and "path" are added. Ensure they are actually required—any leftover or unused imports can be removed if not in use.

Also applies to: 12-12


130-133: Filename creation and case sensitivity.

Here you create a ZIP file named with a lowercased project ID. If uppercase or out-of-band ID formatting is significant, consider removing the strings.ToLower call. Otherwise, this is fine.


178-182: Consider removing commented-out code.

Lines 178-182 with commented code (pid2, etc.) appear to be remnants. If they are no longer needed, removing them helps keep the codebase clean.


212-218: New import flow entrypoint.

The ImportProject method now looks for a team workspace and uncompresses the exported ZIP. Consider explicit error handling for accountdomain.WorkspaceIDFrom instead of ignoring with _.

server/e2e/gql_asset_test.go (2)

15-120: Tests for coreSupport asset handling.

These tests thoroughly validate:

  • Creating assets with and without coreSupport.
  • Direct DB insertion scenarios (lines 79–104).
  • Retrieving only those assets marked coreSupport.

One nitpick: consider testing boundary cases (e.g., extremely large files) if relevant. Otherwise, this looks solid.


200-223: createAsset helper function.

This function neatly wraps the multipart file execution. Watch out for potential large-file handling or timeouts, but as-is, it’s a helpful utility.

server/e2e/gql_storytelling_test.go (3)

15-55: Consider splitting this test into smaller, more focused ones.
This test function is large, covering multiple scenarios (fetching, creating, updating, deleting). Splitting it into smaller, dedicated tests makes it easier to maintain, read, and diagnose potential failures.


154-206: Validate negative scenarios for block operations.
Although the test exercises block creation, movement, and removal, consider adding a scenario for invalid block IDs or invalid positions to ensure complete robustness.


231-413: Ensure clarity and maintainability by extracting repeated checks.
This test includes extensive JSON validation and repeated steps for building expectations. Extracting common logic (e.g., building or verifying the JSON payload) into helper methods may improve readability and reduce duplication.

server/internal/usecase/interactor/project.go (2)

497-516: ExportProjectData handles the project image via AddZipAsset.
When the image is an external URL, AddZipAsset silently skips the asset if unreadable. Consider logging or surfacing that condition to give visibility if an asset isn't found.


611-633: Skipping external URLs in AddZipAsset.
Returning nil on reading errors helps skip invalid or external assets. If skipping assets might impact the final exported zip, consider logging the skip event or providing user feedback.

server/internal/usecase/interactor/storytelling.go (1)

370-370: Hardcoded coreSupport as 'true' during publish.
The publish builder call sets coreSupport to true unconditionally. If the intention is to mirror the project’s or story’s coreSupport setting, consider passing that from the domain model for consistency.

server/e2e/gql_project_export_import_test.go (4)

21-32: Test steps are clearly outlined, but watch out for the function spelling.
The sequence (retrieve data → export → import) is straightforward. However, note that the function call in lines 28-29 is exporProject instead of “exportProject,” which appears to be a typographical slip.

Consider renaming exporProject to exportProject throughout the file for clarity:

- fileName := exporProject(t, e, pID.String())
+ fileName := exportProject(t, e, pID.String())

45-45: Consider using httpexpect string extraction for clarity.
Currently, raw casting is used with (string). You can use Value("id").String().Raw() for a more typed approach.


50-57: Repeated calls to compareValue could be centralized.
All keys (styles, widgets, etc.) are tested individually using compareValue. This is fine, but you might consider a single loop mechanism if you add more fields.


113-120: isID checks only widget IDs.
This works if you only intend to ignore widget IDs. If other ID types can appear in the test data, consider making it generic or clarifying the function name.

server/e2e/seeder.go (2)

120-162: addAsset properly uploads the file and creates an asset object, but consider edge cases.
Overall, it’s robust, but be mindful of missing or invalid files in real scenarios. The function returns the uploaded URL and also saves the asset.


437-497: Consider removing debug print in addGeoJson.
Line 453 prints err before returning it. Logging the error is fine, but fmt.Print may be too minimal. A log statement or direct return is usually enough.

- fmt.Print(err)
  return err
+ // log.Printf("geometry creation error: %v\n", err)
  return err
server/e2e/common.go (1)

63-63: Storing file reference globally (fr).
This design choice is working for tests but be cautious of concurrency if running parallel tests.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1d7ddff and 2daf45d.

⛔ Files ignored due to path filters (3)
  • server/e2e/test.zip is excluded by !**/*.zip
  • server/go.sum is excluded by !**/*.sum
  • server/pkg/layer/decoding/shapetest/shapes.zip is excluded by !**/*.zip
📒 Files selected for processing (107)
  • server/Makefile (3 hunks)
  • server/e2e/common.go (7 hunks)
  • server/e2e/gql_asset_test.go (6 hunks)
  • server/e2e/gql_me_test.go (1 hunks)
  • server/e2e/gql_project_export_import_test.go (3 hunks)
  • server/e2e/gql_project_export_test.go (0 hunks)
  • server/e2e/gql_project_test.go (6 hunks)
  • server/e2e/gql_scene_test.go (4 hunks)
  • server/e2e/gql_storytelling_test.go (6 hunks)
  • server/e2e/gql_user_test.go (2 hunks)
  • server/e2e/gql_validate_geojson_test.go (1 hunks)
  • server/e2e/mock_test.go (1 hunks)
  • server/e2e/ping_test.go (1 hunks)
  • server/e2e/seeder.go (5 hunks)
  • server/go.mod (1 hunks)
  • server/gql/asset.graphql (5 hunks)
  • server/gql/layer.graphql (0 hunks)
  • server/gql/property.graphql (0 hunks)
  • server/gql/storytelling.graphql (3 hunks)
  • server/gql/workspace.graphql (2 hunks)
  • server/gqlgen.yml (0 hunks)
  • server/internal/adapter/gql/gqldataloader/dataloader.go (0 hunks)
  • server/internal/adapter/gql/gqldataloader/layergrouploader_gen.go (0 hunks)
  • server/internal/adapter/gql/gqldataloader/layeritemloader_gen.go (0 hunks)
  • server/internal/adapter/gql/gqldataloader/layerloader_gen.go (0 hunks)
  • server/internal/adapter/gql/gqlmodel/convert_asset.go (1 hunks)
  • server/internal/adapter/gql/gqlmodel/convert_layer.go (0 hunks)
  • server/internal/adapter/gql/gqlmodel/convert_nlslayer_test.go (5 hunks)
  • server/internal/adapter/gql/gqlmodel/convert_project.go (2 hunks)
  • server/internal/adapter/gql/gqlmodel/convert_property.go (3 hunks)
  • server/internal/adapter/gql/gqlmodel/convert_storytelling.go (1 hunks)
  • server/internal/adapter/gql/gqlmodel/models.go (0 hunks)
  • server/internal/adapter/gql/gqlmodel/models_gen.go (5 hunks)
  • server/internal/adapter/gql/gqlmodel/scalar_id.go (0 hunks)
  • server/internal/adapter/gql/loader.go (0 hunks)
  • server/internal/adapter/gql/loader_asset.go (2 hunks)
  • server/internal/adapter/gql/loader_layer.go (0 hunks)
  • server/internal/adapter/gql/loader_property.go (1 hunks)
  • server/internal/adapter/gql/resolver_Storytelling.go (0 hunks)
  • server/internal/adapter/gql/resolver_layer.go (0 hunks)
  • server/internal/adapter/gql/resolver_mutation_asset.go (3 hunks)
  • server/internal/adapter/gql/resolver_mutation_project.go (6 hunks)
  • server/internal/adapter/gql/resolver_mutation_property.go (0 hunks)
  • server/internal/adapter/gql/resolver_mutation_storytelling.go (1 hunks)
  • server/internal/adapter/gql/resolver_property.go (0 hunks)
  • server/internal/adapter/gql/resolver_query.go (1 hunks)
  • server/internal/adapter/gql/resolver_team.go (1 hunks)
  • server/internal/adapter/http/dataset.go (0 hunks)
  • server/internal/app/app.go (2 hunks)
  • server/internal/app/auth_client.go (1 hunks)
  • server/internal/app/private.go (0 hunks)
  • server/internal/infrastructure/fs/file.go (2 hunks)
  • server/internal/infrastructure/fs/file_test.go (3 hunks)
  • server/internal/infrastructure/memory/asset.go (1 hunks)
  • server/internal/infrastructure/memory/container.go (0 hunks)
  • server/internal/infrastructure/memory/dataset.go (0 hunks)
  • server/internal/infrastructure/memory/dataset_schema.go (0 hunks)
  • server/internal/infrastructure/memory/layer.go (0 hunks)
  • server/internal/infrastructure/memory/layer_test.go (0 hunks)
  • server/internal/infrastructure/memory/property.go (1 hunks)
  • server/internal/infrastructure/memory/tag.go (0 hunks)
  • server/internal/infrastructure/memory/tag_test.go (0 hunks)
  • server/internal/infrastructure/mongo/asset.go (2 hunks)
  • server/internal/infrastructure/mongo/container.go (0 hunks)
  • server/internal/infrastructure/mongo/dataset.go (0 hunks)
  • server/internal/infrastructure/mongo/dataset_schema.go (0 hunks)
  • server/internal/infrastructure/mongo/layer.go (0 hunks)
  • server/internal/infrastructure/mongo/layer_test.go (0 hunks)
  • server/internal/infrastructure/mongo/mongodoc/asset.go (3 hunks)
  • server/internal/infrastructure/mongo/mongodoc/dataset.go (0 hunks)
  • server/internal/infrastructure/mongo/mongodoc/dataset_schema.go (0 hunks)
  • server/internal/infrastructure/mongo/mongodoc/layer.go (0 hunks)
  • server/internal/infrastructure/mongo/mongodoc/property.go (0 hunks)
  • server/internal/infrastructure/mongo/mongodoc/property_schema.go (1 hunks)
  • server/internal/infrastructure/mongo/mongodoc/scene.go (0 hunks)
  • server/internal/infrastructure/mongo/mongodoc/storytelling.go (4 hunks)
  • server/internal/infrastructure/mongo/mongodoc/tag.go (0 hunks)
  • server/internal/infrastructure/mongo/mongodoc/tag_test.go (0 hunks)
  • server/internal/infrastructure/mongo/property.go (0 hunks)
  • server/internal/infrastructure/mongo/tag.go (0 hunks)
  • server/internal/usecase/gateway/container.go (0 hunks)
  • server/internal/usecase/gateway/datasouce.go (0 hunks)
  • server/internal/usecase/interactor/asset.go (6 hunks)
  • server/internal/usecase/interactor/common.go (1 hunks)
  • server/internal/usecase/interactor/dataset.go (0 hunks)
  • server/internal/usecase/interactor/layer.go (0 hunks)
  • server/internal/usecase/interactor/layer_test.go (0 hunks)
  • server/internal/usecase/interactor/nlslayer.go (13 hunks)
  • server/internal/usecase/interactor/plugin.go (1 hunks)
  • server/internal/usecase/interactor/plugin_upload.go (1 hunks)
  • server/internal/usecase/interactor/plugin_upload_test.go (1 hunks)
  • server/internal/usecase/interactor/project.go (7 hunks)
  • server/internal/usecase/interactor/project_test.go (0 hunks)
  • server/internal/usecase/interactor/property.go (0 hunks)
  • server/internal/usecase/interactor/scene.go (6 hunks)
  • server/internal/usecase/interactor/scene_plugin.go (3 hunks)
  • server/internal/usecase/interactor/scene_plugin_test.go (2 hunks)
  • server/internal/usecase/interactor/storytelling.go (5 hunks)
  • server/internal/usecase/interactor/storytelling_test.go (1 hunks)
  • server/internal/usecase/interactor/tag.go (0 hunks)
  • server/internal/usecase/interfaces/asset.go (2 hunks)
  • server/internal/usecase/interfaces/common.go (0 hunks)
  • server/internal/usecase/interfaces/dataset.go (0 hunks)
  • server/internal/usecase/interfaces/layer.go (0 hunks)
  • server/internal/usecase/interfaces/project.go (2 hunks)
  • server/internal/usecase/interfaces/property.go (0 hunks)
  • server/internal/usecase/interfaces/scene.go (0 hunks)
⛔ Files not processed due to max files limit (54)
  • server/internal/usecase/interfaces/story.go
  • server/internal/usecase/interfaces/tag.go
  • server/internal/usecase/repo/asset.go
  • server/internal/usecase/repo/container.go
  • server/internal/usecase/repo/dataset.go
  • server/internal/usecase/repo/dataset_schema.go
  • server/internal/usecase/repo/layer.go
  • server/internal/usecase/repo/property.go
  • server/internal/usecase/repo/tag.go
  • server/pkg/asset/asset.go
  • server/pkg/asset/builder.go
  • server/pkg/asset/id.go
  • server/pkg/builtin/main.go
  • server/pkg/builtin/main_test.go
  • server/pkg/dataset/builder.go
  • server/pkg/dataset/csvparser.go
  • server/pkg/dataset/csvparser_test.go
  • server/pkg/dataset/dataset.go
  • server/pkg/dataset/dataset_test.go
  • server/pkg/dataset/diff.go
  • server/pkg/dataset/export.go
  • server/pkg/dataset/export_test.go
  • server/pkg/dataset/field.go
  • server/pkg/dataset/graph_iterator.go
  • server/pkg/dataset/graph_iterator_test.go
  • server/pkg/dataset/graph_loader.go
  • server/pkg/dataset/id.go
  • server/pkg/dataset/list.go
  • server/pkg/dataset/list_test.go
  • server/pkg/dataset/loader.go
  • server/pkg/dataset/schema.go
  • server/pkg/dataset/schema_builder.go
  • server/pkg/dataset/schema_field.go
  • server/pkg/dataset/schema_field_builder.go
  • server/pkg/dataset/schema_field_diff.go
  • server/pkg/dataset/schema_graph_iterator.go
  • server/pkg/dataset/schema_graph_iterator_test.go
  • server/pkg/dataset/schema_list.go
  • server/pkg/dataset/schema_list_test.go
  • server/pkg/dataset/schema_test.go
  • server/pkg/dataset/value.go
  • server/pkg/dataset/value_optional.go
  • server/pkg/dataset/value_optional_test.go
  • server/pkg/dataset/value_test.go
  • server/pkg/id/id.go
  • server/pkg/layer/builder.go
  • server/pkg/layer/decoding/common.go
  • server/pkg/layer/decoding/common_test.go
  • server/pkg/layer/decoding/czml.go
  • server/pkg/layer/decoding/czml_test.go
  • server/pkg/layer/decoding/decoder.go
  • server/pkg/layer/decoding/format.go
  • server/pkg/layer/decoding/geojson.go
  • server/pkg/layer/decoding/geojson_test.go
💤 Files with no reviewable changes (53)
  • server/gql/property.graphql
  • server/internal/usecase/gateway/container.go
  • server/internal/usecase/interfaces/common.go
  • server/internal/infrastructure/mongo/property.go
  • server/internal/usecase/interactor/layer_test.go
  • server/internal/adapter/gql/resolver_mutation_property.go
  • server/e2e/gql_project_export_test.go
  • server/internal/usecase/interactor/project_test.go
  • server/internal/app/private.go
  • server/internal/infrastructure/mongo/mongodoc/property.go
  • server/internal/infrastructure/mongo/layer_test.go
  • server/internal/adapter/gql/gqlmodel/scalar_id.go
  • server/internal/adapter/http/dataset.go
  • server/internal/infrastructure/memory/container.go
  • server/internal/usecase/interfaces/property.go
  • server/gqlgen.yml
  • server/internal/usecase/gateway/datasouce.go
  • server/internal/infrastructure/mongo/container.go
  • server/internal/usecase/interfaces/scene.go
  • server/internal/adapter/gql/resolver_property.go
  • server/internal/infrastructure/mongo/mongodoc/scene.go
  • server/internal/adapter/gql/gqldataloader/dataloader.go
  • server/internal/infrastructure/mongo/mongodoc/tag_test.go
  • server/internal/usecase/interactor/property.go
  • server/internal/adapter/gql/loader.go
  • server/internal/infrastructure/mongo/dataset.go
  • server/internal/infrastructure/mongo/mongodoc/dataset_schema.go
  • server/internal/usecase/interfaces/layer.go
  • server/internal/adapter/gql/gqlmodel/models.go
  • server/internal/infrastructure/mongo/mongodoc/layer.go
  • server/internal/infrastructure/mongo/mongodoc/tag.go
  • server/gql/layer.graphql
  • server/internal/infrastructure/memory/tag_test.go
  • server/internal/infrastructure/memory/layer_test.go
  • server/internal/infrastructure/memory/dataset_schema.go
  • server/internal/usecase/interfaces/dataset.go
  • server/internal/adapter/gql/gqlmodel/convert_layer.go
  • server/internal/infrastructure/memory/dataset.go
  • server/internal/adapter/gql/resolver_Storytelling.go
  • server/internal/usecase/interactor/dataset.go
  • server/internal/adapter/gql/gqldataloader/layerloader_gen.go
  • server/internal/adapter/gql/loader_layer.go
  • server/internal/infrastructure/mongo/dataset_schema.go
  • server/internal/adapter/gql/gqldataloader/layergrouploader_gen.go
  • server/internal/adapter/gql/gqldataloader/layeritemloader_gen.go
  • server/internal/infrastructure/mongo/tag.go
  • server/internal/usecase/interactor/tag.go
  • server/internal/usecase/interactor/layer.go
  • server/internal/infrastructure/memory/layer.go
  • server/internal/adapter/gql/resolver_layer.go
  • server/internal/infrastructure/mongo/mongodoc/dataset.go
  • server/internal/infrastructure/mongo/layer.go
  • server/internal/infrastructure/memory/tag.go
✅ Files skipped from review due to trivial changes (2)
  • server/internal/usecase/interactor/scene_plugin_test.go
  • server/internal/usecase/interactor/plugin_upload_test.go
🧰 Additional context used
🧠 Learnings (2)
server/e2e/gql_project_export_import_test.go (2)
Learnt from: hexaforce
PR: reearth/reearth-visualizer#1141
File: server/e2e/gql_import_export_test.go:48-80
Timestamp: 2024-11-12T15:21:04.151Z
Learning: In `server/e2e/gql_import_export_test.go`, test functions like `TestCallImportProject` may have disabled assertions due to problems with GraphQL.
Learnt from: hexaforce
PR: reearth/reearth-visualizer#1141
File: server/e2e/gql_import_export_test.go:12-44
Timestamp: 2024-11-12T15:21:04.150Z
Learning: The response body assertions in `TestCallExportProject` are disabled due to existing problems with GraphQL.
server/internal/adapter/gql/resolver_mutation_project.go (2)
Learnt from: hexaforce
PR: reearth/reearth-visualizer#1151
File: server/internal/adapter/gql/resolver_mutation_project.go:0-0
Timestamp: 2024-11-12T15:21:04.150Z
Learning: In the project export functionality, the ZIP file is deleted after saving to storage.
Learnt from: hexaforce
PR: reearth/reearth-visualizer#1151
File: server/internal/adapter/gql/resolver_mutation_project.go:215-217
Timestamp: 2024-11-12T15:21:04.150Z
Learning: In the project import functionality, the file names are unique and can be safely replaced uniformly using `bytes.Replace`.
🔇 Additional comments (185)
server/internal/usecase/interactor/common.go (1)

143-147: Good simplification of the SceneDeleter struct.

The SceneDeleter struct has been simplified by removing the Layer, Dataset, and DatasetSchema fields, which aligns with the broader refactoring effort to streamline the id property schema. This change reduces the struct's responsibilities to focus only on Scene, SceneLock, and Property management.

The Delete method implementation (lines 149-181) correctly reflects this simplified structure by only handling property deletion, scene lock release, and scene removal. This suggests that layer, dataset, and schema deletion responsibilities have been moved elsewhere or are no longer needed in the system architecture.

server/internal/usecase/interactor/nlslayer.go (13)

38-54: Well-structured error handling improvements.

The addition of specific error constants enhances error handling clarity and consistency throughout the codebase. This makes debugging easier and provides more meaningful error messages to clients.


388-388: Improved error specificity.

Replacing generic errors with the more specific ErrInfoboxAlreadyExists improves error handling and makes the code more maintainable.


446-446: Improved error specificity.

Using ErrInfoboxNotFound instead of a more generic error enhances clarity for error handling.


478-478: Improved error specificity.

Using ErrPluginNotFound for this specific error case improves clarity and consistency.


489-489: Improved error specificity.

Using ErrExtensionNotFound enhances error handling clarity.


523-523: Improved error specificity.

Using ErrInfoboxNotFound provides better context for the error condition.


531-531: Improved error specificity.

Using ErrExtensionTypeMustBeBlock makes the requirement more explicit.


601-601: Improved error specificity.

Using ErrInfoboxNotFound provides better context for the error condition.


648-648: Improved error specificity.

Using ErrInfoboxNotFound provides better context for the error condition.


774-774: Improved error specificity.

Using ErrSketchNotFound provides better error context.


840-840: Improved error specificity.

Using ErrSketchNotFound provides better error context.


905-907: Improved feature creation with proper ID generation.

Using nlslayer.NewFeatureID() ensures that each feature gets a proper unique identifier.


1155-1180: Streamlined feature collection handling in import process.

The refactored code improves how features are processed during import, with better handling of feature creation, properties, and geometry.

server/internal/usecase/interactor/scene_plugin.go (4)

45-46: Standardized error handling for plugin not found scenarios.

The error handling has been updated to consistently use ErrPluginNotFound instead of interfaces.ErrPluginNotFound throughout the InstallPlugin method. This change aligns with best practices for error standardization and simplifies error handling.

Also applies to: 50-51, 53-54


110-111: Consistent error handling update in UninstallPlugin method.

The error reference has been changed from interfaces.ErrPluginNotFound to ErrPluginNotFound, maintaining consistency with the changes made in the InstallPlugin method.


192-193: Standardized error reference in UpgradePlugin method.

The error handling has been updated to use ErrPluginNotFound instead of interfaces.ErrPluginNotFound, completing the consistent error standardization across all plugin management methods.


3-15:

✅ Verification successful

Verify import dependencies after layer-related code removal.

According to the AI summary, references to the layerops package have been removed from this file. While I can see the error handling changes, I don't see the import statement changes in the provided code. Please verify that all necessary imports are present and any unused imports have been removed.


🏁 Script executed:

#!/bin/bash
# Check if there are any unused imports in the file
echo "Checking for unused imports in scene_plugin.go..."
rg -n "^import" server/internal/usecase/interactor/scene_plugin.go -A 15

Length of output: 868


Imports verified – no unused or extraneous imports remain.

After reviewing the file server/internal/usecase/interactor/scene_plugin.go, the updated import block confirms that the layerops package has been removed as expected. The remaining imports all appear necessary for the current implementation, and no unused imports were detected.

server/internal/infrastructure/memory/property.go (2)

1-205:

✅ Verification successful

Missing implementation for dataset-related functionality.

The FindByDataset method has been completely removed from this file. According to the AI summary, this method was responsible for retrieving properties linked to a specific dataset schema and dataset ID.

Check if all code that previously called this method has been updated accordingly to prevent potential runtime errors. Also, verify if this removal is part of a broader refactoring related to datasets.


🏁 Script executed:

#!/bin/bash
# Search for any references to FindByDataset in the codebase
rg "FindByDataset" --type go

# Check for any interface definitions that might require this method
rg -A 10 -B 10 "type Property interface" --type go

Length of output: 4572


Dataset-related method removal verified as intentional

After verifying the codebase, there are no references to a FindByDataset method in either the memory implementation or in the property interface definitions. This indicates that its removal is part of a broader refactoring and that no runtime errors should occur due to its absence. Please ensure that any required dataset functionality is addressed elsewhere in the code if needed.

  • Verified absence of FindByDataset references in the repository.
  • Confirmed that the property interfaces do not require this method.

78-78:

❓ Verification inconclusive

Behavior change in FindLinkedAll method.

The condition has been simplified to only check if the property belongs to the specified scene, removing the additional check for linked fields (p.HasLinkedField()). This change will result in more properties being returned than before, as it now includes properties without linked fields.

Ensure that all consumers of this method can handle the additional properties that will now be returned. This could affect performance or business logic in code that expects only properties with linked fields.


🏁 Script executed:

#!/bin/bash
# Search for FindLinkedAll usage in the codebase to verify all consumers are updated
rg -A 5 "FindLinkedAll" --type go

Length of output: 1655


Action: Verify Consumers Compatibility for Updated FindLinkedAll Logic

The memory implementation now returns properties based solely on the scene equality without checking for linked fields—unlike the Mongo version which still applies an additional filter. Please verify that all consumers (e.g., those in server/internal/usecase/repo/property.go) are prepared to handle the increased number of properties (including those without linked fields) and that this behavior change does not impact performance or business logic adversely.

  • Review the usage of FindLinkedAll in the repository layer (e.g., in server/internal/usecase/repo/property.go) to ensure that returning properties without linked fields is acceptable.
  • Confirm that any downstream logic or tests expecting properties with linked fields are updated accordingly.
server/internal/usecase/interactor/scene.go (6)

21-21: Import addition looks good.
No issues detected; importing storytelling appears necessary for handling story data in subsequent logic.


530-533: Consider verifying handling of multiple stories.
Currently, only the first story is retrieved from the list. If multiple stories are expected, confirm that ignoring the rest is intended behavior.


586-587: Button icon URL check is appropriate.
This validation properly confirms that the field is a URL type before proceeding. No issues detected.


611-613: Widget page block resource handling is appropriate.
This mirrors the logic for adding ZIP assets for widgets; ensuring the type is *url.URL before usage is sensible.


743-743: Clear plugin retrieval error.
Returning ErrPluginNotFound instead of the generic error clarifies the error source.


749-749: Distinct error for missing extensions.
Using ErrExtensionNotFound improves error granularity and helps distinguish plugin from extension issues.

server/internal/adapter/gql/gqlmodel/convert_asset.go (2)

12-16: Good addition of project ID association to assets

This change correctly extracts the project ID from the asset when available and stores it in a variable, properly handling the case where the project might be nil. The implementation follows good defensive programming practices.


22-22: LGTM: ProjectID field added to Asset struct

The ProjectID field is now properly included in the returned Asset struct, which allows clients to identify which project an asset belongs to.

server/internal/app/auth_client.go (1)

105-107: Suppress debug logs for e2e test user

This change reduces log noise during automated testing by suppressing debug logs when the e2e test user is detected. This is a good practice for keeping test logs clean while maintaining detailed logging for real users.

Also applies to: 115-117

server/Makefile (3)

23-23: Good documentation for the new cache clearing target

The help text clearly explains the purpose of the new run-clear-cache target.


93-95: Useful addition of cache clearing functionality

This target provides a convenient way to clear all Go caches, which is helpful during development when troubleshooting dependency issues or ensuring clean builds.

make run-clear-cache  # To clear all Go caches

116-116: Correctly updated .PHONY declaration

The .PHONY declaration has been properly updated to include the new target, ensuring that Make doesn't look for a file named "run-clear-cache".

server/internal/infrastructure/mongo/mongodoc/property_schema.go (1)

297-297:

✅ Verification successful

Updated ID type package reference

The code now uses id.PropertySchemaGroupID instead of property.SchemaGroupID, which appears to be part of the ID property schema refactoring effort. This change helps centralize ID types management.


🏁 Script executed:

#!/bin/bash
# Check if id.PropertySchemaGroupID is used consistently across the codebase
rg -A 1 "PropertySchemaGroupID" --type go

Length of output: 30049


ID Type Update Consistently Applied
The change replacing property.SchemaGroupID with id.PropertySchemaGroupID has been verified across the codebase—including in server/internal/infrastructure/mongo/mongodoc/property_schema.go at line 297—and is consistently applied as part of the centralized ID types refactoring effort.

server/internal/adapter/gql/resolver_mutation_storytelling.go (1)

58-59: LGTM - Properly added Google Analytics fields.

The addition of EnableGa and TrackingID fields to the UpdateStoryInput struct allows integration of Google Analytics tracking features in stories. Fields are properly positioned within the existing input parameter construction.

server/e2e/gql_validate_geojson_test.go (1)

186-186: LGTM - Updated function call with new projectId parameter.

The createAssetFromFileData function call has been updated to include a nil project ID parameter, matching the new function signature. This is consistent with the refactoring of the ID property schema mentioned in the PR objectives.

server/internal/infrastructure/mongo/mongodoc/asset.go (5)

17-17: LGTM - Added Project field to AssetDocument.

Added a new optional Project field as a pointer to string to allow assets to be associated with projects. This aligns with the ID property schema refactoring.


35-40: LGTM - Proper implementation of Project field handling.

The implementation correctly extracts the project ID from the asset and converts it to a string pointer for storage in the MongoDB document. Using a pointer allows for nil values when no project is associated.


46-46: LGTM - Added Project field to document construction.

Project field is properly included in the AssetDocument constructor, maintaining consistency with the struct definition.


65-72: LGTM - Properly implemented Project ID conversion with error handling.

The implementation correctly converts the string project ID back to a typed ID with appropriate error handling. The error is properly bubbled up if the conversion fails.


78-78: LGTM - Added Project field to asset build chain.

Project field is properly included in the asset build method chain.

server/e2e/mock_test.go (1)

11-11: LGTM - Simplified server initialization.

Replaced detailed server configuration with a call to ServerMockTest(t), which simplifies the test setup by abstracting server initialization details. This makes the test code more maintainable and readable.

server/internal/adapter/gql/resolver_mutation_asset.go (2)

19-26: Project ID handling implementation looks good.

This implementation correctly processes the optional ProjectID parameter from the input, converting it to the appropriate type for use in the Asset.Create call.


41-62: New UpdateAsset resolver implementation is clean and consistent.

The implementation follows established patterns for handling IDs and optional parameters. The error handling is appropriate, and the method signature aligns with the existing code style.

server/internal/adapter/gql/gqlmodel/convert_nlslayer_test.go (2)

11-12: Good refactoring to separate ID generation from feature creation.

The change from using nlslayer.NewFeatureWithNewId to explicitly providing nlslayer.NewFeatureID() as an argument to nlslayer.NewFeature makes the code more explicit and follows better separation of concerns.


21-22: Consistent application of the new feature creation pattern.

The same pattern is applied consistently across all feature creation calls, which is good for code maintainability.

Also applies to: 31-32, 41-42, 51-52

server/internal/adapter/gql/gqlmodel/convert_storytelling.go (1)

35-36: Good addition of Google Analytics support to the Story model.

The addition of EnableGa and TrackingID fields is implemented cleanly and follows the existing patterns of accessing data from the underlying model.

server/internal/infrastructure/fs/file_test.go (3)

165-165: Consistent change to base URL in RemoveAsset test.

The base URL has been updated to use the root path instead of the assets subdirectory, which is consistent with the changes in other tests.


316-316: Consistent change to base URL in GetAssetFileURL test.

This change aligns with the other modifications to use root paths instead of asset-specific paths.


116-117:

❓ Verification inconclusive

Verify that URL construction still works as expected with the new base path.

The test initialization has changed from using "/assets" to "/" as the base path. Ensure that this doesn't affect the expected URL construction behavior, especially considering the assertion on line 128 which still expects paths to start with "/assets/".


🏁 Script executed:

#!/bin/bash
# Check how the base path is used in the File implementation
rg -A 10 'func NewFile' server/internal/infrastructure/fs/file.go
rg -A 5 'getAssetFileURL' server/internal/infrastructure/fs/file.go

Length of output: 912


Ensure Consistency in Asset URL Construction

  • The base path for file initialization has changed from "/assets" to "/", meaning that the urlBase in the file repository is now derived from "/".
  • Since getAssetFileURL simply uses this base to construct asset URLs, the resulting URLs will now likely be prefixed with "/" rather than "/assets/".
  • Please verify that this change is intentional: if asset URLs should continue to include the "/assets/" prefix (as expected by the assertion on line 128 in the test), either adjust the base path provided to NewFile or modify the URL assembly logic in getAssetFileURL accordingly.
  • If the change is deliberate, update the test assertions to match the new behavior.
server/e2e/ping_test.go (1)

9-9: Simplification of server initialization

The code has been refactored to use ServerPingTest(t) instead of a more verbose StartServer function call with explicit configuration. This change improves maintainability by centralizing server setup logic for ping tests.

server/e2e/gql_me_test.go (1)

8-8: Simplified server setup for tests

The server initialization has been streamlined to use Server(t, baseSeeder) instead of the previous approach with explicit configuration. This is part of a broader refactoring to reduce boilerplate in test setup.

server/internal/usecase/interactor/storytelling_test.go (1)

159-187: Updated expected JSON structure to match new implementation

The expected JSON structure has been updated to reflect changes in the storytelling implementation, including:

  1. Added new fields: enableGa and trackingId
  2. Reorganized existing fields
  3. Simplified the blocks structure
  4. Set layersIds to null

These changes align with the modifications made to the Story struct in related files.

server/internal/app/app.go (2)

71-77: Improved authentication handling with conditional middleware

The authentication logic has been enhanced to conditionally use a dummy middleware when authentication is disabled. This improves flexibility for testing and development scenarios.


161-165: New dummy authentication middleware

Added a simple no-op middleware function that can be used when authentication needs to be bypassed. This is a clean implementation that allows for easier testing and configuration.

server/internal/infrastructure/fs/file.go (1)

113-113: Path validation corrected for asset removal

The path validation logic has been improved to ensure that files being removed are located within the expected asset directory.

server/e2e/gql_scene_test.go (4)

16-16: Improved object access chain

The code now correctly uses r.Object().Value(...) instead of r.Value(...), which makes the object access chain more explicit and consistent.


42-42: Improved object access chain

The code now correctly uses r.Object().Value(...) instead of r.Value(...), which makes the object access chain more explicit and consistent.


71-73: Improved object access chain

The code now correctly uses r.Object().Value(...) and HasValue() methods, making the object access chain more explicit and consistent.


77-100: New utility function for project creation with external image

This is a good addition that encapsulates the GraphQL request for creating a project with an external image, making the tests more maintainable and readable.

server/internal/usecase/interfaces/project.go (1)

74-75: Method renaming and type safety improvements

The renaming of methods from ExportProject/ImportProject to ExportProjectData/ImportProjectData better reflects their purpose and the parameter type change from string to idx.ID[accountdomain.Workspace] enhances type safety.

server/internal/adapter/gql/gqlmodel/convert_project.go (1)

108-137: Well-structured project export implementation

The new ProjectExport type and associated conversion functions provide a clean, type-safe structure for the project export/import functionality. The implementations properly handle error cases and nil values.

server/internal/infrastructure/mongo/mongodoc/storytelling.go (2)

34-35: Added Google Analytics support to storytelling

Good addition of Google Analytics tracking capabilities with the EnableGa and TrackingID fields, properly implemented throughout all relevant methods.

Also applies to: 87-88, 197-198


226-231: Improved variable naming for clarity

The variable rename from page to block better reflects the actual content the variable represents.

server/internal/infrastructure/mongo/asset.go (1)

67-80: Enhanced asset filtering capabilities

The method has been renamed from FindByWorkspace to FindByWorkspaceProject and now includes an additional projectId parameter, allowing assets to be filtered by either project ID or workspace ID. The filter construction is also improved with better type safety using bson.M instead of any.

server/gql/asset.graphql (6)

5-5: Good addition of the projectId field to the Asset type.

This change enables association of assets with specific projects, providing better organization and filtering capabilities.


24-24: LGTM! Consistent extension of the CreateAssetInput.

The projectId field aligns with the Asset type changes and enables project association during asset creation.


29-32: Well-structured UpdateAssetInput definition.

The new input type follows GraphQL best practices with required ID fields and optional update fields.


49-52: Consistent UpdateAssetPayload structure.

The payload structure properly returns the updated entity identifiers.


75-75: Good addition of projectId filter to the assets query.

This enables filtering assets by project, improving query flexibility and performance.


84-84: Complete mutation implementation for asset updates.

The updateAsset mutation integrates well with the new input and payload types.

server/internal/adapter/gql/resolver_team.go (1)

27-28: Method signature and implementation updated correctly for project filtering.

The resolver correctly passes the new projectID parameter to the asset loader's FindByWorkspace method, enabling project-specific asset filtering within teams.

server/gql/storytelling.graphql (3)

23-24: Good addition of Google Analytics fields to the Story type.

These fields will enable GA tracking for stories, enhancing analytics capabilities.


84-86: Well-organized Google Analytics section in UpdateStoryInput.

The grouping with a clear comment improves code readability and maintainability.


73-73: Good documentation improvement.

Converting the commented-out line to an active comment provides better clarity about the Publishment section.

server/internal/adapter/gql/loader_asset.go (4)

39-39: Method signature updated correctly to support project filtering.

The FindByWorkspace method now includes a projectId parameter, enabling more targeted asset queries.


45-52: Good error handling for project ID conversion.

The code properly converts the GraphQL ID to the internal type and handles potential errors.


54-54: Updated method call to renamed backend function.

The call has been updated from FindByWorkspace to FindByWorkspaceProject to reflect the enhanced functionality.


60-66: Performance improvement in edge creation.

Allocating a fixed-size slice upfront instead of using append operations is more efficient for known collection sizes.

server/gql/workspace.graphql (3)

8-14: Approve the addition of projectId parameter for improved asset filtering

The addition of the projectId parameter to the assets field enables more granular filtering of assets by project, which aligns well with the ID property schema refactoring described in the PR title. This is a backward-compatible change since the parameter is optional.


15-21: LGTM for consistent formatting

The reformatting of the projects field maintains consistent argument presentation while preserving the existing functionality.


121-123: LGTM for improved readability

The multi-line formatting of the removeMemberFromTeam mutation input improves readability and consistency with other mutation definitions.

server/internal/usecase/interactor/plugin.go (3)

37-47: LGTM for simplified constructor

The NewPlugin constructor is now simpler with one less dependency, which reduces complexity.


197-198: Approve the consistent approach to ID handling

The change from property.SchemaGroupID(sg) to id.PropertySchemaGroupID(sg) standardizes ID handling across the codebase, moving to a more centralized approach. This aligns with the PR's focus on refactoring ID property schema.


26-35:

❓ Verification inconclusive

Approve removal of layerRepo dependency

The removal of the layerRepo field from the Plugin struct reduces coupling between components, which is generally a good practice for maintainability. Make sure this change doesn't break any functionality that might have been relying on this repository.


🏁 Script executed:

#!/bin/bash
# Verify that layerRepo is not used in any method of the Plugin struct

rg -A 5 -B 5 "i\.layerRepo" --type go

Length of output: 39


Action Required: Manual Verification

The removal of the layerRepo dependency from the Plugin struct seems safe based on our automated search—no usage of layerRepo was found in the Plugin-related methods. However, the verification script produced no output, so please ensure by conducting an additional, manual review of the repository that no indirect dependencies remain that rely on layerRepo.

  • File under review: server/internal/usecase/interactor/plugin.go (Lines: 26-35)
server/e2e/gql_project_test.go (5)

42-42: Approved update to expected project count

The increase in expected edge count from 1 to 2 reflects changes in the project data model or filtering logic, ensuring tests pass with the refactored code.


144-144: Approved update to expected edge count

Increasing the expected edge count from 4 to 5 maintains test accuracy with the updated project handling logic.


560-560: LGTM for improved test flexibility

Switching to ServerAndRepos provides direct access to the repository objects, enabling more comprehensive testing capabilities while maintaining the original test functionality.


585-585: Approved updates to expected counts

The updates to expected totalCount values (20→21, 4→5) and edge counts reflect changes in the project filtering logic, ensuring tests remain valid with the refactored implementation.

Also applies to: 617-617, 620-620


632-632: LGTM for consistent test setup

Consistent application of the ServerAndRepos function across test cases improves maintainability.

server/internal/usecase/interfaces/asset.go (4)

28-28: Approve the ProjectID field addition

Adding the ProjectID field to CreateAssetParam enables associating assets with specific projects during creation, providing more granular control over asset organization. The optional pointer type maintains backward compatibility.


39-39: Approve the method rename and enhanced filtering

Renaming FindByWorkspace to FindByWorkspaceProject clearly indicates the method's ability to filter assets by both workspace and project. The parameter type change from *string to *id.ProjectID improves type safety and aligns with the ID property schema refactoring.


41-41: LGTM for added Update method

The new Update method enhances the asset management capabilities by allowing assets to be reassigned to different projects, providing greater flexibility in organizing assets.


43-43: Approve the enhanced import functionality

Renaming UploadAssetFile to ImportAssetFiles better reflects its purpose, and the addition of the ProjectID parameter enables project-specific asset imports, consistent with the overall approach to project-based asset management.

server/internal/usecase/interactor/plugin_upload.go (2)

292-292: Verify no-op layer deletion logic.

Replacing the layer deletion logic with an empty slice return effectively makes this function a no-op. If you intend to remove layer references or perform cleanup, this change may cause stale data references.


296-296: Verify no-op block deletion logic.

Similarly, returning an empty slice here eliminates block deletion, which can lead to leftover references if not handled elsewhere. Confirm that your data remains consistent when removing plugin extensions.

server/internal/adapter/gql/gqlmodel/convert_property.go (3)

333-335: Retaining metadata references.

The addition of OriginalID and ParentID fields in the returned MergedProperty helps preserve references for merged metadata. Confirm that downstream consumers correctly handle these references.


345-347: Ensure consistent merged property references.

Including OriginalID, ParentID, and SchemaID is beneficial for tracking property origins, parents, and schema usage. Double-check that all references to the old structure are updated accordingly.


389-389: Signature change for ToPropertySchemaGroup.

Switching the second parameter to id.PropertySchemaID may break callers if they were passing property.SchemaID. Ensure all invocations are updated to match the new type.

server/internal/adapter/gql/resolver_query.go (1)

15-16: Added projectId parameter for asset listing.

Introducing the projectId parameter provides more granular filtering of workspace assets. Verify all call sites have been updated and confirm no inadvertent behavior changes.

server/internal/adapter/gql/resolver_mutation_project.go (19)

155-155: Refactored call to ExportProjectData.

Switching from a direct export to ExportProjectData can be more modular. Confirm that all plugin, scene, and property references are handled inside the new export path.


183-183: Asset retrieval for export.

Fetching assets via FindByWorkspaceProject is appropriate. Ensure you handle large sets of assets or potential pagination limits, if applicable.


189-194: Parse asset URL and record file names.

Be mindful of invalid or malformed URLs. If path.Base returns an unexpected result, consider additional validation before mapping names.


197-199: Storing export metadata in data.

Adding project, plugins, and schemas to the export data is a clean approach. Confirm that all required fields (e.g., layering data, style references, etc.) are fully captured if needed.


223-226: Initialize operator and load project data.

You’re retrieving the operator, unmarshalling project data, and calling ImportProjectData. Ensure partial or invalid JSON (e.g., missing keys) is handled gracefully by these steps.


229-232: Transactional handling via defer.

Ending the transaction in a deferred block is correct. Verify you still have the necessary coverage for partial import failures and robust rollback logic if intermediate steps fail.


250-270: Asset loop with name remapping.

• Real asset names are mapped from the old to new ones via the imported ZIP.
• The code replaces any references to the old name in tempData.
• If the unmarshal or rename step fails, consider robust error handling or logs.
• Make sure the replaced substring doesn’t inadvertently match partial text (e.g., partial filenames).


278-278: Importing scene from exported data.

Scene.ImportScene rehydrates scene data from the export. Confirm that plugin or property references align with the newly generated IDs.


297-299: Plugin import step.

ImportPlugins loads and reconfigures plugin data, returning new plugin references. Make sure plugin dependencies within the scene are correctly re-linked if any ID changes occur.


303-304: Scene re-import logic.

Re-importing the scene after plugin import can be beneficial, but watch for double updates if partial data is loaded. Confirm consistent state across the entire import sequence.


307-310: NLS layer import.

ImportNLSLayers might replace or remap layer IDs. Validate that they don’t overlap with newly created plugin or property references.


312-315: Style import.

Imported styles are re-linked to the new scene ID. Confirm style references to geometry or layer objects are also correctly adjusted if they rely on old IDs.


317-320: StoryTelling import.

Similar to other imports, ensure that any references to layers or assets in story slides are fully updated to the new IDs.


322-322: Committing transaction.

Once all scene, plugin, style, and story data is imported, finalizing the transaction is correct. If partial imports are a possibility, ensure early failures roll back progress.


333-334: Returning the combined ProjectData.

Your final payload includes project, plugins, schema, scene, NLS layer, style, and story—comprehensive coverage. Looks good for client consumption.


338-347: Replacing old scene IDs in JSON.

Using bytes.Replace to swap IDs is convenient but poses a risk of partial string collisions. For instance, if oldSceneID is a substring of another ID. Keep an eye on collisions or consider more structured replacement if necessary.


349-357: Unmarshal project data.

You’re ignoring an error when casting to map[string]interface{}. Consider verifying the type assertion before reference to avoid potential runtime issues.


359-373: Unmarshal assets data.

Extracting asset metadata into a map is efficient. If asset references in the JSON are nested or differently typed, confirm no edge cases skip proper parsing.


375-385: Unmarshal plugins, scene, and schemas.

Gathering all relevant data from the JSON in one place is neat. As with other sections, verify type assertions and handle any missing keys gracefully.

server/internal/usecase/interactor/asset.go (4)

39-44: Consider verifying project-level permissions.

Currently, Usecase().WithReadableWorkspaces(tid) only verifies workspace accessibility. If pid is not nil, you might want to confirm that the operator can also read from or write to the specified project before retrieving assets under that project.


91-91: Looks good for associating assets with a project.

Adding the project reference here appears consistent with the broader refactor, aligning asset creation to be project-aware.


108-127: Ensure project permission checks in the Update method.

While this method ensures the operator can write to the asset’s workspace, it does not confirm the operator’s rights on the target project. In some cases, project-level checks may be necessary.


154-182: Revisit permission checks for ImportAssetFiles.

This method now accepts a project ID but does not verify that the caller has access to that project. If this is indirectly guaranteed by higher-level logic, no change is needed. Otherwise, consider enforcing a permission check here as well.

server/internal/adapter/gql/gqlmodel/models_gen.go (6)

120-120: Field addition: ProjectID in Asset.

Adding a nullable projectId field aligns with the new project-based asset flow. No issues spotted.


168-168: Field addition: ProjectID in CreateAssetInput.

Enabling asset creation under specific projects is coherent with the refactoring.


1068-1069: New analytics fields in Story.

The enableGa and trackingId fields extend analytics capabilities for stories. Make sure to handle empty tracking IDs if necessary.


1177-1180: Added UpdateAssetInput.

This new input struct properly captures the updated asset ID and its new (optional) project ID.


1182-1185: Added UpdateAssetPayload.

Returning both assetId and projectId after an update helps confirm the new association.


1304-1305: Optional GA fields in UpdateStoryInput.

Using pointers for enableGa and trackingId makes sense for patch-style GraphQL updates, providing flexible partial updates.

server/e2e/gql_asset_test.go (6)

122-180: Tests for project-based asset association.

Great coverage for:

  • Creating assets under different projects.
  • Verifying retrieval by project.
  • Updating (moving assets between projects or removing the project association).
  • Cleaning up by removing assets.

No particular issues. Nicely done!


181-198: CreateAssetMutation GraphQL definition.

Adding projectId aligns with the new backend logic and is clearly documented.


224-241: updateAsset helper function.

Straightforward approach for updating an asset’s project ID. The GraphQL mutation appears well-structured.


242-257: removeAsset helper function.

Properly encapsulates the GraphQL call for asset removal. This is coherent with the rest of the test utilities.


258-285: createAssetFromFileData helper function.

Similar to createAsset, this version reads from in-memory data. It’s well-managed with a temp file.


287-351: getAssets query helper method.

Incorporates teamId and projectId, offering pagination and sorting. This method nicely complements the test scenarios for verifying newly introduced features.

server/e2e/gql_storytelling_test.go (2)

57-152: Good coverage of page-based operations.
This test thoroughly verifies page creation, duplication, and reordering, including negative scenarios (invalid page ID). The approach is sound and covers key functionality comprehensively.


208-229: Straightforward property updates.
This test successfully verifies property updates of various data types. Adding more boundary or edge-case checks (e.g., invalid data types or overflow values) might further strengthen test coverage.

server/internal/usecase/interactor/project.go (4)

35-47: Struct field organization is consistent.
All required repositories and gateway implementations are declared clearly. Ensure that any unused dependencies are removed in the future to keep the struct streamlined.


52-66: Initialization of the Project interactor is clear.
Assigning each repository and gateway reference is straightforward. Consider verifying if all fields are truly necessary to avoid over-injection.


481-485: Validate the cleanup logic for SceneDeleter dependencies.
When deleting a project, you remove both the scene and associated locks/properties. Ensure that other references to the scene (e.g., from external modules) are handled separately or flagged for cleanup to prevent orphaned data.


551-579: Defaulting alias to empty and coreSupport to true.
The code sets a blank alias, archived=false, and coreSupport=true for imported projects, potentially overriding user-provided values. Make sure this reflects the intended import behavior or allow them to be overridden by the import data.

server/internal/usecase/interactor/storytelling.go (3)

182-189: New GA tracking fields appear consistent with the rest of the story updates.
These additions allow toggling GA and setting the tracking ID. Confirm that dependent logic (e.g., analytics dashboards or user metrics) is fully integrated in subsequent steps or tests.


286-306: Enforce published story policy at the workspace level.
This block of code checks the workspace’s policy before switching from private to published. Confirm that the logic for counting public stories aligns with your overall policy approach (e.g., if stories and projects share the same publication limit).


1128-1140: Improved error handling with custom error variables.
Replacing generic errors with ErrPluginNotFound and ErrExtensionNotFound clarifies the intent. Ensure these errors are documented and surfaced properly to the user for debugging.

server/e2e/gql_project_export_import_test.go (11)

4-8: Imports look good.
These imports (encoding/json, fmt, net/http, strings) are all used within the file, and there appear to be no redundancies or conflicts.


12-13: Additional package imports for ID handling.
Importing internal ID packages from reearth and reearthx aligns with the new test logic.


19-19: Helpful test command comment.
This line clarifies how to run the specific test. No issues found.


34-43: Thorough checks on returned objects.
Verifying that project, plugins, schema, scene, nlsLayer, style, and story are non-null is a solid approach for ensuring the import was successful.


47-48: Lookup for imported data looks correct.
The call to getScene with the newly imported ID is direct and clear.


59-62: File cleanup is properly deferred.
This ensures the exported zip is removed after the test completes.


66-70: Function for line conversion is concise.
convertLine accurately marshals and splits JSON. No issues found.


72-102: Line-by-line comparison logic is robust.
Ignoring certain IDs is a practical approach for dynamic fields. The function is clear.


104-111: isIgnore function is straightforward.
This helper accurately checks if two lines start with the same property name.


143-173: Import logic is sound.
The multipart upload approach is valid, and the test checks for projectData. No issues flagged.


175-189: getScene structure is consistent with the test flow.
Retrieves data from the server for comparison. Approved.

server/e2e/seeder.go (15)

5-13: Expanded imports for random, hex encoding, and file handling.
These additions support asset uploads, random UUID generation, and JSON encoding. No immediate issues noted.


15-29: New references to pkg fields for asset, property, scene, etc.
These reflect the new or expanded usage within seeder functions (full seeder, base seeder, etc.). Everything appears consistent with the domain models.


43-44: Updated project description.
Appending " desc" to pDesc is minor but clarifies the property.


45-45: Scene ID initialization.
Line sets a global ID for the scene. Nothing problematic here.


53-66: baseSeeder now takes a gateway.File.
This parameter injection is consistent with the new asset workflow. No immediate concerns.


68-81: Add language to the user’s data in baseSeederWithLang.
Carrying a language tag is helpful for i18n. The approach to call baseSetup with the file param looks correct.


83-118: baseSetup now creates an asset for the project.
Attaching an image URL to the project is a practical demonstration. Implementation flow is logical.


164-178: fullSeeder extends seeding functionality.
Builds on baseSetup. Good separation of concerns.


219-265: addWidget logic.
This function cleanly builds a new widget, property, and updates the scene. No major concerns beyond ensuring the plugin extension is valid.


267-296: addStory sets up a story with property and page references.
Implementation is straightforward, with correct saving of property and story.


298-322: _createPage for story pages.
Page creation is well-structured: property, blocks, ID. Looks good.


324-352: _createBlock correctly links a plugin extension property.
Checks the extension type and assigns the property. No issues noted.


354-378: addLayerStyle: minimal JSON unmarshal and style creation.
The function is straightforward, applying a scene style with a “marker” config.


380-435: addLayerSimple sets up a basic layer with config and a placeholder property schema.
Allows for geojson data to be attached later. Good separation with addGeoJson.


499-514: UUID generation is standard.
Generates a compliant random UUIDv4. No issues found.

server/e2e/common.go (16)

11-11: Reflection import usage.
reflect is used in the ValueDump function to identify unsupported types. This is a valid approach.


35-43: Introducing global fr and disabledAuthConfig.
Allows skipping auth for tests and referencing a global file pointer. Straightforward for e2e convenience.


45-45: Accepting f gateway.File in the Seeder type.
This lines up with the new asset seeding approach in other files.


51-51: Updated initRepos to return a file.
Ensures that the file gateway is seeded properly for uploading assets.


65-68: Seeding logic.
If a seeder is given, we call it after setting up repos. Straightforward approach.


70-70: Returning both repos and file.
No issues with the final return signature.


74-82: Handling nil fr in initGateway.
Falls back to creating a new file gateway if fr is nil. Clear fallback logic.


138-139: Mongo-based repos get seeded with baseSeeder.
The call is consistent with your approach of passing true for useMongo.


143-147: startServer function merges config, repo init, and server creation.
Centralizing the server start is a clean approach for e2e tests.


149-151: Exported ServerAndRepos: a convenience wrapper.
Offers the same multi-return approach for external usage.


153-156: Exported Server: test server with default config.
Encapsulates startServer usage.


158-161: ServerPingTest: toggles off DB usage.
Handy for basic server availability checks without seeding.


163-174: ServerMockTest: includes mock auth.
Allows local dev testing. No issues found.


177-183: ServerLanguage: specialized seeder call.
Invokes baseSeederWithLang to seed in a specific language.


266-271: JSONEqRegexpValue: no major concerns.
Ensures the output matches the expected JSON pattern using regex.


283-297: ValueDump function for debugging.
Leverages reflection to handle different raw data types. Useful in test contexts.

Comment on lines 56 to 58
func (c *PropertyLoader) FetchMerged(ctx context.Context, org, parent, linked *gqlmodel.ID) (*gqlmodel.MergedProperty, error) {
res, err := c.usecase.FetchMerged(
ctx,
gqlmodel.ToIDRef[id.Property](org),
gqlmodel.ToIDRef[id.Property](parent),
gqlmodel.ToIDRef[id.Dataset](linked),
getOperator(ctx),
)
if err != nil {
return nil, err
}

return gqlmodel.ToMergedProperty(res), nil
return nil, nil
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Emptied implementation might impact dependent code.

The implementation of FetchMerged now just returns nil, nil rather than actually fetching and merging properties. This appears to be part of a larger refactoring effort to simplify property management logic across the codebase, but any code that depends on this method will now receive nil values instead of merged properties.

Consider adding a comment explaining this intentional change, such as whether the functionality has been deprecated, moved elsewhere, or is no longer needed. You can also check which code might be affected by this change:


🏁 Script executed:

#!/bin/bash
# Find references to FetchMerged in the codebase
rg "FetchMerged" --type go

Length of output: 351


Action: Clarify the Intentional Stub in FetchMerged

We’ve confirmed that the FetchMerged method in server/internal/adapter/gql/loader_property.go is still being called in server/internal/adapter/gql/resolver_property.go. Returning nil, nil here means that any resolver relying on a proper merged property will instead receive nil values, which could lead to unexpected behavior. Please add a comment in the method (or a TODO) explaining whether this empty implementation is intentional—such as due to deprecation, a planned refactoring, or a temporary stub—and verify that dependent code can safely handle a nil result.

Comment on lines +557 to +559
u, _ := url.Parse(urlStr)
if err := AddZipAsset(ctx, i.file, zipWriter, u.Path); err != nil {
log.Infofc(ctx, "Fail nLayer addZipAsset :", err.Error())
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid ignoring potential URL parse errors.
Using _ to ignore the error from url.Parse could lead to u being nil, causing unintended behavior when calling AddZipAsset. Properly handle or propagate the parse error:

- u, _ := url.Parse(urlStr)
- if err := AddZipAsset(ctx, i.file, zipWriter, u.Path); err != nil {
-   log.Infofc(ctx, "Fail nLayer addZipAsset :", err.Error())
+ u, err := url.Parse(urlStr)
+ if err != nil {
+   log.Warnfc(ctx, "Invalid URL for nLayer: %s", urlStr)
+ } else {
+   if err := AddZipAsset(ctx, i.file, zipWriter, u.Path); err != nil {
+     log.Infofc(ctx, "Fail nLayer addZipAsset :", err.Error())
+   }
+ }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
u, _ := url.Parse(urlStr)
if err := AddZipAsset(ctx, i.file, zipWriter, u.Path); err != nil {
log.Infofc(ctx, "Fail nLayer addZipAsset :", err.Error())
u, err := url.Parse(urlStr)
if err != nil {
log.Warnfc(ctx, "Invalid URL for nLayer: %s", urlStr)
} else {
if err := AddZipAsset(ctx, i.file, zipWriter, u.Path); err != nil {
log.Infofc(ctx, "Fail nLayer addZipAsset :", err.Error())
}
}

Comment on lines +49 to +57
func (r *Asset) FindByWorkspaceProject(_ context.Context, wid accountdomain.WorkspaceID, pid *id.ProjectID, filter repo.AssetFilter) ([]*asset.Asset, *usecasex.PageInfo, error) {
if !r.f.CanRead(wid) {
return nil, usecasex.EmptyPageInfo(), nil
}

result := r.data.FindAll(func(k id.AssetID, v *asset.Asset) bool {
if pid != nil {
return v.Project() != nil && *v.Project() == *pid && v.CoreSupport() && (filter.Keyword == nil || strings.Contains(v.Name(), *filter.Keyword))
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Missing workspace check when filtering by project ID

When filtering assets by project ID (pid != nil), the implementation only checks if the asset's project matches the provided project ID, but it does not verify if the asset belongs to the given workspace (wid). This could potentially expose assets from other workspaces if they happen to have the same project ID.

Consider adding the workspace check to ensure proper access control:

if pid != nil {
-   return v.Project() != nil && *v.Project() == *pid && v.CoreSupport() && (filter.Keyword == nil || strings.Contains(v.Name(), *filter.Keyword))
+   return v.Workspace() == wid && v.Project() != nil && *v.Project() == *pid && v.CoreSupport() && (filter.Keyword == nil || strings.Contains(v.Name(), *filter.Keyword))
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (r *Asset) FindByWorkspaceProject(_ context.Context, wid accountdomain.WorkspaceID, pid *id.ProjectID, filter repo.AssetFilter) ([]*asset.Asset, *usecasex.PageInfo, error) {
if !r.f.CanRead(wid) {
return nil, usecasex.EmptyPageInfo(), nil
}
result := r.data.FindAll(func(k id.AssetID, v *asset.Asset) bool {
if pid != nil {
return v.Project() != nil && *v.Project() == *pid && v.CoreSupport() && (filter.Keyword == nil || strings.Contains(v.Name(), *filter.Keyword))
}
func (r *Asset) FindByWorkspaceProject(_ context.Context, wid accountdomain.WorkspaceID, pid *id.ProjectID, filter repo.AssetFilter) ([]*asset.Asset, *usecasex.PageInfo, error) {
if !r.f.CanRead(wid) {
return nil, usecasex.EmptyPageInfo(), nil
}
result := r.data.FindAll(func(k id.AssetID, v *asset.Asset) bool {
if pid != nil {
return v.Workspace() == wid && v.Project() != nil && *v.Project() == *pid && v.CoreSupport() && (filter.Keyword == nil || strings.Contains(v.Name(), *filter.Keyword))
}
// ... potentially more code follows
})
// ... remainder of function code
}

Comment on lines 284 to 291
// https://github.com/golang/go/issues/38351
b := *base
b.Path = path.Join(b.Path, filename)
if b.Path == "/" {
b.Path = path.Join(b.Path, assetDir, filename)
} else {
b.Path = path.Join(b.Path, filename)
}
return &b
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Inconsistent URL construction in getAssetFileURL

The function now handles two different scenarios based on the base path, but this creates an inconsistency. When the base path is root ("/"), it includes the asset directory in the constructed path, but when the base path is not root, it doesn't. This might lead to unexpected behavior where assets have different URL patterns depending on the base path.

Consider standardizing the URL construction to always include the asset directory:

func getAssetFileURL(base *url.URL, filename string) *url.URL {
  if base == nil {
    return nil
  }

  // https://github.com/golang/go/issues/38351
  b := *base
- if b.Path == "/" {
-   b.Path = path.Join(b.Path, assetDir, filename)
- } else {
-   b.Path = path.Join(b.Path, filename)
- }
+ b.Path = path.Join(b.Path, assetDir, filename)
  return &b
}

Alternatively, if this is intentional, add a comment explaining the different behaviors.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// https://github.com/golang/go/issues/38351
b := *base
b.Path = path.Join(b.Path, filename)
if b.Path == "/" {
b.Path = path.Join(b.Path, assetDir, filename)
} else {
b.Path = path.Join(b.Path, filename)
}
return &b
func getAssetFileURL(base *url.URL, filename string) *url.URL {
if base == nil {
return nil
}
// https://github.com/golang/go/issues/38351
b := *base
b.Path = path.Join(b.Path, assetDir, filename)
return &b
}

Comment on lines +122 to 142
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": p,
},
}
r := Request(e, uID.String(), requestBody)
// ValueDump(r)
downloadPath := r.Path("$.data.exportProject.projectDataPath").Raw().(string)
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
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Typo in function name and potential rename.
The function is spelled exporProject. It couples well with the GraphQL call, but a rename to exportProject would improve readability.

-func exporProject(t *testing.T, e *httpexpect.Expect, p string) string {
+func exportProject(t *testing.T, e *httpexpect.Expect, p string) string {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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": p,
},
}
r := Request(e, uID.String(), requestBody)
// ValueDump(r)
downloadPath := r.Path("$.data.exportProject.projectDataPath").Raw().(string)
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
}
func exportProject(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": p,
},
}
r := Request(e, uID.String(), requestBody)
// ValueDump(r)
downloadPath := r.Path("$.data.exportProject.projectDataPath").Raw().(string)
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
}

Comment on lines +180 to +217
func fullSetup(ctx context.Context, r *repo.Container) error {
schema := builtin.GetPropertySchemaByVisualizer(visualizer.VisualizerCesiumBeta)
prop, err := property.New().NewID().Schema(schema.ID()).Scene(sID).Build()
if err != nil {
return err
}
ps := scene.NewPlugins([]*scene.Plugin{
scene.NewPlugin(id.OfficialPluginID, nil),
})
s, err := scene.New().ID(sID).
Project(pID).
Workspace(wID).
Property(prop.ID()).
Plugins(ps).
Build()
if err != nil {
return err
}
if err = r.Scene.Save(ctx, s); err != err {
return err
}
if err = r.Property.Save(ctx, prop); err != err {
return err
}
if err = addWidget(ctx, s, r); err != err {
return err
}
if err = addStory(ctx, r); err != err {
return err
}
if err = addLayerSimple(ctx, r); err != err {
return err
}
if err = addLayerStyle(s.ID(), ctx, r); err != err {
return err
}
return nil
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Critical bug in repeated conditions: if err = r.Scene.Save(ctx, s); err != err { ... }.
You likely meant err != nil. As written, err != err is always false and will never handle the error case. Apply the fix in all similar lines here (e.g., lines 198, 201, 204, 207, 210, 213).

- if err = r.Scene.Save(ctx, s); err != err {
+ if err = r.Scene.Save(ctx, s); err != nil {
    return err
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func fullSetup(ctx context.Context, r *repo.Container) error {
schema := builtin.GetPropertySchemaByVisualizer(visualizer.VisualizerCesiumBeta)
prop, err := property.New().NewID().Schema(schema.ID()).Scene(sID).Build()
if err != nil {
return err
}
ps := scene.NewPlugins([]*scene.Plugin{
scene.NewPlugin(id.OfficialPluginID, nil),
})
s, err := scene.New().ID(sID).
Project(pID).
Workspace(wID).
Property(prop.ID()).
Plugins(ps).
Build()
if err != nil {
return err
}
if err = r.Scene.Save(ctx, s); err != err {
return err
}
if err = r.Property.Save(ctx, prop); err != err {
return err
}
if err = addWidget(ctx, s, r); err != err {
return err
}
if err = addStory(ctx, r); err != err {
return err
}
if err = addLayerSimple(ctx, r); err != err {
return err
}
if err = addLayerStyle(s.ID(), ctx, r); err != err {
return err
}
return nil
}
func fullSetup(ctx context.Context, r *repo.Container) error {
schema := builtin.GetPropertySchemaByVisualizer(visualizer.VisualizerCesiumBeta)
prop, err := property.New().NewID().Schema(schema.ID()).Scene(sID).Build()
if err != nil {
return err
}
ps := scene.NewPlugins([]*scene.Plugin{
scene.NewPlugin(id.OfficialPluginID, nil),
})
s, err := scene.New().ID(sID).
Project(pID).
Workspace(wID).
Property(prop.ID()).
Plugins(ps).
Build()
if err != nil {
return err
}
if err = r.Scene.Save(ctx, s); err != nil {
return err
}
if err = r.Property.Save(ctx, prop); err != nil {
return err
}
if err = addWidget(ctx, s, r); err != nil {
return err
}
if err = addStory(ctx, r); err != nil {
return err
}
if err = addLayerSimple(ctx, r); err != nil {
return err
}
if err = addLayerStyle(s.ID(), ctx, r); err != nil {
return err
}
return nil
}

@hexaforce hexaforce changed the title chore(server): refactoring id property schema chore(server): refactoring id property schema [VIZ-BE-574] Feb 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant