diff --git a/server/e2e/common.go b/server/e2e/common.go index 889d9861ed..8eb6b16155 100644 --- a/server/e2e/common.go +++ b/server/e2e/common.go @@ -8,6 +8,7 @@ import ( "io" "net" "net/http" + "reflect" "regexp" "strings" "testing" @@ -59,7 +60,7 @@ func initRepos(t *testing.T, useMongo bool, seeder Seeder) (repos *repo.Containe func initGateway() *gateway.Container { return &gateway.Container{ - File: lo.Must(fs.NewFile(afero.NewMemMapFs(), "https://example.com")), + File: lo.Must(fs.NewFile(afero.NewMemMapFs(), "https://example.com/")), } } @@ -284,6 +285,13 @@ func JSONEqRegexpInterface(t *testing.T, actual interface{}, expected string) bo return JSONEqRegexp(t, string(actualBytes), expected) } +func JSONEqRegexpValue(t *testing.T, actual *httpexpect.Value, expected string) bool { + if actualData, ok := actual.Raw().(map[string]interface{}); ok { + return JSONEqRegexpInterface(t, actualData, expected) + } + return false +} + func aligningJSON(t *testing.T, str string) string { // Unmarshal and Marshal to make the JSON format consistent var obj interface{} @@ -295,9 +303,17 @@ func aligningJSON(t *testing.T, str string) string { } func ValueDump(val *httpexpect.Value) { - if data, ok := val.Raw().(map[string]interface{}); ok { + raw := val.Raw() + switch data := raw.(type) { + case map[string]interface{}: + if text, err := json.MarshalIndent(data, "", " "); err == nil { + fmt.Println(string(text)) + } + case []interface{}: if text, err := json.MarshalIndent(data, "", " "); err == nil { fmt.Println(string(text)) } + default: + fmt.Println("Unsupported type:", reflect.TypeOf(raw)) } } diff --git a/server/e2e/gql_asset_test.go b/server/e2e/gql_asset_test.go index fcb5c539b5..9511427b83 100644 --- a/server/e2e/gql_asset_test.go +++ b/server/e2e/gql_asset_test.go @@ -13,9 +13,9 @@ import ( "github.com/stretchr/testify/assert" ) -// go test -v -run TestGetAssets ./e2e/... +// go test -v -run TestCoreSupportGetAssets ./e2e/... -func TestGetAssets(t *testing.T) { +func TestCoreSupportGetAssets(t *testing.T) { c := &config.Config{ Origins: []string{"https://example.com"}, AuthSrv: config.AuthSrvConfig{ @@ -26,31 +26,64 @@ func TestGetAssets(t *testing.T) { teamId := wID.String() - res := createAsset(t, e, "test.png", true, teamId) - res.Object().Value("data").Object().Value("createAsset").Object().Value("asset").Object(). - HasValue("teamId", teamId). - HasValue("name", "test.png"). - HasValue("coreSupport", true) - - res = createAsset(t, e, "test.png", false, teamId) - res.Object().Value("data").Object().Value("createAsset").Object().Value("asset").Object(). - HasValue("teamId", teamId). - HasValue("name", "test.png"). - HasValue("coreSupport", false) - - res = createAsset(t, e, "test.csv", true, teamId) - res.Object().Value("data").Object().Value("createAsset").Object().Value("asset").Object(). - HasValue("teamId", teamId). - HasValue("name", "test.csv"). - HasValue("coreSupport", true) - - res = createAsset(t, e, "test.csv", false, teamId) - res.Object().Value("data").Object().Value("createAsset").Object().Value("asset").Object(). - HasValue("teamId", teamId). - HasValue("name", "test.csv"). - HasValue("coreSupport", false) + res := createAsset(t, e, "test.png", true, teamId, nil) + a := res.Path("$.data.createAsset.asset") + JSONEqRegexpValue(t, a, `{ + "__typename": "Asset", + "contentType": "", + "coreSupport": true, + "id": ".*", + "name": "test.png", + "projectId": null, + "size": 30438, + "teamId": ".*", + "url": ".*" + }`) + + res = createAsset(t, e, "test.png", false, teamId, nil) + a = res.Path("$.data.createAsset.asset") + JSONEqRegexpValue(t, a, `{ + "__typename": "Asset", + "contentType": "", + "coreSupport": false, + "id": ".*", + "name": "test.png", + "projectId": null, + "size": 30438, + "teamId": ".*", + "url": ".*" + }`) + + res = createAsset(t, e, "test.csv", true, teamId, nil) + a = res.Path("$.data.createAsset.asset") + JSONEqRegexpValue(t, a, `{ + "__typename": "Asset", + "contentType": "", + "coreSupport": true, + "id": ".*", + "name": "test.csv", + "projectId": null, + "size": 231, + "teamId": ".*", + "url": ".*" + }`) + + res = createAsset(t, e, "test.csv", false, teamId, nil) + a = res.Path("$.data.createAsset.asset") + JSONEqRegexpValue(t, a, `{ + "__typename": "Asset", + "contentType": "", + "coreSupport": false, + "id": ".*", + "name": "test.csv", + "projectId": null, + "size": 231, + "teamId": ".*", + "url": ".*" + }`) // Write directly to the DB + ctx := context.Background() a1, err := asset.New(). NewID().Workspace(wID).Name("test.png").Size(30438).URL("https://example.com/xxxxxxxxxxxxxxxxxxxxxxxxxx.png"). @@ -77,7 +110,7 @@ func TestGetAssets(t *testing.T) { assert.Nil(t, err) f := int64(20) - as, _, err := r.Asset.FindByWorkspace(ctx, wID, repo.AssetFilter{ + as, _, err := r.Asset.FindByWorkspace(ctx, wID, nil, repo.AssetFilter{ Pagination: usecasex.CursorPagination{ First: &f, }.Wrap(), @@ -85,31 +118,101 @@ func TestGetAssets(t *testing.T) { assert.Nil(t, err) assert.Equal(t, len(as), 3) - res = getAssets(e, teamId) - assets := res.Object().Value("data").Object().Value("assets").Object().Value("nodes").Array().Iter() + res = getAssets(e, teamId, nil) + assets := res.Path("$.data.assets.nodes").Array().Iter() for _, a := range assets { a.Object().HasValue("coreSupport", true) // coreSupport true only } } -const CreateAssetMutation = `mutation CreateAsset($teamId: ID!, $file: Upload!, $coreSupport: Boolean!) { - createAsset(input: {teamId: $teamId, file: $file, coreSupport: $coreSupport}) { +// go test -v -run TestAssociateProjectGetAssets ./e2e/... + +func TestAssociateProjectGetAssets(t *testing.T) { + + c := &config.Config{ + Origins: []string{"https://example.com"}, + AuthSrv: config.AuthSrvConfig{ + Disabled: true, + }, + } + + e, _, _ := StartServerAndRepos(t, c, true, baseSeeder) + teamId := wID.String() + + // Create projectA >>> test.png + pidA := createProject(e, "projectA") + createAsset(t, e, "test.png", true, teamId, &pidA) + + // Create projectB >>> test.csv + pidB := createProject(e, "projectB") + createAsset(t, e, "test.csv", true, teamId, &pidB) + + // Get projectA >>> test.png + res := getAssets(e, teamId, &pidA) + assets := res.Path("$.data.assets.nodes").Array() + assets.Length().IsEqual(1) + assets.Value(0).Object().HasValue("name", "test.png") + + // Get projectB >>> test.csv + res = getAssets(e, teamId, &pidB) + assets = res.Path("$.data.assets.nodes").Array() + assets.Length().IsEqual(1) + assets.Value(0).Object().HasValue("name", "test.csv") + + // Get none project(Workspace) >>> test.png, test.csv + res = getAssets(e, teamId, nil) + assets = res.Path("$.data.assets.nodes").Array() + assets.Length().IsEqual(2) + assets.Value(0).Object().HasValue("name", "test.csv") + assets.Value(1).Object().HasValue("name", "test.png") + + assetId0 := assets.Value(0).Object().Value("id").Raw().(string) + assetId1 := assets.Value(1).Object().Value("id").Raw().(string) + + // Move projectA(test.png) >>> projectB + updateAsset(e, assetId1, &pidB) + res = getAssets(e, teamId, &pidB) + assets = res.Path("$.data.assets.nodes").Array() + assets.Length().IsEqual(2) // projectB >>> test.png, test.csv + + // Remove projectID test + updateAsset(e, assetId0, nil) // projectID > null + updateAsset(e, assetId1, nil) // projectID > null + + res = getAssets(e, teamId, &pidB) + assets = res.Path("$.data.assets.nodes").Array() + assets.Length().IsEqual(0) // projectB >>> none + + // Remove asset test + removeAsset(e, assetId0) + removeAsset(e, assetId1) + + res = getAssets(e, teamId, nil) + assets = res.Path("$.data.assets.nodes").Array() + assets.Length().IsEqual(0) +} + +const CreateAssetMutation = `mutation CreateAsset($teamId: ID!, $projectId: ID, $file: Upload!, $coreSupport: Boolean!) { + createAsset( + input: {teamId: $teamId, projectId: $projectId, file: $file, coreSupport: $coreSupport} + ) { asset { id teamId + projectId name size url - contentType coreSupport + contentType __typename } __typename } }` -func createAsset(t *testing.T, e *httpexpect.Expect, filePath string, coreSupport bool, teamId string) *httpexpect.Value { +func createAsset(t *testing.T, e *httpexpect.Expect, filePath string, coreSupport bool, teamId string, projectId *string) *httpexpect.Value { file, err := os.Open(filePath) if err != nil { t.Fatalf("failed to open file: %v", err) @@ -123,6 +226,7 @@ func createAsset(t *testing.T, e *httpexpect.Expect, filePath string, coreSuppor "operationName": "CreateAsset", "variables": map[string]interface{}{ "teamId": teamId, + "projectId": projectId, "coreSupport": coreSupport, "file": nil, }, @@ -132,7 +236,41 @@ func createAsset(t *testing.T, e *httpexpect.Expect, filePath string, coreSuppor return RequestWithMultipart(e, uID.String(), requestBody, filePath) } -func createAssetFromFileData(t *testing.T, e *httpexpect.Expect, fileData []byte, coreSupport bool, teamId string) *httpexpect.Value { +func updateAsset(e *httpexpect.Expect, assetId string, projectId *string) *httpexpect.Value { + requestBody := GraphQLRequest{ + OperationName: "UpdateAsset", + Query: `mutation UpdateAsset($assetId: ID!, $projectId: ID) { + updateAsset(input: { assetId: $assetId projectId: $projectId }) { + assetId + projectId + __typename + } + }`, + Variables: map[string]any{ + "assetId": assetId, + "projectId": projectId, + }, + } + return Request(e, uID.String(), requestBody) +} + +func removeAsset(e *httpexpect.Expect, assetId string) *httpexpect.Value { + requestBody := GraphQLRequest{ + OperationName: "RemoveAsset", + Query: `mutation RemoveAsset($assetId: ID!) { + removeAsset(input: { assetId: $assetId }) { + assetId + __typename + } + }`, + Variables: map[string]any{ + "assetId": assetId, + }, + } + return Request(e, uID.String(), requestBody) +} + +func createAssetFromFileData(t *testing.T, e *httpexpect.Expect, fileData []byte, coreSupport bool, teamId string, projectId *string) *httpexpect.Value { tempFile, err := os.CreateTemp("", "requestBody-*.json") if err != nil { t.Fatalf("failed to create temp file: %v", err) @@ -152,6 +290,7 @@ func createAssetFromFileData(t *testing.T, e *httpexpect.Expect, fileData []byte "operationName": "CreateAsset", "variables": map[string]interface{}{ "teamId": teamId, + "projectId": projectId, "coreSupport": coreSupport, "file": nil, }, @@ -160,52 +299,59 @@ func createAssetFromFileData(t *testing.T, e *httpexpect.Expect, fileData []byte return RequestWithMultipart(e, uID.String(), requestBody, tempFile.Name()) } -const GetAssetsQuery = `query GetAssets($teamId: ID!, $pagination: Pagination, $keyword: String, $sort: AssetSort) { - assets(teamId: $teamId, pagination: $pagination, keyword: $keyword, sort: $sort) { - edges { - cursor - node { - id - teamId - name - size - url - createdAt - contentType - coreSupport - __typename - } - __typename - } - nodes { - id - teamId - name - size - url - createdAt - contentType - coreSupport - __typename - } - pageInfo { - endCursor - hasNextPage - hasPreviousPage - startCursor - __typename - } - totalCount - __typename - } - }` - -func getAssets(e *httpexpect.Expect, teamId string) *httpexpect.Value { +func getAssets(e *httpexpect.Expect, teamId string, projectId *string) *httpexpect.Value { requestBody := GraphQLRequest{ OperationName: "GetAssets", - Query: GetAssetsQuery, + Query: `query GetAssets($teamId: ID!, $projectId: ID, $pagination: Pagination, $keyword: String, $sort: AssetSort) { + assets( + teamId: $teamId + projectId: $projectId + pagination: $pagination + keyword: $keyword + sort: $sort + ) { + edges { + cursor + node { + id + teamId + projectId + name + size + url + createdAt + contentType + coreSupport + __typename + } + __typename + } + nodes { + id + teamId + projectId + name + size + url + createdAt + contentType + coreSupport + __typename + } + pageInfo { + endCursor + hasNextPage + hasPreviousPage + startCursor + __typename + } + totalCount + __typename + } +}`, Variables: map[string]any{ - "teamId": teamId, + "teamId": teamId, + "projectId": projectId, "pagination": map[string]any{ "first": 20, }, diff --git a/server/e2e/gql_validate_geojson_test.go b/server/e2e/gql_validate_geojson_test.go index 4359e9b372..eb155571bf 100644 --- a/server/e2e/gql_validate_geojson_test.go +++ b/server/e2e/gql_validate_geojson_test.go @@ -183,7 +183,7 @@ func TestValidateGeoJsonOfAssets(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - res := createAssetFromFileData(t, e, []byte(tt.data), true, teamId) + res := createAssetFromFileData(t, e, []byte(tt.data), true, teamId, nil) title := res.Path("$.data.createAsset.asset.name").Raw().(string) url := res.Path("$.data.createAsset.asset.url").Raw().(string) res = addNLSLayerSimpleByGeojson(e, sId, url, title, 0) diff --git a/server/gql/asset.graphql b/server/gql/asset.graphql index 41e01ff063..1cb6b5fa9a 100644 --- a/server/gql/asset.graphql +++ b/server/gql/asset.graphql @@ -2,6 +2,7 @@ type Asset implements Node { id: ID! createdAt: DateTime! teamId: ID! + projectId: ID name: String! size: FileSize! url: String! @@ -20,10 +21,16 @@ enum AssetSortField { input CreateAssetInput { teamId: ID! + projectId: ID coreSupport: Boolean! file: Upload! } +input UpdateAssetInput { + assetId: ID! + projectId: ID +} + input RemoveAssetInput { assetId: ID! } @@ -39,6 +46,11 @@ type CreateAssetPayload { asset: Asset! } +type UpdateAssetPayload { + assetId: ID! + projectId: ID +} + type RemoveAssetPayload { assetId: ID! } @@ -60,6 +72,7 @@ type AssetEdge { extend type Query { assets( teamId: ID! + projectId: ID pagination: Pagination keyword: String sort: AssetSort @@ -68,5 +81,6 @@ extend type Query { extend type Mutation { createAsset(input: CreateAssetInput!): CreateAssetPayload + updateAsset(input: UpdateAssetInput!): UpdateAssetPayload removeAsset(input: RemoveAssetInput!): RemoveAssetPayload } diff --git a/server/gql/workspace.graphql b/server/gql/workspace.graphql index fa0c64beaf..0e357ee533 100644 --- a/server/gql/workspace.graphql +++ b/server/gql/workspace.graphql @@ -5,8 +5,20 @@ type Team implements Node { personal: Boolean! policyId: ID policy: Policy - assets(first: Int, last: Int, after: Cursor, before: Cursor): AssetConnection! - projects(includeArchived: Boolean, first: Int, last: Int, after: Cursor, before: Cursor): ProjectConnection! + assets( + projectId: ID + first: Int + last: Int + after: Cursor + before: Cursor + ): AssetConnection! + projects( + includeArchived: Boolean + first: Int + last: Int + after: Cursor + before: Cursor + ): ProjectConnection! } type TeamMember { @@ -106,6 +118,8 @@ extend type Mutation { deleteTeam(input: DeleteTeamInput!): DeleteTeamPayload updateTeam(input: UpdateTeamInput!): UpdateTeamPayload addMemberToTeam(input: AddMemberToTeamInput!): AddMemberToTeamPayload - removeMemberFromTeam(input: RemoveMemberFromTeamInput!): RemoveMemberFromTeamPayload + removeMemberFromTeam( + input: RemoveMemberFromTeamInput! + ): RemoveMemberFromTeamPayload updateMemberOfTeam(input: UpdateMemberOfTeamInput!): UpdateMemberOfTeamPayload } diff --git a/server/internal/adapter/gql/generated.go b/server/internal/adapter/gql/generated.go index 5eb946c167..71ed59f0ad 100644 --- a/server/internal/adapter/gql/generated.go +++ b/server/internal/adapter/gql/generated.go @@ -114,6 +114,7 @@ type ComplexityRoot struct { CreatedAt func(childComplexity int) int ID func(childComplexity int) int Name func(childComplexity int) int + ProjectID func(childComplexity int) int Size func(childComplexity int) int Team func(childComplexity int) int TeamID func(childComplexity int) int @@ -494,6 +495,7 @@ type ComplexityRoot struct { Signup func(childComplexity int, input gqlmodel.SignupInput) int UninstallPlugin func(childComplexity int, input gqlmodel.UninstallPluginInput) int UnlinkPropertyValue func(childComplexity int, input gqlmodel.UnlinkPropertyValueInput) int + UpdateAsset func(childComplexity int, input gqlmodel.UpdateAssetInput) int UpdateCustomProperties func(childComplexity int, input gqlmodel.UpdateCustomPropertySchemaInput) int UpdateGeoJSONFeature func(childComplexity int, input gqlmodel.UpdateGeoJSONFeatureInput) int UpdateMe func(childComplexity int, input gqlmodel.UpdateMeInput) int @@ -798,7 +800,7 @@ type ComplexityRoot struct { } Query struct { - Assets func(childComplexity int, teamID gqlmodel.ID, pagination *gqlmodel.Pagination, keyword *string, sort *gqlmodel.AssetSort) int + Assets func(childComplexity int, teamID gqlmodel.ID, projectID *gqlmodel.ID, pagination *gqlmodel.Pagination, keyword *string, sort *gqlmodel.AssetSort) int CheckProjectAlias func(childComplexity int, alias string) int DeletedProjects func(childComplexity int, teamID gqlmodel.ID) int Me func(childComplexity int) int @@ -980,7 +982,7 @@ type ComplexityRoot struct { } Team struct { - Assets func(childComplexity int, first *int, last *int, after *usecasex.Cursor, before *usecasex.Cursor) int + Assets func(childComplexity int, projectID *gqlmodel.ID, first *int, last *int, after *usecasex.Cursor, before *usecasex.Cursor) int ID func(childComplexity int) int Members func(childComplexity int) int Name func(childComplexity int) int @@ -1018,6 +1020,11 @@ type ComplexityRoot struct { Scene func(childComplexity int) int } + UpdateAssetPayload struct { + AssetID func(childComplexity int) int + ProjectID func(childComplexity int) int + } + UpdateMePayload struct { Me func(childComplexity int) int } @@ -1202,6 +1209,7 @@ type MergedPropertyGroupResolver interface { } type MutationResolver interface { CreateAsset(ctx context.Context, input gqlmodel.CreateAssetInput) (*gqlmodel.CreateAssetPayload, error) + UpdateAsset(ctx context.Context, input gqlmodel.UpdateAssetInput) (*gqlmodel.UpdateAssetPayload, error) RemoveAsset(ctx context.Context, input gqlmodel.RemoveAssetInput) (*gqlmodel.RemoveAssetPayload, error) AddGeoJSONFeature(ctx context.Context, input gqlmodel.AddGeoJSONFeatureInput) (*gqlmodel.Feature, error) UpdateGeoJSONFeature(ctx context.Context, input gqlmodel.UpdateGeoJSONFeatureInput) (*gqlmodel.Feature, error) @@ -1338,7 +1346,7 @@ type PropertySchemaGroupResolver interface { type QueryResolver interface { Node(ctx context.Context, id gqlmodel.ID, typeArg gqlmodel.NodeType) (gqlmodel.Node, error) Nodes(ctx context.Context, id []gqlmodel.ID, typeArg gqlmodel.NodeType) ([]gqlmodel.Node, error) - Assets(ctx context.Context, teamID gqlmodel.ID, pagination *gqlmodel.Pagination, keyword *string, sort *gqlmodel.AssetSort) (*gqlmodel.AssetConnection, error) + Assets(ctx context.Context, teamID gqlmodel.ID, projectID *gqlmodel.ID, pagination *gqlmodel.Pagination, keyword *string, sort *gqlmodel.AssetSort) (*gqlmodel.AssetConnection, error) Plugin(ctx context.Context, id gqlmodel.ID) (*gqlmodel.Plugin, error) Plugins(ctx context.Context, id []gqlmodel.ID) ([]*gqlmodel.Plugin, error) Projects(ctx context.Context, teamID gqlmodel.ID, pagination *gqlmodel.Pagination, keyword *string, sort *gqlmodel.ProjectSort) (*gqlmodel.ProjectConnection, error) @@ -1392,7 +1400,7 @@ type StyleResolver interface { } type TeamResolver interface { Policy(ctx context.Context, obj *gqlmodel.Team) (*gqlmodel.Policy, error) - Assets(ctx context.Context, obj *gqlmodel.Team, first *int, last *int, after *usecasex.Cursor, before *usecasex.Cursor) (*gqlmodel.AssetConnection, error) + Assets(ctx context.Context, obj *gqlmodel.Team, projectID *gqlmodel.ID, first *int, last *int, after *usecasex.Cursor, before *usecasex.Cursor) (*gqlmodel.AssetConnection, error) Projects(ctx context.Context, obj *gqlmodel.Team, includeArchived *bool, first *int, last *int, after *usecasex.Cursor, before *usecasex.Cursor) (*gqlmodel.ProjectConnection, error) } type TeamMemberResolver interface { @@ -1502,6 +1510,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Asset.Name(childComplexity), true + case "Asset.projectId": + if e.complexity.Asset.ProjectID == nil { + break + } + + return e.complexity.Asset.ProjectID(childComplexity), true + case "Asset.size": if e.complexity.Asset.Size == nil { break @@ -3524,6 +3539,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.UnlinkPropertyValue(childComplexity, args["input"].(gqlmodel.UnlinkPropertyValueInput)), true + case "Mutation.updateAsset": + if e.complexity.Mutation.UpdateAsset == nil { + break + } + + args, err := ec.field_Mutation_updateAsset_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.UpdateAsset(childComplexity, args["input"].(gqlmodel.UpdateAssetInput)), true + case "Mutation.updateCustomProperties": if e.complexity.Mutation.UpdateCustomProperties == nil { break @@ -5219,7 +5246,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return 0, false } - return e.complexity.Query.Assets(childComplexity, args["teamId"].(gqlmodel.ID), args["pagination"].(*gqlmodel.Pagination), args["keyword"].(*string), args["sort"].(*gqlmodel.AssetSort)), true + return e.complexity.Query.Assets(childComplexity, args["teamId"].(gqlmodel.ID), args["projectId"].(*gqlmodel.ID), args["pagination"].(*gqlmodel.Pagination), args["keyword"].(*string), args["sort"].(*gqlmodel.AssetSort)), true case "Query.checkProjectAlias": if e.complexity.Query.CheckProjectAlias == nil { @@ -6096,7 +6123,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return 0, false } - return e.complexity.Team.Assets(childComplexity, args["first"].(*int), args["last"].(*int), args["after"].(*usecasex.Cursor), args["before"].(*usecasex.Cursor)), true + return e.complexity.Team.Assets(childComplexity, args["projectId"].(*gqlmodel.ID), args["first"].(*int), args["last"].(*int), args["after"].(*usecasex.Cursor), args["before"].(*usecasex.Cursor)), true case "Team.id": if e.complexity.Team.ID == nil { @@ -6264,6 +6291,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.UninstallPluginPayload.Scene(childComplexity), true + case "UpdateAssetPayload.assetId": + if e.complexity.UpdateAssetPayload.AssetID == nil { + break + } + + return e.complexity.UpdateAssetPayload.AssetID(childComplexity), true + + case "UpdateAssetPayload.projectId": + if e.complexity.UpdateAssetPayload.ProjectID == nil { + break + } + + return e.complexity.UpdateAssetPayload.ProjectID(childComplexity), true + case "UpdateMePayload.me": if e.complexity.UpdateMePayload.Me == nil { break @@ -6642,6 +6683,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputSignupInput, ec.unmarshalInputUninstallPluginInput, ec.unmarshalInputUnlinkPropertyValueInput, + ec.unmarshalInputUpdateAssetInput, ec.unmarshalInputUpdateCustomPropertySchemaInput, ec.unmarshalInputUpdateGeoJSONFeatureInput, ec.unmarshalInputUpdateMeInput, @@ -6893,6 +6935,7 @@ schema { id: ID! createdAt: DateTime! teamId: ID! + projectId: ID name: String! size: FileSize! url: String! @@ -6911,10 +6954,16 @@ enum AssetSortField { input CreateAssetInput { teamId: ID! + projectId: ID coreSupport: Boolean! file: Upload! } +input UpdateAssetInput { + assetId: ID! + projectId: ID +} + input RemoveAssetInput { assetId: ID! } @@ -6930,6 +6979,11 @@ type CreateAssetPayload { asset: Asset! } +type UpdateAssetPayload { + assetId: ID! + projectId: ID +} + type RemoveAssetPayload { assetId: ID! } @@ -6951,6 +7005,7 @@ type AssetEdge { extend type Query { assets( teamId: ID! + projectId: ID pagination: Pagination keyword: String sort: AssetSort @@ -6959,6 +7014,7 @@ extend type Query { extend type Mutation { createAsset(input: CreateAssetInput!): CreateAssetPayload + updateAsset(input: UpdateAssetInput!): UpdateAssetPayload removeAsset(input: RemoveAssetInput!): RemoveAssetPayload } `, BuiltIn: false}, @@ -8548,8 +8604,20 @@ extend type Mutation { personal: Boolean! policyId: ID policy: Policy - assets(first: Int, last: Int, after: Cursor, before: Cursor): AssetConnection! - projects(includeArchived: Boolean, first: Int, last: Int, after: Cursor, before: Cursor): ProjectConnection! + assets( + projectId: ID + first: Int + last: Int + after: Cursor + before: Cursor + ): AssetConnection! + projects( + includeArchived: Boolean + first: Int + last: Int + after: Cursor + before: Cursor + ): ProjectConnection! } type TeamMember { @@ -8649,7 +8717,9 @@ extend type Mutation { deleteTeam(input: DeleteTeamInput!): DeleteTeamPayload updateTeam(input: UpdateTeamInput!): UpdateTeamPayload addMemberToTeam(input: AddMemberToTeamInput!): AddMemberToTeamPayload - removeMemberFromTeam(input: RemoveMemberFromTeamInput!): RemoveMemberFromTeamPayload + removeMemberFromTeam( + input: RemoveMemberFromTeamInput! + ): RemoveMemberFromTeamPayload updateMemberOfTeam(input: UpdateMemberOfTeamInput!): UpdateMemberOfTeamPayload } `, BuiltIn: false}, @@ -10144,6 +10214,34 @@ func (ec *executionContext) field_Mutation_unlinkPropertyValue_argsInput( return zeroVal, nil } +func (ec *executionContext) field_Mutation_updateAsset_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_updateAsset_argsInput(ctx, rawArgs) + if err != nil { + return nil, err + } + args["input"] = arg0 + return args, nil +} +func (ec *executionContext) field_Mutation_updateAsset_argsInput( + ctx context.Context, + rawArgs map[string]any, +) (gqlmodel.UpdateAssetInput, error) { + if _, ok := rawArgs["input"]; !ok { + var zeroVal gqlmodel.UpdateAssetInput + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + if tmp, ok := rawArgs["input"]; ok { + return ec.unmarshalNUpdateAssetInput2githubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐUpdateAssetInput(ctx, tmp) + } + + var zeroVal gqlmodel.UpdateAssetInput + return zeroVal, nil +} + func (ec *executionContext) field_Mutation_updateCustomProperties_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -10992,21 +11090,26 @@ func (ec *executionContext) field_Query_assets_args(ctx context.Context, rawArgs return nil, err } args["teamId"] = arg0 - arg1, err := ec.field_Query_assets_argsPagination(ctx, rawArgs) + arg1, err := ec.field_Query_assets_argsProjectID(ctx, rawArgs) if err != nil { return nil, err } - args["pagination"] = arg1 - arg2, err := ec.field_Query_assets_argsKeyword(ctx, rawArgs) + args["projectId"] = arg1 + arg2, err := ec.field_Query_assets_argsPagination(ctx, rawArgs) if err != nil { return nil, err } - args["keyword"] = arg2 - arg3, err := ec.field_Query_assets_argsSort(ctx, rawArgs) + args["pagination"] = arg2 + arg3, err := ec.field_Query_assets_argsKeyword(ctx, rawArgs) if err != nil { return nil, err } - args["sort"] = arg3 + args["keyword"] = arg3 + arg4, err := ec.field_Query_assets_argsSort(ctx, rawArgs) + if err != nil { + return nil, err + } + args["sort"] = arg4 return args, nil } func (ec *executionContext) field_Query_assets_argsTeamID( @@ -11027,6 +11130,24 @@ func (ec *executionContext) field_Query_assets_argsTeamID( return zeroVal, nil } +func (ec *executionContext) field_Query_assets_argsProjectID( + ctx context.Context, + rawArgs map[string]any, +) (*gqlmodel.ID, error) { + if _, ok := rawArgs["projectId"]; !ok { + var zeroVal *gqlmodel.ID + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("projectId")) + if tmp, ok := rawArgs["projectId"]; ok { + return ec.unmarshalOID2ᚖgithub.comᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐID(ctx, tmp) + } + + var zeroVal *gqlmodel.ID + return zeroVal, nil +} + func (ec *executionContext) field_Query_assets_argsPagination( ctx context.Context, rawArgs map[string]any, @@ -11535,28 +11656,51 @@ func (ec *executionContext) field_Query_starredProjects_argsTeamID( func (ec *executionContext) field_Team_assets_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} - arg0, err := ec.field_Team_assets_argsFirst(ctx, rawArgs) + arg0, err := ec.field_Team_assets_argsProjectID(ctx, rawArgs) + if err != nil { + return nil, err + } + args["projectId"] = arg0 + arg1, err := ec.field_Team_assets_argsFirst(ctx, rawArgs) if err != nil { return nil, err } - args["first"] = arg0 - arg1, err := ec.field_Team_assets_argsLast(ctx, rawArgs) + args["first"] = arg1 + arg2, err := ec.field_Team_assets_argsLast(ctx, rawArgs) if err != nil { return nil, err } - args["last"] = arg1 - arg2, err := ec.field_Team_assets_argsAfter(ctx, rawArgs) + args["last"] = arg2 + arg3, err := ec.field_Team_assets_argsAfter(ctx, rawArgs) if err != nil { return nil, err } - args["after"] = arg2 - arg3, err := ec.field_Team_assets_argsBefore(ctx, rawArgs) + args["after"] = arg3 + arg4, err := ec.field_Team_assets_argsBefore(ctx, rawArgs) if err != nil { return nil, err } - args["before"] = arg3 + args["before"] = arg4 return args, nil } +func (ec *executionContext) field_Team_assets_argsProjectID( + ctx context.Context, + rawArgs map[string]any, +) (*gqlmodel.ID, error) { + if _, ok := rawArgs["projectId"]; !ok { + var zeroVal *gqlmodel.ID + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("projectId")) + if tmp, ok := rawArgs["projectId"]; ok { + return ec.unmarshalOID2ᚖgithub.comᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐID(ctx, tmp) + } + + var zeroVal *gqlmodel.ID + return zeroVal, nil +} + func (ec *executionContext) field_Team_assets_argsFirst( ctx context.Context, rawArgs map[string]any, @@ -12437,6 +12581,47 @@ func (ec *executionContext) fieldContext_Asset_teamId(_ context.Context, field g return fc, nil } +func (ec *executionContext) _Asset_projectId(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.Asset) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Asset_projectId(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) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.ProjectID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*gqlmodel.ID) + fc.Result = res + return ec.marshalOID2ᚖgithub.comᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐID(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Asset_projectId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Asset", + 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) _Asset_name(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.Asset) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Asset_name(ctx, field) if err != nil { @@ -12811,6 +12996,8 @@ func (ec *executionContext) fieldContext_AssetConnection_nodes(_ context.Context return ec.fieldContext_Asset_createdAt(ctx, field) case "teamId": return ec.fieldContext_Asset_teamId(ctx, field) + case "projectId": + return ec.fieldContext_Asset_projectId(ctx, field) case "name": return ec.fieldContext_Asset_name(ctx, field) case "size": @@ -13014,6 +13201,8 @@ func (ec *executionContext) fieldContext_AssetEdge_node(_ context.Context, field return ec.fieldContext_Asset_createdAt(ctx, field) case "teamId": return ec.fieldContext_Asset_teamId(ctx, field) + case "projectId": + return ec.fieldContext_Asset_projectId(ctx, field) case "name": return ec.fieldContext_Asset_name(ctx, field) case "size": @@ -13386,6 +13575,8 @@ func (ec *executionContext) fieldContext_CreateAssetPayload_asset(_ context.Cont return ec.fieldContext_Asset_createdAt(ctx, field) case "teamId": return ec.fieldContext_Asset_teamId(ctx, field) + case "projectId": + return ec.fieldContext_Asset_projectId(ctx, field) case "name": return ec.fieldContext_Asset_name(ctx, field) case "size": @@ -22952,6 +23143,64 @@ func (ec *executionContext) fieldContext_Mutation_createAsset(ctx context.Contex return fc, nil } +func (ec *executionContext) _Mutation_updateAsset(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_updateAsset(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) (any, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().UpdateAsset(rctx, fc.Args["input"].(gqlmodel.UpdateAssetInput)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*gqlmodel.UpdateAssetPayload) + fc.Result = res + return ec.marshalOUpdateAssetPayload2ᚖgithub.comᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐUpdateAssetPayload(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_updateAsset(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "assetId": + return ec.fieldContext_UpdateAssetPayload_assetId(ctx, field) + case "projectId": + return ec.fieldContext_UpdateAssetPayload_projectId(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type UpdateAssetPayload", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_updateAsset_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Mutation_removeAsset(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Mutation_removeAsset(ctx, field) if err != nil { @@ -36973,7 +37222,7 @@ func (ec *executionContext) _Query_assets(ctx context.Context, field graphql.Col }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Assets(rctx, fc.Args["teamId"].(gqlmodel.ID), fc.Args["pagination"].(*gqlmodel.Pagination), fc.Args["keyword"].(*string), fc.Args["sort"].(*gqlmodel.AssetSort)) + return ec.resolvers.Query().Assets(rctx, fc.Args["teamId"].(gqlmodel.ID), fc.Args["projectId"].(*gqlmodel.ID), fc.Args["pagination"].(*gqlmodel.Pagination), fc.Args["keyword"].(*string), fc.Args["sort"].(*gqlmodel.AssetSort)) }) if err != nil { ec.Error(ctx, err) @@ -43471,7 +43720,7 @@ func (ec *executionContext) _Team_assets(ctx context.Context, field graphql.Coll }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Team().Assets(rctx, obj, fc.Args["first"].(*int), fc.Args["last"].(*int), fc.Args["after"].(*usecasex.Cursor), fc.Args["before"].(*usecasex.Cursor)) + return ec.resolvers.Team().Assets(rctx, obj, fc.Args["projectId"].(*gqlmodel.ID), fc.Args["first"].(*int), fc.Args["last"].(*int), fc.Args["after"].(*usecasex.Cursor), fc.Args["before"].(*usecasex.Cursor)) }) if err != nil { ec.Error(ctx, err) @@ -44297,6 +44546,91 @@ func (ec *executionContext) fieldContext_UninstallPluginPayload_scene(_ context. return fc, nil } +func (ec *executionContext) _UpdateAssetPayload_assetId(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.UpdateAssetPayload) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_UpdateAssetPayload_assetId(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) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.AssetID, 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_UpdateAssetPayload_assetId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "UpdateAssetPayload", + 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) _UpdateAssetPayload_projectId(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.UpdateAssetPayload) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_UpdateAssetPayload_projectId(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) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.ProjectID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*gqlmodel.ID) + fc.Result = res + return ec.marshalOID2ᚖgithub.comᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐID(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_UpdateAssetPayload_projectId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "UpdateAssetPayload", + 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) _UpdateMePayload_me(ctx context.Context, field graphql.CollectedField, obj *gqlmodel.UpdateMePayload) (ret graphql.Marshaler) { fc, err := ec.fieldContext_UpdateMePayload_me(ctx, field) if err != nil { @@ -48997,7 +49331,7 @@ func (ec *executionContext) unmarshalInputCreateAssetInput(ctx context.Context, asMap[k] = v } - fieldsInOrder := [...]string{"teamId", "coreSupport", "file"} + fieldsInOrder := [...]string{"teamId", "projectId", "coreSupport", "file"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -49011,6 +49345,13 @@ func (ec *executionContext) unmarshalInputCreateAssetInput(ctx context.Context, return it, err } it.TeamID = data + case "projectId": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("projectId")) + data, err := ec.unmarshalOID2ᚖgithub.comᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐID(ctx, v) + if err != nil { + return it, err + } + it.ProjectID = data case "coreSupport": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("coreSupport")) data, err := ec.unmarshalNBoolean2bool(ctx, v) @@ -50785,6 +51126,40 @@ func (ec *executionContext) unmarshalInputUnlinkPropertyValueInput(ctx context.C return it, nil } +func (ec *executionContext) unmarshalInputUpdateAssetInput(ctx context.Context, obj any) (gqlmodel.UpdateAssetInput, error) { + var it gqlmodel.UpdateAssetInput + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"assetId", "projectId"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "assetId": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("assetId")) + data, err := ec.unmarshalNID2githubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐID(ctx, v) + if err != nil { + return it, err + } + it.AssetID = data + case "projectId": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("projectId")) + data, err := ec.unmarshalOID2ᚖgithub.comᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐID(ctx, v) + if err != nil { + return it, err + } + it.ProjectID = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputUpdateCustomPropertySchemaInput(ctx context.Context, obj any) (gqlmodel.UpdateCustomPropertySchemaInput, error) { var it gqlmodel.UpdateCustomPropertySchemaInput asMap := map[string]any{} @@ -52427,6 +52802,8 @@ func (ec *executionContext) _Asset(ctx context.Context, sel ast.SelectionSet, ob if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } + case "projectId": + out.Values[i] = ec._Asset_projectId(ctx, field, obj) case "name": out.Values[i] = ec._Asset_name(ctx, field, obj) if out.Values[i] == graphql.Null { @@ -56245,6 +56622,10 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_createAsset(ctx, field) }) + case "updateAsset": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_updateAsset(ctx, field) + }) case "removeAsset": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { return ec._Mutation_removeAsset(ctx, field) @@ -61834,6 +62215,47 @@ func (ec *executionContext) _UninstallPluginPayload(ctx context.Context, sel ast return out } +var updateAssetPayloadImplementors = []string{"UpdateAssetPayload"} + +func (ec *executionContext) _UpdateAssetPayload(ctx context.Context, sel ast.SelectionSet, obj *gqlmodel.UpdateAssetPayload) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, updateAssetPayloadImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("UpdateAssetPayload") + case "assetId": + out.Values[i] = ec._UpdateAssetPayload_assetId(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "projectId": + out.Values[i] = ec._UpdateAssetPayload_projectId(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var updateMePayloadImplementors = []string{"UpdateMePayload"} func (ec *executionContext) _UpdateMePayload(ctx context.Context, sel ast.SelectionSet, obj *gqlmodel.UpdateMePayload) graphql.Marshaler { @@ -65700,6 +66122,11 @@ func (ec *executionContext) unmarshalNUnlinkPropertyValueInput2githubᚗcomᚋre return res, graphql.ErrorOnPath(ctx, err) } +func (ec *executionContext) unmarshalNUpdateAssetInput2githubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐUpdateAssetInput(ctx context.Context, v any) (gqlmodel.UpdateAssetInput, error) { + res, err := ec.unmarshalInputUpdateAssetInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) unmarshalNUpdateCustomPropertySchemaInput2githubᚗcomᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐUpdateCustomPropertySchemaInput(ctx context.Context, v any) (gqlmodel.UpdateCustomPropertySchemaInput, error) { res, err := ec.unmarshalInputUpdateCustomPropertySchemaInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -67107,6 +67534,13 @@ func (ec *executionContext) marshalOUninstallPluginPayload2ᚖgithub.comᚋree return ec._UninstallPluginPayload(ctx, sel, v) } +func (ec *executionContext) marshalOUpdateAssetPayload2ᚖgithub.comᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐUpdateAssetPayload(ctx context.Context, sel ast.SelectionSet, v *gqlmodel.UpdateAssetPayload) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._UpdateAssetPayload(ctx, sel, v) +} + func (ec *executionContext) marshalOUpdateMePayload2ᚖgithub.comᚋreearthᚋreearthᚋserverᚋinternalᚋadapterᚋgqlᚋgqlmodelᚐUpdateMePayload(ctx context.Context, sel ast.SelectionSet, v *gqlmodel.UpdateMePayload) graphql.Marshaler { if v == nil { return graphql.Null diff --git a/server/internal/adapter/gql/gqlmodel/convert_asset.go b/server/internal/adapter/gql/gqlmodel/convert_asset.go index 8d9d145818..6e6f3a0821 100644 --- a/server/internal/adapter/gql/gqlmodel/convert_asset.go +++ b/server/internal/adapter/gql/gqlmodel/convert_asset.go @@ -9,10 +9,17 @@ func ToAsset(a *asset.Asset) *Asset { return nil } + var pid *ID + if project := a.Project(); project != nil { + pidValue := IDFrom(*a.Project()) + pid = &pidValue + } + return &Asset{ ID: IDFrom(a.ID()), CreatedAt: a.CreatedAt(), TeamID: IDFrom(a.Workspace()), + ProjectID: pid, Name: a.Name(), Size: a.Size(), URL: a.URL(), diff --git a/server/internal/adapter/gql/gqlmodel/models_gen.go b/server/internal/adapter/gql/gqlmodel/models_gen.go index c530c6b23a..a51c0c5327 100644 --- a/server/internal/adapter/gql/gqlmodel/models_gen.go +++ b/server/internal/adapter/gql/gqlmodel/models_gen.go @@ -135,6 +135,7 @@ type Asset struct { ID ID `json:"id"` CreatedAt time.Time `json:"createdAt"` TeamID ID `json:"teamId"` + ProjectID *ID `json:"projectId,omitempty"` Name string `json:"name"` Size int64 `json:"size"` URL string `json:"url"` @@ -182,6 +183,7 @@ type ChangeCustomPropertyTitleInput struct { type CreateAssetInput struct { TeamID ID `json:"teamId"` + ProjectID *ID `json:"projectId,omitempty"` CoreSupport bool `json:"coreSupport"` File graphql.Upload `json:"file"` } @@ -1325,6 +1327,16 @@ type UnlinkPropertyValueInput struct { FieldID ID `json:"fieldId"` } +type UpdateAssetInput struct { + AssetID ID `json:"assetId"` + ProjectID *ID `json:"projectId,omitempty"` +} + +type UpdateAssetPayload struct { + AssetID ID `json:"assetId"` + ProjectID *ID `json:"projectId,omitempty"` +} + type UpdateCustomPropertySchemaInput struct { LayerID ID `json:"layerId"` Schema JSON `json:"schema,omitempty"` diff --git a/server/internal/adapter/gql/loader_asset.go b/server/internal/adapter/gql/loader_asset.go index 28567123b1..0db5442d88 100644 --- a/server/internal/adapter/gql/loader_asset.go +++ b/server/internal/adapter/gql/loader_asset.go @@ -9,6 +9,7 @@ import ( "github.com/reearth/reearth/server/pkg/asset" "github.com/reearth/reearth/server/pkg/id" "github.com/reearth/reearthx/account/accountdomain" + "github.com/reearth/reearthx/idx" "github.com/reearth/reearthx/usecasex" "github.com/reearth/reearthx/util" ) @@ -35,24 +36,33 @@ func (c *AssetLoader) Fetch(ctx context.Context, ids []gqlmodel.ID) ([]*gqlmodel return util.Map(res, gqlmodel.ToAsset), nil } -func (c *AssetLoader) FindByWorkspace(ctx context.Context, wsID gqlmodel.ID, keyword *string, sort *asset.SortType, pagination *gqlmodel.Pagination) (*gqlmodel.AssetConnection, error) { +func (c *AssetLoader) FindByWorkspace(ctx context.Context, wsID gqlmodel.ID, proId *gqlmodel.ID, keyword *string, sort *asset.SortType, pagination *gqlmodel.Pagination) (*gqlmodel.AssetConnection, error) { tid, err := gqlmodel.ToID[accountdomain.Workspace](wsID) if err != nil { return nil, err } - assets, pi, err := c.usecase.FindByWorkspace(ctx, tid, keyword, sort, gqlmodel.ToPagination(pagination), getOperator(ctx)) + var pid *idx.ID[id.Project] + if proId != nil { + pidValue, err := gqlmodel.ToID[id.Project](*proId) + if err != nil { + return nil, err + } + pid = &pidValue + } + + assets, pi, err := c.usecase.FindByWorkspace(ctx, tid, pid, keyword, sort, gqlmodel.ToPagination(pagination), getOperator(ctx)) if err != nil { return nil, err } nodes := gqlmodel.ToAssets(assets) - edges := make([]*gqlmodel.AssetEdge, 0, len(nodes)) - for _, asset := range nodes { - edges = append(edges, &gqlmodel.AssetEdge{ + edges := make([]*gqlmodel.AssetEdge, len(nodes)) + for i, asset := range nodes { + edges[i] = &gqlmodel.AssetEdge{ Node: asset, Cursor: usecasex.Cursor(asset.ID), - }) + } } return &gqlmodel.AssetConnection{ diff --git a/server/internal/adapter/gql/resolver_mutation_asset.go b/server/internal/adapter/gql/resolver_mutation_asset.go index bc783554b1..cfd91505b6 100644 --- a/server/internal/adapter/gql/resolver_mutation_asset.go +++ b/server/internal/adapter/gql/resolver_mutation_asset.go @@ -7,6 +7,7 @@ import ( "github.com/reearth/reearth/server/internal/usecase/interfaces" "github.com/reearth/reearth/server/pkg/id" "github.com/reearth/reearthx/account/accountdomain" + "github.com/reearth/reearthx/idx" ) func (r *mutationResolver) CreateAsset(ctx context.Context, input gqlmodel.CreateAssetInput) (*gqlmodel.CreateAssetPayload, error) { @@ -15,8 +16,18 @@ func (r *mutationResolver) CreateAsset(ctx context.Context, input gqlmodel.Creat return nil, err } + var pid *idx.ID[id.Project] + if input.ProjectID != nil { + pidValue, err := gqlmodel.ToID[id.Project](*input.ProjectID) + if err != nil { + return nil, err + } + pid = &pidValue + } + res, err := usecases(ctx).Asset.Create(ctx, interfaces.CreateAssetParam{ WorkspaceID: tid, + ProjectID: pid, CoreSupport: input.CoreSupport, File: gqlmodel.FromFile(&input.File), }, getOperator(ctx)) @@ -27,6 +38,29 @@ func (r *mutationResolver) CreateAsset(ctx context.Context, input gqlmodel.Creat return &gqlmodel.CreateAssetPayload{Asset: gqlmodel.ToAsset(res)}, nil } +func (r *mutationResolver) UpdateAsset(ctx context.Context, input gqlmodel.UpdateAssetInput) (*gqlmodel.UpdateAssetPayload, error) { + aid, err := gqlmodel.ToID[id.Asset](input.AssetID) + if err != nil { + return nil, err + } + + var pid *id.ProjectID + if project := input.ProjectID; project != nil { + pidValue, err := gqlmodel.ToID[id.Project](*input.ProjectID) + if err != nil { + return nil, err + } + pid = &pidValue + } + + a, p, err2 := usecases(ctx).Asset.Update(ctx, aid, pid, getOperator(ctx)) + if err2 != nil { + return nil, err2 + } + + return &gqlmodel.UpdateAssetPayload{AssetID: gqlmodel.IDFrom(a), ProjectID: gqlmodel.IDFromRef(p)}, nil +} + func (r *mutationResolver) RemoveAsset(ctx context.Context, input gqlmodel.RemoveAssetInput) (*gqlmodel.RemoveAssetPayload, error) { aid, err := gqlmodel.ToID[id.Asset](input.AssetID) if err != nil { diff --git a/server/internal/adapter/gql/resolver_mutation_project.go b/server/internal/adapter/gql/resolver_mutation_project.go index 4c779a38be..519c8b1452 100644 --- a/server/internal/adapter/gql/resolver_mutation_project.go +++ b/server/internal/adapter/gql/resolver_mutation_project.go @@ -181,7 +181,7 @@ func (r *mutationResolver) ExportProject(ctx context.Context, input gqlmodel.Exp Key: "id", Desc: true, } - assets, _, err := usecases(ctx).Asset.FindByWorkspace(ctx, prj.Workspace(), nil, sort, page, getOperator(ctx)) + assets, _, err := usecases(ctx).Asset.FindByWorkspace(ctx, prj.Workspace(), nil, nil, sort, page, getOperator(ctx)) if err != nil { return nil, errors.New("Fail ExportAsset :" + err.Error()) } @@ -259,6 +259,17 @@ func (r *mutationResolver) ImportProject(ctx context.Context, input gqlmodel.Imp return nil, errors.New("Fail UncompressExportZip :" + err.Error()) } + projectData, _ := unmarshalProject(tempData) + prj, tx, err := usecases(ctx).Project.ImportProject(ctx, workspace.String(), projectData) + if err != nil { + return nil, errors.New("Fail ImportProject :" + err.Error()) + } + defer func() { + if err2 := tx.End(ctx); err == nil && err2 != nil { + err = err2 + } + }() + // Assets file import assetNames, _ := unmarshalAssets(tempData) for fileName, file := range assets { @@ -273,7 +284,11 @@ func (r *mutationResolver) ImportProject(ctx context.Context, input gqlmodel.Imp } } - url, _, err := usecases(ctx).Asset.UploadAssetFile(ctx, realName, file, workspace) + pid, err := id.ProjectIDFrom(prj.ID().String()) + if err != nil { + return nil, errors.New("Fail UploadAssetFile :" + err.Error()) + } + url, _, err := usecases(ctx).Asset.UploadAssetFile(ctx, realName, file, workspace, &pid) if err != nil { return nil, errors.New("Fail UploadAssetFile :" + err.Error()) } @@ -283,17 +298,6 @@ func (r *mutationResolver) ImportProject(ctx context.Context, input gqlmodel.Imp tempData = bytes.Replace(tempData, []byte(beforeName), []byte(afterName), -1) } - projectData, _ := unmarshalProject(tempData) - prj, tx, err := usecases(ctx).Project.ImportProject(ctx, workspace.String(), projectData) - if err != nil { - return nil, errors.New("Fail ImportProject :" + err.Error()) - } - defer func() { - if err2 := tx.End(ctx); err == nil && err2 != nil { - err = err2 - } - }() - // need to create a Scene firsts sce, err := usecases(ctx).Scene.Create(ctx, prj.ID(), getOperator(ctx)) oldSceneID, tempData, _ := replaceOldSceneID(tempData, sce) diff --git a/server/internal/adapter/gql/resolver_query.go b/server/internal/adapter/gql/resolver_query.go index 1495c81b86..7dd6df29bc 100644 --- a/server/internal/adapter/gql/resolver_query.go +++ b/server/internal/adapter/gql/resolver_query.go @@ -12,8 +12,8 @@ func (r *Resolver) Query() QueryResolver { type queryResolver struct{ *Resolver } -func (r *queryResolver) Assets(ctx context.Context, teamID gqlmodel.ID, pagination *gqlmodel.Pagination, keyword *string, sortType *gqlmodel.AssetSort) (*gqlmodel.AssetConnection, error) { - return loaders(ctx).Asset.FindByWorkspace(ctx, teamID, keyword, gqlmodel.AssetSortTypeFrom(sortType), pagination) +func (r *queryResolver) Assets(ctx context.Context, teamID gqlmodel.ID, projectId *gqlmodel.ID, pagination *gqlmodel.Pagination, keyword *string, sortType *gqlmodel.AssetSort) (*gqlmodel.AssetConnection, error) { + return loaders(ctx).Asset.FindByWorkspace(ctx, teamID, projectId, keyword, gqlmodel.AssetSortTypeFrom(sortType), pagination) } func (r *queryResolver) Me(ctx context.Context) (*gqlmodel.Me, error) { diff --git a/server/internal/adapter/gql/resolver_team.go b/server/internal/adapter/gql/resolver_team.go index 3f5470e1b1..ba092be917 100644 --- a/server/internal/adapter/gql/resolver_team.go +++ b/server/internal/adapter/gql/resolver_team.go @@ -24,8 +24,8 @@ func (r *teamResolver) Policy(ctx context.Context, obj *gqlmodel.Team) (*gqlmode return single(loaders(ctx).Policy.Fetch(ctx, []gqlmodel.ID{*obj.PolicyID})) } -func (r *teamResolver) Assets(ctx context.Context, obj *gqlmodel.Team, first *int, last *int, after *usecasex.Cursor, before *usecasex.Cursor) (*gqlmodel.AssetConnection, error) { - return loaders(ctx).Asset.FindByWorkspace(ctx, obj.ID, nil, nil, &gqlmodel.Pagination{ +func (r *teamResolver) Assets(ctx context.Context, obj *gqlmodel.Team, projectID *gqlmodel.ID, first *int, last *int, after *usecasex.Cursor, before *usecasex.Cursor) (*gqlmodel.AssetConnection, error) { + return loaders(ctx).Asset.FindByWorkspace(ctx, obj.ID, projectID, nil, nil, &gqlmodel.Pagination{ First: first, Last: last, After: after, diff --git a/server/internal/infrastructure/memory/asset.go b/server/internal/infrastructure/memory/asset.go index e24225a222..c0289791b2 100644 --- a/server/internal/infrastructure/memory/asset.go +++ b/server/internal/infrastructure/memory/asset.go @@ -46,12 +46,15 @@ func (r *Asset) FindByIDs(_ context.Context, ids id.AssetIDList) ([]*asset.Asset }), nil } -func (r *Asset) FindByWorkspace(_ context.Context, wid accountdomain.WorkspaceID, filter repo.AssetFilter) ([]*asset.Asset, *usecasex.PageInfo, error) { +func (r *Asset) FindByWorkspace(_ 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)) + } return v.Workspace() == wid && v.CoreSupport() && (filter.Keyword == nil || strings.Contains(v.Name(), *filter.Keyword)) }) diff --git a/server/internal/infrastructure/mongo/asset.go b/server/internal/infrastructure/mongo/asset.go index 8754d84cd0..bb7efa9db2 100644 --- a/server/internal/infrastructure/mongo/asset.go +++ b/server/internal/infrastructure/mongo/asset.go @@ -64,21 +64,24 @@ func (r *Asset) FindByIDs(ctx context.Context, ids id.AssetIDList) ([]*asset.Ass return filterAssets(ids, res), nil } -func (r *Asset) FindByWorkspace(ctx context.Context, id accountdomain.WorkspaceID, uFilter repo.AssetFilter) ([]*asset.Asset, *usecasex.PageInfo, error) { +func (r *Asset) FindByWorkspace(ctx context.Context, id accountdomain.WorkspaceID, projectId *id.ProjectID, uFilter repo.AssetFilter) ([]*asset.Asset, *usecasex.PageInfo, error) { if !r.f.CanRead(id) { return nil, usecasex.EmptyPageInfo(), nil } - var filter any = bson.M{ - "team": id.String(), + filter := bson.M{ "coresupport": true, } + if projectId != nil { + filter["project"] = projectId.String() + } else { + filter["team"] = id.String() + } + if uFilter.Keyword != nil { keyword := fmt.Sprintf(".*%s.*", regexp.QuoteMeta(*uFilter.Keyword)) - filter = mongox.And(filter, "name", bson.M{ - "$regex": primitive.Regex{Pattern: keyword, Options: "i"}, - }) + filter["name"] = bson.M{"$regex": primitive.Regex{Pattern: keyword, Options: "i"}} } bucketPattern := adapter.CurrentHost(ctx) @@ -90,9 +93,11 @@ func (r *Asset) FindByWorkspace(ctx context.Context, id accountdomain.WorkspaceI bucketPattern = "visualizer" } - filter = mongox.And(filter, "url", bson.M{ + if andFilter, ok := mongox.And(filter, "url", bson.M{ "$regex": primitive.Regex{Pattern: bucketPattern, Options: "i"}, - }) + }).(bson.M); ok { + filter = andFilter + } return r.paginate(ctx, filter, uFilter.Sort, uFilter.Pagination) } @@ -149,7 +154,6 @@ func (r *Asset) paginate(ctx context.Context, filter any, sort *asset.SortType, Reverted: sort.Desc, } } - c := mongodoc.NewAssetConsumer(r.f.Readable) pageInfo, err := r.client.Paginate(ctx, filter, usort, pagination, c) if err != nil { diff --git a/server/internal/infrastructure/mongo/mongodoc/asset.go b/server/internal/infrastructure/mongo/mongodoc/asset.go index a23929658e..dd23e49152 100644 --- a/server/internal/infrastructure/mongo/mongodoc/asset.go +++ b/server/internal/infrastructure/mongo/mongodoc/asset.go @@ -6,6 +6,7 @@ import ( "github.com/reearth/reearth/server/pkg/asset" "github.com/reearth/reearth/server/pkg/id" "github.com/reearth/reearthx/account/accountdomain" + "github.com/reearth/reearthx/idx" "golang.org/x/exp/slices" ) @@ -13,6 +14,7 @@ type AssetDocument struct { ID string CreatedAt time.Time Team string // DON'T CHANGE NAME' + Project *string Name string Size int64 URL string @@ -30,10 +32,18 @@ func NewAssetConsumer(workspaces []accountdomain.WorkspaceID) *AssetConsumer { func NewAsset(asset *asset.Asset) (*AssetDocument, string) { aid := asset.ID().String() + + var pid *string + if project := asset.Project(); project != nil { + pidValue := project.String() + pid = &pidValue + } + return &AssetDocument{ ID: aid, CreatedAt: asset.CreatedAt(), Team: asset.Workspace().String(), + Project: pid, Name: asset.Name(), Size: asset.Size(), URL: asset.URL(), @@ -52,10 +62,20 @@ func (d *AssetDocument) Model() (*asset.Asset, error) { return nil, err } + var pid *idx.ID[id.Project] + if d.Project != nil { + pidValue, err := id.ProjectIDFrom(*d.Project) + if err != nil { + return nil, err + } + pid = &pidValue + } + return asset.New(). ID(aid). CreatedAt(d.CreatedAt). Workspace(tid). + Project(pid). Name(d.Name). Size(d.Size). URL(d.URL). diff --git a/server/internal/usecase/interactor/asset.go b/server/internal/usecase/interactor/asset.go index 52b05f86d4..18523f759e 100644 --- a/server/internal/usecase/interactor/asset.go +++ b/server/internal/usecase/interactor/asset.go @@ -36,12 +36,12 @@ func (i *Asset) Fetch(ctx context.Context, assets []id.AssetID, operator *usecas return i.repos.Asset.FindByIDs(ctx, assets) } -func (i *Asset) FindByWorkspace(ctx context.Context, tid accountdomain.WorkspaceID, keyword *string, sort *asset.SortType, p *usecasex.Pagination, operator *usecase.Operator) ([]*asset.Asset, *usecasex.PageInfo, error) { +func (i *Asset) FindByWorkspace(ctx context.Context, tid accountdomain.WorkspaceID, pid *id.ProjectID, keyword *string, sort *asset.SortType, p *usecasex.Pagination, operator *usecase.Operator) ([]*asset.Asset, *usecasex.PageInfo, error) { return Run2( ctx, operator, i.repos, Usecase().WithReadableWorkspaces(tid), func(ctx context.Context) ([]*asset.Asset, *usecasex.PageInfo, error) { - return i.repos.Asset.FindByWorkspace(ctx, tid, repo.AssetFilter{ + return i.repos.Asset.FindByWorkspace(ctx, tid, pid, repo.AssetFilter{ Sort: sort, Keyword: keyword, Pagination: p, @@ -88,6 +88,7 @@ func (i *Asset) Create(ctx context.Context, inp interfaces.CreateAssetParam, ope a, err := asset.New(). NewID(). Workspace(inp.WorkspaceID). + Project(inp.ProjectID). Name(path.Base(inp.File.Path)). Size(size). URL(url.String()). @@ -104,6 +105,27 @@ func (i *Asset) Create(ctx context.Context, inp interfaces.CreateAssetParam, ope return a, nil } +func (i *Asset) Update(ctx context.Context, aid id.AssetID, pid *id.ProjectID, operator *usecase.Operator) (id.AssetID, *id.ProjectID, error) { + return Run2( + ctx, operator, i.repos, + Usecase().Transaction(), + func(ctx context.Context) (id.AssetID, *id.ProjectID, error) { + asset, err := i.repos.Asset.FindByID(ctx, aid) + if err != nil { + return aid, pid, err + } + + if ok := operator.IsWritableWorkspace(asset.Workspace()); !ok { + return aid, pid, interfaces.ErrOperationDenied + } + + asset.SetProject(pid) + + return aid, pid, i.repos.Asset.Save(ctx, asset) + }, + ) +} + func (i *Asset) Remove(ctx context.Context, aid id.AssetID, operator *usecase.Operator) (result id.AssetID, err error) { return Run1( ctx, operator, i.repos, @@ -129,7 +151,7 @@ func (i *Asset) Remove(ctx context.Context, aid id.AssetID, operator *usecase.Op ) } -func (i *Asset) UploadAssetFile(ctx context.Context, name string, zipFile *zip.File, workspace idx.ID[accountdomain.Workspace]) (*url.URL, int64, error) { +func (i *Asset) UploadAssetFile(ctx context.Context, name string, zipFile *zip.File, workspace idx.ID[accountdomain.Workspace], project *id.ProjectID) (*url.URL, int64, error) { readCloser, err := zipFile.Open() if err != nil { @@ -156,6 +178,7 @@ func (i *Asset) UploadAssetFile(ctx context.Context, name string, zipFile *zip.F a, err := asset.New(). NewID(). Workspace(workspace). + Project(project). Name(path.Base(name)). Size(size). URL(url.String()). diff --git a/server/internal/usecase/interfaces/asset.go b/server/internal/usecase/interfaces/asset.go index 76c676e5c2..b3456521b1 100644 --- a/server/internal/usecase/interfaces/asset.go +++ b/server/internal/usecase/interfaces/asset.go @@ -25,6 +25,7 @@ const ( type CreateAssetParam struct { WorkspaceID accountdomain.WorkspaceID + ProjectID *id.ProjectID CoreSupport bool File *file.File } @@ -35,8 +36,9 @@ var ( type Asset interface { Fetch(context.Context, []id.AssetID, *usecase.Operator) ([]*asset.Asset, error) - FindByWorkspace(context.Context, accountdomain.WorkspaceID, *string, *asset.SortType, *usecasex.Pagination, *usecase.Operator) ([]*asset.Asset, *usecasex.PageInfo, error) + FindByWorkspace(context.Context, accountdomain.WorkspaceID, *id.ProjectID, *string, *asset.SortType, *usecasex.Pagination, *usecase.Operator) ([]*asset.Asset, *usecasex.PageInfo, error) Create(context.Context, CreateAssetParam, *usecase.Operator) (*asset.Asset, error) + Update(context.Context, id.AssetID, *id.ProjectID, *usecase.Operator) (id.AssetID, *id.ProjectID, error) Remove(context.Context, id.AssetID, *usecase.Operator) (id.AssetID, error) - UploadAssetFile(context.Context, string, *zip.File, idx.ID[accountdomain.Workspace]) (*url.URL, int64, error) + UploadAssetFile(context.Context, string, *zip.File, idx.ID[accountdomain.Workspace], *id.ProjectID) (*url.URL, int64, error) } diff --git a/server/internal/usecase/repo/asset.go b/server/internal/usecase/repo/asset.go index 258fc2beb4..7fd5dd621e 100644 --- a/server/internal/usecase/repo/asset.go +++ b/server/internal/usecase/repo/asset.go @@ -17,7 +17,7 @@ type AssetFilter struct { type Asset interface { Filtered(WorkspaceFilter) Asset - FindByWorkspace(context.Context, accountdomain.WorkspaceID, AssetFilter) ([]*asset.Asset, *usecasex.PageInfo, error) + FindByWorkspace(context.Context, accountdomain.WorkspaceID, *id.ProjectID, AssetFilter) ([]*asset.Asset, *usecasex.PageInfo, error) FindByID(context.Context, id.AssetID) (*asset.Asset, error) FindByIDs(context.Context, id.AssetIDList) ([]*asset.Asset, error) TotalSizeByWorkspace(context.Context, accountdomain.WorkspaceID) (int64, error) diff --git a/server/pkg/asset/asset.go b/server/pkg/asset/asset.go index 7a65dd0f66..2ea4fa06d6 100644 --- a/server/pkg/asset/asset.go +++ b/server/pkg/asset/asset.go @@ -15,6 +15,7 @@ type Asset struct { id ID createdAt time.Time workspace WorkspaceID + project *ProjectID name string // file name size int64 // file size url string @@ -30,6 +31,14 @@ func (a *Asset) Workspace() WorkspaceID { return a.workspace } +func (a *Asset) Project() *ProjectID { + return a.project +} + +func (a *Asset) SetProject(project *ProjectID) { + a.project = project +} + func (a *Asset) Name() string { return a.name } diff --git a/server/pkg/asset/builder.go b/server/pkg/asset/builder.go index 7d73f7a820..77ca4a1b54 100644 --- a/server/pkg/asset/builder.go +++ b/server/pkg/asset/builder.go @@ -54,6 +54,11 @@ func (b *Builder) Workspace(workspace WorkspaceID) *Builder { return b } +func (b *Builder) Project(project *ProjectID) *Builder { + b.a.project = project + return b +} + func (b *Builder) Name(name string) *Builder { b.a.name = name return b diff --git a/server/pkg/asset/id.go b/server/pkg/asset/id.go index 5e7480135a..a697d89535 100644 --- a/server/pkg/asset/id.go +++ b/server/pkg/asset/id.go @@ -7,18 +7,23 @@ import ( type ID = id.AssetID type WorkspaceID = accountdomain.WorkspaceID +type ProjectID = id.ProjectID var NewID = id.NewAssetID var NewWorkspaceID = accountdomain.NewWorkspaceID +var NewProjectID = id.NewProjectID var MustID = id.MustAssetID var MustWorkspaceID = id.MustWorkspaceID +var MustProjectID = id.MustProjectID var IDFrom = id.AssetIDFrom var WorkspaceIDFrom = accountdomain.WorkspaceIDFrom +var ProjectIDFrom = id.ProjectIDFrom var IDFromRef = id.AssetIDFromRef var WorkspaceIDFromRef = accountdomain.WorkspaceIDFromRef +var ProjectIDFromRef = id.ProjectIDFromRef var ErrInvalidID = id.ErrInvalidID