From 09c254ef2ac4e298388802948b38c0dd8658c94c Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Tue, 5 Nov 2024 19:04:34 +0900 Subject: [PATCH 01/39] wip --- go.work.sum | 4 ++ server/schemas/integration.yml | 80 ++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/go.work.sum b/go.work.sum index 4df069b56b..ab7fb719c0 100644 --- a/go.work.sum +++ b/go.work.sum @@ -250,8 +250,11 @@ cloud.google.com/go/auth v0.7.2/go.mod h1:VEc4p5NNxycWQTMQEDQF0bd6aTMb6VgYDXEwiJ cloud.google.com/go/auth v0.8.0/go.mod h1:qGVp/Y3kDRSDZ5gFD/XPUfYQ9xW1iI7q8RIRoCyBbJc= cloud.google.com/go/auth v0.9.0/go.mod h1:2HsApZBr9zGZhC9QAXsYVYaWk8kNUt37uny+XVKi7wM= cloud.google.com/go/auth v0.9.3/go.mod h1:7z6VY+7h3KUdRov5F1i8NDP5ZzWKYmEPO842BgCsmTk= +cloud.google.com/go/auth v0.9.4/go.mod h1:SHia8n6//Ya940F1rLimhJCjjx7KE17t0ctFEci3HkA= +cloud.google.com/go/auth v0.9.9/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I= +cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= cloud.google.com/go/automl v1.5.0 h1:Av8bE5rMQxUl4SVfYsEczEJf1ftIKQOUGGzpzEYwodY= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= cloud.google.com/go/automl v1.6.0 h1:U+kHmeKGXgBvTlrecPJhwkItWaIpIscG5DUpQxBQZZg= @@ -3378,6 +3381,7 @@ google.golang.org/genproto/googleapis/bytestream v0.0.0-20240903143218-8af14fe29 google.golang.org/genproto/googleapis/bytestream v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:q0eWNnCW04EJlyrmLT+ZHsjuoUiZ36/eAEdCCezZoco= google.golang.org/genproto/googleapis/bytestream v0.0.0-20241015192408-796eee8c2d53 h1:mVZqGNBNN8C63iGnWgHZSGbT/vG7voylnp4atysmReg= google.golang.org/genproto/googleapis/bytestream v0.0.0-20241015192408-796eee8c2d53/go.mod h1:T8O3fECQbif8cez15vxAcjbwXxvL2xbnvbQ7ZfiMAMs= +google.golang.org/genproto/googleapis/bytestream v0.0.0-20241021214115-324edc3d5d38/go.mod h1:T8O3fECQbif8cez15vxAcjbwXxvL2xbnvbQ7ZfiMAMs= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= diff --git a/server/schemas/integration.yml b/server/schemas/integration.yml index 4b9d187750..2518538d87 100644 --- a/server/schemas/integration.yml +++ b/server/schemas/integration.yml @@ -925,6 +925,35 @@ paths: description: Not found '500': description: Internal server error + '/projects/{projectIdOrAlias}/models/{modelIdOrKey}/schema.json': + parameters: + - $ref: '#/components/parameters/projectIdOrAliasParam' + - $ref: '#/components/parameters/modelIdOrKeyParam' + get: + operationId: SchemaByIDAsJSON + security: + - bearerAuth: [] + summary: Returns a JSON that has schema. + tags: + - Schema + - JSON + description: Returns a JSON that has schema. + responses: + '200': + description: A JSON object + content: + application/json: + schema: + $ref: '#/components/schemas/Schema' + format: binary + '400': + description: Invalid request parameter value + '401': + $ref: '#/components/responses/UnauthorizedError' + '404': + description: Not found + '500': + description: Internal server error '/items/{itemId}': parameters: - $ref: '#/components/parameters/itemIdParam' @@ -1658,6 +1687,57 @@ components: createdAt: type: string format: date-time + schemaJSON: + type: object + properties: + $schema: + type: string + description: "The schema URL." + $id: + type: string + description: "The identifier for the model or schema." + title: + type: string + description: "The name of the model." # model only + description: + type: string + description: "The description of the model." # model only + type: + type: string + description: "The type of the model." + properties: + type: object + properties: + id: + type: string # note that it is not always the same as CMS's field type. + title: "ID" + description: "The unique identifier for the project." + workspaceId: + type: string + title: "Workspace ID" + description: "The unique identifier for the workspace." + name: + type: string + title: "Name" + description: "The name of the project." + description: + type: string + title: "Description" + description: "A brief description of the project." + alias: + type: string + title: "Alias" + description: "An alias for the project." + createdAt: + type: string + format: date-time + title: "Created At" + description: "The timestamp when the project was created." + updatedAt: + type: string + format: date-time + title: "Updated At" + description: "The timestamp when the project was last updated." valueType: type: string enum: From 3a9a7fbf0f174fb958349f52530662116e1ec235 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 6 Nov 2024 13:11:11 +0900 Subject: [PATCH 02/39] wip --- server/internal/adapter/integration/schema.go | 8 + .../adapter/integration/server.gen.go | 357 ++++++++++++++---- server/pkg/integrationapi/types.gen.go | 40 ++ server/schemas/integration.yml | 33 +- 4 files changed, 368 insertions(+), 70 deletions(-) diff --git a/server/internal/adapter/integration/schema.go b/server/internal/adapter/integration/schema.go index 38741c00ef..6dbe98480f 100644 --- a/server/internal/adapter/integration/schema.go +++ b/server/internal/adapter/integration/schema.go @@ -360,6 +360,14 @@ func (s *Server) FieldDeleteWithProject(ctx context.Context, request FieldDelete }, err } +func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request SchemaByModelWithProjectAsJSONRequestObject) (SchemaByModelWithProjectAsJSONResponseObject, error) { + panic("not implemented") +} + +func (s *Server) SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONRequestObject) (SchemaByIDAsJSONResponseObject, error) { + panic("not implemented") +} + func FromSchemaTypeProperty(t integrationapi.ValueType, multiple bool) (tpRes *schema.TypeProperty, dv *value.Multiple, err error) { switch t { case integrationapi.ValueTypeText: diff --git a/server/internal/adapter/integration/server.gen.go b/server/internal/adapter/integration/server.gen.go index 78d98f6d97..d463941623 100644 --- a/server/internal/adapter/integration/server.gen.go +++ b/server/internal/adapter/integration/server.gen.go @@ -126,9 +126,15 @@ type ServerInterface interface { // Returns a GeoJSON that has a list of items as features. // (GET /projects/{projectIdOrAlias}/models/{modelIdOrKey}/items.geojson) ItemsWithProjectAsGeoJSON(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, modelIdOrKey ModelIdOrKeyParam, params ItemsWithProjectAsGeoJSONParams) error + // Returns a JSON that has schema. + // (GET /projects/{projectIdOrAlias}/models/{modelIdOrKey}/schema.json) + SchemaByModelWithProjectAsJSON(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, modelIdOrKey ModelIdOrKeyParam) error // Returns a schema. // (GET /projects/{projectIdOrAlias}/schemata) SchemaFilter(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, params SchemaFilterParams) error + // Returns a JSON that has schema. + // (GET /projects/{projectIdOrAlias}/schemata/{schemaId}/schema.json) + SchemaByIDAsJSON(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, schemaId SchemaIdParam) error // Returns a list of assets. // (GET /projects/{projectId}/assets) AssetFilter(ctx echo.Context, projectId ProjectIdParam, params AssetFilterParams) error @@ -1110,6 +1116,32 @@ func (w *ServerInterfaceWrapper) ItemsWithProjectAsGeoJSON(ctx echo.Context) err return err } +// SchemaByModelWithProjectAsJSON converts echo context to params. +func (w *ServerInterfaceWrapper) SchemaByModelWithProjectAsJSON(ctx echo.Context) error { + var err error + // ------------- Path parameter "projectIdOrAlias" ------------- + var projectIdOrAlias ProjectIdOrAliasParam + + err = runtime.BindStyledParameterWithOptions("simple", "projectIdOrAlias", ctx.Param("projectIdOrAlias"), &projectIdOrAlias, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter projectIdOrAlias: %s", err)) + } + + // ------------- Path parameter "modelIdOrKey" ------------- + var modelIdOrKey ModelIdOrKeyParam + + err = runtime.BindStyledParameterWithOptions("simple", "modelIdOrKey", ctx.Param("modelIdOrKey"), &modelIdOrKey, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter modelIdOrKey: %s", err)) + } + + ctx.Set(BearerAuthScopes, []string{}) + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.SchemaByModelWithProjectAsJSON(ctx, projectIdOrAlias, modelIdOrKey) + return err +} + // SchemaFilter converts echo context to params. func (w *ServerInterfaceWrapper) SchemaFilter(ctx echo.Context) error { var err error @@ -1151,6 +1183,32 @@ func (w *ServerInterfaceWrapper) SchemaFilter(ctx echo.Context) error { return err } +// SchemaByIDAsJSON converts echo context to params. +func (w *ServerInterfaceWrapper) SchemaByIDAsJSON(ctx echo.Context) error { + var err error + // ------------- Path parameter "projectIdOrAlias" ------------- + var projectIdOrAlias ProjectIdOrAliasParam + + err = runtime.BindStyledParameterWithOptions("simple", "projectIdOrAlias", ctx.Param("projectIdOrAlias"), &projectIdOrAlias, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter projectIdOrAlias: %s", err)) + } + + // ------------- Path parameter "schemaId" ------------- + var schemaId SchemaIdParam + + err = runtime.BindStyledParameterWithOptions("simple", "schemaId", ctx.Param("schemaId"), &schemaId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter schemaId: %s", err)) + } + + ctx.Set(BearerAuthScopes, []string{}) + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.SchemaByIDAsJSON(ctx, projectIdOrAlias, schemaId) + return err +} + // AssetFilter converts echo context to params. func (w *ServerInterfaceWrapper) AssetFilter(ctx echo.Context) error { var err error @@ -1407,7 +1465,9 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL router.POST(baseURL+"/projects/:projectIdOrAlias/models/:modelIdOrKey/items", wrapper.ItemCreateWithProject) router.GET(baseURL+"/projects/:projectIdOrAlias/models/:modelIdOrKey/items.csv", wrapper.ItemsWithProjectAsCSV) router.GET(baseURL+"/projects/:projectIdOrAlias/models/:modelIdOrKey/items.geojson", wrapper.ItemsWithProjectAsGeoJSON) + router.GET(baseURL+"/projects/:projectIdOrAlias/models/:modelIdOrKey/schema.json", wrapper.SchemaByModelWithProjectAsJSON) router.GET(baseURL+"/projects/:projectIdOrAlias/schemata", wrapper.SchemaFilter) + router.GET(baseURL+"/projects/:projectIdOrAlias/schemata/:schemaId/schema.json", wrapper.SchemaByIDAsJSON) router.GET(baseURL+"/projects/:projectId/assets", wrapper.AssetFilter) router.POST(baseURL+"/projects/:projectId/assets", wrapper.AssetCreate) router.POST(baseURL+"/projects/:projectId/assets/uploads", wrapper.AssetUploadCreate) @@ -2900,6 +2960,55 @@ func (response ItemsWithProjectAsGeoJSON500Response) VisitItemsWithProjectAsGeoJ return nil } +type SchemaByModelWithProjectAsJSONRequestObject struct { + ProjectIdOrAlias ProjectIdOrAliasParam `json:"projectIdOrAlias"` + ModelIdOrKey ModelIdOrKeyParam `json:"modelIdOrKey"` +} + +type SchemaByModelWithProjectAsJSONResponseObject interface { + VisitSchemaByModelWithProjectAsJSONResponse(w http.ResponseWriter) error +} + +type SchemaByModelWithProjectAsJSON200JSONResponse SchemaJSON + +func (response SchemaByModelWithProjectAsJSON200JSONResponse) VisitSchemaByModelWithProjectAsJSONResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +type SchemaByModelWithProjectAsJSON400Response struct { +} + +func (response SchemaByModelWithProjectAsJSON400Response) VisitSchemaByModelWithProjectAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(400) + return nil +} + +type SchemaByModelWithProjectAsJSON401Response = UnauthorizedErrorResponse + +func (response SchemaByModelWithProjectAsJSON401Response) VisitSchemaByModelWithProjectAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(401) + return nil +} + +type SchemaByModelWithProjectAsJSON404Response struct { +} + +func (response SchemaByModelWithProjectAsJSON404Response) VisitSchemaByModelWithProjectAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(404) + return nil +} + +type SchemaByModelWithProjectAsJSON500Response struct { +} + +func (response SchemaByModelWithProjectAsJSON500Response) VisitSchemaByModelWithProjectAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(500) + return nil +} + type SchemaFilterRequestObject struct { ProjectIdOrAlias ProjectIdOrAliasParam `json:"projectIdOrAlias"` Params SchemaFilterParams @@ -2954,6 +3063,55 @@ func (response SchemaFilter500Response) VisitSchemaFilterResponse(w http.Respons return nil } +type SchemaByIDAsJSONRequestObject struct { + ProjectIdOrAlias ProjectIdOrAliasParam `json:"projectIdOrAlias"` + SchemaId SchemaIdParam `json:"schemaId"` +} + +type SchemaByIDAsJSONResponseObject interface { + VisitSchemaByIDAsJSONResponse(w http.ResponseWriter) error +} + +type SchemaByIDAsJSON200JSONResponse SchemaJSON + +func (response SchemaByIDAsJSON200JSONResponse) VisitSchemaByIDAsJSONResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +type SchemaByIDAsJSON400Response struct { +} + +func (response SchemaByIDAsJSON400Response) VisitSchemaByIDAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(400) + return nil +} + +type SchemaByIDAsJSON401Response = UnauthorizedErrorResponse + +func (response SchemaByIDAsJSON401Response) VisitSchemaByIDAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(401) + return nil +} + +type SchemaByIDAsJSON404Response struct { +} + +func (response SchemaByIDAsJSON404Response) VisitSchemaByIDAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(404) + return nil +} + +type SchemaByIDAsJSON500Response struct { +} + +func (response SchemaByIDAsJSON500Response) VisitSchemaByIDAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(500) + return nil +} + type AssetFilterRequestObject struct { ProjectId ProjectIdParam `json:"projectId"` Params AssetFilterParams @@ -3345,9 +3503,15 @@ type StrictServerInterface interface { // Returns a GeoJSON that has a list of items as features. // (GET /projects/{projectIdOrAlias}/models/{modelIdOrKey}/items.geojson) ItemsWithProjectAsGeoJSON(ctx context.Context, request ItemsWithProjectAsGeoJSONRequestObject) (ItemsWithProjectAsGeoJSONResponseObject, error) + // Returns a JSON that has schema. + // (GET /projects/{projectIdOrAlias}/models/{modelIdOrKey}/schema.json) + SchemaByModelWithProjectAsJSON(ctx context.Context, request SchemaByModelWithProjectAsJSONRequestObject) (SchemaByModelWithProjectAsJSONResponseObject, error) // Returns a schema. // (GET /projects/{projectIdOrAlias}/schemata) SchemaFilter(ctx context.Context, request SchemaFilterRequestObject) (SchemaFilterResponseObject, error) + // Returns a JSON that has schema. + // (GET /projects/{projectIdOrAlias}/schemata/{schemaId}/schema.json) + SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONRequestObject) (SchemaByIDAsJSONResponseObject, error) // Returns a list of assets. // (GET /projects/{projectId}/assets) AssetFilter(ctx context.Context, request AssetFilterRequestObject) (AssetFilterResponseObject, error) @@ -4325,6 +4489,32 @@ func (sh *strictHandler) ItemsWithProjectAsGeoJSON(ctx echo.Context, projectIdOr return nil } +// SchemaByModelWithProjectAsJSON operation middleware +func (sh *strictHandler) SchemaByModelWithProjectAsJSON(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, modelIdOrKey ModelIdOrKeyParam) error { + var request SchemaByModelWithProjectAsJSONRequestObject + + request.ProjectIdOrAlias = projectIdOrAlias + request.ModelIdOrKey = modelIdOrKey + + handler := func(ctx echo.Context, request interface{}) (interface{}, error) { + return sh.ssi.SchemaByModelWithProjectAsJSON(ctx.Request().Context(), request.(SchemaByModelWithProjectAsJSONRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "SchemaByModelWithProjectAsJSON") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(SchemaByModelWithProjectAsJSONResponseObject); ok { + return validResponse.VisitSchemaByModelWithProjectAsJSONResponse(ctx.Response()) + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + // SchemaFilter operation middleware func (sh *strictHandler) SchemaFilter(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, params SchemaFilterParams) error { var request SchemaFilterRequestObject @@ -4351,6 +4541,32 @@ func (sh *strictHandler) SchemaFilter(ctx echo.Context, projectIdOrAlias Project return nil } +// SchemaByIDAsJSON operation middleware +func (sh *strictHandler) SchemaByIDAsJSON(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, schemaId SchemaIdParam) error { + var request SchemaByIDAsJSONRequestObject + + request.ProjectIdOrAlias = projectIdOrAlias + request.SchemaId = schemaId + + handler := func(ctx echo.Context, request interface{}) (interface{}, error) { + return sh.ssi.SchemaByIDAsJSON(ctx.Request().Context(), request.(SchemaByIDAsJSONRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "SchemaByIDAsJSON") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(SchemaByIDAsJSONResponseObject); ok { + return validResponse.VisitSchemaByIDAsJSONResponse(ctx.Response()) + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + // AssetFilter operation middleware func (sh *strictHandler) AssetFilter(ctx echo.Context, projectId ProjectIdParam, params AssetFilterParams) error { var request AssetFilterRequestObject @@ -4565,74 +4781,79 @@ func (sh *strictHandler) ProjectFilter(ctx echo.Context, workspaceId WorkspaceId // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", + "fwEAAP//ITPhIuioAAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/server/pkg/integrationapi/types.gen.go b/server/pkg/integrationapi/types.gen.go index 2056450597..edd07e2333 100644 --- a/server/pkg/integrationapi/types.gen.go +++ b/server/pkg/integrationapi/types.gen.go @@ -551,6 +551,46 @@ type SchemaField struct { Type *ValueType `json:"type,omitempty"` } +// SchemaJSON defines model for schemaJSON. +type SchemaJSON struct { + // Id The identifier for the model or schema. + Id *string `json:"$id,omitempty"` + + // Schema The schema URL. + Schema *string `json:"$schema,omitempty"` + + // Description The description of the model. + Description *string `json:"description,omitempty"` + Properties *struct { + // Alias An alias for the project. + Alias *string `json:"alias,omitempty"` + + // CreatedAt The timestamp when the project was created. + CreatedAt *time.Time `json:"createdAt,omitempty"` + + // Description A brief description of the project. + Description *string `json:"description,omitempty"` + + // Id The unique identifier for the project. + Id *string `json:"id,omitempty"` + + // Name The name of the project. + Name *string `json:"name,omitempty"` + + // UpdatedAt The timestamp when the project was last updated. + UpdatedAt *time.Time `json:"updatedAt,omitempty"` + + // WorkspaceId The unique identifier for the workspace. + WorkspaceId *string `json:"workspaceId,omitempty"` + } `json:"properties,omitempty"` + + // Title The name of the model. + Title *string `json:"title,omitempty"` + + // Type The type of the model. + Type *string `json:"type,omitempty"` +} + // TagResponse defines model for tagResponse. type TagResponse struct { Color *string `json:"color,omitempty"` diff --git a/server/schemas/integration.yml b/server/schemas/integration.yml index 2518538d87..05f0d0143f 100644 --- a/server/schemas/integration.yml +++ b/server/schemas/integration.yml @@ -162,6 +162,35 @@ paths: description: Not found '500': description: Internal server error + '/projects/{projectIdOrAlias}/schemata/{schemaId}/schema.json': + parameters: + - $ref: '#/components/parameters/projectIdOrAliasParam' + - $ref: '#/components/parameters/schemaIdParam' + get: + operationId: SchemaByIDAsJSON + security: + - bearerAuth: [] + summary: Returns a JSON that has schema. + tags: + - Schema + - JSON + description: Returns a JSON that has schema. + responses: + '200': + description: A JSON object + content: + application/json: + schema: + $ref: '#/components/schemas/schemaJSON' + format: binary + '400': + description: Invalid request parameter value + '401': + $ref: '#/components/responses/UnauthorizedError' + '404': + description: Not found + '500': + description: Internal server error '/models/{modelId}': parameters: - $ref: '#/components/parameters/modelIdParam' @@ -930,7 +959,7 @@ paths: - $ref: '#/components/parameters/projectIdOrAliasParam' - $ref: '#/components/parameters/modelIdOrKeyParam' get: - operationId: SchemaByIDAsJSON + operationId: SchemaByModelWithProjectAsJSON security: - bearerAuth: [] summary: Returns a JSON that has schema. @@ -944,7 +973,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Schema' + $ref: '#/components/schemas/schemaJSON' format: binary '400': description: Invalid request parameter value From 4ea11be4a80d6d516fc3b671ed16f2af38d3fbef Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 6 Nov 2024 15:58:32 +0900 Subject: [PATCH 03/39] wip --- server/internal/adapter/integration/schema.go | 56 ++++++- .../adapter/integration/server.gen.go | 143 +++++++++--------- server/pkg/integrationapi/types.gen.go | 42 +---- server/schemas/integration.yml | 37 +---- 4 files changed, 131 insertions(+), 147 deletions(-) diff --git a/server/internal/adapter/integration/schema.go b/server/internal/adapter/integration/schema.go index 6dbe98480f..a09fe7435d 100644 --- a/server/internal/adapter/integration/schema.go +++ b/server/internal/adapter/integration/schema.go @@ -361,11 +361,63 @@ func (s *Server) FieldDeleteWithProject(ctx context.Context, request FieldDelete } func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request SchemaByModelWithProjectAsJSONRequestObject) (SchemaByModelWithProjectAsJSONResponseObject, error) { - panic("not implemented") + uc := adapter.Usecases(ctx) + op := adapter.Operator(ctx) + + p, err := uc.Project.FindByIDOrAlias(ctx, request.ProjectIdOrAlias, op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return SchemaByModelWithProjectAsJSON400Response{}, err + } + return SchemaByModelWithProjectAsJSON400Response{}, err + } + + m, err := uc.Model.FindByIDOrKey(ctx, p.ID(), request.ModelIdOrKey, op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return SchemaByModelWithProjectAsJSON400Response{}, err + } + return SchemaByModelWithProjectAsJSON400Response{}, err + } + + sch, err := uc.Schema.FindByModel(ctx, m.ID(), op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return SchemaByModelWithProjectAsJSON400Response{}, err + } + return SchemaByModelWithProjectAsJSON400Response{}, err + } + + var pp *map[string]interface{} + return SchemaByModelWithProjectAsJSON200JSONResponse{ + Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), + Id: sch.Schema().ID().Ref().StringRef(), + Title: lo.ToPtr(m.Name()), + Description: lo.ToPtr(m.Description()), + Type: lo.ToPtr("object"), + Properties: pp, + }, nil } func (s *Server) SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONRequestObject) (SchemaByIDAsJSONResponseObject, error) { - panic("not implemented") + uc := adapter.Usecases(ctx) + op := adapter.Operator(ctx) + + sch, err := uc.Schema.FindByID(ctx, request.SchemaId, op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return SchemaByIDAsJSON400Response{}, err + } + return SchemaByIDAsJSON400Response{}, err + } + + var pp *map[string]interface{} + return SchemaByIDAsJSON200JSONResponse{ + Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), + Id: sch.ID().Ref().StringRef(), + Type: lo.ToPtr("object"), + Properties: pp, + }, nil } func FromSchemaTypeProperty(t integrationapi.ValueType, multiple bool) (tpRes *schema.TypeProperty, dv *value.Multiple, err error) { diff --git a/server/internal/adapter/integration/server.gen.go b/server/internal/adapter/integration/server.gen.go index d463941623..f61c6c79f4 100644 --- a/server/internal/adapter/integration/server.gen.go +++ b/server/internal/adapter/integration/server.gen.go @@ -4781,79 +4781,76 @@ func (sh *strictHandler) ProjectFilter(ctx echo.Context, workspaceId WorkspaceId // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "fwEAAP//ITPhIuioAAA=", + "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", + "m3JHM55kV/9isfhfAAAA///iOG1HOqUAAA==", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/server/pkg/integrationapi/types.gen.go b/server/pkg/integrationapi/types.gen.go index edd07e2333..884ce58cb1 100644 --- a/server/pkg/integrationapi/types.gen.go +++ b/server/pkg/integrationapi/types.gen.go @@ -553,42 +553,12 @@ type SchemaField struct { // SchemaJSON defines model for schemaJSON. type SchemaJSON struct { - // Id The identifier for the model or schema. - Id *string `json:"$id,omitempty"` - - // Schema The schema URL. - Schema *string `json:"$schema,omitempty"` - - // Description The description of the model. - Description *string `json:"description,omitempty"` - Properties *struct { - // Alias An alias for the project. - Alias *string `json:"alias,omitempty"` - - // CreatedAt The timestamp when the project was created. - CreatedAt *time.Time `json:"createdAt,omitempty"` - - // Description A brief description of the project. - Description *string `json:"description,omitempty"` - - // Id The unique identifier for the project. - Id *string `json:"id,omitempty"` - - // Name The name of the project. - Name *string `json:"name,omitempty"` - - // UpdatedAt The timestamp when the project was last updated. - UpdatedAt *time.Time `json:"updatedAt,omitempty"` - - // WorkspaceId The unique identifier for the workspace. - WorkspaceId *string `json:"workspaceId,omitempty"` - } `json:"properties,omitempty"` - - // Title The name of the model. - Title *string `json:"title,omitempty"` - - // Type The type of the model. - Type *string `json:"type,omitempty"` + Id *string `json:"$id,omitempty"` + Schema *string `json:"$schema,omitempty"` + Description *string `json:"description,omitempty"` + Properties *map[string]interface{} `json:"properties,omitempty"` + Title *string `json:"title,omitempty"` + Type *string `json:"type,omitempty"` } // TagResponse defines model for tagResponse. diff --git a/server/schemas/integration.yml b/server/schemas/integration.yml index 05f0d0143f..e86e8a9cd3 100644 --- a/server/schemas/integration.yml +++ b/server/schemas/integration.yml @@ -1721,52 +1721,17 @@ components: properties: $schema: type: string - description: "The schema URL." $id: type: string - description: "The identifier for the model or schema." title: type: string - description: "The name of the model." # model only description: type: string - description: "The description of the model." # model only type: type: string - description: "The type of the model." properties: type: object - properties: - id: - type: string # note that it is not always the same as CMS's field type. - title: "ID" - description: "The unique identifier for the project." - workspaceId: - type: string - title: "Workspace ID" - description: "The unique identifier for the workspace." - name: - type: string - title: "Name" - description: "The name of the project." - description: - type: string - title: "Description" - description: "A brief description of the project." - alias: - type: string - title: "Alias" - description: "An alias for the project." - createdAt: - type: string - format: date-time - title: "Created At" - description: "The timestamp when the project was created." - updatedAt: - type: string - format: date-time - title: "Updated At" - description: "The timestamp when the project was last updated." + additionalProperties: true valueType: type: string enum: From a69a084046ab818c8315a8805251420c56ea0e7f Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 6 Nov 2024 18:02:10 +0900 Subject: [PATCH 04/39] wip --- server/internal/adapter/integration/schema.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/server/internal/adapter/integration/schema.go b/server/internal/adapter/integration/schema.go index a09fe7435d..d2e34a6a06 100644 --- a/server/internal/adapter/integration/schema.go +++ b/server/internal/adapter/integration/schema.go @@ -388,14 +388,13 @@ func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request Sch return SchemaByModelWithProjectAsJSON400Response{}, err } - var pp *map[string]interface{} return SchemaByModelWithProjectAsJSON200JSONResponse{ Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), - Id: sch.Schema().ID().Ref().StringRef(), + Id: m.ID().Ref().StringRef(), Title: lo.ToPtr(m.Name()), Description: lo.ToPtr(m.Description()), Type: lo.ToPtr("object"), - Properties: pp, + Properties: toProperties(sch.Schema()), }, nil } @@ -411,15 +410,18 @@ func (s *Server) SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONR return SchemaByIDAsJSON400Response{}, err } - var pp *map[string]interface{} return SchemaByIDAsJSON200JSONResponse{ Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), Id: sch.ID().Ref().StringRef(), Type: lo.ToPtr("object"), - Properties: pp, + Properties: toProperties(sch), }, nil } +func toProperties(sch *schema.Schema) *map[string]interface{} { + return nil +} + func FromSchemaTypeProperty(t integrationapi.ValueType, multiple bool) (tpRes *schema.TypeProperty, dv *value.Multiple, err error) { switch t { case integrationapi.ValueTypeText: From 0a426aac5d15706c13db29b52b9c2a04478df0ef Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 6 Nov 2024 18:03:54 +0900 Subject: [PATCH 05/39] wip: implement schema for public api --- server/internal/adapter/publicapi/api.go | 28 ++++++++++++--- server/internal/adapter/publicapi/schema.go | 40 +++++++++++++++++++++ server/internal/adapter/publicapi/types.go | 18 ++++++++++ 3 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 server/internal/adapter/publicapi/schema.go diff --git a/server/internal/adapter/publicapi/api.go b/server/internal/adapter/publicapi/api.go index 4385fa8242..031dbe2d5e 100644 --- a/server/internal/adapter/publicapi/api.go +++ b/server/internal/adapter/publicapi/api.go @@ -33,11 +33,12 @@ func GetController(ctx context.Context) *Controller { func Echo(e *echo.Group) { e.Use(middleware.CORS()) - e.GET("/:project/:model", PublicApiItemOrAssetList()) - e.GET("/:project/:model/:item", PublicApiItemOrAsset()) + e.GET("/:project/:model", publicApiItemOrAssetList()) + e.GET("/:project/:model/:item", publicApiItemOrAsset()) + e.GET("/:project/:model/:schema", publicApiSchema()) } -func PublicApiItemOrAsset() echo.HandlerFunc { +func publicApiItemOrAsset() echo.HandlerFunc { return func(c echo.Context) error { ctx := c.Request().Context() ctrl := GetController(c.Request().Context()) @@ -59,7 +60,26 @@ func PublicApiItemOrAsset() echo.HandlerFunc { } } -func PublicApiItemOrAssetList() echo.HandlerFunc { +func publicApiSchema() echo.HandlerFunc { + return func(c echo.Context) error { + ctx := c.Request().Context() + ctrl := GetController(c.Request().Context()) + + p, m, s := c.Param("project"), c.Param("model"), c.Param("schema") + var res any + var err error + if s == "schema.json" { + res, err = ctrl.getSchema(ctx, p, m) + } + if err != nil { + return err + } + + return c.JSON(http.StatusOK, res) + } +} + +func publicApiItemOrAssetList() echo.HandlerFunc { return func(c echo.Context) error { ctx := c.Request().Context() ctrl := GetController(ctx) diff --git a/server/internal/adapter/publicapi/schema.go b/server/internal/adapter/publicapi/schema.go new file mode 100644 index 0000000000..1dc63517d1 --- /dev/null +++ b/server/internal/adapter/publicapi/schema.go @@ -0,0 +1,40 @@ +package publicapi + +import ( + "context" + + "github.com/reearth/reearth-cms/server/pkg/id" + "github.com/reearth/reearthx/rerror" +) + +func (c *Controller) getSchema(ctx context.Context, prj, mkey string) (SchemaJSON, error) { + _, err := c.checkProject(ctx, prj) + if err != nil { + return SchemaJSON{}, err + } + + if mkey == "" { + return SchemaJSON{}, rerror.ErrNotFound + } + + mid, err := id.ModelIDFrom(mkey) + if err != nil { + return SchemaJSON{}, rerror.ErrNotFound + } + + m, err := c.usecases.Model.FindByID(ctx, mid, nil) + if err != nil { + return SchemaJSON{}, err + } + + if m.Key().String() != mkey || !m.Public() { + return SchemaJSON{}, rerror.ErrNotFound + } + + sp, err := c.usecases.Schema.FindByModel(ctx, m.ID(), nil) + if err != nil { + return SchemaJSON{}, err + } + + return NewSchemaJSON(sp.Schema()), nil +} diff --git a/server/internal/adapter/publicapi/types.go b/server/internal/adapter/publicapi/types.go index 4e1d495e91..fc4d312777 100644 --- a/server/internal/adapter/publicapi/types.go +++ b/server/internal/adapter/publicapi/types.go @@ -212,6 +212,24 @@ func NewItemAsset(a *asset.Asset, urlResolver asset.URLResolver) ItemAsset { } } +type SchemaJSON struct { + Id *string `json:"$id,omitempty"` + Schema *string `json:"$schema,omitempty"` + Description *string `json:"description,omitempty"` + Properties *map[string]interface{} `json:"properties,omitempty"` + Title *string `json:"title,omitempty"` + Type *string `json:"type,omitempty"` +} + +func (s SchemaJSON) MarshalJSON() ([]byte, error) { + return json.Marshal(s) +} + +func NewSchemaJSON(s *schema.Schema) SchemaJSON { + return SchemaJSON{} +} + + // GeoJSON type GeoJSON = FeatureCollection From 08c0302fea36e46bc00eb451e2c841baf0525bda Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 6 Nov 2024 19:36:03 +0900 Subject: [PATCH 06/39] revert --- go.work.sum | 4 ---- 1 file changed, 4 deletions(-) diff --git a/go.work.sum b/go.work.sum index ab7fb719c0..4df069b56b 100644 --- a/go.work.sum +++ b/go.work.sum @@ -250,11 +250,8 @@ cloud.google.com/go/auth v0.7.2/go.mod h1:VEc4p5NNxycWQTMQEDQF0bd6aTMb6VgYDXEwiJ cloud.google.com/go/auth v0.8.0/go.mod h1:qGVp/Y3kDRSDZ5gFD/XPUfYQ9xW1iI7q8RIRoCyBbJc= cloud.google.com/go/auth v0.9.0/go.mod h1:2HsApZBr9zGZhC9QAXsYVYaWk8kNUt37uny+XVKi7wM= cloud.google.com/go/auth v0.9.3/go.mod h1:7z6VY+7h3KUdRov5F1i8NDP5ZzWKYmEPO842BgCsmTk= -cloud.google.com/go/auth v0.9.4/go.mod h1:SHia8n6//Ya940F1rLimhJCjjx7KE17t0ctFEci3HkA= -cloud.google.com/go/auth v0.9.9/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I= -cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= cloud.google.com/go/automl v1.5.0 h1:Av8bE5rMQxUl4SVfYsEczEJf1ftIKQOUGGzpzEYwodY= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= cloud.google.com/go/automl v1.6.0 h1:U+kHmeKGXgBvTlrecPJhwkItWaIpIscG5DUpQxBQZZg= @@ -3381,7 +3378,6 @@ google.golang.org/genproto/googleapis/bytestream v0.0.0-20240903143218-8af14fe29 google.golang.org/genproto/googleapis/bytestream v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:q0eWNnCW04EJlyrmLT+ZHsjuoUiZ36/eAEdCCezZoco= google.golang.org/genproto/googleapis/bytestream v0.0.0-20241015192408-796eee8c2d53 h1:mVZqGNBNN8C63iGnWgHZSGbT/vG7voylnp4atysmReg= google.golang.org/genproto/googleapis/bytestream v0.0.0-20241015192408-796eee8c2d53/go.mod h1:T8O3fECQbif8cez15vxAcjbwXxvL2xbnvbQ7ZfiMAMs= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20241021214115-324edc3d5d38/go.mod h1:T8O3fECQbif8cez15vxAcjbwXxvL2xbnvbQ7ZfiMAMs= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= From 5c01ae6ae619cdd1d3bcf318d0cb3a21af389310 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 6 Nov 2024 19:39:30 +0900 Subject: [PATCH 07/39] fix --- server/internal/adapter/publicapi/api.go | 28 +++++++----------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/server/internal/adapter/publicapi/api.go b/server/internal/adapter/publicapi/api.go index 031dbe2d5e..c8f3693fb2 100644 --- a/server/internal/adapter/publicapi/api.go +++ b/server/internal/adapter/publicapi/api.go @@ -35,7 +35,6 @@ func Echo(e *echo.Group) { e.Use(middleware.CORS()) e.GET("/:project/:model", publicApiItemOrAssetList()) e.GET("/:project/:model/:item", publicApiItemOrAsset()) - e.GET("/:project/:model/:schema", publicApiSchema()) } func publicApiItemOrAsset() echo.HandlerFunc { @@ -44,6 +43,14 @@ func publicApiItemOrAsset() echo.HandlerFunc { ctrl := GetController(c.Request().Context()) p, m, i := c.Param("project"), c.Param("model"), c.Param("item") + if i == "schema.json" { + res, err := ctrl.getSchema(ctx, p, m) + if err != nil { + return err + } + return c.JSON(http.StatusOK, res) + } + var res any var err error if m == "assets" { @@ -60,25 +67,6 @@ func publicApiItemOrAsset() echo.HandlerFunc { } } -func publicApiSchema() echo.HandlerFunc { - return func(c echo.Context) error { - ctx := c.Request().Context() - ctrl := GetController(c.Request().Context()) - - p, m, s := c.Param("project"), c.Param("model"), c.Param("schema") - var res any - var err error - if s == "schema.json" { - res, err = ctrl.getSchema(ctx, p, m) - } - if err != nil { - return err - } - - return c.JSON(http.StatusOK, res) - } -} - func publicApiItemOrAssetList() echo.HandlerFunc { return func(c echo.Context) error { ctx := c.Request().Context() From 29c7f49a27c71aed60201e8f01ac4b477f3ac7d5 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Thu, 7 Nov 2024 14:47:11 +0900 Subject: [PATCH 08/39] refactor --- server/internal/adapter/publicapi/api.go | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/server/internal/adapter/publicapi/api.go b/server/internal/adapter/publicapi/api.go index c8f3693fb2..378816adbf 100644 --- a/server/internal/adapter/publicapi/api.go +++ b/server/internal/adapter/publicapi/api.go @@ -33,29 +33,28 @@ func GetController(ctx context.Context) *Controller { func Echo(e *echo.Group) { e.Use(middleware.CORS()) - e.GET("/:project/:model", publicApiItemOrAssetList()) - e.GET("/:project/:model/:item", publicApiItemOrAsset()) + e.GET("/:project/:model", PublicApiItemOrAssetList()) + e.GET("/:project/:model/:item", PublicApiItemOrAsset()) } -func publicApiItemOrAsset() echo.HandlerFunc { +func PublicApiItemOrAsset() echo.HandlerFunc { return func(c echo.Context) error { ctx := c.Request().Context() ctrl := GetController(c.Request().Context()) p, m, i := c.Param("project"), c.Param("model"), c.Param("item") - if i == "schema.json" { - res, err := ctrl.getSchema(ctx, p, m) - if err != nil { - return err - } - return c.JSON(http.StatusOK, res) - } - var res any var err error if m == "assets" { res, err = ctrl.GetAsset(ctx, p, i) } else { + if i == "schema.json" { + res, err := ctrl.getSchema(ctx, p, m) + if err != nil { + return err + } + return c.JSON(http.StatusOK, res) + } res, err = ctrl.GetItem(ctx, p, m, i) } @@ -67,7 +66,7 @@ func publicApiItemOrAsset() echo.HandlerFunc { } } -func publicApiItemOrAssetList() echo.HandlerFunc { +func PublicApiItemOrAssetList() echo.HandlerFunc { return func(c echo.Context) error { ctx := c.Request().Context() ctrl := GetController(ctx) From 8b58bc3509ab4737f0e20fb0a805e5520e442108 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Fri, 8 Nov 2024 15:21:06 +0900 Subject: [PATCH 09/39] wip: update integration end points --- server/internal/adapter/integration/schema.go | 12 + .../adapter/integration/server.gen.go | 445 +++++++++++++++--- server/schemas/integration.yml | 86 ++++ 3 files changed, 473 insertions(+), 70 deletions(-) diff --git a/server/internal/adapter/integration/schema.go b/server/internal/adapter/integration/schema.go index d2e34a6a06..da21e16d10 100644 --- a/server/internal/adapter/integration/schema.go +++ b/server/internal/adapter/integration/schema.go @@ -360,6 +360,14 @@ func (s *Server) FieldDeleteWithProject(ctx context.Context, request FieldDelete }, err } +func (s *Server) SchemaByModelAsJSON(ctx context.Context, request SchemaByModelAsJSONRequestObject) (SchemaByModelAsJSONResponseObject, error) { + panic("not implemented") +} + +func (s *Server) MetadataSchemaByModelAsJSON(ctx context.Context, request MetadataSchemaByModelAsJSONRequestObject) (MetadataSchemaByModelAsJSONResponseObject, error) { + panic("not implemented") +} + func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request SchemaByModelWithProjectAsJSONRequestObject) (SchemaByModelWithProjectAsJSONResponseObject, error) { uc := adapter.Usecases(ctx) op := adapter.Operator(ctx) @@ -398,6 +406,10 @@ func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request Sch }, nil } +func (s *Server) MetadataSchemaByModelWithProjectAsJSON(ctx context.Context, request MetadataSchemaByModelWithProjectAsJSONRequestObject) (MetadataSchemaByModelWithProjectAsJSONResponseObject, error) { + panic("not implemented") +} + func (s *Server) SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONRequestObject) (SchemaByIDAsJSONResponseObject, error) { uc := adapter.Usecases(ctx) op := adapter.Operator(ctx) diff --git a/server/internal/adapter/integration/server.gen.go b/server/internal/adapter/integration/server.gen.go index f61c6c79f4..dd5212326e 100644 --- a/server/internal/adapter/integration/server.gen.go +++ b/server/internal/adapter/integration/server.gen.go @@ -90,6 +90,12 @@ type ServerInterface interface { // Returns a GeoJSON that has a list of items as features. // (GET /models/{modelId}/items.geojson) ItemsAsGeoJSON(ctx echo.Context, modelId ModelIdParam, params ItemsAsGeoJSONParams) error + // Returns a JSON that has schema + // (GET /models/{modelId}/metadata_schema.json) + MetadataSchemaByModelAsJSON(ctx echo.Context, modelId ModelIdParam) error + // Returns a JSON that has schema + // (GET /models/{modelId}/schema.json) + SchemaByModelAsJSON(ctx echo.Context, modelId ModelIdParam) error // Returns a list of models. // (GET /projects/{projectIdOrAlias}/models) ModelFilter(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, params ModelFilterParams) error @@ -127,6 +133,9 @@ type ServerInterface interface { // (GET /projects/{projectIdOrAlias}/models/{modelIdOrKey}/items.geojson) ItemsWithProjectAsGeoJSON(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, modelIdOrKey ModelIdOrKeyParam, params ItemsWithProjectAsGeoJSONParams) error // Returns a JSON that has schema. + // (GET /projects/{projectIdOrAlias}/models/{modelIdOrKey}/metadata_schema.json) + MetadataSchemaByModelWithProjectAsJSON(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, modelIdOrKey ModelIdOrKeyParam) error + // Returns a JSON that has schema. // (GET /projects/{projectIdOrAlias}/models/{modelIdOrKey}/schema.json) SchemaByModelWithProjectAsJSON(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, modelIdOrKey ModelIdOrKeyParam) error // Returns a schema. @@ -682,6 +691,42 @@ func (w *ServerInterfaceWrapper) ItemsAsGeoJSON(ctx echo.Context) error { return err } +// MetadataSchemaByModelAsJSON converts echo context to params. +func (w *ServerInterfaceWrapper) MetadataSchemaByModelAsJSON(ctx echo.Context) error { + var err error + // ------------- Path parameter "modelId" ------------- + var modelId ModelIdParam + + err = runtime.BindStyledParameterWithOptions("simple", "modelId", ctx.Param("modelId"), &modelId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter modelId: %s", err)) + } + + ctx.Set(BearerAuthScopes, []string{}) + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.MetadataSchemaByModelAsJSON(ctx, modelId) + return err +} + +// SchemaByModelAsJSON converts echo context to params. +func (w *ServerInterfaceWrapper) SchemaByModelAsJSON(ctx echo.Context) error { + var err error + // ------------- Path parameter "modelId" ------------- + var modelId ModelIdParam + + err = runtime.BindStyledParameterWithOptions("simple", "modelId", ctx.Param("modelId"), &modelId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter modelId: %s", err)) + } + + ctx.Set(BearerAuthScopes, []string{}) + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.SchemaByModelAsJSON(ctx, modelId) + return err +} + // ModelFilter converts echo context to params. func (w *ServerInterfaceWrapper) ModelFilter(ctx echo.Context) error { var err error @@ -1116,6 +1161,32 @@ func (w *ServerInterfaceWrapper) ItemsWithProjectAsGeoJSON(ctx echo.Context) err return err } +// MetadataSchemaByModelWithProjectAsJSON converts echo context to params. +func (w *ServerInterfaceWrapper) MetadataSchemaByModelWithProjectAsJSON(ctx echo.Context) error { + var err error + // ------------- Path parameter "projectIdOrAlias" ------------- + var projectIdOrAlias ProjectIdOrAliasParam + + err = runtime.BindStyledParameterWithOptions("simple", "projectIdOrAlias", ctx.Param("projectIdOrAlias"), &projectIdOrAlias, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter projectIdOrAlias: %s", err)) + } + + // ------------- Path parameter "modelIdOrKey" ------------- + var modelIdOrKey ModelIdOrKeyParam + + err = runtime.BindStyledParameterWithOptions("simple", "modelIdOrKey", ctx.Param("modelIdOrKey"), &modelIdOrKey, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter modelIdOrKey: %s", err)) + } + + ctx.Set(BearerAuthScopes, []string{}) + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.MetadataSchemaByModelWithProjectAsJSON(ctx, projectIdOrAlias, modelIdOrKey) + return err +} + // SchemaByModelWithProjectAsJSON converts echo context to params. func (w *ServerInterfaceWrapper) SchemaByModelWithProjectAsJSON(ctx echo.Context) error { var err error @@ -1453,6 +1524,8 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL router.POST(baseURL+"/models/:modelId/items", wrapper.ItemCreate) router.GET(baseURL+"/models/:modelId/items.csv", wrapper.ItemsAsCSV) router.GET(baseURL+"/models/:modelId/items.geojson", wrapper.ItemsAsGeoJSON) + router.GET(baseURL+"/models/:modelId/metadata_schema.json", wrapper.MetadataSchemaByModelAsJSON) + router.GET(baseURL+"/models/:modelId/schema.json", wrapper.SchemaByModelAsJSON) router.GET(baseURL+"/projects/:projectIdOrAlias/models", wrapper.ModelFilter) router.POST(baseURL+"/projects/:projectIdOrAlias/models", wrapper.ModelCreate) router.DELETE(baseURL+"/projects/:projectIdOrAlias/models/:modelIdOrKey", wrapper.ModelDeleteWithProject) @@ -1465,6 +1538,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL router.POST(baseURL+"/projects/:projectIdOrAlias/models/:modelIdOrKey/items", wrapper.ItemCreateWithProject) router.GET(baseURL+"/projects/:projectIdOrAlias/models/:modelIdOrKey/items.csv", wrapper.ItemsWithProjectAsCSV) router.GET(baseURL+"/projects/:projectIdOrAlias/models/:modelIdOrKey/items.geojson", wrapper.ItemsWithProjectAsGeoJSON) + router.GET(baseURL+"/projects/:projectIdOrAlias/models/:modelIdOrKey/metadata_schema.json", wrapper.MetadataSchemaByModelWithProjectAsJSON) router.GET(baseURL+"/projects/:projectIdOrAlias/models/:modelIdOrKey/schema.json", wrapper.SchemaByModelWithProjectAsJSON) router.GET(baseURL+"/projects/:projectIdOrAlias/schemata", wrapper.SchemaFilter) router.GET(baseURL+"/projects/:projectIdOrAlias/schemata/:schemaId/schema.json", wrapper.SchemaByIDAsJSON) @@ -2402,6 +2476,102 @@ func (response ItemsAsGeoJSON500Response) VisitItemsAsGeoJSONResponse(w http.Res return nil } +type MetadataSchemaByModelAsJSONRequestObject struct { + ModelId ModelIdParam `json:"modelId"` +} + +type MetadataSchemaByModelAsJSONResponseObject interface { + VisitMetadataSchemaByModelAsJSONResponse(w http.ResponseWriter) error +} + +type MetadataSchemaByModelAsJSON200JSONResponse SchemaJSON + +func (response MetadataSchemaByModelAsJSON200JSONResponse) VisitMetadataSchemaByModelAsJSONResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +type MetadataSchemaByModelAsJSON400Response struct { +} + +func (response MetadataSchemaByModelAsJSON400Response) VisitMetadataSchemaByModelAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(400) + return nil +} + +type MetadataSchemaByModelAsJSON401Response = UnauthorizedErrorResponse + +func (response MetadataSchemaByModelAsJSON401Response) VisitMetadataSchemaByModelAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(401) + return nil +} + +type MetadataSchemaByModelAsJSON404Response struct { +} + +func (response MetadataSchemaByModelAsJSON404Response) VisitMetadataSchemaByModelAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(404) + return nil +} + +type MetadataSchemaByModelAsJSON500Response struct { +} + +func (response MetadataSchemaByModelAsJSON500Response) VisitMetadataSchemaByModelAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(500) + return nil +} + +type SchemaByModelAsJSONRequestObject struct { + ModelId ModelIdParam `json:"modelId"` +} + +type SchemaByModelAsJSONResponseObject interface { + VisitSchemaByModelAsJSONResponse(w http.ResponseWriter) error +} + +type SchemaByModelAsJSON200JSONResponse SchemaJSON + +func (response SchemaByModelAsJSON200JSONResponse) VisitSchemaByModelAsJSONResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +type SchemaByModelAsJSON400Response struct { +} + +func (response SchemaByModelAsJSON400Response) VisitSchemaByModelAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(400) + return nil +} + +type SchemaByModelAsJSON401Response = UnauthorizedErrorResponse + +func (response SchemaByModelAsJSON401Response) VisitSchemaByModelAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(401) + return nil +} + +type SchemaByModelAsJSON404Response struct { +} + +func (response SchemaByModelAsJSON404Response) VisitSchemaByModelAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(404) + return nil +} + +type SchemaByModelAsJSON500Response struct { +} + +func (response SchemaByModelAsJSON500Response) VisitSchemaByModelAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(500) + return nil +} + type ModelFilterRequestObject struct { ProjectIdOrAlias ProjectIdOrAliasParam `json:"projectIdOrAlias"` Params ModelFilterParams @@ -2960,6 +3130,55 @@ func (response ItemsWithProjectAsGeoJSON500Response) VisitItemsWithProjectAsGeoJ return nil } +type MetadataSchemaByModelWithProjectAsJSONRequestObject struct { + ProjectIdOrAlias ProjectIdOrAliasParam `json:"projectIdOrAlias"` + ModelIdOrKey ModelIdOrKeyParam `json:"modelIdOrKey"` +} + +type MetadataSchemaByModelWithProjectAsJSONResponseObject interface { + VisitMetadataSchemaByModelWithProjectAsJSONResponse(w http.ResponseWriter) error +} + +type MetadataSchemaByModelWithProjectAsJSON200JSONResponse SchemaJSON + +func (response MetadataSchemaByModelWithProjectAsJSON200JSONResponse) VisitMetadataSchemaByModelWithProjectAsJSONResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +type MetadataSchemaByModelWithProjectAsJSON400Response struct { +} + +func (response MetadataSchemaByModelWithProjectAsJSON400Response) VisitMetadataSchemaByModelWithProjectAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(400) + return nil +} + +type MetadataSchemaByModelWithProjectAsJSON401Response = UnauthorizedErrorResponse + +func (response MetadataSchemaByModelWithProjectAsJSON401Response) VisitMetadataSchemaByModelWithProjectAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(401) + return nil +} + +type MetadataSchemaByModelWithProjectAsJSON404Response struct { +} + +func (response MetadataSchemaByModelWithProjectAsJSON404Response) VisitMetadataSchemaByModelWithProjectAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(404) + return nil +} + +type MetadataSchemaByModelWithProjectAsJSON500Response struct { +} + +func (response MetadataSchemaByModelWithProjectAsJSON500Response) VisitMetadataSchemaByModelWithProjectAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(500) + return nil +} + type SchemaByModelWithProjectAsJSONRequestObject struct { ProjectIdOrAlias ProjectIdOrAliasParam `json:"projectIdOrAlias"` ModelIdOrKey ModelIdOrKeyParam `json:"modelIdOrKey"` @@ -3467,6 +3686,12 @@ type StrictServerInterface interface { // Returns a GeoJSON that has a list of items as features. // (GET /models/{modelId}/items.geojson) ItemsAsGeoJSON(ctx context.Context, request ItemsAsGeoJSONRequestObject) (ItemsAsGeoJSONResponseObject, error) + // Returns a JSON that has schema + // (GET /models/{modelId}/metadata_schema.json) + MetadataSchemaByModelAsJSON(ctx context.Context, request MetadataSchemaByModelAsJSONRequestObject) (MetadataSchemaByModelAsJSONResponseObject, error) + // Returns a JSON that has schema + // (GET /models/{modelId}/schema.json) + SchemaByModelAsJSON(ctx context.Context, request SchemaByModelAsJSONRequestObject) (SchemaByModelAsJSONResponseObject, error) // Returns a list of models. // (GET /projects/{projectIdOrAlias}/models) ModelFilter(ctx context.Context, request ModelFilterRequestObject) (ModelFilterResponseObject, error) @@ -3504,6 +3729,9 @@ type StrictServerInterface interface { // (GET /projects/{projectIdOrAlias}/models/{modelIdOrKey}/items.geojson) ItemsWithProjectAsGeoJSON(ctx context.Context, request ItemsWithProjectAsGeoJSONRequestObject) (ItemsWithProjectAsGeoJSONResponseObject, error) // Returns a JSON that has schema. + // (GET /projects/{projectIdOrAlias}/models/{modelIdOrKey}/metadata_schema.json) + MetadataSchemaByModelWithProjectAsJSON(ctx context.Context, request MetadataSchemaByModelWithProjectAsJSONRequestObject) (MetadataSchemaByModelWithProjectAsJSONResponseObject, error) + // Returns a JSON that has schema. // (GET /projects/{projectIdOrAlias}/models/{modelIdOrKey}/schema.json) SchemaByModelWithProjectAsJSON(ctx context.Context, request SchemaByModelWithProjectAsJSONRequestObject) (SchemaByModelWithProjectAsJSONResponseObject, error) // Returns a schema. @@ -4142,6 +4370,56 @@ func (sh *strictHandler) ItemsAsGeoJSON(ctx echo.Context, modelId ModelIdParam, return nil } +// MetadataSchemaByModelAsJSON operation middleware +func (sh *strictHandler) MetadataSchemaByModelAsJSON(ctx echo.Context, modelId ModelIdParam) error { + var request MetadataSchemaByModelAsJSONRequestObject + + request.ModelId = modelId + + handler := func(ctx echo.Context, request interface{}) (interface{}, error) { + return sh.ssi.MetadataSchemaByModelAsJSON(ctx.Request().Context(), request.(MetadataSchemaByModelAsJSONRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "MetadataSchemaByModelAsJSON") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(MetadataSchemaByModelAsJSONResponseObject); ok { + return validResponse.VisitMetadataSchemaByModelAsJSONResponse(ctx.Response()) + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + +// SchemaByModelAsJSON operation middleware +func (sh *strictHandler) SchemaByModelAsJSON(ctx echo.Context, modelId ModelIdParam) error { + var request SchemaByModelAsJSONRequestObject + + request.ModelId = modelId + + handler := func(ctx echo.Context, request interface{}) (interface{}, error) { + return sh.ssi.SchemaByModelAsJSON(ctx.Request().Context(), request.(SchemaByModelAsJSONRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "SchemaByModelAsJSON") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(SchemaByModelAsJSONResponseObject); ok { + return validResponse.VisitSchemaByModelAsJSONResponse(ctx.Response()) + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + // ModelFilter operation middleware func (sh *strictHandler) ModelFilter(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, params ModelFilterParams) error { var request ModelFilterRequestObject @@ -4489,6 +4767,32 @@ func (sh *strictHandler) ItemsWithProjectAsGeoJSON(ctx echo.Context, projectIdOr return nil } +// MetadataSchemaByModelWithProjectAsJSON operation middleware +func (sh *strictHandler) MetadataSchemaByModelWithProjectAsJSON(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, modelIdOrKey ModelIdOrKeyParam) error { + var request MetadataSchemaByModelWithProjectAsJSONRequestObject + + request.ProjectIdOrAlias = projectIdOrAlias + request.ModelIdOrKey = modelIdOrKey + + handler := func(ctx echo.Context, request interface{}) (interface{}, error) { + return sh.ssi.MetadataSchemaByModelWithProjectAsJSON(ctx.Request().Context(), request.(MetadataSchemaByModelWithProjectAsJSONRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "MetadataSchemaByModelWithProjectAsJSON") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(MetadataSchemaByModelWithProjectAsJSONResponseObject); ok { + return validResponse.VisitMetadataSchemaByModelWithProjectAsJSONResponse(ctx.Response()) + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + // SchemaByModelWithProjectAsJSON operation middleware func (sh *strictHandler) SchemaByModelWithProjectAsJSON(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, modelIdOrKey ModelIdOrKeyParam) error { var request SchemaByModelWithProjectAsJSONRequestObject @@ -4781,76 +5085,77 @@ func (sh *strictHandler) ProjectFilter(ctx echo.Context, workspaceId WorkspaceId // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "m3JHM55kV/9isfhfAAAA///iOG1HOqUAAA==", + "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/server/schemas/integration.yml b/server/schemas/integration.yml index e86e8a9cd3..75e30cc056 100644 --- a/server/schemas/integration.yml +++ b/server/schemas/integration.yml @@ -271,6 +271,63 @@ paths: description: Invalid request parameter value '401': $ref: '#/components/responses/UnauthorizedError' + /models/{modelId}/schema.json: + parameters: + - $ref: '#/components/parameters/modelIdParam' + get: + operationId: SchemaByModelAsJSON + security: + - bearerAuth: [] + summary: Returns a JSON that has schema + tags: + - Schema + - JSON + description: Returns a JSON that has schema + responses: + '200': + description: A JSON object + content: + application/json: + schema: + $ref: '#/components/schemas/schemaJSON' + format: binary + '400': + description: Invalid request parameter value + '401': + $ref: '#/components/responses/UnauthorizedError' + '404': + description: Not found + '500': + description: Internal server error + + /models/{modelId}/metadata_schema.json: + parameters: + - $ref: '#/components/parameters/modelIdParam' + get: + operationId: MetadataSchemaByModelAsJSON + security: + - bearerAuth: [] + summary: Returns a JSON that has schema + tags: + - MetadataSchema + - JSON + description: Returns a JSON that has metadata schema + responses: + '200': + description: A JSON object + content: + application/json: + schema: + $ref: '#/components/schemas/schemaJSON' + format: binary + '400': + description: Invalid request parameter value + '401': + $ref: '#/components/responses/UnauthorizedError' + '404': + description: Not found + '500': + description: Internal server error '/models/{modelId}/import': parameters: - $ref: '#/components/parameters/modelIdParam' @@ -983,6 +1040,35 @@ paths: description: Not found '500': description: Internal server error + '/projects/{projectIdOrAlias}/models/{modelIdOrKey}/metadata_schema.json': + parameters: + - $ref: '#/components/parameters/projectIdOrAliasParam' + - $ref: '#/components/parameters/modelIdOrKeyParam' + get: + operationId: MetadataSchemaByModelWithProjectAsJSON + security: + - bearerAuth: [] + summary: Returns a JSON that has schema. + tags: + - Schema + - JSON + description: Returns a JSON that has schema. + responses: + '200': + description: A JSON object + content: + application/json: + schema: + $ref: '#/components/schemas/schemaJSON' + format: binary + '400': + description: Invalid request parameter value + '401': + $ref: '#/components/responses/UnauthorizedError' + '404': + description: Not found + '500': + description: Internal server error '/items/{itemId}': parameters: - $ref: '#/components/parameters/itemIdParam' From c3edb1ac5e05c88c04836e1f3505ee4b9e68897a Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Mon, 11 Nov 2024 14:48:13 +0900 Subject: [PATCH 10/39] wip: add 4 more integration api endpoints --- server/e2e/integration_schema_test.go | 34 ++++ server/internal/adapter/integration/schema.go | 132 +++++++++++++- .../adapter/integration/server.gen.go | 166 ++++++++++++++---- server/schemas/integration.yml | 31 +++- 4 files changed, 324 insertions(+), 39 deletions(-) diff --git a/server/e2e/integration_schema_test.go b/server/e2e/integration_schema_test.go index 04ecbf605e..6becc48551 100644 --- a/server/e2e/integration_schema_test.go +++ b/server/e2e/integration_schema_test.go @@ -800,3 +800,37 @@ func TestIntegrationFieldDeleteWithProjectAPI(t *testing.T) { obj1.Value("updatedAt").NotNull() obj1.Value("lastModified").NotNull() } + +func TestIntegrationSchemaJSONExportAPI(t *testing.T) { + e := StartServer(t, &app.Config{}, true, baseSeeder) + + e.GET("/api/schemata/{schemaId}/schema.json", sid1). + WithHeader("authorization", "Bearer "+secret). + Expect(). + Status(http.StatusOK) + + e.GET("/api/projects/{projectIdOrKey}/schemata/{schemaId}/schema.json", pid, sid1). + WithHeader("authorization", "Bearer "+secret). + Expect(). + Status(http.StatusOK) + + e.GET("/api/projects/{projectIdOrKey}/models/{modelId}/schema.json", pid, mId1). + WithHeader("authorization", "Bearer "+secret). + Expect(). + Status(http.StatusOK) + + e.GET("/api/projects/{projectIdOrKey}/models/{modelId}/metadata_schema.json", pid, mId1). + WithHeader("authorization", "Bearer "+secret). + Expect(). + Status(http.StatusOK) + + e.GET("/api/models/{modelId}/schema.json", mId1). + WithHeader("authorization", "Bearer "+secret). + Expect(). + Status(http.StatusOK) + + e.GET("/api/models/{modelId}/metadata_schema.json", mId1). + WithHeader("authorization", "Bearer "+secret). + Expect(). + Status(http.StatusOK) +} diff --git a/server/internal/adapter/integration/schema.go b/server/internal/adapter/integration/schema.go index da21e16d10..fa386de46e 100644 --- a/server/internal/adapter/integration/schema.go +++ b/server/internal/adapter/integration/schema.go @@ -361,11 +361,57 @@ func (s *Server) FieldDeleteWithProject(ctx context.Context, request FieldDelete } func (s *Server) SchemaByModelAsJSON(ctx context.Context, request SchemaByModelAsJSONRequestObject) (SchemaByModelAsJSONResponseObject, error) { - panic("not implemented") + op := adapter.Operator(ctx) + uc := adapter.Usecases(ctx) + + m, err := uc.Model.FindByID(ctx, request.ModelId, op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return SchemaByModelAsJSON400Response{}, err + } + return SchemaByModelAsJSON400Response{}, err + } + + sp, err := uc.Schema.FindByModel(ctx, m.ID(), op) + if err != nil { + return SchemaByModelAsJSON400Response{}, err + } + + return SchemaByModelAsJSON200JSONResponse{ + Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), + Id: m.ID().Ref().StringRef(), + Title: lo.ToPtr(m.Name()), + Description: lo.ToPtr(m.Description()), + Type: lo.ToPtr("object"), + Properties: toProperties(sp.Schema()), + }, nil } func (s *Server) MetadataSchemaByModelAsJSON(ctx context.Context, request MetadataSchemaByModelAsJSONRequestObject) (MetadataSchemaByModelAsJSONResponseObject, error) { - panic("not implemented") + op := adapter.Operator(ctx) + uc := adapter.Usecases(ctx) + + m, err := uc.Model.FindByID(ctx, request.ModelId, op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return MetadataSchemaByModelAsJSON400Response{}, err + } + return MetadataSchemaByModelAsJSON400Response{}, err + } + + sp, err := uc.Schema.FindByModel(ctx, request.ModelId, op) + if err != nil { + return MetadataSchemaByModelAsJSON400Response{}, err + } + + return MetadataSchemaByModelAsJSON200JSONResponse{ + Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), + Id: m.ID().Ref().StringRef(), + Title: lo.ToPtr(m.Name()), + Description: lo.ToPtr(m.Description()), + Type: lo.ToPtr("object"), + Properties: toProperties(sp.MetaSchema()), + }, nil } func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request SchemaByModelWithProjectAsJSONRequestObject) (SchemaByModelWithProjectAsJSONResponseObject, error) { @@ -407,7 +453,41 @@ func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request Sch } func (s *Server) MetadataSchemaByModelWithProjectAsJSON(ctx context.Context, request MetadataSchemaByModelWithProjectAsJSONRequestObject) (MetadataSchemaByModelWithProjectAsJSONResponseObject, error) { - panic("not implemented") + uc := adapter.Usecases(ctx) + op := adapter.Operator(ctx) + + p, err := uc.Project.FindByIDOrAlias(ctx, request.ProjectIdOrAlias, op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return MetadataSchemaByModelWithProjectAsJSON400Response{}, err + } + return MetadataSchemaByModelWithProjectAsJSON400Response{}, err + } + + m, err := uc.Model.FindByIDOrKey(ctx, p.ID(), request.ModelIdOrKey, op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return MetadataSchemaByModelWithProjectAsJSON400Response{}, err + } + return MetadataSchemaByModelWithProjectAsJSON400Response{}, err + } + + sch, err := uc.Schema.FindByModel(ctx, m.ID(), op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return MetadataSchemaByModelWithProjectAsJSON400Response{}, err + } + return MetadataSchemaByModelWithProjectAsJSON400Response{}, err + } + + return MetadataSchemaByModelWithProjectAsJSON200JSONResponse{ + Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), + Id: m.ID().Ref().StringRef(), + Title: lo.ToPtr(m.Name()), + Description: lo.ToPtr(m.Description()), + Type: lo.ToPtr("object"), + Properties: toProperties(sch.MetaSchema()), + }, nil } func (s *Server) SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONRequestObject) (SchemaByIDAsJSONResponseObject, error) { @@ -430,6 +510,52 @@ func (s *Server) SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONR }, nil } +func (s *Server) SchemaByIDWithProjectAsJSON(ctx context.Context, request SchemaByIDWithProjectAsJSONRequestObject) (SchemaByIDWithProjectAsJSONResponseObject, error) { + uc := adapter.Usecases(ctx) + op := adapter.Operator(ctx) + + // prj, err := uc.Project.FindByIDOrAlias(ctx, request.ProjectIdOrAlias, op) + // if err != nil { + // if errors.Is(err, rerror.ErrNotFound) { + // return SchemaByIDWithProjectAsJSON400Response{}, err + // } + // return SchemaByIDWithProjectAsJSON400Response{}, err + // } + + // ms, _, err := uc.Model.FindByProjectAndKeyword(ctx, prj.ID(), lo.FromPtrOr(request.Params.Keyword, ""), p, op) + // if err != nil { + // return nil, err + // } + + // models := make([]integrationapi.Model, 0, len(ms)) + // for _, m := range ms { + // sp, err := uc.Schema.FindByModel(ctx, m.ID(), op) + // if err != nil { + // return nil, err + // } + // lastModified, err := uc.Item.LastModifiedByModel(ctx, m.ID(), op) + // if err != nil && !errors.Is(err, rerror.ErrNotFound) { + // return nil, err + // } + // models = append(models, integrationapi.NewModel(m, sp, lastModified)) + // } + + sch, err := uc.Schema.FindByID(ctx, request.SchemaId, op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return SchemaByIDWithProjectAsJSON400Response{}, err + } + return SchemaByIDWithProjectAsJSON400Response{}, err + } + + return SchemaByIDWithProjectAsJSON200JSONResponse{ + Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), + Id: sch.ID().Ref().StringRef(), + Type: lo.ToPtr("object"), + Properties: toProperties(sch), + }, nil +} + func toProperties(sch *schema.Schema) *map[string]interface{} { return nil } diff --git a/server/internal/adapter/integration/server.gen.go b/server/internal/adapter/integration/server.gen.go index dd5212326e..b925f1515f 100644 --- a/server/internal/adapter/integration/server.gen.go +++ b/server/internal/adapter/integration/server.gen.go @@ -143,7 +143,7 @@ type ServerInterface interface { SchemaFilter(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, params SchemaFilterParams) error // Returns a JSON that has schema. // (GET /projects/{projectIdOrAlias}/schemata/{schemaId}/schema.json) - SchemaByIDAsJSON(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, schemaId SchemaIdParam) error + SchemaByIDWithProjectAsJSON(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, schemaId SchemaIdParam) error // Returns a list of assets. // (GET /projects/{projectId}/assets) AssetFilter(ctx echo.Context, projectId ProjectIdParam, params AssetFilterParams) error @@ -162,6 +162,9 @@ type ServerInterface interface { // update a field // (PATCH /schemata/{schemaId}/fields/{fieldIdOrKey}) FieldUpdate(ctx echo.Context, schemaId SchemaIdParam, fieldIdOrKey FieldIdOrKeyParam) error + // Returns a JSON that has schema. + // (GET /schemata/{schemaId}/schema.json) + SchemaByIDAsJSON(ctx echo.Context, schemaId SchemaIdParam) error // Returns a list of projects. // (GET /{workspaceId}/projects) ProjectFilter(ctx echo.Context, workspaceId WorkspaceIdParam, params ProjectFilterParams) error @@ -1254,8 +1257,8 @@ func (w *ServerInterfaceWrapper) SchemaFilter(ctx echo.Context) error { return err } -// SchemaByIDAsJSON converts echo context to params. -func (w *ServerInterfaceWrapper) SchemaByIDAsJSON(ctx echo.Context) error { +// SchemaByIDWithProjectAsJSON converts echo context to params. +func (w *ServerInterfaceWrapper) SchemaByIDWithProjectAsJSON(ctx echo.Context) error { var err error // ------------- Path parameter "projectIdOrAlias" ------------- var projectIdOrAlias ProjectIdOrAliasParam @@ -1276,7 +1279,7 @@ func (w *ServerInterfaceWrapper) SchemaByIDAsJSON(ctx echo.Context) error { ctx.Set(BearerAuthScopes, []string{}) // Invoke the callback with all the unmarshaled arguments - err = w.Handler.SchemaByIDAsJSON(ctx, projectIdOrAlias, schemaId) + err = w.Handler.SchemaByIDWithProjectAsJSON(ctx, projectIdOrAlias, schemaId) return err } @@ -1441,6 +1444,24 @@ func (w *ServerInterfaceWrapper) FieldUpdate(ctx echo.Context) error { return err } +// SchemaByIDAsJSON converts echo context to params. +func (w *ServerInterfaceWrapper) SchemaByIDAsJSON(ctx echo.Context) error { + var err error + // ------------- Path parameter "schemaId" ------------- + var schemaId SchemaIdParam + + err = runtime.BindStyledParameterWithOptions("simple", "schemaId", ctx.Param("schemaId"), &schemaId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter schemaId: %s", err)) + } + + ctx.Set(BearerAuthScopes, []string{}) + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.SchemaByIDAsJSON(ctx, schemaId) + return err +} + // ProjectFilter converts echo context to params. func (w *ServerInterfaceWrapper) ProjectFilter(ctx echo.Context) error { var err error @@ -1541,13 +1562,14 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL router.GET(baseURL+"/projects/:projectIdOrAlias/models/:modelIdOrKey/metadata_schema.json", wrapper.MetadataSchemaByModelWithProjectAsJSON) router.GET(baseURL+"/projects/:projectIdOrAlias/models/:modelIdOrKey/schema.json", wrapper.SchemaByModelWithProjectAsJSON) router.GET(baseURL+"/projects/:projectIdOrAlias/schemata", wrapper.SchemaFilter) - router.GET(baseURL+"/projects/:projectIdOrAlias/schemata/:schemaId/schema.json", wrapper.SchemaByIDAsJSON) + router.GET(baseURL+"/projects/:projectIdOrAlias/schemata/:schemaId/schema.json", wrapper.SchemaByIDWithProjectAsJSON) router.GET(baseURL+"/projects/:projectId/assets", wrapper.AssetFilter) router.POST(baseURL+"/projects/:projectId/assets", wrapper.AssetCreate) router.POST(baseURL+"/projects/:projectId/assets/uploads", wrapper.AssetUploadCreate) router.POST(baseURL+"/schemata/:schemaId/fields", wrapper.FieldCreate) router.DELETE(baseURL+"/schemata/:schemaId/fields/:fieldIdOrKey", wrapper.FieldDelete) router.PATCH(baseURL+"/schemata/:schemaId/fields/:fieldIdOrKey", wrapper.FieldUpdate) + router.GET(baseURL+"/schemata/:schemaId/schema.json", wrapper.SchemaByIDAsJSON) router.GET(baseURL+"/:workspaceId/projects", wrapper.ProjectFilter) } @@ -3282,51 +3304,51 @@ func (response SchemaFilter500Response) VisitSchemaFilterResponse(w http.Respons return nil } -type SchemaByIDAsJSONRequestObject struct { +type SchemaByIDWithProjectAsJSONRequestObject struct { ProjectIdOrAlias ProjectIdOrAliasParam `json:"projectIdOrAlias"` SchemaId SchemaIdParam `json:"schemaId"` } -type SchemaByIDAsJSONResponseObject interface { - VisitSchemaByIDAsJSONResponse(w http.ResponseWriter) error +type SchemaByIDWithProjectAsJSONResponseObject interface { + VisitSchemaByIDWithProjectAsJSONResponse(w http.ResponseWriter) error } -type SchemaByIDAsJSON200JSONResponse SchemaJSON +type SchemaByIDWithProjectAsJSON200JSONResponse SchemaJSON -func (response SchemaByIDAsJSON200JSONResponse) VisitSchemaByIDAsJSONResponse(w http.ResponseWriter) error { +func (response SchemaByIDWithProjectAsJSON200JSONResponse) VisitSchemaByIDWithProjectAsJSONResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) return json.NewEncoder(w).Encode(response) } -type SchemaByIDAsJSON400Response struct { +type SchemaByIDWithProjectAsJSON400Response struct { } -func (response SchemaByIDAsJSON400Response) VisitSchemaByIDAsJSONResponse(w http.ResponseWriter) error { +func (response SchemaByIDWithProjectAsJSON400Response) VisitSchemaByIDWithProjectAsJSONResponse(w http.ResponseWriter) error { w.WriteHeader(400) return nil } -type SchemaByIDAsJSON401Response = UnauthorizedErrorResponse +type SchemaByIDWithProjectAsJSON401Response = UnauthorizedErrorResponse -func (response SchemaByIDAsJSON401Response) VisitSchemaByIDAsJSONResponse(w http.ResponseWriter) error { +func (response SchemaByIDWithProjectAsJSON401Response) VisitSchemaByIDWithProjectAsJSONResponse(w http.ResponseWriter) error { w.WriteHeader(401) return nil } -type SchemaByIDAsJSON404Response struct { +type SchemaByIDWithProjectAsJSON404Response struct { } -func (response SchemaByIDAsJSON404Response) VisitSchemaByIDAsJSONResponse(w http.ResponseWriter) error { +func (response SchemaByIDWithProjectAsJSON404Response) VisitSchemaByIDWithProjectAsJSONResponse(w http.ResponseWriter) error { w.WriteHeader(404) return nil } -type SchemaByIDAsJSON500Response struct { +type SchemaByIDWithProjectAsJSON500Response struct { } -func (response SchemaByIDAsJSON500Response) VisitSchemaByIDAsJSONResponse(w http.ResponseWriter) error { +func (response SchemaByIDWithProjectAsJSON500Response) VisitSchemaByIDWithProjectAsJSONResponse(w http.ResponseWriter) error { w.WriteHeader(500) return nil } @@ -3568,6 +3590,54 @@ func (response FieldUpdate401Response) VisitFieldUpdateResponse(w http.ResponseW return nil } +type SchemaByIDAsJSONRequestObject struct { + SchemaId SchemaIdParam `json:"schemaId"` +} + +type SchemaByIDAsJSONResponseObject interface { + VisitSchemaByIDAsJSONResponse(w http.ResponseWriter) error +} + +type SchemaByIDAsJSON200JSONResponse SchemaJSON + +func (response SchemaByIDAsJSON200JSONResponse) VisitSchemaByIDAsJSONResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +type SchemaByIDAsJSON400Response struct { +} + +func (response SchemaByIDAsJSON400Response) VisitSchemaByIDAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(400) + return nil +} + +type SchemaByIDAsJSON401Response = UnauthorizedErrorResponse + +func (response SchemaByIDAsJSON401Response) VisitSchemaByIDAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(401) + return nil +} + +type SchemaByIDAsJSON404Response struct { +} + +func (response SchemaByIDAsJSON404Response) VisitSchemaByIDAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(404) + return nil +} + +type SchemaByIDAsJSON500Response struct { +} + +func (response SchemaByIDAsJSON500Response) VisitSchemaByIDAsJSONResponse(w http.ResponseWriter) error { + w.WriteHeader(500) + return nil +} + type ProjectFilterRequestObject struct { WorkspaceId WorkspaceIdParam `json:"workspaceId"` Params ProjectFilterParams @@ -3739,7 +3809,7 @@ type StrictServerInterface interface { SchemaFilter(ctx context.Context, request SchemaFilterRequestObject) (SchemaFilterResponseObject, error) // Returns a JSON that has schema. // (GET /projects/{projectIdOrAlias}/schemata/{schemaId}/schema.json) - SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONRequestObject) (SchemaByIDAsJSONResponseObject, error) + SchemaByIDWithProjectAsJSON(ctx context.Context, request SchemaByIDWithProjectAsJSONRequestObject) (SchemaByIDWithProjectAsJSONResponseObject, error) // Returns a list of assets. // (GET /projects/{projectId}/assets) AssetFilter(ctx context.Context, request AssetFilterRequestObject) (AssetFilterResponseObject, error) @@ -3758,6 +3828,9 @@ type StrictServerInterface interface { // update a field // (PATCH /schemata/{schemaId}/fields/{fieldIdOrKey}) FieldUpdate(ctx context.Context, request FieldUpdateRequestObject) (FieldUpdateResponseObject, error) + // Returns a JSON that has schema. + // (GET /schemata/{schemaId}/schema.json) + SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONRequestObject) (SchemaByIDAsJSONResponseObject, error) // Returns a list of projects. // (GET /{workspaceId}/projects) ProjectFilter(ctx context.Context, request ProjectFilterRequestObject) (ProjectFilterResponseObject, error) @@ -4845,26 +4918,26 @@ func (sh *strictHandler) SchemaFilter(ctx echo.Context, projectIdOrAlias Project return nil } -// SchemaByIDAsJSON operation middleware -func (sh *strictHandler) SchemaByIDAsJSON(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, schemaId SchemaIdParam) error { - var request SchemaByIDAsJSONRequestObject +// SchemaByIDWithProjectAsJSON operation middleware +func (sh *strictHandler) SchemaByIDWithProjectAsJSON(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, schemaId SchemaIdParam) error { + var request SchemaByIDWithProjectAsJSONRequestObject request.ProjectIdOrAlias = projectIdOrAlias request.SchemaId = schemaId handler := func(ctx echo.Context, request interface{}) (interface{}, error) { - return sh.ssi.SchemaByIDAsJSON(ctx.Request().Context(), request.(SchemaByIDAsJSONRequestObject)) + return sh.ssi.SchemaByIDWithProjectAsJSON(ctx.Request().Context(), request.(SchemaByIDWithProjectAsJSONRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "SchemaByIDAsJSON") + handler = middleware(handler, "SchemaByIDWithProjectAsJSON") } response, err := handler(ctx, request) if err != nil { return err - } else if validResponse, ok := response.(SchemaByIDAsJSONResponseObject); ok { - return validResponse.VisitSchemaByIDAsJSONResponse(ctx.Response()) + } else if validResponse, ok := response.(SchemaByIDWithProjectAsJSONResponseObject); ok { + return validResponse.VisitSchemaByIDWithProjectAsJSONResponse(ctx.Response()) } else if response != nil { return fmt.Errorf("unexpected response type: %T", response) } @@ -5056,6 +5129,31 @@ func (sh *strictHandler) FieldUpdate(ctx echo.Context, schemaId SchemaIdParam, f return nil } +// SchemaByIDAsJSON operation middleware +func (sh *strictHandler) SchemaByIDAsJSON(ctx echo.Context, schemaId SchemaIdParam) error { + var request SchemaByIDAsJSONRequestObject + + request.SchemaId = schemaId + + handler := func(ctx echo.Context, request interface{}) (interface{}, error) { + return sh.ssi.SchemaByIDAsJSON(ctx.Request().Context(), request.(SchemaByIDAsJSONRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "SchemaByIDAsJSON") + } + + response, err := handler(ctx, request) + + if err != nil { + return err + } else if validResponse, ok := response.(SchemaByIDAsJSONResponseObject); ok { + return validResponse.VisitSchemaByIDAsJSONResponse(ctx.Response()) + } else if response != nil { + return fmt.Errorf("unexpected response type: %T", response) + } + return nil +} + // ProjectFilter operation middleware func (sh *strictHandler) ProjectFilter(ctx echo.Context, workspaceId WorkspaceIdParam, params ProjectFilterParams) error { var request ProjectFilterRequestObject @@ -5148,14 +5246,14 @@ var swaggerSpec = []string{ "S4hQ83Mpuy3o7YzebHyqGHDgw9dzRiztnaqf/214yUjNaXthzN4Gv04bnNmAZWAb/KQVi2XA74sXt3uu", "yL78b58O6Fr+l5ebPH92wKxcyqw4yQvAzmtPXdnewmZfb/jG6g2rcKvTlg287tNUJjr6sC9S3Bcpvqwi", "xUF9xyaq+KQ1kCWV3JdD7ssht1YO6Sjo+mWRL0BJB6m6NH27VVuWdHRfBvdCy+AOBqyDewEw3wa696je", - "o/qpUK3J16chtIC3Ga77stCBMl96NkbL3nD2q06xBNqRotDeb7J31dXRo/1O5Xb9z/np3uPsPU7jpo3B", - "YQuCl+YbJD02rcw3onrtWqmjjt7cQRue4zCeaQfKfPBrx/zvTnyNbP3NIz29g+rnNwbYPuq6BRQQuDOf", - "OJEazBSRqiTIfIhT36zR6IFfn+A3eHEKcmYMuP2YYwITlKUiPJqglEMUkixN0TiFlW+uuhUW9Ab8ZacZ", - "S7tVl27zWLJOs1yd1TZOtNngC4G7r47FplSuAY2a2OI/R9kipcjUqno17pzzTCrc1/98UqqGAoXTQNBA", - "982/iFWjbF9Vq1zlNjYMgx7G/AnItPSFf8cpxBnjlG1a770c+GsH7WTrJtf+DzVHIYF74f+Y7eb2p+Zj", - "jBoor+HQ6ArgGxXPt7xatzZ8NTDuUN69ryfc1xMOUNNdj+LGqu3aeuyXX4S9i7JMSgXUQ9RPr1ic7ZVA", - "7+3U3k4NUPf8eEfZDV+gGKSFskFvjwxR3mU1jjW7ZdvYkBg4keHOulOGxQYsnhzLdjclckqfMyps7vmF", - "ijMZJG79+OF6KLoh5qXlWH9T7mjGkxxesVwu/xcAAP//GFXWURetAAA=", + "o/qpUK3J16chtIC3Ga77stCBMl96NkbL3nD2q06xBNqRotDeb7J31dXRo/1O5Xb9z/np3vnsnU/X/RsD", + "yRYwL83nSHrsX5nPRfXawFKnHr25Mzc8J2M802aU+fbXjrninfgw2fr7SHp6B9UvcQywk9R1NyggcGe+", + "diI1mCkiVXWQ+Sanvlmj0QO/ScFv8OIU5MwYcPtdxwQmKEtFeDRBKYcoJFmaonEKK59fdYst6A34K1Az", + "lnYrNN3mCWWdZrk6q20cbrPBxwJ3Xx2L/alcAxo1scV/jrJFSpEpW/Vq3DnnmVS4r//5pFQNBQqngaCB", + "7pt/HKtG2b6qVrnKbWwYBj2X+ROQaelj/45TiDPGKdu09Hs58IcP2snWTa7932yOQgL3wv9d283tT813", + "GTVQXsP50RXANyqeb6W1bpn4amDcodJ7X1q4Ly0coLy7HsWNBdy1pdkvvx57F2WZlGqphyilXrE426uG", + "3tupvZ0aoAT66fOa+2Tmm0hm+nKSj3eU3fAFikHCzK6weqQj8y6r8DKJ8m1shA2cNXNn3SmdZ6NjT0Jv", + "u5thOaXPqSPNPb9QcSZVZuvHXtdD0dWZS8ux/uriaMaTHJqyXC7/FwAA//99LJUzj68AAA==", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/server/schemas/integration.yml b/server/schemas/integration.yml index 75e30cc056..88f0a181c3 100644 --- a/server/schemas/integration.yml +++ b/server/schemas/integration.yml @@ -162,12 +162,40 @@ paths: description: Not found '500': description: Internal server error + '/schemata/{schemaId}/schema.json': + parameters: + - $ref: '#/components/parameters/schemaIdParam' + get: + operationId: SchemaByIDAsJSON + security: + - bearerAuth: [] + summary: Returns a JSON that has schema. + tags: + - Schema + - JSON + description: Returns a JSON that has schema. + responses: + '200': + description: A JSON object + content: + application/json: + schema: + $ref: '#/components/schemas/schemaJSON' + format: binary + '400': + description: Invalid request parameter value + '401': + $ref: '#/components/responses/UnauthorizedError' + '404': + description: Not found + '500': + description: Internal server error '/projects/{projectIdOrAlias}/schemata/{schemaId}/schema.json': parameters: - $ref: '#/components/parameters/projectIdOrAliasParam' - $ref: '#/components/parameters/schemaIdParam' get: - operationId: SchemaByIDAsJSON + operationId: SchemaByIDWithProjectAsJSON security: - bearerAuth: [] summary: Returns a JSON that has schema. @@ -299,7 +327,6 @@ paths: description: Not found '500': description: Internal server error - /models/{modelId}/metadata_schema.json: parameters: - $ref: '#/components/parameters/modelIdParam' From ff95373b515f42d2fb951183cdad71b791aaa27d Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Mon, 11 Nov 2024 14:52:58 +0900 Subject: [PATCH 11/39] refactor PublicApiItemOrAsset --- server/internal/adapter/publicapi/api.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/server/internal/adapter/publicapi/api.go b/server/internal/adapter/publicapi/api.go index 378816adbf..0c14629b25 100644 --- a/server/internal/adapter/publicapi/api.go +++ b/server/internal/adapter/publicapi/api.go @@ -47,14 +47,9 @@ func PublicApiItemOrAsset() echo.HandlerFunc { var err error if m == "assets" { res, err = ctrl.GetAsset(ctx, p, i) + } else if i == "schema.json" { + res, err = ctrl.getSchema(ctx, p, m) } else { - if i == "schema.json" { - res, err := ctrl.getSchema(ctx, p, m) - if err != nil { - return err - } - return c.JSON(http.StatusOK, res) - } res, err = ctrl.GetItem(ctx, p, m, i) } From 9ebe3253e18dda9fa2bf917b326a813cccbbbdae Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Mon, 11 Nov 2024 17:19:15 +0900 Subject: [PATCH 12/39] implement toJSONSchemaProperties --- server/internal/adapter/integration/schema.go | 52 ++++++++++++++++--- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/server/internal/adapter/integration/schema.go b/server/internal/adapter/integration/schema.go index fa386de46e..d205183614 100644 --- a/server/internal/adapter/integration/schema.go +++ b/server/internal/adapter/integration/schema.go @@ -383,7 +383,7 @@ func (s *Server) SchemaByModelAsJSON(ctx context.Context, request SchemaByModelA Title: lo.ToPtr(m.Name()), Description: lo.ToPtr(m.Description()), Type: lo.ToPtr("object"), - Properties: toProperties(sp.Schema()), + Properties: toJSONSchemaProperties(sp.Schema().Fields()), }, nil } @@ -410,7 +410,7 @@ func (s *Server) MetadataSchemaByModelAsJSON(ctx context.Context, request Metada Title: lo.ToPtr(m.Name()), Description: lo.ToPtr(m.Description()), Type: lo.ToPtr("object"), - Properties: toProperties(sp.MetaSchema()), + Properties: toJSONSchemaProperties(sp.MetaSchema().Fields()), }, nil } @@ -448,7 +448,7 @@ func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request Sch Title: lo.ToPtr(m.Name()), Description: lo.ToPtr(m.Description()), Type: lo.ToPtr("object"), - Properties: toProperties(sch.Schema()), + Properties: toJSONSchemaProperties(sch.Schema().Fields()), }, nil } @@ -486,7 +486,7 @@ func (s *Server) MetadataSchemaByModelWithProjectAsJSON(ctx context.Context, req Title: lo.ToPtr(m.Name()), Description: lo.ToPtr(m.Description()), Type: lo.ToPtr("object"), - Properties: toProperties(sch.MetaSchema()), + Properties: toJSONSchemaProperties(sch.MetaSchema().Fields()), }, nil } @@ -506,7 +506,7 @@ func (s *Server) SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONR Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), Id: sch.ID().Ref().StringRef(), Type: lo.ToPtr("object"), - Properties: toProperties(sch), + Properties: toJSONSchemaProperties(sch.Fields()), }, nil } @@ -552,12 +552,48 @@ func (s *Server) SchemaByIDWithProjectAsJSON(ctx context.Context, request Schema Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), Id: sch.ID().Ref().StringRef(), Type: lo.ToPtr("object"), - Properties: toProperties(sch), + Properties: toJSONSchemaProperties(sch.Fields()), }, nil } -func toProperties(sch *schema.Schema) *map[string]interface{} { - return nil +func toJSONSchemaProperties(f schema.FieldList) *map[string]interface{} { + properties := make(map[string]interface{}) + for _, field := range f { + fieldType, format := toJSONSchemaTypeAndFormat(field.Type()) + fieldSchema := map[string]interface{}{ + "type": fieldType, + "title": field.Name(), + "description": field.Description(), + } + if format != "" { + fieldSchema["format"] = format + } + properties[field.Key().String()] = fieldSchema + } + return &properties +} + +func toJSONSchemaTypeAndFormat(t value.Type) (string, string) { + switch t { + case "text", "textArea", "richText", "markdown", "select", "tag", "asset", "reference": + return "string", "" + case "integer": + return "integer", "" + case "number": + return "number", "" + case "bool", "checkbox": + return "boolean", "" + case "date": + return "string", "date" + case "url": + return "string", "uri" + case "group": + return "array", "" + case "geometryObject", "geometryEditor": + return "object", "" + default: + return "string", "" + } } func FromSchemaTypeProperty(t integrationapi.ValueType, multiple bool) (tpRes *schema.TypeProperty, dv *value.Multiple, err error) { From 7cced871f42e654894459c363254de6184815032 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Mon, 11 Nov 2024 22:03:57 +0900 Subject: [PATCH 13/39] implement schema json export for public api --- server/e2e/publicapi_test.go | 45 ++++++++++++ server/internal/adapter/publicapi/api.go | 2 +- server/internal/adapter/publicapi/schema.go | 40 ---------- .../adapter/publicapi/schema_export.go | 73 +++++++++++++++++++ server/internal/adapter/publicapi/types.go | 25 ++++--- 5 files changed, 133 insertions(+), 52 deletions(-) delete mode 100644 server/internal/adapter/publicapi/schema.go create mode 100644 server/internal/adapter/publicapi/schema_export.go diff --git a/server/e2e/publicapi_test.go b/server/e2e/publicapi_test.go index bca973a4a6..9130aa5446 100644 --- a/server/e2e/publicapi_test.go +++ b/server/e2e/publicapi_test.go @@ -355,6 +355,51 @@ func TestPublicAPI(t *testing.T) { // publicAPIField2Key should be removed }) + // schema.json + e.GET("/api/p/{project}/{model}/schema.json", publicAPIProjectAlias, publicAPIModelKey). + Expect(). + Status(http.StatusOK). + JSON(). + IsEqual(map[string]any{ + "description": "", + "id": publicAPIModelID, + "properties": map[string]any{ + "asset": map[string]any{ + "description": "", + "title": "asset", + "type": "string", + }, + "asset2": map[string]any{ + "description": "", + "title": "asset2", + "type": "string", + }, + "geometry-editor": map[string]any{ + "description": "", + "title": "geometry-editor", + "type": "object", + }, + "geometry-object": map[string]any{ + "description": "", + "title": "geometry-object", + "type": "object", + }, + "test-field-1": map[string]any{ + "description": "", + "title": "test-field-1", + "type": "string", + }, + "test-field-2": map[string]any{ + "description": "", + "title": "test-field-2", + "type": "string", + }, + }, + "schema": "https://json-schema.org/draft/2020-12/schema", + "title": "", + "type": "object", + }) + // make the project private prj.Publication().SetScope(project.PublicationScopePrivate) lo.Must0(repos.Project.Save(ctx, prj)) diff --git a/server/internal/adapter/publicapi/api.go b/server/internal/adapter/publicapi/api.go index 0c14629b25..6cee233250 100644 --- a/server/internal/adapter/publicapi/api.go +++ b/server/internal/adapter/publicapi/api.go @@ -48,7 +48,7 @@ func PublicApiItemOrAsset() echo.HandlerFunc { if m == "assets" { res, err = ctrl.GetAsset(ctx, p, i) } else if i == "schema.json" { - res, err = ctrl.getSchema(ctx, p, m) + res, err = ctrl.GetSchemaJSON(ctx, p, m) } else { res, err = ctrl.GetItem(ctx, p, m, i) } diff --git a/server/internal/adapter/publicapi/schema.go b/server/internal/adapter/publicapi/schema.go deleted file mode 100644 index 1dc63517d1..0000000000 --- a/server/internal/adapter/publicapi/schema.go +++ /dev/null @@ -1,40 +0,0 @@ -package publicapi - -import ( - "context" - - "github.com/reearth/reearth-cms/server/pkg/id" - "github.com/reearth/reearthx/rerror" -) - -func (c *Controller) getSchema(ctx context.Context, prj, mkey string) (SchemaJSON, error) { - _, err := c.checkProject(ctx, prj) - if err != nil { - return SchemaJSON{}, err - } - - if mkey == "" { - return SchemaJSON{}, rerror.ErrNotFound - } - - mid, err := id.ModelIDFrom(mkey) - if err != nil { - return SchemaJSON{}, rerror.ErrNotFound - } - - m, err := c.usecases.Model.FindByID(ctx, mid, nil) - if err != nil { - return SchemaJSON{}, err - } - - if m.Key().String() != mkey || !m.Public() { - return SchemaJSON{}, rerror.ErrNotFound - } - - sp, err := c.usecases.Schema.FindByModel(ctx, m.ID(), nil) - if err != nil { - return SchemaJSON{}, err - } - - return NewSchemaJSON(sp.Schema()), nil -} diff --git a/server/internal/adapter/publicapi/schema_export.go b/server/internal/adapter/publicapi/schema_export.go new file mode 100644 index 0000000000..39fa4fb7e3 --- /dev/null +++ b/server/internal/adapter/publicapi/schema_export.go @@ -0,0 +1,73 @@ +package publicapi + +import ( + "context" + + "github.com/reearth/reearth-cms/server/pkg/model" + "github.com/reearth/reearth-cms/server/pkg/schema" + "github.com/reearth/reearth-cms/server/pkg/value" + "github.com/reearth/reearthx/rerror" +) + +func (c *Controller) GetSchemaJSON(ctx context.Context, pKey, mKey string) (SchemaJSON, error) { + pr, err := c.checkProject(ctx, pKey) + if err != nil { + return SchemaJSON{}, err + } + + m, err := c.usecases.Model.FindByIDOrKey(ctx, pr.ID(), model.IDOrKey(mKey), nil) + if err != nil { + return SchemaJSON{}, err + } + + if !m.Public() { + return SchemaJSON{}, rerror.ErrNotFound + } + + sp, err := c.usecases.Schema.FindByModel(ctx, m.ID(), nil) + if err != nil { + return SchemaJSON{}, err + } + + return NewSchemaJSON(m, sp.Schema()), nil +} + +func toSchemaJSONProperties(f schema.FieldList) *map[string]interface{} { + properties := make(map[string]interface{}) + for _, field := range f { + fieldType, format := toSchemaJSONTypeAndFormat(field.Type()) + fieldSchema := map[string]interface{}{ + "type": fieldType, + "title": field.Name(), + "description": field.Description(), + } + if format != "" { + fieldSchema["format"] = format + } + properties[field.Key().String()] = fieldSchema + } + return &properties +} + +func toSchemaJSONTypeAndFormat(t value.Type) (string, string) { + switch t { + case "text", "textArea", "richText", "markdown", "select", "tag", "asset", "reference": + return "string", "" + case "integer": + return "integer", "" + case "number": + return "number", "" + case "bool", "checkbox": + return "boolean", "" + case "date": + return "string", "date" + case "url": + return "string", "uri" + case "group": + return "array", "" + case "geometryObject", "geometryEditor": + return "object", "" + default: + return "string", "" + } +} diff --git a/server/internal/adapter/publicapi/types.go b/server/internal/adapter/publicapi/types.go index fc4d312777..655946d088 100644 --- a/server/internal/adapter/publicapi/types.go +++ b/server/internal/adapter/publicapi/types.go @@ -8,6 +8,7 @@ import ( "github.com/reearth/reearth-cms/server/pkg/asset" "github.com/reearth/reearth-cms/server/pkg/item" + "github.com/reearth/reearth-cms/server/pkg/model" "github.com/reearth/reearth-cms/server/pkg/schema" "github.com/reearth/reearth-cms/server/pkg/value" "github.com/reearth/reearthx/usecasex" @@ -213,23 +214,25 @@ func NewItemAsset(a *asset.Asset, urlResolver asset.URLResolver) ItemAsset { } type SchemaJSON struct { - Id *string `json:"$id,omitempty"` - Schema *string `json:"$schema,omitempty"` - Description *string `json:"description,omitempty"` - Properties *map[string]interface{} `json:"properties,omitempty"` + Schema *string `json:"schema,omitempty"` + Id *string `json:"id,omitempty"` Title *string `json:"title,omitempty"` + Description *string `json:"description,omitempty"` Type *string `json:"type,omitempty"` + Properties *map[string]interface{} `json:"properties,omitempty"` } -func (s SchemaJSON) MarshalJSON() ([]byte, error) { - return json.Marshal(s) -} - -func NewSchemaJSON(s *schema.Schema) SchemaJSON { - return SchemaJSON{} +func NewSchemaJSON(m *model.Model, s *schema.Schema) SchemaJSON { + return SchemaJSON{ + Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), + Id: m.ID().Ref().StringRef(), + Title: lo.ToPtr(m.Name()), + Description: lo.ToPtr(m.Description()), + Type: lo.ToPtr("object"), + Properties: toSchemaJSONProperties(s.Fields()), + } } - // GeoJSON type GeoJSON = FeatureCollection From 25784d74fe01ee3494cb13b48623327e16fa2eb2 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Mon, 11 Nov 2024 22:04:33 +0900 Subject: [PATCH 14/39] refactor integration schema --- server/internal/adapter/integration/schema.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/server/internal/adapter/integration/schema.go b/server/internal/adapter/integration/schema.go index d205183614..ae134703e7 100644 --- a/server/internal/adapter/integration/schema.go +++ b/server/internal/adapter/integration/schema.go @@ -383,7 +383,7 @@ func (s *Server) SchemaByModelAsJSON(ctx context.Context, request SchemaByModelA Title: lo.ToPtr(m.Name()), Description: lo.ToPtr(m.Description()), Type: lo.ToPtr("object"), - Properties: toJSONSchemaProperties(sp.Schema().Fields()), + Properties: toSchemaJSONProperties(sp.Schema().Fields()), }, nil } @@ -410,7 +410,7 @@ func (s *Server) MetadataSchemaByModelAsJSON(ctx context.Context, request Metada Title: lo.ToPtr(m.Name()), Description: lo.ToPtr(m.Description()), Type: lo.ToPtr("object"), - Properties: toJSONSchemaProperties(sp.MetaSchema().Fields()), + Properties: toSchemaJSONProperties(sp.MetaSchema().Fields()), }, nil } @@ -448,7 +448,7 @@ func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request Sch Title: lo.ToPtr(m.Name()), Description: lo.ToPtr(m.Description()), Type: lo.ToPtr("object"), - Properties: toJSONSchemaProperties(sch.Schema().Fields()), + Properties: toSchemaJSONProperties(sch.Schema().Fields()), }, nil } @@ -486,7 +486,7 @@ func (s *Server) MetadataSchemaByModelWithProjectAsJSON(ctx context.Context, req Title: lo.ToPtr(m.Name()), Description: lo.ToPtr(m.Description()), Type: lo.ToPtr("object"), - Properties: toJSONSchemaProperties(sch.MetaSchema().Fields()), + Properties: toSchemaJSONProperties(sch.MetaSchema().Fields()), }, nil } @@ -506,7 +506,7 @@ func (s *Server) SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONR Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), Id: sch.ID().Ref().StringRef(), Type: lo.ToPtr("object"), - Properties: toJSONSchemaProperties(sch.Fields()), + Properties: toSchemaJSONProperties(sch.Fields()), }, nil } @@ -552,14 +552,14 @@ func (s *Server) SchemaByIDWithProjectAsJSON(ctx context.Context, request Schema Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), Id: sch.ID().Ref().StringRef(), Type: lo.ToPtr("object"), - Properties: toJSONSchemaProperties(sch.Fields()), + Properties: toSchemaJSONProperties(sch.Fields()), }, nil } -func toJSONSchemaProperties(f schema.FieldList) *map[string]interface{} { +func toSchemaJSONProperties(f schema.FieldList) *map[string]interface{} { properties := make(map[string]interface{}) for _, field := range f { - fieldType, format := toJSONSchemaTypeAndFormat(field.Type()) + fieldType, format := toSchemaJSONTypeAndFormat(field.Type()) fieldSchema := map[string]interface{}{ "type": fieldType, "title": field.Name(), @@ -573,7 +573,7 @@ func toJSONSchemaProperties(f schema.FieldList) *map[string]interface{} { return &properties } -func toJSONSchemaTypeAndFormat(t value.Type) (string, string) { +func toSchemaJSONTypeAndFormat(t value.Type) (string, string) { switch t { case "text", "textArea", "richText", "markdown", "select", "tag", "asset", "reference": return "string", "" From 23fc23a18acd7d7ce4398c56f8b2170ef52318b5 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Mon, 11 Nov 2024 22:52:24 +0900 Subject: [PATCH 15/39] refactor schema export integration api --- server/internal/adapter/integration/schema.go | 236 --------------- .../adapter/integration/schema_export.go | 276 ++++++++++++++++++ 2 files changed, 276 insertions(+), 236 deletions(-) create mode 100644 server/internal/adapter/integration/schema_export.go diff --git a/server/internal/adapter/integration/schema.go b/server/internal/adapter/integration/schema.go index ae134703e7..38741c00ef 100644 --- a/server/internal/adapter/integration/schema.go +++ b/server/internal/adapter/integration/schema.go @@ -360,242 +360,6 @@ func (s *Server) FieldDeleteWithProject(ctx context.Context, request FieldDelete }, err } -func (s *Server) SchemaByModelAsJSON(ctx context.Context, request SchemaByModelAsJSONRequestObject) (SchemaByModelAsJSONResponseObject, error) { - op := adapter.Operator(ctx) - uc := adapter.Usecases(ctx) - - m, err := uc.Model.FindByID(ctx, request.ModelId, op) - if err != nil { - if errors.Is(err, rerror.ErrNotFound) { - return SchemaByModelAsJSON400Response{}, err - } - return SchemaByModelAsJSON400Response{}, err - } - - sp, err := uc.Schema.FindByModel(ctx, m.ID(), op) - if err != nil { - return SchemaByModelAsJSON400Response{}, err - } - - return SchemaByModelAsJSON200JSONResponse{ - Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), - Id: m.ID().Ref().StringRef(), - Title: lo.ToPtr(m.Name()), - Description: lo.ToPtr(m.Description()), - Type: lo.ToPtr("object"), - Properties: toSchemaJSONProperties(sp.Schema().Fields()), - }, nil -} - -func (s *Server) MetadataSchemaByModelAsJSON(ctx context.Context, request MetadataSchemaByModelAsJSONRequestObject) (MetadataSchemaByModelAsJSONResponseObject, error) { - op := adapter.Operator(ctx) - uc := adapter.Usecases(ctx) - - m, err := uc.Model.FindByID(ctx, request.ModelId, op) - if err != nil { - if errors.Is(err, rerror.ErrNotFound) { - return MetadataSchemaByModelAsJSON400Response{}, err - } - return MetadataSchemaByModelAsJSON400Response{}, err - } - - sp, err := uc.Schema.FindByModel(ctx, request.ModelId, op) - if err != nil { - return MetadataSchemaByModelAsJSON400Response{}, err - } - - return MetadataSchemaByModelAsJSON200JSONResponse{ - Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), - Id: m.ID().Ref().StringRef(), - Title: lo.ToPtr(m.Name()), - Description: lo.ToPtr(m.Description()), - Type: lo.ToPtr("object"), - Properties: toSchemaJSONProperties(sp.MetaSchema().Fields()), - }, nil -} - -func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request SchemaByModelWithProjectAsJSONRequestObject) (SchemaByModelWithProjectAsJSONResponseObject, error) { - uc := adapter.Usecases(ctx) - op := adapter.Operator(ctx) - - p, err := uc.Project.FindByIDOrAlias(ctx, request.ProjectIdOrAlias, op) - if err != nil { - if errors.Is(err, rerror.ErrNotFound) { - return SchemaByModelWithProjectAsJSON400Response{}, err - } - return SchemaByModelWithProjectAsJSON400Response{}, err - } - - m, err := uc.Model.FindByIDOrKey(ctx, p.ID(), request.ModelIdOrKey, op) - if err != nil { - if errors.Is(err, rerror.ErrNotFound) { - return SchemaByModelWithProjectAsJSON400Response{}, err - } - return SchemaByModelWithProjectAsJSON400Response{}, err - } - - sch, err := uc.Schema.FindByModel(ctx, m.ID(), op) - if err != nil { - if errors.Is(err, rerror.ErrNotFound) { - return SchemaByModelWithProjectAsJSON400Response{}, err - } - return SchemaByModelWithProjectAsJSON400Response{}, err - } - - return SchemaByModelWithProjectAsJSON200JSONResponse{ - Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), - Id: m.ID().Ref().StringRef(), - Title: lo.ToPtr(m.Name()), - Description: lo.ToPtr(m.Description()), - Type: lo.ToPtr("object"), - Properties: toSchemaJSONProperties(sch.Schema().Fields()), - }, nil -} - -func (s *Server) MetadataSchemaByModelWithProjectAsJSON(ctx context.Context, request MetadataSchemaByModelWithProjectAsJSONRequestObject) (MetadataSchemaByModelWithProjectAsJSONResponseObject, error) { - uc := adapter.Usecases(ctx) - op := adapter.Operator(ctx) - - p, err := uc.Project.FindByIDOrAlias(ctx, request.ProjectIdOrAlias, op) - if err != nil { - if errors.Is(err, rerror.ErrNotFound) { - return MetadataSchemaByModelWithProjectAsJSON400Response{}, err - } - return MetadataSchemaByModelWithProjectAsJSON400Response{}, err - } - - m, err := uc.Model.FindByIDOrKey(ctx, p.ID(), request.ModelIdOrKey, op) - if err != nil { - if errors.Is(err, rerror.ErrNotFound) { - return MetadataSchemaByModelWithProjectAsJSON400Response{}, err - } - return MetadataSchemaByModelWithProjectAsJSON400Response{}, err - } - - sch, err := uc.Schema.FindByModel(ctx, m.ID(), op) - if err != nil { - if errors.Is(err, rerror.ErrNotFound) { - return MetadataSchemaByModelWithProjectAsJSON400Response{}, err - } - return MetadataSchemaByModelWithProjectAsJSON400Response{}, err - } - - return MetadataSchemaByModelWithProjectAsJSON200JSONResponse{ - Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), - Id: m.ID().Ref().StringRef(), - Title: lo.ToPtr(m.Name()), - Description: lo.ToPtr(m.Description()), - Type: lo.ToPtr("object"), - Properties: toSchemaJSONProperties(sch.MetaSchema().Fields()), - }, nil -} - -func (s *Server) SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONRequestObject) (SchemaByIDAsJSONResponseObject, error) { - uc := adapter.Usecases(ctx) - op := adapter.Operator(ctx) - - sch, err := uc.Schema.FindByID(ctx, request.SchemaId, op) - if err != nil { - if errors.Is(err, rerror.ErrNotFound) { - return SchemaByIDAsJSON400Response{}, err - } - return SchemaByIDAsJSON400Response{}, err - } - - return SchemaByIDAsJSON200JSONResponse{ - Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), - Id: sch.ID().Ref().StringRef(), - Type: lo.ToPtr("object"), - Properties: toSchemaJSONProperties(sch.Fields()), - }, nil -} - -func (s *Server) SchemaByIDWithProjectAsJSON(ctx context.Context, request SchemaByIDWithProjectAsJSONRequestObject) (SchemaByIDWithProjectAsJSONResponseObject, error) { - uc := adapter.Usecases(ctx) - op := adapter.Operator(ctx) - - // prj, err := uc.Project.FindByIDOrAlias(ctx, request.ProjectIdOrAlias, op) - // if err != nil { - // if errors.Is(err, rerror.ErrNotFound) { - // return SchemaByIDWithProjectAsJSON400Response{}, err - // } - // return SchemaByIDWithProjectAsJSON400Response{}, err - // } - - // ms, _, err := uc.Model.FindByProjectAndKeyword(ctx, prj.ID(), lo.FromPtrOr(request.Params.Keyword, ""), p, op) - // if err != nil { - // return nil, err - // } - - // models := make([]integrationapi.Model, 0, len(ms)) - // for _, m := range ms { - // sp, err := uc.Schema.FindByModel(ctx, m.ID(), op) - // if err != nil { - // return nil, err - // } - // lastModified, err := uc.Item.LastModifiedByModel(ctx, m.ID(), op) - // if err != nil && !errors.Is(err, rerror.ErrNotFound) { - // return nil, err - // } - // models = append(models, integrationapi.NewModel(m, sp, lastModified)) - // } - - sch, err := uc.Schema.FindByID(ctx, request.SchemaId, op) - if err != nil { - if errors.Is(err, rerror.ErrNotFound) { - return SchemaByIDWithProjectAsJSON400Response{}, err - } - return SchemaByIDWithProjectAsJSON400Response{}, err - } - - return SchemaByIDWithProjectAsJSON200JSONResponse{ - Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), - Id: sch.ID().Ref().StringRef(), - Type: lo.ToPtr("object"), - Properties: toSchemaJSONProperties(sch.Fields()), - }, nil -} - -func toSchemaJSONProperties(f schema.FieldList) *map[string]interface{} { - properties := make(map[string]interface{}) - for _, field := range f { - fieldType, format := toSchemaJSONTypeAndFormat(field.Type()) - fieldSchema := map[string]interface{}{ - "type": fieldType, - "title": field.Name(), - "description": field.Description(), - } - if format != "" { - fieldSchema["format"] = format - } - properties[field.Key().String()] = fieldSchema - } - return &properties -} - -func toSchemaJSONTypeAndFormat(t value.Type) (string, string) { - switch t { - case "text", "textArea", "richText", "markdown", "select", "tag", "asset", "reference": - return "string", "" - case "integer": - return "integer", "" - case "number": - return "number", "" - case "bool", "checkbox": - return "boolean", "" - case "date": - return "string", "date" - case "url": - return "string", "uri" - case "group": - return "array", "" - case "geometryObject", "geometryEditor": - return "object", "" - default: - return "string", "" - } -} - func FromSchemaTypeProperty(t integrationapi.ValueType, multiple bool) (tpRes *schema.TypeProperty, dv *value.Multiple, err error) { switch t { case integrationapi.ValueTypeText: diff --git a/server/internal/adapter/integration/schema_export.go b/server/internal/adapter/integration/schema_export.go new file mode 100644 index 0000000000..9e4e7149f8 --- /dev/null +++ b/server/internal/adapter/integration/schema_export.go @@ -0,0 +1,276 @@ +package integration + +import ( + "context" + "errors" + + "github.com/reearth/reearth-cms/server/internal/adapter" + "github.com/reearth/reearth-cms/server/pkg/integrationapi" + "github.com/reearth/reearth-cms/server/pkg/model" + "github.com/reearth/reearth-cms/server/pkg/schema" + "github.com/reearth/reearth-cms/server/pkg/value" + "github.com/reearth/reearthx/rerror" + "github.com/samber/lo" +) + +func NewSchemaJSON(s *schema.Schema) integrationapi.SchemaJSON { + return integrationapi.SchemaJSON{ + Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), + Id: s.ID().Ref().StringRef(), + Type: lo.ToPtr("object"), + Properties: toSchemaJSONProperties(s.Fields()), + } +} + +func NewSchemaJSONWitModel(m *model.Model, s *schema.Schema) integrationapi.SchemaJSON { + return integrationapi.SchemaJSON{ + Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), + Id: m.ID().Ref().StringRef(), + Title: lo.ToPtr(m.Name()), + Description: lo.ToPtr(m.Description()), + Type: lo.ToPtr("object"), + Properties: toSchemaJSONProperties(s.Fields()), + } +} + +func (s *Server) SchemaByModelAsJSON(ctx context.Context, request SchemaByModelAsJSONRequestObject) (SchemaByModelAsJSONResponseObject, error) { + op := adapter.Operator(ctx) + uc := adapter.Usecases(ctx) + + m, err := uc.Model.FindByID(ctx, request.ModelId, op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return SchemaByModelAsJSON400Response{}, err + } + return SchemaByModelAsJSON400Response{}, err + } + + sp, err := uc.Schema.FindByModel(ctx, m.ID(), op) + if err != nil { + return SchemaByModelAsJSON400Response{}, err + } + + res := NewSchemaJSONWitModel(m, sp.Schema()) + return SchemaByModelAsJSON200JSONResponse{ + Schema: res.Schema, + Id: res.Id, + Title: res.Title, + Description: res.Description, + Type: res.Type, + Properties: res.Properties, + }, nil +} + +func (s *Server) MetadataSchemaByModelAsJSON(ctx context.Context, request MetadataSchemaByModelAsJSONRequestObject) (MetadataSchemaByModelAsJSONResponseObject, error) { + op := adapter.Operator(ctx) + uc := adapter.Usecases(ctx) + + m, err := uc.Model.FindByID(ctx, request.ModelId, op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return MetadataSchemaByModelAsJSON400Response{}, err + } + return MetadataSchemaByModelAsJSON400Response{}, err + } + + sp, err := uc.Schema.FindByModel(ctx, request.ModelId, op) + if err != nil { + return MetadataSchemaByModelAsJSON400Response{}, err + } + + res := NewSchemaJSONWitModel(m, sp.MetaSchema()) + return MetadataSchemaByModelAsJSON200JSONResponse{ + Schema: res.Schema, + Id: res.Id, + Title: res.Title, + Description: res.Description, + Type: res.Type, + Properties: res.Properties, + }, nil +} + +func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request SchemaByModelWithProjectAsJSONRequestObject) (SchemaByModelWithProjectAsJSONResponseObject, error) { + uc := adapter.Usecases(ctx) + op := adapter.Operator(ctx) + + p, err := uc.Project.FindByIDOrAlias(ctx, request.ProjectIdOrAlias, op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return SchemaByModelWithProjectAsJSON400Response{}, err + } + return SchemaByModelWithProjectAsJSON400Response{}, err + } + + m, err := uc.Model.FindByIDOrKey(ctx, p.ID(), request.ModelIdOrKey, op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return SchemaByModelWithProjectAsJSON400Response{}, err + } + return SchemaByModelWithProjectAsJSON400Response{}, err + } + + sch, err := uc.Schema.FindByModel(ctx, m.ID(), op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return SchemaByModelWithProjectAsJSON400Response{}, err + } + return SchemaByModelWithProjectAsJSON400Response{}, err + } + + res := NewSchemaJSONWitModel(m, sch.Schema()) + return SchemaByModelWithProjectAsJSON200JSONResponse{ + Schema: res.Schema, + Id: res.Id, + Title: res.Title, + Description: res.Description, + Type: res.Type, + Properties: res.Properties, + }, nil +} + +func (s *Server) MetadataSchemaByModelWithProjectAsJSON(ctx context.Context, request MetadataSchemaByModelWithProjectAsJSONRequestObject) (MetadataSchemaByModelWithProjectAsJSONResponseObject, error) { + uc := adapter.Usecases(ctx) + op := adapter.Operator(ctx) + + p, err := uc.Project.FindByIDOrAlias(ctx, request.ProjectIdOrAlias, op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return MetadataSchemaByModelWithProjectAsJSON400Response{}, err + } + return MetadataSchemaByModelWithProjectAsJSON400Response{}, err + } + + m, err := uc.Model.FindByIDOrKey(ctx, p.ID(), request.ModelIdOrKey, op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return MetadataSchemaByModelWithProjectAsJSON400Response{}, err + } + return MetadataSchemaByModelWithProjectAsJSON400Response{}, err + } + + sch, err := uc.Schema.FindByModel(ctx, m.ID(), op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return MetadataSchemaByModelWithProjectAsJSON400Response{}, err + } + return MetadataSchemaByModelWithProjectAsJSON400Response{}, err + } + + res := NewSchemaJSONWitModel(m, sch.MetaSchema()) + return MetadataSchemaByModelWithProjectAsJSON200JSONResponse{ + Schema: res.Schema, + Id: res.Id, + Title: res.Title, + Description: res.Description, + Type: res.Type, + Properties: res.Properties, + }, nil +} + +func (s *Server) SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONRequestObject) (SchemaByIDAsJSONResponseObject, error) { + uc := adapter.Usecases(ctx) + op := adapter.Operator(ctx) + + sch, err := uc.Schema.FindByID(ctx, request.SchemaId, op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return SchemaByIDAsJSON400Response{}, err + } + return SchemaByIDAsJSON400Response{}, err + } + + res := NewSchemaJSON(sch) + return SchemaByIDAsJSON200JSONResponse{ + Schema: res.Schema, + Id: res.Id, + Type: res.Type, + Properties: res.Properties, + }, nil +} + +func (s *Server) SchemaByIDWithProjectAsJSON(ctx context.Context, request SchemaByIDWithProjectAsJSONRequestObject) (SchemaByIDWithProjectAsJSONResponseObject, error) { + uc := adapter.Usecases(ctx) + op := adapter.Operator(ctx) + + // prj, err := uc.Project.FindByIDOrAlias(ctx, request.ProjectIdOrAlias, op) + // if err != nil { + // if errors.Is(err, rerror.ErrNotFound) { + // return SchemaByIDWithProjectAsJSON400Response{}, err + // } + // return SchemaByIDWithProjectAsJSON400Response{}, err + // } + + // ms, _, err := uc.Model.FindByProjectAndKeyword(ctx, prj.ID(), lo.FromPtrOr(request.Params.Keyword, ""), p, op) + // if err != nil { + // return nil, err + // } + + // models := make([]integrationapi.Model, 0, len(ms)) + // for _, m := range ms { + // sp, err := uc.Schema.FindByModel(ctx, m.ID(), op) + // if err != nil { + // return nil, err + // } + // lastModified, err := uc.Item.LastModifiedByModel(ctx, m.ID(), op) + // if err != nil && !errors.Is(err, rerror.ErrNotFound) { + // return nil, err + // } + // models = append(models, integrationapi.NewModel(m, sp, lastModified)) + // } + + sch, err := uc.Schema.FindByID(ctx, request.SchemaId, op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return SchemaByIDWithProjectAsJSON400Response{}, err + } + return SchemaByIDWithProjectAsJSON400Response{}, err + } + + res := NewSchemaJSON(sch) + return SchemaByIDWithProjectAsJSON200JSONResponse{ + Schema: res.Schema, + Id: res.Id, + Type: res.Type, + Properties: res.Properties, + }, nil +} + +func toSchemaJSONProperties(f schema.FieldList) *map[string]interface{} { + properties := make(map[string]interface{}) + for _, field := range f { + fieldType, format := toSchemaJSONTypeAndFormat(field.Type()) + fieldSchema := map[string]interface{}{ + "type": fieldType, + "title": field.Name(), + "description": field.Description(), + } + if format != "" { + fieldSchema["format"] = format + } + properties[field.Key().String()] = fieldSchema + } + return &properties +} + +func toSchemaJSONTypeAndFormat(t value.Type) (string, string) { + switch t { + case "text", "textArea", "richText", "markdown", "select", "tag", "asset", "reference": + return "string", "" + case "integer": + return "integer", "" + case "number": + return "number", "" + case "bool", "checkbox": + return "boolean", "" + case "date": + return "string", "date" + case "url": + return "string", "uri" + case "group": + return "array", "" + case "geometryObject", "geometryEditor": + return "object", "" + default: + return "string", "" + } +} From fe530585c2630d93f0cac01345ca838378b993a4 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Tue, 12 Nov 2024 11:37:27 +0900 Subject: [PATCH 16/39] add integration api e2e tests --- server/e2e/integration_schema_test.go | 118 ++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 6 deletions(-) diff --git a/server/e2e/integration_schema_test.go b/server/e2e/integration_schema_test.go index 6becc48551..bac62bee8d 100644 --- a/server/e2e/integration_schema_test.go +++ b/server/e2e/integration_schema_test.go @@ -807,30 +807,136 @@ func TestIntegrationSchemaJSONExportAPI(t *testing.T) { e.GET("/api/schemata/{schemaId}/schema.json", sid1). WithHeader("authorization", "Bearer "+secret). Expect(). - Status(http.StatusOK) + Status(http.StatusOK). + JSON(). + IsEqual(map[string]any{ + "$id": sid1, + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": map[string]any{ + "asset": map[string]any{ + "description": "", + "title": "", + "type": "string", + }, + sfKey1.String(): map[string]any{ + "description": "", + "title": "", + "type": "string", + }, + }, + "type": "object", + }) e.GET("/api/projects/{projectIdOrKey}/schemata/{schemaId}/schema.json", pid, sid1). WithHeader("authorization", "Bearer "+secret). Expect(). - Status(http.StatusOK) + Status(http.StatusOK). + JSON(). + IsEqual(map[string]any{ + "$id": sid1, + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": map[string]any{ + "asset": map[string]any{ + "description": "", + "title": "", + "type": "string", + }, + sfKey1.String(): map[string]any{ + "description": "", + "title": "", + "type": "string", + }, + }, + "type": "object", + }) e.GET("/api/projects/{projectIdOrKey}/models/{modelId}/schema.json", pid, mId1). WithHeader("authorization", "Bearer "+secret). Expect(). - Status(http.StatusOK) + Status(http.StatusOK). + JSON(). + IsEqual(map[string]any{ + "$id": mId1, + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": map[string]any{ + "asset": map[string]any{ + "description": "", + "title": "", + "type": "string", + }, + sfKey1.String(): map[string]any{ + "description": "", + "title": "", + "type": "string", + }, + }, + "type": "object", + "description": "m1 desc", + "title": "m1", + }) e.GET("/api/projects/{projectIdOrKey}/models/{modelId}/metadata_schema.json", pid, mId1). WithHeader("authorization", "Bearer "+secret). Expect(). - Status(http.StatusOK) + Status(http.StatusOK). + JSON(). + IsEqual(map[string]any{ + "$id": mId1, + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": map[string]any{ + sfKey4.String(): map[string]any{ + "description": "", + "title": "", + "type": "boolean", + }, + }, + "type": "object", + "description": "m1 desc", + "title": "m1", + }) e.GET("/api/models/{modelId}/schema.json", mId1). WithHeader("authorization", "Bearer "+secret). Expect(). - Status(http.StatusOK) + Status(http.StatusOK). + JSON(). + IsEqual(map[string]any{ + "$id": mId1, + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": map[string]any{ + "asset": map[string]any{ + "description": "", + "title": "", + "type": "string", + }, + sfKey1.String(): map[string]any{ + "description": "", + "title": "", + "type": "string", + }, + }, + "type": "object", + "description": "m1 desc", + "title": "m1", + }) e.GET("/api/models/{modelId}/metadata_schema.json", mId1). WithHeader("authorization", "Bearer "+secret). Expect(). - Status(http.StatusOK) + Status(http.StatusOK). + JSON(). + IsEqual(map[string]any{ + "$id": mId1, + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": map[string]any{ + sfKey4.String(): map[string]any{ + "description": "", + "title": "", + "type": "boolean", + }, + }, + "type": "object", + "description": "m1 desc", + "title": "m1", + }) } From ca39bb8d4ca3dbc1b1ffe2d21d699de9b11209dc Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Tue, 12 Nov 2024 13:37:19 +0900 Subject: [PATCH 17/39] refactor integration schema --- .../adapter/integration/server.gen.go | 167 +++++++++--------- server/schemas/integration.yml | 26 +-- 2 files changed, 97 insertions(+), 96 deletions(-) diff --git a/server/internal/adapter/integration/server.gen.go b/server/internal/adapter/integration/server.gen.go index b925f1515f..556932b725 100644 --- a/server/internal/adapter/integration/server.gen.go +++ b/server/internal/adapter/integration/server.gen.go @@ -90,10 +90,10 @@ type ServerInterface interface { // Returns a GeoJSON that has a list of items as features. // (GET /models/{modelId}/items.geojson) ItemsAsGeoJSON(ctx echo.Context, modelId ModelIdParam, params ItemsAsGeoJSONParams) error - // Returns a JSON that has schema + // Returns a metadata schema as json by model ID // (GET /models/{modelId}/metadata_schema.json) MetadataSchemaByModelAsJSON(ctx echo.Context, modelId ModelIdParam) error - // Returns a JSON that has schema + // Returns a schema as json by model ID // (GET /models/{modelId}/schema.json) SchemaByModelAsJSON(ctx echo.Context, modelId ModelIdParam) error // Returns a list of models. @@ -132,16 +132,16 @@ type ServerInterface interface { // Returns a GeoJSON that has a list of items as features. // (GET /projects/{projectIdOrAlias}/models/{modelIdOrKey}/items.geojson) ItemsWithProjectAsGeoJSON(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, modelIdOrKey ModelIdOrKeyParam, params ItemsWithProjectAsGeoJSONParams) error - // Returns a JSON that has schema. + // Returns a metadata schema as json by project and model ID // (GET /projects/{projectIdOrAlias}/models/{modelIdOrKey}/metadata_schema.json) MetadataSchemaByModelWithProjectAsJSON(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, modelIdOrKey ModelIdOrKeyParam) error - // Returns a JSON that has schema. + // Returns a schema as json by project and model ID // (GET /projects/{projectIdOrAlias}/models/{modelIdOrKey}/schema.json) SchemaByModelWithProjectAsJSON(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, modelIdOrKey ModelIdOrKeyParam) error // Returns a schema. // (GET /projects/{projectIdOrAlias}/schemata) SchemaFilter(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, params SchemaFilterParams) error - // Returns a JSON that has schema. + // Returns a schema as json by project and schema ID // (GET /projects/{projectIdOrAlias}/schemata/{schemaId}/schema.json) SchemaByIDWithProjectAsJSON(ctx echo.Context, projectIdOrAlias ProjectIdOrAliasParam, schemaId SchemaIdParam) error // Returns a list of assets. @@ -162,7 +162,7 @@ type ServerInterface interface { // update a field // (PATCH /schemata/{schemaId}/fields/{fieldIdOrKey}) FieldUpdate(ctx echo.Context, schemaId SchemaIdParam, fieldIdOrKey FieldIdOrKeyParam) error - // Returns a JSON that has schema. + // Returns a schema as json by schema ID // (GET /schemata/{schemaId}/schema.json) SchemaByIDAsJSON(ctx echo.Context, schemaId SchemaIdParam) error // Returns a list of projects. @@ -3756,10 +3756,10 @@ type StrictServerInterface interface { // Returns a GeoJSON that has a list of items as features. // (GET /models/{modelId}/items.geojson) ItemsAsGeoJSON(ctx context.Context, request ItemsAsGeoJSONRequestObject) (ItemsAsGeoJSONResponseObject, error) - // Returns a JSON that has schema + // Returns a metadata schema as json by model ID // (GET /models/{modelId}/metadata_schema.json) MetadataSchemaByModelAsJSON(ctx context.Context, request MetadataSchemaByModelAsJSONRequestObject) (MetadataSchemaByModelAsJSONResponseObject, error) - // Returns a JSON that has schema + // Returns a schema as json by model ID // (GET /models/{modelId}/schema.json) SchemaByModelAsJSON(ctx context.Context, request SchemaByModelAsJSONRequestObject) (SchemaByModelAsJSONResponseObject, error) // Returns a list of models. @@ -3798,16 +3798,16 @@ type StrictServerInterface interface { // Returns a GeoJSON that has a list of items as features. // (GET /projects/{projectIdOrAlias}/models/{modelIdOrKey}/items.geojson) ItemsWithProjectAsGeoJSON(ctx context.Context, request ItemsWithProjectAsGeoJSONRequestObject) (ItemsWithProjectAsGeoJSONResponseObject, error) - // Returns a JSON that has schema. + // Returns a metadata schema as json by project and model ID // (GET /projects/{projectIdOrAlias}/models/{modelIdOrKey}/metadata_schema.json) MetadataSchemaByModelWithProjectAsJSON(ctx context.Context, request MetadataSchemaByModelWithProjectAsJSONRequestObject) (MetadataSchemaByModelWithProjectAsJSONResponseObject, error) - // Returns a JSON that has schema. + // Returns a schema as json by project and model ID // (GET /projects/{projectIdOrAlias}/models/{modelIdOrKey}/schema.json) SchemaByModelWithProjectAsJSON(ctx context.Context, request SchemaByModelWithProjectAsJSONRequestObject) (SchemaByModelWithProjectAsJSONResponseObject, error) // Returns a schema. // (GET /projects/{projectIdOrAlias}/schemata) SchemaFilter(ctx context.Context, request SchemaFilterRequestObject) (SchemaFilterResponseObject, error) - // Returns a JSON that has schema. + // Returns a schema as json by project and schema ID // (GET /projects/{projectIdOrAlias}/schemata/{schemaId}/schema.json) SchemaByIDWithProjectAsJSON(ctx context.Context, request SchemaByIDWithProjectAsJSONRequestObject) (SchemaByIDWithProjectAsJSONResponseObject, error) // Returns a list of assets. @@ -3828,7 +3828,7 @@ type StrictServerInterface interface { // update a field // (PATCH /schemata/{schemaId}/fields/{fieldIdOrKey}) FieldUpdate(ctx context.Context, request FieldUpdateRequestObject) (FieldUpdateResponseObject, error) - // Returns a JSON that has schema. + // Returns a schema as json by schema ID // (GET /schemata/{schemaId}/schema.json) SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONRequestObject) (SchemaByIDAsJSONResponseObject, error) // Returns a list of projects. @@ -5183,77 +5183,78 @@ func (sh *strictHandler) ProjectFilter(ctx echo.Context, workspaceId WorkspaceId // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", + "zbXlWH91KWnGixzhslwu/xcAAP//gROObT6wAAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/server/schemas/integration.yml b/server/schemas/integration.yml index 88f0a181c3..28fa760735 100644 --- a/server/schemas/integration.yml +++ b/server/schemas/integration.yml @@ -169,11 +169,11 @@ paths: operationId: SchemaByIDAsJSON security: - bearerAuth: [] - summary: Returns a JSON that has schema. + summary: Returns a schema as json by schema ID tags: - Schema - JSON - description: Returns a JSON that has schema. + description: Returns a schema as json by schema ID responses: '200': description: A JSON object @@ -198,11 +198,11 @@ paths: operationId: SchemaByIDWithProjectAsJSON security: - bearerAuth: [] - summary: Returns a JSON that has schema. + summary: Returns a schema as json by project and schema ID tags: - Schema - JSON - description: Returns a JSON that has schema. + description: Returns a schema as json by project and schema ID responses: '200': description: A JSON object @@ -306,11 +306,11 @@ paths: operationId: SchemaByModelAsJSON security: - bearerAuth: [] - summary: Returns a JSON that has schema + summary: Returns a schema as json by model ID tags: - Schema - JSON - description: Returns a JSON that has schema + description: Returns a schema as json by model ID responses: '200': description: A JSON object @@ -334,11 +334,11 @@ paths: operationId: MetadataSchemaByModelAsJSON security: - bearerAuth: [] - summary: Returns a JSON that has schema + summary: Returns a metadata schema as json by model ID tags: - MetadataSchema - JSON - description: Returns a JSON that has metadata schema + description: Returns a metadata schema as json by model ID responses: '200': description: A JSON object @@ -1046,11 +1046,11 @@ paths: operationId: SchemaByModelWithProjectAsJSON security: - bearerAuth: [] - summary: Returns a JSON that has schema. + summary: Returns a schema as json by project and model ID tags: - Schema - JSON - description: Returns a JSON that has schema. + description: Returns a schema as json by project and model ID responses: '200': description: A JSON object @@ -1075,11 +1075,11 @@ paths: operationId: MetadataSchemaByModelWithProjectAsJSON security: - bearerAuth: [] - summary: Returns a JSON that has schema. + summary: Returns a metadata schema as json by project and model ID tags: - - Schema + - MetadataSchema - JSON - description: Returns a JSON that has schema. + description: Returns a metadata schema as json by project and model ID responses: '200': description: A JSON object From 8255a348108c20a75b8851ae14a1b5f1f474ce27 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Tue, 12 Nov 2024 13:51:06 +0900 Subject: [PATCH 18/39] add more e2e cases --- server/e2e/integration_schema_export_test.go | 215 +++++++++++++++++++ server/e2e/integration_schema_test.go | 140 ------------ 2 files changed, 215 insertions(+), 140 deletions(-) create mode 100644 server/e2e/integration_schema_export_test.go diff --git a/server/e2e/integration_schema_export_test.go b/server/e2e/integration_schema_export_test.go new file mode 100644 index 0000000000..aa36adcc27 --- /dev/null +++ b/server/e2e/integration_schema_export_test.go @@ -0,0 +1,215 @@ +package e2e + +import ( + "net/http" + "testing" + + "github.com/reearth/reearth-cms/server/internal/app" + "github.com/reearth/reearth-cms/server/pkg/id" +) + +func TestIntegrationSchemaJSONExportAPI(t *testing.T) { + e := StartServer(t, &app.Config{}, true, baseSeeder) + + // /api/schemata/{schemaId}/schema.json + e.GET("/api/schemata/{schemaId}/schema.json", sid1). + WithHeader("authorization", "Bearer abcd"). + Expect(). + Status(http.StatusUnauthorized) + + e.GET("/api/schemata/{schemaId}/schema.json", id.NewSchemaID()). + WithHeader("authorization", "Bearer "+secret). + Expect(). + Status(http.StatusNotFound) + + e.GET("/api/schemata/{schemaId}/schema.json", sid1). + WithHeader("authorization", "Bearer "+secret). + Expect(). + Status(http.StatusOK). + JSON(). + IsEqual(map[string]any{ + "$id": sid1, + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": map[string]any{ + "asset": map[string]any{ + "description": "", + "title": "", + "type": "string", + }, + sfKey1.String(): map[string]any{ + "description": "", + "title": "", + "type": "string", + }, + }, + "type": "object", + }) + + // /api/projects/{projectIdOrKey}/schemata/{schemaId}/schema.json + e.GET("/api/projects/{projectIdOrKey}/schemata/{schemaId}/schema.json", pid, sid1). + WithHeader("authorization", "Bearer abcd"). + Expect(). + Status(http.StatusUnauthorized) + + e.GET("/api/projects/{projectIdOrKey}/schemata/{schemaId}/schema.json", pid, id.NewSchemaID()). + WithHeader("authorization", "Bearer "+secret). + Expect(). + Status(http.StatusNotFound) + + e.GET("/api/projects/{projectIdOrKey}/schemata/{schemaId}/schema.json", pid, sid1). + WithHeader("authorization", "Bearer "+secret). + Expect(). + Status(http.StatusOK). + JSON(). + IsEqual(map[string]any{ + "$id": sid1, + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": map[string]any{ + "asset": map[string]any{ + "description": "", + "title": "", + "type": "string", + }, + sfKey1.String(): map[string]any{ + "description": "", + "title": "", + "type": "string", + }, + }, + "type": "object", + }) + + // /api/projects/{projectIdOrKey}/models/{modelId}/schema.json + e.GET("/api/projects/{projectIdOrKey}/models/{modelId}/schema.json", pid, mId1). + WithHeader("authorization", "Bearer abcd"). + Expect(). + Status(http.StatusUnauthorized) + + e.GET("/api/projects/{projectIdOrKey}/models/{modelId}/schema.json", pid, id.NewModelID()). + WithHeader("authorization", "Bearer "+secret). + Expect(). + Status(http.StatusNotFound) + + e.GET("/api/projects/{projectIdOrKey}/models/{modelId}/schema.json", pid, mId1). + WithHeader("authorization", "Bearer "+secret). + Expect(). + Status(http.StatusOK). + JSON(). + IsEqual(map[string]any{ + "$id": mId1, + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": map[string]any{ + "asset": map[string]any{ + "description": "", + "title": "", + "type": "string", + }, + sfKey1.String(): map[string]any{ + "description": "", + "title": "", + "type": "string", + }, + }, + "type": "object", + "description": "m1 desc", + "title": "m1", + }) + + // /api/projects/{projectIdOrKey}/models/{modelId}/metadata_schema.json + e.GET("/api/projects/{projectIdOrKey}/models/{modelId}/metadata_schema.json", pid, mId1). + WithHeader("authorization", "Bearer abcd"). + Expect(). + Status(http.StatusUnauthorized) + + e.GET("/api/projects/{projectIdOrKey}/models/{modelId}/metadata_schema.json", pid, id.NewModelID()). + WithHeader("authorization", "Bearer "+secret). + Expect(). + Status(http.StatusNotFound) + + e.GET("/api/projects/{projectIdOrKey}/models/{modelId}/metadata_schema.json", pid, mId1). + WithHeader("authorization", "Bearer "+secret). + Expect(). + Status(http.StatusOK). + JSON(). + IsEqual(map[string]any{ + "$id": mId1, + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": map[string]any{ + sfKey4.String(): map[string]any{ + "description": "", + "title": "", + "type": "boolean", + }, + }, + "type": "object", + "description": "m1 desc", + "title": "m1", + }) + + // /api/models/{modelId}/schema.json + e.GET("/api/models/{modelId}/schema.json", mId1). + WithHeader("authorization", "Bearer abcd"). + Expect(). + Status(http.StatusUnauthorized) + + e.GET("/api/models/{modelId}/schema.json", id.NewModelID()). + WithHeader("authorization", "Bearer "+secret). + Expect(). + Status(http.StatusNotFound) + + e.GET("/api/models/{modelId}/schema.json", mId1). + WithHeader("authorization", "Bearer "+secret). + Expect(). + Status(http.StatusOK). + JSON(). + IsEqual(map[string]any{ + "$id": mId1, + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": map[string]any{ + "asset": map[string]any{ + "description": "", + "title": "", + "type": "string", + }, + sfKey1.String(): map[string]any{ + "description": "", + "title": "", + "type": "string", + }, + }, + "type": "object", + "description": "m1 desc", + "title": "m1", + }) + + // /api/models/{modelId}/metadata_schema.json + e.GET("/api/models/{modelId}/metadata_schema.json", mId1). + WithHeader("authorization", "Bearer abcd"). + Expect(). + Status(http.StatusUnauthorized) + + e.GET("/api/models/{modelId}/metadata_schema.json", id.NewModelID()). + WithHeader("authorization", "Bearer "+secret). + Expect(). + Status(http.StatusNotFound) + + e.GET("/api/models/{modelId}/metadata_schema.json", mId1). + WithHeader("authorization", "Bearer "+secret). + Expect(). + Status(http.StatusOK). + JSON(). + IsEqual(map[string]any{ + "$id": mId1, + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": map[string]any{ + sfKey4.String(): map[string]any{ + "description": "", + "title": "", + "type": "boolean", + }, + }, + "type": "object", + "description": "m1 desc", + "title": "m1", + }) +} diff --git a/server/e2e/integration_schema_test.go b/server/e2e/integration_schema_test.go index bac62bee8d..04ecbf605e 100644 --- a/server/e2e/integration_schema_test.go +++ b/server/e2e/integration_schema_test.go @@ -800,143 +800,3 @@ func TestIntegrationFieldDeleteWithProjectAPI(t *testing.T) { obj1.Value("updatedAt").NotNull() obj1.Value("lastModified").NotNull() } - -func TestIntegrationSchemaJSONExportAPI(t *testing.T) { - e := StartServer(t, &app.Config{}, true, baseSeeder) - - e.GET("/api/schemata/{schemaId}/schema.json", sid1). - WithHeader("authorization", "Bearer "+secret). - Expect(). - Status(http.StatusOK). - JSON(). - IsEqual(map[string]any{ - "$id": sid1, - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": map[string]any{ - "asset": map[string]any{ - "description": "", - "title": "", - "type": "string", - }, - sfKey1.String(): map[string]any{ - "description": "", - "title": "", - "type": "string", - }, - }, - "type": "object", - }) - - e.GET("/api/projects/{projectIdOrKey}/schemata/{schemaId}/schema.json", pid, sid1). - WithHeader("authorization", "Bearer "+secret). - Expect(). - Status(http.StatusOK). - JSON(). - IsEqual(map[string]any{ - "$id": sid1, - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": map[string]any{ - "asset": map[string]any{ - "description": "", - "title": "", - "type": "string", - }, - sfKey1.String(): map[string]any{ - "description": "", - "title": "", - "type": "string", - }, - }, - "type": "object", - }) - - e.GET("/api/projects/{projectIdOrKey}/models/{modelId}/schema.json", pid, mId1). - WithHeader("authorization", "Bearer "+secret). - Expect(). - Status(http.StatusOK). - JSON(). - IsEqual(map[string]any{ - "$id": mId1, - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": map[string]any{ - "asset": map[string]any{ - "description": "", - "title": "", - "type": "string", - }, - sfKey1.String(): map[string]any{ - "description": "", - "title": "", - "type": "string", - }, - }, - "type": "object", - "description": "m1 desc", - "title": "m1", - }) - - e.GET("/api/projects/{projectIdOrKey}/models/{modelId}/metadata_schema.json", pid, mId1). - WithHeader("authorization", "Bearer "+secret). - Expect(). - Status(http.StatusOK). - JSON(). - IsEqual(map[string]any{ - "$id": mId1, - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": map[string]any{ - sfKey4.String(): map[string]any{ - "description": "", - "title": "", - "type": "boolean", - }, - }, - "type": "object", - "description": "m1 desc", - "title": "m1", - }) - - e.GET("/api/models/{modelId}/schema.json", mId1). - WithHeader("authorization", "Bearer "+secret). - Expect(). - Status(http.StatusOK). - JSON(). - IsEqual(map[string]any{ - "$id": mId1, - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": map[string]any{ - "asset": map[string]any{ - "description": "", - "title": "", - "type": "string", - }, - sfKey1.String(): map[string]any{ - "description": "", - "title": "", - "type": "string", - }, - }, - "type": "object", - "description": "m1 desc", - "title": "m1", - }) - - e.GET("/api/models/{modelId}/metadata_schema.json", mId1). - WithHeader("authorization", "Bearer "+secret). - Expect(). - Status(http.StatusOK). - JSON(). - IsEqual(map[string]any{ - "$id": mId1, - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": map[string]any{ - sfKey4.String(): map[string]any{ - "description": "", - "title": "", - "type": "boolean", - }, - }, - "type": "object", - "description": "m1 desc", - "title": "m1", - }) -} From a308f1b3655c4893bf63c61d65002b879c8fc9af Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 13 Nov 2024 12:03:57 +0900 Subject: [PATCH 19/39] wip: public api properties --- server/e2e/publicapi_test.go | 6 +- .../adapter/publicapi/schema_export.go | 63 ++++++++++++++++--- server/internal/adapter/publicapi/types.go | 4 +- 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/server/e2e/publicapi_test.go b/server/e2e/publicapi_test.go index 9130aa5446..65ab83f8d2 100644 --- a/server/e2e/publicapi_test.go +++ b/server/e2e/publicapi_test.go @@ -355,7 +355,11 @@ func TestPublicAPI(t *testing.T) { // publicAPIField2Key should be removed }) - // schema.json + // schema export json + e.GET("/api/p/{project}/{model}/schema.json", publicAPIProjectAlias, id.RandomKey()). + Expect(). + Status(http.StatusNotFound) + e.GET("/api/p/{project}/{model}/schema.json", publicAPIProjectAlias, publicAPIModelKey). Expect(). Status(http.StatusOK). diff --git a/server/internal/adapter/publicapi/schema_export.go b/server/internal/adapter/publicapi/schema_export.go index 39fa4fb7e3..15c04fcec5 100644 --- a/server/internal/adapter/publicapi/schema_export.go +++ b/server/internal/adapter/publicapi/schema_export.go @@ -16,26 +16,22 @@ func (c *Controller) GetSchemaJSON(ctx context.Context, pKey, mKey string) (Sche } m, err := c.usecases.Model.FindByIDOrKey(ctx, pr.ID(), model.IDOrKey(mKey), nil) - if err != nil { - return SchemaJSON{}, err - } - - if !m.Public() { + if err != nil || !m.Public() { return SchemaJSON{}, rerror.ErrNotFound } sp, err := c.usecases.Schema.FindByModel(ctx, m.ID(), nil) if err != nil { - return SchemaJSON{}, err + return SchemaJSON{}, rerror.ErrNotFound } - return NewSchemaJSON(m, sp.Schema()), nil + return NewSchemaJSON(m, buildProperties(c, sp.Schema().Fields(), ctx)), nil } -func toSchemaJSONProperties(f schema.FieldList) *map[string]interface{} { +func buildProperties(c *Controller, f schema.FieldList, ctx context.Context) *map[string]interface{} { properties := make(map[string]interface{}) for _, field := range f { - fieldType, format := toSchemaJSONTypeAndFormat(field.Type()) + fieldType, format := determineTypeAndFormat(field.Type()) fieldSchema := map[string]interface{}{ "type": fieldType, "title": field.Name(), @@ -44,12 +40,59 @@ func toSchemaJSONProperties(f schema.FieldList) *map[string]interface{} { if format != "" { fieldSchema["format"] = format } + + var maxLength *int + field.TypeProperty().Match(schema.TypePropertyMatch{ + Text: func(f *schema.FieldText) { + if maxLength = f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + TextArea: func(f *schema.FieldTextArea) { + if maxLength = f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + RichText: func(f *schema.FieldRichText) { + if maxLength = f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + Markdown: func(f *schema.FieldMarkdown) { + if maxLength = f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + Integer: func(f *schema.FieldInteger) { + if min := f.Min(); min != nil { + fieldSchema["minimum"] = *min + } + if max := f.Max(); max != nil { + fieldSchema["maximum"] = *max + } + }, + Number: func(f *schema.FieldNumber) { + if min := f.Min(); min != nil { + fieldSchema["minimum"] = *min + } + if max := f.Max(); max != nil { + fieldSchema["maximum"] = *max + } + }, + Group: func(f *schema.FieldGroup) { + gs, _ := c.usecases.Schema.FindByGroup(ctx, f.Group(), nil) + if gs != nil { + fieldSchema["items"] = buildProperties(c, gs.Fields(), ctx) + } + }, + }) + properties[field.Key().String()] = fieldSchema } return &properties } -func toSchemaJSONTypeAndFormat(t value.Type) (string, string) { +func determineTypeAndFormat(t value.Type) (string, string) { switch t { case "text", "textArea", "richText", "markdown", "select", "tag", "asset", "reference": return "string", "" diff --git a/server/internal/adapter/publicapi/types.go b/server/internal/adapter/publicapi/types.go index 655946d088..f8162d6b33 100644 --- a/server/internal/adapter/publicapi/types.go +++ b/server/internal/adapter/publicapi/types.go @@ -222,14 +222,14 @@ type SchemaJSON struct { Properties *map[string]interface{} `json:"properties,omitempty"` } -func NewSchemaJSON(m *model.Model, s *schema.Schema) SchemaJSON { +func NewSchemaJSON(m *model.Model, pp *map[string]interface{}) SchemaJSON { return SchemaJSON{ Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), Id: m.ID().Ref().StringRef(), Title: lo.ToPtr(m.Name()), Description: lo.ToPtr(m.Description()), Type: lo.ToPtr("object"), - Properties: toSchemaJSONProperties(s.Fields()), + Properties: pp, } } From 6ddca8016fc613d63e137e884cdda08e3142514c Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 13 Nov 2024 12:15:50 +0900 Subject: [PATCH 20/39] implement find schema by group --- server/internal/usecase/interactor/schema.go | 12 ++++++++++++ server/internal/usecase/interfaces/schema.go | 1 + 2 files changed, 13 insertions(+) diff --git a/server/internal/usecase/interactor/schema.go b/server/internal/usecase/interactor/schema.go index b472a791f0..b631f09440 100644 --- a/server/internal/usecase/interactor/schema.go +++ b/server/internal/usecase/interactor/schema.go @@ -72,6 +72,18 @@ func (i Schema) FindByModel(ctx context.Context, mID id.ModelID, _ *usecase.Oper return schema.NewPackage(s, sList.Schema(m.Metadata()), gsm, rs), nil } +func (i Schema) FindByGroup(ctx context.Context, gID id.GroupID, _ *usecase.Operator) (*schema.Schema, error) { + g, err := i.repos.Group.FindByID(ctx, gID) + if err != nil { + return nil, err + } + s, err := i.repos.Schema.FindByID(ctx, g.Schema()) + if err != nil { + return nil, err + } + return s, nil +} + func (i Schema) CreateField(ctx context.Context, param interfaces.CreateFieldParam, op *usecase.Operator) (*schema.Field, error) { return Run1(ctx, op, i.repos, Usecase().Transaction(), func(ctx context.Context) (*schema.Field, error) { s, err := i.repos.Schema.FindByID(ctx, param.SchemaID) diff --git a/server/internal/usecase/interfaces/schema.go b/server/internal/usecase/interfaces/schema.go index 4e29eb2d2d..eee847dc44 100644 --- a/server/internal/usecase/interfaces/schema.go +++ b/server/internal/usecase/interfaces/schema.go @@ -56,6 +56,7 @@ type Schema interface { FindByID(context.Context, id.SchemaID, *usecase.Operator) (*schema.Schema, error) FindByIDs(context.Context, []id.SchemaID, *usecase.Operator) (schema.List, error) FindByModel(context.Context, id.ModelID, *usecase.Operator) (*schema.Package, error) + FindByGroup(context.Context, id.GroupID, *usecase.Operator) (*schema.Schema, error) CreateField(context.Context, CreateFieldParam, *usecase.Operator) (*schema.Field, error) UpdateField(context.Context, UpdateFieldParam, *usecase.Operator) (*schema.Field, error) UpdateFields(context.Context, id.SchemaID, []UpdateFieldParam, *usecase.Operator) (schema.FieldList, error) From e8626bcb9803a1ba585e3b96f5d0190094d52b21 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 13 Nov 2024 12:17:10 +0900 Subject: [PATCH 21/39] refactor integration api --- .../adapter/integration/schema_export.go | 130 +++++++++++------- 1 file changed, 80 insertions(+), 50 deletions(-) diff --git a/server/internal/adapter/integration/schema_export.go b/server/internal/adapter/integration/schema_export.go index 9e4e7149f8..f9b9813d78 100644 --- a/server/internal/adapter/integration/schema_export.go +++ b/server/internal/adapter/integration/schema_export.go @@ -5,6 +5,7 @@ import ( "errors" "github.com/reearth/reearth-cms/server/internal/adapter" + "github.com/reearth/reearth-cms/server/internal/usecase/interfaces" "github.com/reearth/reearth-cms/server/pkg/integrationapi" "github.com/reearth/reearth-cms/server/pkg/model" "github.com/reearth/reearth-cms/server/pkg/schema" @@ -13,23 +14,23 @@ import ( "github.com/samber/lo" ) -func NewSchemaJSON(s *schema.Schema) integrationapi.SchemaJSON { +func NewSchemaJSON(s *schema.Schema, pp *map[string]interface{}) integrationapi.SchemaJSON { return integrationapi.SchemaJSON{ Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), Id: s.ID().Ref().StringRef(), Type: lo.ToPtr("object"), - Properties: toSchemaJSONProperties(s.Fields()), + Properties: pp, } } -func NewSchemaJSONWitModel(m *model.Model, s *schema.Schema) integrationapi.SchemaJSON { +func NewSchemaJSONWitModel(m *model.Model, pp *map[string]interface{}) integrationapi.SchemaJSON { return integrationapi.SchemaJSON{ Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), Id: m.ID().Ref().StringRef(), Title: lo.ToPtr(m.Name()), Description: lo.ToPtr(m.Description()), Type: lo.ToPtr("object"), - Properties: toSchemaJSONProperties(s.Fields()), + Properties: pp, } } @@ -40,17 +41,17 @@ func (s *Server) SchemaByModelAsJSON(ctx context.Context, request SchemaByModelA m, err := uc.Model.FindByID(ctx, request.ModelId, op) if err != nil { if errors.Is(err, rerror.ErrNotFound) { - return SchemaByModelAsJSON400Response{}, err + return SchemaByModelAsJSON404Response{}, err } return SchemaByModelAsJSON400Response{}, err } sp, err := uc.Schema.FindByModel(ctx, m.ID(), op) if err != nil { - return SchemaByModelAsJSON400Response{}, err + return SchemaByModelAsJSON404Response{}, err } - res := NewSchemaJSONWitModel(m, sp.Schema()) + res := NewSchemaJSONWitModel(m, buildProperties(uc, sp.Schema().Fields(), ctx)) return SchemaByModelAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -68,17 +69,17 @@ func (s *Server) MetadataSchemaByModelAsJSON(ctx context.Context, request Metada m, err := uc.Model.FindByID(ctx, request.ModelId, op) if err != nil { if errors.Is(err, rerror.ErrNotFound) { - return MetadataSchemaByModelAsJSON400Response{}, err + return MetadataSchemaByModelAsJSON404Response{}, err } return MetadataSchemaByModelAsJSON400Response{}, err } sp, err := uc.Schema.FindByModel(ctx, request.ModelId, op) if err != nil { - return MetadataSchemaByModelAsJSON400Response{}, err + return MetadataSchemaByModelAsJSON404Response{}, err } - res := NewSchemaJSONWitModel(m, sp.MetaSchema()) + res := NewSchemaJSONWitModel(m, buildProperties(uc, sp.MetaSchema().Fields(), ctx)) return MetadataSchemaByModelAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -96,7 +97,7 @@ func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request Sch p, err := uc.Project.FindByIDOrAlias(ctx, request.ProjectIdOrAlias, op) if err != nil { if errors.Is(err, rerror.ErrNotFound) { - return SchemaByModelWithProjectAsJSON400Response{}, err + return SchemaByModelWithProjectAsJSON404Response{}, err } return SchemaByModelWithProjectAsJSON400Response{}, err } @@ -104,7 +105,7 @@ func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request Sch m, err := uc.Model.FindByIDOrKey(ctx, p.ID(), request.ModelIdOrKey, op) if err != nil { if errors.Is(err, rerror.ErrNotFound) { - return SchemaByModelWithProjectAsJSON400Response{}, err + return SchemaByModelWithProjectAsJSON404Response{}, err } return SchemaByModelWithProjectAsJSON400Response{}, err } @@ -112,12 +113,12 @@ func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request Sch sch, err := uc.Schema.FindByModel(ctx, m.ID(), op) if err != nil { if errors.Is(err, rerror.ErrNotFound) { - return SchemaByModelWithProjectAsJSON400Response{}, err + return SchemaByModelWithProjectAsJSON404Response{}, err } return SchemaByModelWithProjectAsJSON400Response{}, err } - res := NewSchemaJSONWitModel(m, sch.Schema()) + res := NewSchemaJSONWitModel(m, buildProperties(uc, sch.Schema().Fields(), ctx)) return SchemaByModelWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -135,7 +136,7 @@ func (s *Server) MetadataSchemaByModelWithProjectAsJSON(ctx context.Context, req p, err := uc.Project.FindByIDOrAlias(ctx, request.ProjectIdOrAlias, op) if err != nil { if errors.Is(err, rerror.ErrNotFound) { - return MetadataSchemaByModelWithProjectAsJSON400Response{}, err + return MetadataSchemaByModelWithProjectAsJSON404Response{}, err } return MetadataSchemaByModelWithProjectAsJSON400Response{}, err } @@ -143,7 +144,7 @@ func (s *Server) MetadataSchemaByModelWithProjectAsJSON(ctx context.Context, req m, err := uc.Model.FindByIDOrKey(ctx, p.ID(), request.ModelIdOrKey, op) if err != nil { if errors.Is(err, rerror.ErrNotFound) { - return MetadataSchemaByModelWithProjectAsJSON400Response{}, err + return MetadataSchemaByModelWithProjectAsJSON404Response{}, err } return MetadataSchemaByModelWithProjectAsJSON400Response{}, err } @@ -151,12 +152,12 @@ func (s *Server) MetadataSchemaByModelWithProjectAsJSON(ctx context.Context, req sch, err := uc.Schema.FindByModel(ctx, m.ID(), op) if err != nil { if errors.Is(err, rerror.ErrNotFound) { - return MetadataSchemaByModelWithProjectAsJSON400Response{}, err + return MetadataSchemaByModelWithProjectAsJSON404Response{}, err } return MetadataSchemaByModelWithProjectAsJSON400Response{}, err } - res := NewSchemaJSONWitModel(m, sch.MetaSchema()) + res := NewSchemaJSONWitModel(m, buildProperties(uc, sch.MetaSchema().Fields(), ctx)) return MetadataSchemaByModelWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -174,12 +175,12 @@ func (s *Server) SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONR sch, err := uc.Schema.FindByID(ctx, request.SchemaId, op) if err != nil { if errors.Is(err, rerror.ErrNotFound) { - return SchemaByIDAsJSON400Response{}, err + return SchemaByIDAsJSON404Response{}, err } return SchemaByIDAsJSON400Response{}, err } - res := NewSchemaJSON(sch) + res := NewSchemaJSON(sch, buildProperties(uc, sch.Fields(), ctx)) return SchemaByIDAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -192,41 +193,23 @@ func (s *Server) SchemaByIDWithProjectAsJSON(ctx context.Context, request Schema uc := adapter.Usecases(ctx) op := adapter.Operator(ctx) - // prj, err := uc.Project.FindByIDOrAlias(ctx, request.ProjectIdOrAlias, op) - // if err != nil { - // if errors.Is(err, rerror.ErrNotFound) { - // return SchemaByIDWithProjectAsJSON400Response{}, err - // } - // return SchemaByIDWithProjectAsJSON400Response{}, err - // } - - // ms, _, err := uc.Model.FindByProjectAndKeyword(ctx, prj.ID(), lo.FromPtrOr(request.Params.Keyword, ""), p, op) - // if err != nil { - // return nil, err - // } - - // models := make([]integrationapi.Model, 0, len(ms)) - // for _, m := range ms { - // sp, err := uc.Schema.FindByModel(ctx, m.ID(), op) - // if err != nil { - // return nil, err - // } - // lastModified, err := uc.Item.LastModifiedByModel(ctx, m.ID(), op) - // if err != nil && !errors.Is(err, rerror.ErrNotFound) { - // return nil, err - // } - // models = append(models, integrationapi.NewModel(m, sp, lastModified)) - // } + _, err := uc.Project.FindByIDOrAlias(ctx, request.ProjectIdOrAlias, op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return SchemaByIDWithProjectAsJSON404Response{}, err + } + return SchemaByIDWithProjectAsJSON400Response{}, err + } sch, err := uc.Schema.FindByID(ctx, request.SchemaId, op) if err != nil { if errors.Is(err, rerror.ErrNotFound) { - return SchemaByIDWithProjectAsJSON400Response{}, err + return SchemaByIDWithProjectAsJSON404Response{}, err } return SchemaByIDWithProjectAsJSON400Response{}, err } - res := NewSchemaJSON(sch) + res := NewSchemaJSON(sch, buildProperties(uc, sch.Fields(), ctx)) return SchemaByIDWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -235,10 +218,10 @@ func (s *Server) SchemaByIDWithProjectAsJSON(ctx context.Context, request Schema }, nil } -func toSchemaJSONProperties(f schema.FieldList) *map[string]interface{} { +func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.Context) *map[string]interface{} { properties := make(map[string]interface{}) for _, field := range f { - fieldType, format := toSchemaJSONTypeAndFormat(field.Type()) + fieldType, format := determineTypeAndFormat(field.Type()) fieldSchema := map[string]interface{}{ "type": fieldType, "title": field.Name(), @@ -247,12 +230,59 @@ func toSchemaJSONProperties(f schema.FieldList) *map[string]interface{} { if format != "" { fieldSchema["format"] = format } + + var maxLength *int + field.TypeProperty().Match(schema.TypePropertyMatch{ + Text: func(f *schema.FieldText) { + if maxLength = f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + TextArea: func(f *schema.FieldTextArea) { + if maxLength = f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + RichText: func(f *schema.FieldRichText) { + if maxLength = f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + Markdown: func(f *schema.FieldMarkdown) { + if maxLength = f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + Integer: func(f *schema.FieldInteger) { + if min := f.Min(); min != nil { + fieldSchema["minimum"] = *min + } + if max := f.Max(); max != nil { + fieldSchema["maximum"] = *max + } + }, + Number: func(f *schema.FieldNumber) { + if min := f.Min(); min != nil { + fieldSchema["minimum"] = *min + } + if max := f.Max(); max != nil { + fieldSchema["maximum"] = *max + } + }, + Group: func(f *schema.FieldGroup) { + gs, _ := uc.Schema.FindByGroup(ctx, f.Group(), nil) + if gs != nil { + fieldSchema["items"] = buildProperties(uc, gs.Fields(), ctx) + } + }, + }) + properties[field.Key().String()] = fieldSchema } return &properties } -func toSchemaJSONTypeAndFormat(t value.Type) (string, string) { +func determineTypeAndFormat(t value.Type) (string, string) { switch t { case "text", "textArea", "richText", "markdown", "select", "tag", "asset", "reference": return "string", "" From 2e750dc3abf11f90bffef7e37cd4c7e069a4fb5a Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 13 Nov 2024 12:26:45 +0900 Subject: [PATCH 22/39] lint --- server/e2e/integration_schema_export_test.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/server/e2e/integration_schema_export_test.go b/server/e2e/integration_schema_export_test.go index aa36adcc27..7898a73b7f 100644 --- a/server/e2e/integration_schema_export_test.go +++ b/server/e2e/integration_schema_export_test.go @@ -45,8 +45,8 @@ func TestIntegrationSchemaJSONExportAPI(t *testing.T) { "type": "object", }) - // /api/projects/{projectIdOrKey}/schemata/{schemaId}/schema.json - e.GET("/api/projects/{projectIdOrKey}/schemata/{schemaId}/schema.json", pid, sid1). + // /api/projects/{projectIdOrKey}/schemata/{schemaId}/schema.json + e.GET("/api/projects/{projectIdOrKey}/schemata/{schemaId}/schema.json", pid, sid1). WithHeader("authorization", "Bearer abcd"). Expect(). Status(http.StatusUnauthorized) @@ -79,8 +79,8 @@ func TestIntegrationSchemaJSONExportAPI(t *testing.T) { "type": "object", }) - // /api/projects/{projectIdOrKey}/models/{modelId}/schema.json - e.GET("/api/projects/{projectIdOrKey}/models/{modelId}/schema.json", pid, mId1). + // /api/projects/{projectIdOrKey}/models/{modelId}/schema.json + e.GET("/api/projects/{projectIdOrKey}/models/{modelId}/schema.json", pid, mId1). WithHeader("authorization", "Bearer abcd"). Expect(). Status(http.StatusUnauthorized) @@ -115,8 +115,8 @@ func TestIntegrationSchemaJSONExportAPI(t *testing.T) { "title": "m1", }) - // /api/projects/{projectIdOrKey}/models/{modelId}/metadata_schema.json - e.GET("/api/projects/{projectIdOrKey}/models/{modelId}/metadata_schema.json", pid, mId1). + // /api/projects/{projectIdOrKey}/models/{modelId}/metadata_schema.json + e.GET("/api/projects/{projectIdOrKey}/models/{modelId}/metadata_schema.json", pid, mId1). WithHeader("authorization", "Bearer abcd"). Expect(). Status(http.StatusUnauthorized) @@ -146,8 +146,8 @@ func TestIntegrationSchemaJSONExportAPI(t *testing.T) { "title": "m1", }) - // /api/models/{modelId}/schema.json - e.GET("/api/models/{modelId}/schema.json", mId1). + // /api/models/{modelId}/schema.json + e.GET("/api/models/{modelId}/schema.json", mId1). WithHeader("authorization", "Bearer abcd"). Expect(). Status(http.StatusUnauthorized) @@ -182,8 +182,8 @@ func TestIntegrationSchemaJSONExportAPI(t *testing.T) { "title": "m1", }) - // /api/models/{modelId}/metadata_schema.json - e.GET("/api/models/{modelId}/metadata_schema.json", mId1). + // /api/models/{modelId}/metadata_schema.json + e.GET("/api/models/{modelId}/metadata_schema.json", mId1). WithHeader("authorization", "Bearer abcd"). Expect(). Status(http.StatusUnauthorized) From 8edf568970e6c69ac9216df9caf47950eb2f24df Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 13 Nov 2024 12:43:15 +0900 Subject: [PATCH 23/39] update determineTypeAndFormat --- server/e2e/integration_schema_export_test.go | 4 ++++ server/e2e/publicapi_test.go | 2 ++ server/internal/adapter/integration/schema_export.go | 4 +++- server/internal/adapter/publicapi/schema_export.go | 6 ++++-- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/server/e2e/integration_schema_export_test.go b/server/e2e/integration_schema_export_test.go index 7898a73b7f..c6b4fdeeed 100644 --- a/server/e2e/integration_schema_export_test.go +++ b/server/e2e/integration_schema_export_test.go @@ -35,6 +35,7 @@ func TestIntegrationSchemaJSONExportAPI(t *testing.T) { "description": "", "title": "", "type": "string", + "format": "binary", }, sfKey1.String(): map[string]any{ "description": "", @@ -69,6 +70,7 @@ func TestIntegrationSchemaJSONExportAPI(t *testing.T) { "description": "", "title": "", "type": "string", + "format": "binary", }, sfKey1.String(): map[string]any{ "description": "", @@ -103,6 +105,7 @@ func TestIntegrationSchemaJSONExportAPI(t *testing.T) { "description": "", "title": "", "type": "string", + "format": "binary", }, sfKey1.String(): map[string]any{ "description": "", @@ -170,6 +173,7 @@ func TestIntegrationSchemaJSONExportAPI(t *testing.T) { "description": "", "title": "", "type": "string", + "format": "binary", }, sfKey1.String(): map[string]any{ "description": "", diff --git a/server/e2e/publicapi_test.go b/server/e2e/publicapi_test.go index 65ab83f8d2..689f7250c8 100644 --- a/server/e2e/publicapi_test.go +++ b/server/e2e/publicapi_test.go @@ -372,11 +372,13 @@ func TestPublicAPI(t *testing.T) { "description": "", "title": "asset", "type": "string", + "format": "binary", }, "asset2": map[string]any{ "description": "", "title": "asset2", "type": "string", + "format": "binary", }, "geometry-editor": map[string]any{ "description": "", diff --git a/server/internal/adapter/integration/schema_export.go b/server/internal/adapter/integration/schema_export.go index f9b9813d78..fb3a3c676c 100644 --- a/server/internal/adapter/integration/schema_export.go +++ b/server/internal/adapter/integration/schema_export.go @@ -284,7 +284,7 @@ func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.C func determineTypeAndFormat(t value.Type) (string, string) { switch t { - case "text", "textArea", "richText", "markdown", "select", "tag", "asset", "reference": + case "text", "textArea", "richText", "markdown", "select", "tag", "reference": return "string", "" case "integer": return "integer", "" @@ -296,6 +296,8 @@ func determineTypeAndFormat(t value.Type) (string, string) { return "string", "date" case "url": return "string", "uri" + case "asset": + return "string", "binary" case "group": return "array", "" case "geometryObject", "geometryEditor": diff --git a/server/internal/adapter/publicapi/schema_export.go b/server/internal/adapter/publicapi/schema_export.go index 15c04fcec5..f98e3697e8 100644 --- a/server/internal/adapter/publicapi/schema_export.go +++ b/server/internal/adapter/publicapi/schema_export.go @@ -94,7 +94,7 @@ func buildProperties(c *Controller, f schema.FieldList, ctx context.Context) *ma func determineTypeAndFormat(t value.Type) (string, string) { switch t { - case "text", "textArea", "richText", "markdown", "select", "tag", "asset", "reference": + case "text", "textArea", "richText", "markdown", "select", "tag", "reference": return "string", "" case "integer": return "integer", "" @@ -106,6 +106,8 @@ func determineTypeAndFormat(t value.Type) (string, string) { return "string", "date" case "url": return "string", "uri" + case "asset": + return "string", "binary" case "group": return "array", "" case "geometryObject", "geometryEditor": @@ -113,4 +115,4 @@ func determineTypeAndFormat(t value.Type) (string, string) { default: return "string", "" } -} +} \ No newline at end of file From ef87bd6c1eb710db226053ce73ee700bb69a84e7 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 13 Nov 2024 14:27:29 +0900 Subject: [PATCH 24/39] add const defaultJSONSchemaVersion --- server/internal/adapter/integration/schema_export.go | 6 ++++-- server/internal/adapter/publicapi/types.go | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/server/internal/adapter/integration/schema_export.go b/server/internal/adapter/integration/schema_export.go index fb3a3c676c..685a50a37a 100644 --- a/server/internal/adapter/integration/schema_export.go +++ b/server/internal/adapter/integration/schema_export.go @@ -14,9 +14,11 @@ import ( "github.com/samber/lo" ) +const defaultJSONSchemaVersion = "https://json-schema.org/draft/2020-12/schema" + func NewSchemaJSON(s *schema.Schema, pp *map[string]interface{}) integrationapi.SchemaJSON { return integrationapi.SchemaJSON{ - Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), + Schema: lo.ToPtr(defaultJSONSchemaVersion), Id: s.ID().Ref().StringRef(), Type: lo.ToPtr("object"), Properties: pp, @@ -25,7 +27,7 @@ func NewSchemaJSON(s *schema.Schema, pp *map[string]interface{}) integrationapi. func NewSchemaJSONWitModel(m *model.Model, pp *map[string]interface{}) integrationapi.SchemaJSON { return integrationapi.SchemaJSON{ - Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), + Schema: lo.ToPtr(defaultJSONSchemaVersion), Id: m.ID().Ref().StringRef(), Title: lo.ToPtr(m.Name()), Description: lo.ToPtr(m.Description()), diff --git a/server/internal/adapter/publicapi/types.go b/server/internal/adapter/publicapi/types.go index f8162d6b33..929419770f 100644 --- a/server/internal/adapter/publicapi/types.go +++ b/server/internal/adapter/publicapi/types.go @@ -213,6 +213,8 @@ func NewItemAsset(a *asset.Asset, urlResolver asset.URLResolver) ItemAsset { } } +const defaultJSONSchemaVersion = "https://json-schema.org/draft/2020-12/schema" + type SchemaJSON struct { Schema *string `json:"schema,omitempty"` Id *string `json:"id,omitempty"` @@ -224,7 +226,7 @@ type SchemaJSON struct { func NewSchemaJSON(m *model.Model, pp *map[string]interface{}) SchemaJSON { return SchemaJSON{ - Schema: lo.ToPtr("https://json-schema.org/draft/2020-12/schema"), + Schema: lo.ToPtr(defaultJSONSchemaVersion), Id: m.ID().Ref().StringRef(), Title: lo.ToPtr(m.Name()), Description: lo.ToPtr(m.Description()), From b86109498c6de04e05b7e6b977ad01f316cc7658 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 13 Nov 2024 14:34:36 +0900 Subject: [PATCH 25/39] refactor --- server/internal/adapter/publicapi/schema_export.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/server/internal/adapter/publicapi/schema_export.go b/server/internal/adapter/publicapi/schema_export.go index f98e3697e8..a8ea933568 100644 --- a/server/internal/adapter/publicapi/schema_export.go +++ b/server/internal/adapter/publicapi/schema_export.go @@ -3,6 +3,7 @@ package publicapi import ( "context" + "github.com/reearth/reearth-cms/server/internal/usecase/interfaces" "github.com/reearth/reearth-cms/server/pkg/model" "github.com/reearth/reearth-cms/server/pkg/schema" "github.com/reearth/reearth-cms/server/pkg/value" @@ -25,10 +26,10 @@ func (c *Controller) GetSchemaJSON(ctx context.Context, pKey, mKey string) (Sche return SchemaJSON{}, rerror.ErrNotFound } - return NewSchemaJSON(m, buildProperties(c, sp.Schema().Fields(), ctx)), nil + return NewSchemaJSON(m, buildProperties(c.usecases, sp.Schema().Fields(), ctx)), nil } -func buildProperties(c *Controller, f schema.FieldList, ctx context.Context) *map[string]interface{} { +func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.Context) *map[string]interface{} { properties := make(map[string]interface{}) for _, field := range f { fieldType, format := determineTypeAndFormat(field.Type()) @@ -80,9 +81,9 @@ func buildProperties(c *Controller, f schema.FieldList, ctx context.Context) *ma } }, Group: func(f *schema.FieldGroup) { - gs, _ := c.usecases.Schema.FindByGroup(ctx, f.Group(), nil) + gs, _ := uc.Schema.FindByGroup(ctx, f.Group(), nil) if gs != nil { - fieldSchema["items"] = buildProperties(c, gs.Fields(), ctx) + fieldSchema["items"] = buildProperties(uc, gs.Fields(), ctx) } }, }) @@ -115,4 +116,4 @@ func determineTypeAndFormat(t value.Type) (string, string) { default: return "string", "" } -} \ No newline at end of file +} From 132d722af788e9c40614cad8b5a3efd601b9744a Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Thu, 14 Nov 2024 10:13:06 +0900 Subject: [PATCH 26/39] add unit test for determineTypeAndFormat --- .../adapter/integration/schema_export.go | 20 ++++----- .../adapter/integration/schema_export_test.go | 42 +++++++++++++++++++ .../adapter/publicapi/schema_export.go | 20 ++++----- .../adapter/publicapi/schema_export_test.go | 42 +++++++++++++++++++ 4 files changed, 104 insertions(+), 20 deletions(-) create mode 100644 server/internal/adapter/integration/schema_export_test.go create mode 100644 server/internal/adapter/publicapi/schema_export_test.go diff --git a/server/internal/adapter/integration/schema_export.go b/server/internal/adapter/integration/schema_export.go index 685a50a37a..11c50ae665 100644 --- a/server/internal/adapter/integration/schema_export.go +++ b/server/internal/adapter/integration/schema_export.go @@ -286,23 +286,23 @@ func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.C func determineTypeAndFormat(t value.Type) (string, string) { switch t { - case "text", "textArea", "richText", "markdown", "select", "tag", "reference": + case value.TypeText, value.TypeTextArea, value.TypeRichText, value.TypeMarkdown, value.TypeSelect, value.TypeTag, value.TypeReference: return "string", "" - case "integer": + case value.TypeInteger: return "integer", "" - case "number": + case value.TypeNumber: return "number", "" - case "bool", "checkbox": + case value.TypeBool, value.TypeCheckbox: return "boolean", "" - case "date": - return "string", "date" - case "url": + case value.TypeDateTime: + return "string", "date-time" + case value.TypeURL: return "string", "uri" - case "asset": + case value.TypeAsset: return "string", "binary" - case "group": + case value.TypeGroup: return "array", "" - case "geometryObject", "geometryEditor": + case value.TypeGeometryObject, value.TypeGeometryEditor: return "object", "" default: return "string", "" diff --git a/server/internal/adapter/integration/schema_export_test.go b/server/internal/adapter/integration/schema_export_test.go new file mode 100644 index 0000000000..db7a7edd69 --- /dev/null +++ b/server/internal/adapter/integration/schema_export_test.go @@ -0,0 +1,42 @@ +package integration + +import ( + "testing" + + "github.com/reearth/reearth-cms/server/pkg/value" + "github.com/stretchr/testify/assert" +) + +func TestDetermineTypeAndFormat(t *testing.T) { + tests := []struct { + input value.Type + wantType string + wantFmt string + }{ + {value.TypeText, "string", ""}, + {value.TypeTextArea, "string", ""}, + {value.TypeRichText, "string", ""}, + {value.TypeMarkdown, "string", ""}, + {value.TypeSelect, "string", ""}, + {value.TypeTag, "string", ""}, + {value.TypeReference, "string", ""}, + {value.TypeInteger, "integer", ""}, + {value.TypeNumber, "number", ""}, + {value.TypeBool, "boolean", ""}, + {value.TypeDateTime, "string", "date-time"}, + {value.TypeURL, "string", "uri"}, + {value.TypeAsset, "string", "binary"}, + {value.TypeGroup, "array", ""}, + {value.TypeGeometryObject, "object", ""}, + {value.TypeGeometryEditor, "object", ""}, + {"unknown", "string", ""}, + } + + for _, tt := range tests { + t.Run(string(tt.input), func(t *testing.T) { + gotType, gotFmt := determineTypeAndFormat(tt.input) + assert.Equal(t, tt.wantType, gotType) + assert.Equal(t, tt.wantFmt, gotFmt) + }) + } +} diff --git a/server/internal/adapter/publicapi/schema_export.go b/server/internal/adapter/publicapi/schema_export.go index a8ea933568..7c3af4c2ed 100644 --- a/server/internal/adapter/publicapi/schema_export.go +++ b/server/internal/adapter/publicapi/schema_export.go @@ -95,23 +95,23 @@ func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.C func determineTypeAndFormat(t value.Type) (string, string) { switch t { - case "text", "textArea", "richText", "markdown", "select", "tag", "reference": + case value.TypeText, value.TypeTextArea, value.TypeRichText, value.TypeMarkdown, value.TypeSelect, value.TypeTag, value.TypeReference: return "string", "" - case "integer": + case value.TypeInteger: return "integer", "" - case "number": + case value.TypeNumber: return "number", "" - case "bool", "checkbox": + case value.TypeBool, value.TypeCheckbox: return "boolean", "" - case "date": - return "string", "date" - case "url": + case value.TypeDateTime: + return "string", "date-time" + case value.TypeURL: return "string", "uri" - case "asset": + case value.TypeAsset: return "string", "binary" - case "group": + case value.TypeGroup: return "array", "" - case "geometryObject", "geometryEditor": + case value.TypeGeometryObject, value.TypeGeometryEditor: return "object", "" default: return "string", "" diff --git a/server/internal/adapter/publicapi/schema_export_test.go b/server/internal/adapter/publicapi/schema_export_test.go new file mode 100644 index 0000000000..465d8d4458 --- /dev/null +++ b/server/internal/adapter/publicapi/schema_export_test.go @@ -0,0 +1,42 @@ +package publicapi + +import ( + "testing" + + "github.com/reearth/reearth-cms/server/pkg/value" + "github.com/stretchr/testify/assert" +) + +func TestDetermineTypeAndFormat(t *testing.T) { + tests := []struct { + input value.Type + wantType string + wantFmt string + }{ + {value.TypeText, "string", ""}, + {value.TypeTextArea, "string", ""}, + {value.TypeRichText, "string", ""}, + {value.TypeMarkdown, "string", ""}, + {value.TypeSelect, "string", ""}, + {value.TypeTag, "string", ""}, + {value.TypeReference, "string", ""}, + {value.TypeInteger, "integer", ""}, + {value.TypeNumber, "number", ""}, + {value.TypeBool, "boolean", ""}, + {value.TypeDateTime, "string", "date-time"}, + {value.TypeURL, "string", "uri"}, + {value.TypeAsset, "string", "binary"}, + {value.TypeGroup, "array", ""}, + {value.TypeGeometryObject, "object", ""}, + {value.TypeGeometryEditor, "object", ""}, + {"unknown", "string", ""}, + } + + for _, tt := range tests { + t.Run(string(tt.input), func(t *testing.T) { + gotType, gotFmt := determineTypeAndFormat(tt.input) + assert.Equal(t, tt.wantType, gotType) + assert.Equal(t, tt.wantFmt, gotFmt) + }) + } +} From e370e3d561b0f64788f8090ed49b79cbeb12005b Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Thu, 14 Nov 2024 11:33:54 +0900 Subject: [PATCH 27/39] add TestBuildProperties --- .../adapter/integration/schema_export_test.go | 118 ++++++++++++++++++ .../adapter/publicapi/schema_export_test.go | 118 ++++++++++++++++++ 2 files changed, 236 insertions(+) diff --git a/server/internal/adapter/integration/schema_export_test.go b/server/internal/adapter/integration/schema_export_test.go index db7a7edd69..d6139bf689 100644 --- a/server/internal/adapter/integration/schema_export_test.go +++ b/server/internal/adapter/integration/schema_export_test.go @@ -1,12 +1,130 @@ package integration import ( + "context" "testing" + "github.com/reearth/reearth-cms/server/internal/infrastructure/memory" + "github.com/reearth/reearth-cms/server/internal/usecase/interactor" + "github.com/reearth/reearth-cms/server/internal/usecase/interfaces" + "github.com/reearth/reearth-cms/server/pkg/group" + "github.com/reearth/reearth-cms/server/pkg/id" + "github.com/reearth/reearth-cms/server/pkg/schema" "github.com/reearth/reearth-cms/server/pkg/value" + "github.com/reearth/reearthx/account/accountdomain" + "github.com/samber/lo" "github.com/stretchr/testify/assert" ) +func TestBuildProperties(t *testing.T) { + ctx := context.Background() + r := memory.New() + uc := &interfaces.Container{Schema: interactor.NewSchema(r, nil)} + + wid := accountdomain.NewWorkspaceID() + pid := id.NewProjectID() + + // text field + fId1 := id.NewFieldID() + sfKey1 := id.RandomKey() + sf1 := schema.NewField(schema.NewText(lo.ToPtr(100)).TypeProperty()).ID(fId1).Key(sfKey1).MustBuild() + + // number field + fId2 := id.NewFieldID() + sfKey2 := id.RandomKey() + intField, err := schema.NewInteger(lo.ToPtr(int64(1)), lo.ToPtr(int64(100))) + assert.NoError(t, err) + sf2 := schema.NewField(intField.TypeProperty()).ID(fId2).Key(sfKey2).MustBuild() + + // asset field + gsfKey := id.NewKey("asset-key") + gsfId2 := id.NewFieldID() + gsf := schema.NewField(schema.NewAsset().TypeProperty()).ID(gsfId2).Key(gsfKey).Multiple(true).MustBuild() + + // group schema + gs := schema.New().ID(id.NewSchemaID()).Workspace(wid).Project(pid).Fields([]*schema.Field{gsf}).MustBuild() + lo.Must0(r.Schema.Save(ctx, gs)) + + // group + gid := id.NewGroupID() + gkey := id.RandomKey() + g := group.New().ID(gid).Name("group").Project(pid).Key(gkey).Schema(gs.ID()).MustBuild() + lo.Must0(r.Group.Save(ctx, g)) + + // group field + fId3 := id.NewFieldID() + sfKey3 := id.NewKey("group-key") + sf3 := schema.NewField(schema.NewGroup(g.ID()).TypeProperty()).ID(fId3).Key(sfKey3).Multiple(true).MustBuild() + + // bool field + fId4 := id.NewFieldID() + sfKey4 := id.RandomKey() + sf4 := schema.NewField(schema.NewBool().TypeProperty()).ID(fId4).Key(sfKey4).MustBuild() + + // date field + fId5 := id.NewFieldID() + sfKey5 := id.RandomKey() + sf5 := schema.NewField(schema.NewDateTime().TypeProperty()).ID(fId5).Key(sfKey5).MustBuild() + + // url field + fId6 := id.NewFieldID() + sfKey6 := id.RandomKey() + sf6 := schema.NewField(schema.NewURL().TypeProperty()).ID(fId6).Key(sfKey6).MustBuild() + + fieldList := schema.FieldList{sf1, sf2, sf3, sf4, sf5, sf6} + s1 := schema.New().NewID().Workspace(wid).Project(pid).Fields(schema.FieldList{sf2}).MustBuild() + lo.Must0(r.Schema.Save(ctx, s1)) + + expectedProperties := &map[string]interface{}{ + sfKey1.String(): map[string]interface{}{ + "type": "string", + "title": "", + "description": "", + "maxLength": 100, + }, + sfKey2.String(): map[string]interface{}{ + "type": "integer", + "title": "", + "description": "", + "minimum": int64(1), + "maximum": int64(100), + }, + sfKey3.String(): map[string]interface{}{ + "title": "", + "type": "array", + "description": "", + "items": &map[string]interface{}{ + "asset-key": map[string]interface{}{ + "description": "", + "format": "binary", + "title": "", + "type": "string", + }, + }, + }, + sfKey4.String(): map[string]interface{}{ + "type": "boolean", + "title": "", + "description": "", + }, + sfKey5.String(): map[string]interface{}{ + "type": "string", + "title": "", + "description": "", + "format": "date-time", + }, + sfKey6.String(): map[string]interface{}{ + "type": "string", + "title": "", + "description": "", + "format": "uri", + }, + } + + properties := buildProperties(uc, fieldList, ctx) + assert.Equal(t, expectedProperties, properties) +} + func TestDetermineTypeAndFormat(t *testing.T) { tests := []struct { input value.Type diff --git a/server/internal/adapter/publicapi/schema_export_test.go b/server/internal/adapter/publicapi/schema_export_test.go index 465d8d4458..a34c51fb13 100644 --- a/server/internal/adapter/publicapi/schema_export_test.go +++ b/server/internal/adapter/publicapi/schema_export_test.go @@ -1,12 +1,130 @@ package publicapi import ( + "context" "testing" + "github.com/reearth/reearth-cms/server/internal/infrastructure/memory" + "github.com/reearth/reearth-cms/server/internal/usecase/interactor" + "github.com/reearth/reearth-cms/server/internal/usecase/interfaces" + "github.com/reearth/reearth-cms/server/pkg/group" + "github.com/reearth/reearth-cms/server/pkg/id" + "github.com/reearth/reearth-cms/server/pkg/schema" "github.com/reearth/reearth-cms/server/pkg/value" + "github.com/reearth/reearthx/account/accountdomain" + "github.com/samber/lo" "github.com/stretchr/testify/assert" ) +func TestBuildProperties(t *testing.T) { + ctx := context.Background() + r := memory.New() + uc := &interfaces.Container{Schema: interactor.NewSchema(r, nil)} + + wid := accountdomain.NewWorkspaceID() + pid := id.NewProjectID() + + // text field + fId1 := id.NewFieldID() + sfKey1 := id.RandomKey() + sf1 := schema.NewField(schema.NewText(lo.ToPtr(100)).TypeProperty()).ID(fId1).Key(sfKey1).MustBuild() + + // number field + fId2 := id.NewFieldID() + sfKey2 := id.RandomKey() + intField, err := schema.NewInteger(lo.ToPtr(int64(1)), lo.ToPtr(int64(100))) + assert.NoError(t, err) + sf2 := schema.NewField(intField.TypeProperty()).ID(fId2).Key(sfKey2).MustBuild() + + // asset field + gsfKey := id.NewKey("asset-key") + gsfId2 := id.NewFieldID() + gsf := schema.NewField(schema.NewAsset().TypeProperty()).ID(gsfId2).Key(gsfKey).Multiple(true).MustBuild() + + // group schema + gs := schema.New().ID(id.NewSchemaID()).Workspace(wid).Project(pid).Fields([]*schema.Field{gsf}).MustBuild() + lo.Must0(r.Schema.Save(ctx, gs)) + + // group + gid := id.NewGroupID() + gkey := id.RandomKey() + g := group.New().ID(gid).Name("group").Project(pid).Key(gkey).Schema(gs.ID()).MustBuild() + lo.Must0(r.Group.Save(ctx, g)) + + // group field + fId3 := id.NewFieldID() + sfKey3 := id.NewKey("group-key") + sf3 := schema.NewField(schema.NewGroup(g.ID()).TypeProperty()).ID(fId3).Key(sfKey3).Multiple(true).MustBuild() + + // bool field + fId4 := id.NewFieldID() + sfKey4 := id.RandomKey() + sf4 := schema.NewField(schema.NewBool().TypeProperty()).ID(fId4).Key(sfKey4).MustBuild() + + // date field + fId5 := id.NewFieldID() + sfKey5 := id.RandomKey() + sf5 := schema.NewField(schema.NewDateTime().TypeProperty()).ID(fId5).Key(sfKey5).MustBuild() + + // url field + fId6 := id.NewFieldID() + sfKey6 := id.RandomKey() + sf6 := schema.NewField(schema.NewURL().TypeProperty()).ID(fId6).Key(sfKey6).MustBuild() + + fieldList := schema.FieldList{sf1, sf2, sf3, sf4, sf5, sf6} + s1 := schema.New().NewID().Workspace(wid).Project(pid).Fields(schema.FieldList{sf2}).MustBuild() + lo.Must0(r.Schema.Save(ctx, s1)) + + expectedProperties := &map[string]interface{}{ + sfKey1.String(): map[string]interface{}{ + "type": "string", + "title": "", + "description": "", + "maxLength": 100, + }, + sfKey2.String(): map[string]interface{}{ + "type": "integer", + "title": "", + "description": "", + "minimum": int64(1), + "maximum": int64(100), + }, + sfKey3.String(): map[string]interface{}{ + "title": "", + "type": "array", + "description": "", + "items": &map[string]interface{}{ + "asset-key": map[string]interface{}{ + "description": "", + "format": "binary", + "title": "", + "type": "string", + }, + }, + }, + sfKey4.String(): map[string]interface{}{ + "type": "boolean", + "title": "", + "description": "", + }, + sfKey5.String(): map[string]interface{}{ + "type": "string", + "title": "", + "description": "", + "format": "date-time", + }, + sfKey6.String(): map[string]interface{}{ + "type": "string", + "title": "", + "description": "", + "format": "uri", + }, + } + + properties := buildProperties(uc, fieldList, ctx) + assert.Equal(t, expectedProperties, properties) +} + func TestDetermineTypeAndFormat(t *testing.T) { tests := []struct { input value.Type From 1577665a1fe3f561abf5959eb85ef7f6ea5a3767 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Tue, 19 Nov 2024 12:01:23 +0900 Subject: [PATCH 28/39] refactor --- .../adapter/integration/schema_export.go | 125 ++++++++++-------- .../adapter/integration/schema_export_test.go | 15 +-- .../adapter/publicapi/schema_export.go | 110 ++++++++------- .../adapter/publicapi/schema_export_test.go | 15 +-- 4 files changed, 137 insertions(+), 128 deletions(-) diff --git a/server/internal/adapter/integration/schema_export.go b/server/internal/adapter/integration/schema_export.go index 11c50ae665..f2b4ff5085 100644 --- a/server/internal/adapter/integration/schema_export.go +++ b/server/internal/adapter/integration/schema_export.go @@ -6,6 +6,7 @@ import ( "github.com/reearth/reearth-cms/server/internal/adapter" "github.com/reearth/reearth-cms/server/internal/usecase/interfaces" + "github.com/reearth/reearth-cms/server/pkg/id" "github.com/reearth/reearth-cms/server/pkg/integrationapi" "github.com/reearth/reearth-cms/server/pkg/model" "github.com/reearth/reearth-cms/server/pkg/schema" @@ -53,7 +54,8 @@ func (s *Server) SchemaByModelAsJSON(ctx context.Context, request SchemaByModelA return SchemaByModelAsJSON404Response{}, err } - res := NewSchemaJSONWitModel(m, buildProperties(uc, sp.Schema().Fields(), ctx)) + gsMap := buildGroupSchemaMap(ctx, sp.Schema(), uc) + res := NewSchemaJSONWitModel(m, buildProperties(sp.Schema().Fields(), gsMap)) return SchemaByModelAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -76,12 +78,12 @@ func (s *Server) MetadataSchemaByModelAsJSON(ctx context.Context, request Metada return MetadataSchemaByModelAsJSON400Response{}, err } - sp, err := uc.Schema.FindByModel(ctx, request.ModelId, op) + sp, err := uc.Schema.FindByModel(ctx, m.ID(), op) if err != nil { return MetadataSchemaByModelAsJSON404Response{}, err } - res := NewSchemaJSONWitModel(m, buildProperties(uc, sp.MetaSchema().Fields(), ctx)) + res := NewSchemaJSONWitModel(m, buildProperties(sp.MetaSchema().Fields(), nil)) return MetadataSchemaByModelAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -120,7 +122,8 @@ func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request Sch return SchemaByModelWithProjectAsJSON400Response{}, err } - res := NewSchemaJSONWitModel(m, buildProperties(uc, sch.Schema().Fields(), ctx)) + gsMap := buildGroupSchemaMap(ctx, sch.Schema(), uc) + res := NewSchemaJSONWitModel(m, buildProperties(sch.Schema().Fields(), gsMap)) return SchemaByModelWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -159,7 +162,7 @@ func (s *Server) MetadataSchemaByModelWithProjectAsJSON(ctx context.Context, req return MetadataSchemaByModelWithProjectAsJSON400Response{}, err } - res := NewSchemaJSONWitModel(m, buildProperties(uc, sch.MetaSchema().Fields(), ctx)) + res := NewSchemaJSONWitModel(m, buildProperties(sch.MetaSchema().Fields(), nil)) return MetadataSchemaByModelWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -182,7 +185,8 @@ func (s *Server) SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONR return SchemaByIDAsJSON400Response{}, err } - res := NewSchemaJSON(sch, buildProperties(uc, sch.Fields(), ctx)) + gsMap := buildGroupSchemaMap(ctx, sch, uc) + res := NewSchemaJSON(sch, buildProperties(sch.Fields(), gsMap)) return SchemaByIDAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -211,7 +215,8 @@ func (s *Server) SchemaByIDWithProjectAsJSON(ctx context.Context, request Schema return SchemaByIDWithProjectAsJSON400Response{}, err } - res := NewSchemaJSON(sch, buildProperties(uc, sch.Fields(), ctx)) + gsMap := buildGroupSchemaMap(ctx, sch, uc) + res := NewSchemaJSON(sch, buildProperties(sch.Fields(), gsMap)) return SchemaByIDWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -220,9 +225,9 @@ func (s *Server) SchemaByIDWithProjectAsJSON(ctx context.Context, request Schema }, nil } -func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.Context) *map[string]interface{} { +func buildProperties(fields schema.FieldList, gsMap map[id.GroupID]*schema.Schema) *map[string]interface{} { properties := make(map[string]interface{}) - for _, field := range f { + for _, field := range fields { fieldType, format := determineTypeAndFormat(field.Type()) fieldSchema := map[string]interface{}{ "type": fieldType, @@ -232,58 +237,55 @@ func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.C if format != "" { fieldSchema["format"] = format } - - var maxLength *int field.TypeProperty().Match(schema.TypePropertyMatch{ - Text: func(f *schema.FieldText) { - if maxLength = f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength - } - }, - TextArea: func(f *schema.FieldTextArea) { - if maxLength = f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength - } - }, - RichText: func(f *schema.FieldRichText) { - if maxLength = f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength - } - }, - Markdown: func(f *schema.FieldMarkdown) { - if maxLength = f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength - } - }, - Integer: func(f *schema.FieldInteger) { - if min := f.Min(); min != nil { - fieldSchema["minimum"] = *min - } - if max := f.Max(); max != nil { - fieldSchema["maximum"] = *max - } - }, - Number: func(f *schema.FieldNumber) { - if min := f.Min(); min != nil { - fieldSchema["minimum"] = *min - } - if max := f.Max(); max != nil { - fieldSchema["maximum"] = *max - } - }, - Group: func(f *schema.FieldGroup) { - gs, _ := uc.Schema.FindByGroup(ctx, f.Group(), nil) - if gs != nil { - fieldSchema["items"] = buildProperties(uc, gs.Fields(), ctx) - } - }, + Text: func(f *schema.FieldText) { addMaxLength(fieldSchema, f.MaxLength()) }, + TextArea: func(f *schema.FieldTextArea) { addMaxLength(fieldSchema, f.MaxLength()) }, + RichText: func(f *schema.FieldRichText) { addMaxLength(fieldSchema, f.MaxLength()) }, + Markdown: func(f *schema.FieldMarkdown) { addMaxLength(fieldSchema, f.MaxLength()) }, + Integer: func(f *schema.FieldInteger) { addMinMax(fieldSchema, f.Min(), f.Max()) }, + Number: func(f *schema.FieldNumber) { addMinMax(fieldSchema, f.Min(), f.Max()) }, + Group: func(f *schema.FieldGroup) { addGroupItems(fieldSchema, gsMap[f.Group()]) }, }) - properties[field.Key().String()] = fieldSchema } return &properties } +func addMaxLength(schemaMap map[string]interface{}, maxLength *int) { + if maxLength != nil { + schemaMap["maxLength"] = *maxLength + } +} + +func addMinMax(schemaMap map[string]interface{}, min, max interface{}) { + switch minVal := min.(type) { + case *int64: + if minVal != nil { + schemaMap["minimum"] = *minVal + } + case *float64: + if minVal != nil { + schemaMap["minimum"] = *minVal + } + } + switch maxVal := max.(type) { + case *int64: + if maxVal != nil { + schemaMap["maximum"] = *maxVal + } + case *float64: + if maxVal != nil { + schemaMap["maximum"] = *maxVal + } + } +} + +func addGroupItems(fieldSchema map[string]interface{}, gs *schema.Schema) { + if gs != nil { + fieldSchema["items"] = buildProperties(gs.Fields(), nil) + } +} + func determineTypeAndFormat(t value.Type) (string, string) { switch t { case value.TypeText, value.TypeTextArea, value.TypeRichText, value.TypeMarkdown, value.TypeSelect, value.TypeTag, value.TypeReference: @@ -308,3 +310,18 @@ func determineTypeAndFormat(t value.Type) (string, string) { return "string", "" } } + +func buildGroupSchemaMap(ctx context.Context, sch *schema.Schema, uc *interfaces.Container) map[id.GroupID]*schema.Schema { + groupSchemaMap := make(map[id.GroupID]*schema.Schema) + for _, field := range sch.Fields() { + field.TypeProperty().Match(schema.TypePropertyMatch{ + Group: func(fg *schema.FieldGroup) { + groupSchema, err := uc.Schema.FindByGroup(ctx, fg.Group(), nil) + if err == nil { + groupSchemaMap[fg.Group()] = groupSchema + } + }, + }) + } + return groupSchemaMap +} diff --git a/server/internal/adapter/integration/schema_export_test.go b/server/internal/adapter/integration/schema_export_test.go index d6139bf689..a5599599ee 100644 --- a/server/internal/adapter/integration/schema_export_test.go +++ b/server/internal/adapter/integration/schema_export_test.go @@ -1,12 +1,8 @@ package integration import ( - "context" "testing" - "github.com/reearth/reearth-cms/server/internal/infrastructure/memory" - "github.com/reearth/reearth-cms/server/internal/usecase/interactor" - "github.com/reearth/reearth-cms/server/internal/usecase/interfaces" "github.com/reearth/reearth-cms/server/pkg/group" "github.com/reearth/reearth-cms/server/pkg/id" "github.com/reearth/reearth-cms/server/pkg/schema" @@ -17,10 +13,6 @@ import ( ) func TestBuildProperties(t *testing.T) { - ctx := context.Background() - r := memory.New() - uc := &interfaces.Container{Schema: interactor.NewSchema(r, nil)} - wid := accountdomain.NewWorkspaceID() pid := id.NewProjectID() @@ -43,13 +35,12 @@ func TestBuildProperties(t *testing.T) { // group schema gs := schema.New().ID(id.NewSchemaID()).Workspace(wid).Project(pid).Fields([]*schema.Field{gsf}).MustBuild() - lo.Must0(r.Schema.Save(ctx, gs)) // group gid := id.NewGroupID() gkey := id.RandomKey() g := group.New().ID(gid).Name("group").Project(pid).Key(gkey).Schema(gs.ID()).MustBuild() - lo.Must0(r.Group.Save(ctx, g)) + gsMap := map[id.GroupID]*schema.Schema{g.ID(): gs} // group field fId3 := id.NewFieldID() @@ -72,8 +63,6 @@ func TestBuildProperties(t *testing.T) { sf6 := schema.NewField(schema.NewURL().TypeProperty()).ID(fId6).Key(sfKey6).MustBuild() fieldList := schema.FieldList{sf1, sf2, sf3, sf4, sf5, sf6} - s1 := schema.New().NewID().Workspace(wid).Project(pid).Fields(schema.FieldList{sf2}).MustBuild() - lo.Must0(r.Schema.Save(ctx, s1)) expectedProperties := &map[string]interface{}{ sfKey1.String(): map[string]interface{}{ @@ -121,7 +110,7 @@ func TestBuildProperties(t *testing.T) { }, } - properties := buildProperties(uc, fieldList, ctx) + properties := buildProperties(fieldList, gsMap) assert.Equal(t, expectedProperties, properties) } diff --git a/server/internal/adapter/publicapi/schema_export.go b/server/internal/adapter/publicapi/schema_export.go index 7c3af4c2ed..29ca10213b 100644 --- a/server/internal/adapter/publicapi/schema_export.go +++ b/server/internal/adapter/publicapi/schema_export.go @@ -4,6 +4,7 @@ import ( "context" "github.com/reearth/reearth-cms/server/internal/usecase/interfaces" + "github.com/reearth/reearth-cms/server/pkg/id" "github.com/reearth/reearth-cms/server/pkg/model" "github.com/reearth/reearth-cms/server/pkg/schema" "github.com/reearth/reearth-cms/server/pkg/value" @@ -26,12 +27,13 @@ func (c *Controller) GetSchemaJSON(ctx context.Context, pKey, mKey string) (Sche return SchemaJSON{}, rerror.ErrNotFound } - return NewSchemaJSON(m, buildProperties(c.usecases, sp.Schema().Fields(), ctx)), nil + gsMap := buildGroupSchemaMap(ctx, sp.Schema(), c.usecases) + return NewSchemaJSON(m, buildProperties(sp.Schema().Fields(), gsMap)), nil } -func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.Context) *map[string]interface{} { +func buildProperties(fields schema.FieldList, gsMap map[id.GroupID]*schema.Schema) *map[string]interface{} { properties := make(map[string]interface{}) - for _, field := range f { + for _, field := range fields { fieldType, format := determineTypeAndFormat(field.Type()) fieldSchema := map[string]interface{}{ "type": fieldType, @@ -41,58 +43,55 @@ func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.C if format != "" { fieldSchema["format"] = format } - - var maxLength *int field.TypeProperty().Match(schema.TypePropertyMatch{ - Text: func(f *schema.FieldText) { - if maxLength = f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength - } - }, - TextArea: func(f *schema.FieldTextArea) { - if maxLength = f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength - } - }, - RichText: func(f *schema.FieldRichText) { - if maxLength = f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength - } - }, - Markdown: func(f *schema.FieldMarkdown) { - if maxLength = f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength - } - }, - Integer: func(f *schema.FieldInteger) { - if min := f.Min(); min != nil { - fieldSchema["minimum"] = *min - } - if max := f.Max(); max != nil { - fieldSchema["maximum"] = *max - } - }, - Number: func(f *schema.FieldNumber) { - if min := f.Min(); min != nil { - fieldSchema["minimum"] = *min - } - if max := f.Max(); max != nil { - fieldSchema["maximum"] = *max - } - }, - Group: func(f *schema.FieldGroup) { - gs, _ := uc.Schema.FindByGroup(ctx, f.Group(), nil) - if gs != nil { - fieldSchema["items"] = buildProperties(uc, gs.Fields(), ctx) - } - }, + Text: func(f *schema.FieldText) { addMaxLength(fieldSchema, f.MaxLength()) }, + TextArea: func(f *schema.FieldTextArea) { addMaxLength(fieldSchema, f.MaxLength()) }, + RichText: func(f *schema.FieldRichText) { addMaxLength(fieldSchema, f.MaxLength()) }, + Markdown: func(f *schema.FieldMarkdown) { addMaxLength(fieldSchema, f.MaxLength()) }, + Integer: func(f *schema.FieldInteger) { addMinMax(fieldSchema, f.Min(), f.Max()) }, + Number: func(f *schema.FieldNumber) { addMinMax(fieldSchema, f.Min(), f.Max()) }, + Group: func(f *schema.FieldGroup) { addGroupItems(fieldSchema, gsMap[f.Group()]) }, }) - properties[field.Key().String()] = fieldSchema } return &properties } +func addMaxLength(schemaMap map[string]interface{}, maxLength *int) { + if maxLength != nil { + schemaMap["maxLength"] = *maxLength + } +} + +func addMinMax(schemaMap map[string]interface{}, min, max interface{}) { + switch minVal := min.(type) { + case *int64: + if minVal != nil { + schemaMap["minimum"] = *minVal + } + case *float64: + if minVal != nil { + schemaMap["minimum"] = *minVal + } + } + switch maxVal := max.(type) { + case *int64: + if maxVal != nil { + schemaMap["maximum"] = *maxVal + } + case *float64: + if maxVal != nil { + schemaMap["maximum"] = *maxVal + } + } +} + +func addGroupItems(fieldSchema map[string]interface{}, gs *schema.Schema) { + if gs != nil { + fieldSchema["items"] = buildProperties(gs.Fields(), nil) + } +} + func determineTypeAndFormat(t value.Type) (string, string) { switch t { case value.TypeText, value.TypeTextArea, value.TypeRichText, value.TypeMarkdown, value.TypeSelect, value.TypeTag, value.TypeReference: @@ -117,3 +116,18 @@ func determineTypeAndFormat(t value.Type) (string, string) { return "string", "" } } + +func buildGroupSchemaMap(ctx context.Context, sch *schema.Schema, uc *interfaces.Container) map[id.GroupID]*schema.Schema { + groupSchemaMap := make(map[id.GroupID]*schema.Schema) + for _, field := range sch.Fields() { + field.TypeProperty().Match(schema.TypePropertyMatch{ + Group: func(fg *schema.FieldGroup) { + groupSchema, err := uc.Schema.FindByGroup(ctx, fg.Group(), nil) + if err == nil { + groupSchemaMap[fg.Group()] = groupSchema + } + }, + }) + } + return groupSchemaMap +} diff --git a/server/internal/adapter/publicapi/schema_export_test.go b/server/internal/adapter/publicapi/schema_export_test.go index a34c51fb13..4f407fce13 100644 --- a/server/internal/adapter/publicapi/schema_export_test.go +++ b/server/internal/adapter/publicapi/schema_export_test.go @@ -1,12 +1,8 @@ package publicapi import ( - "context" "testing" - "github.com/reearth/reearth-cms/server/internal/infrastructure/memory" - "github.com/reearth/reearth-cms/server/internal/usecase/interactor" - "github.com/reearth/reearth-cms/server/internal/usecase/interfaces" "github.com/reearth/reearth-cms/server/pkg/group" "github.com/reearth/reearth-cms/server/pkg/id" "github.com/reearth/reearth-cms/server/pkg/schema" @@ -17,10 +13,6 @@ import ( ) func TestBuildProperties(t *testing.T) { - ctx := context.Background() - r := memory.New() - uc := &interfaces.Container{Schema: interactor.NewSchema(r, nil)} - wid := accountdomain.NewWorkspaceID() pid := id.NewProjectID() @@ -43,13 +35,12 @@ func TestBuildProperties(t *testing.T) { // group schema gs := schema.New().ID(id.NewSchemaID()).Workspace(wid).Project(pid).Fields([]*schema.Field{gsf}).MustBuild() - lo.Must0(r.Schema.Save(ctx, gs)) // group gid := id.NewGroupID() gkey := id.RandomKey() g := group.New().ID(gid).Name("group").Project(pid).Key(gkey).Schema(gs.ID()).MustBuild() - lo.Must0(r.Group.Save(ctx, g)) + gsMap := map[id.GroupID]*schema.Schema{g.ID(): gs} // group field fId3 := id.NewFieldID() @@ -72,8 +63,6 @@ func TestBuildProperties(t *testing.T) { sf6 := schema.NewField(schema.NewURL().TypeProperty()).ID(fId6).Key(sfKey6).MustBuild() fieldList := schema.FieldList{sf1, sf2, sf3, sf4, sf5, sf6} - s1 := schema.New().NewID().Workspace(wid).Project(pid).Fields(schema.FieldList{sf2}).MustBuild() - lo.Must0(r.Schema.Save(ctx, s1)) expectedProperties := &map[string]interface{}{ sfKey1.String(): map[string]interface{}{ @@ -121,7 +110,7 @@ func TestBuildProperties(t *testing.T) { }, } - properties := buildProperties(uc, fieldList, ctx) + properties := buildProperties(fieldList, gsMap) assert.Equal(t, expectedProperties, properties) } From 53520c5dea1582b8bd58aaf580a0cdfb20069c4a Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Mon, 25 Nov 2024 18:08:44 +0900 Subject: [PATCH 29/39] Revert "refactor" This reverts commit 1577665a1fe3f561abf5959eb85ef7f6ea5a3767. --- .../adapter/integration/schema_export.go | 125 ++++++++---------- .../adapter/integration/schema_export_test.go | 15 ++- .../adapter/publicapi/schema_export.go | 110 +++++++-------- .../adapter/publicapi/schema_export_test.go | 15 ++- 4 files changed, 128 insertions(+), 137 deletions(-) diff --git a/server/internal/adapter/integration/schema_export.go b/server/internal/adapter/integration/schema_export.go index f2b4ff5085..11c50ae665 100644 --- a/server/internal/adapter/integration/schema_export.go +++ b/server/internal/adapter/integration/schema_export.go @@ -6,7 +6,6 @@ import ( "github.com/reearth/reearth-cms/server/internal/adapter" "github.com/reearth/reearth-cms/server/internal/usecase/interfaces" - "github.com/reearth/reearth-cms/server/pkg/id" "github.com/reearth/reearth-cms/server/pkg/integrationapi" "github.com/reearth/reearth-cms/server/pkg/model" "github.com/reearth/reearth-cms/server/pkg/schema" @@ -54,8 +53,7 @@ func (s *Server) SchemaByModelAsJSON(ctx context.Context, request SchemaByModelA return SchemaByModelAsJSON404Response{}, err } - gsMap := buildGroupSchemaMap(ctx, sp.Schema(), uc) - res := NewSchemaJSONWitModel(m, buildProperties(sp.Schema().Fields(), gsMap)) + res := NewSchemaJSONWitModel(m, buildProperties(uc, sp.Schema().Fields(), ctx)) return SchemaByModelAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -78,12 +76,12 @@ func (s *Server) MetadataSchemaByModelAsJSON(ctx context.Context, request Metada return MetadataSchemaByModelAsJSON400Response{}, err } - sp, err := uc.Schema.FindByModel(ctx, m.ID(), op) + sp, err := uc.Schema.FindByModel(ctx, request.ModelId, op) if err != nil { return MetadataSchemaByModelAsJSON404Response{}, err } - res := NewSchemaJSONWitModel(m, buildProperties(sp.MetaSchema().Fields(), nil)) + res := NewSchemaJSONWitModel(m, buildProperties(uc, sp.MetaSchema().Fields(), ctx)) return MetadataSchemaByModelAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -122,8 +120,7 @@ func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request Sch return SchemaByModelWithProjectAsJSON400Response{}, err } - gsMap := buildGroupSchemaMap(ctx, sch.Schema(), uc) - res := NewSchemaJSONWitModel(m, buildProperties(sch.Schema().Fields(), gsMap)) + res := NewSchemaJSONWitModel(m, buildProperties(uc, sch.Schema().Fields(), ctx)) return SchemaByModelWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -162,7 +159,7 @@ func (s *Server) MetadataSchemaByModelWithProjectAsJSON(ctx context.Context, req return MetadataSchemaByModelWithProjectAsJSON400Response{}, err } - res := NewSchemaJSONWitModel(m, buildProperties(sch.MetaSchema().Fields(), nil)) + res := NewSchemaJSONWitModel(m, buildProperties(uc, sch.MetaSchema().Fields(), ctx)) return MetadataSchemaByModelWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -185,8 +182,7 @@ func (s *Server) SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONR return SchemaByIDAsJSON400Response{}, err } - gsMap := buildGroupSchemaMap(ctx, sch, uc) - res := NewSchemaJSON(sch, buildProperties(sch.Fields(), gsMap)) + res := NewSchemaJSON(sch, buildProperties(uc, sch.Fields(), ctx)) return SchemaByIDAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -215,8 +211,7 @@ func (s *Server) SchemaByIDWithProjectAsJSON(ctx context.Context, request Schema return SchemaByIDWithProjectAsJSON400Response{}, err } - gsMap := buildGroupSchemaMap(ctx, sch, uc) - res := NewSchemaJSON(sch, buildProperties(sch.Fields(), gsMap)) + res := NewSchemaJSON(sch, buildProperties(uc, sch.Fields(), ctx)) return SchemaByIDWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -225,9 +220,9 @@ func (s *Server) SchemaByIDWithProjectAsJSON(ctx context.Context, request Schema }, nil } -func buildProperties(fields schema.FieldList, gsMap map[id.GroupID]*schema.Schema) *map[string]interface{} { +func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.Context) *map[string]interface{} { properties := make(map[string]interface{}) - for _, field := range fields { + for _, field := range f { fieldType, format := determineTypeAndFormat(field.Type()) fieldSchema := map[string]interface{}{ "type": fieldType, @@ -237,55 +232,58 @@ func buildProperties(fields schema.FieldList, gsMap map[id.GroupID]*schema.Schem if format != "" { fieldSchema["format"] = format } + + var maxLength *int field.TypeProperty().Match(schema.TypePropertyMatch{ - Text: func(f *schema.FieldText) { addMaxLength(fieldSchema, f.MaxLength()) }, - TextArea: func(f *schema.FieldTextArea) { addMaxLength(fieldSchema, f.MaxLength()) }, - RichText: func(f *schema.FieldRichText) { addMaxLength(fieldSchema, f.MaxLength()) }, - Markdown: func(f *schema.FieldMarkdown) { addMaxLength(fieldSchema, f.MaxLength()) }, - Integer: func(f *schema.FieldInteger) { addMinMax(fieldSchema, f.Min(), f.Max()) }, - Number: func(f *schema.FieldNumber) { addMinMax(fieldSchema, f.Min(), f.Max()) }, - Group: func(f *schema.FieldGroup) { addGroupItems(fieldSchema, gsMap[f.Group()]) }, + Text: func(f *schema.FieldText) { + if maxLength = f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + TextArea: func(f *schema.FieldTextArea) { + if maxLength = f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + RichText: func(f *schema.FieldRichText) { + if maxLength = f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + Markdown: func(f *schema.FieldMarkdown) { + if maxLength = f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + Integer: func(f *schema.FieldInteger) { + if min := f.Min(); min != nil { + fieldSchema["minimum"] = *min + } + if max := f.Max(); max != nil { + fieldSchema["maximum"] = *max + } + }, + Number: func(f *schema.FieldNumber) { + if min := f.Min(); min != nil { + fieldSchema["minimum"] = *min + } + if max := f.Max(); max != nil { + fieldSchema["maximum"] = *max + } + }, + Group: func(f *schema.FieldGroup) { + gs, _ := uc.Schema.FindByGroup(ctx, f.Group(), nil) + if gs != nil { + fieldSchema["items"] = buildProperties(uc, gs.Fields(), ctx) + } + }, }) + properties[field.Key().String()] = fieldSchema } return &properties } -func addMaxLength(schemaMap map[string]interface{}, maxLength *int) { - if maxLength != nil { - schemaMap["maxLength"] = *maxLength - } -} - -func addMinMax(schemaMap map[string]interface{}, min, max interface{}) { - switch minVal := min.(type) { - case *int64: - if minVal != nil { - schemaMap["minimum"] = *minVal - } - case *float64: - if minVal != nil { - schemaMap["minimum"] = *minVal - } - } - switch maxVal := max.(type) { - case *int64: - if maxVal != nil { - schemaMap["maximum"] = *maxVal - } - case *float64: - if maxVal != nil { - schemaMap["maximum"] = *maxVal - } - } -} - -func addGroupItems(fieldSchema map[string]interface{}, gs *schema.Schema) { - if gs != nil { - fieldSchema["items"] = buildProperties(gs.Fields(), nil) - } -} - func determineTypeAndFormat(t value.Type) (string, string) { switch t { case value.TypeText, value.TypeTextArea, value.TypeRichText, value.TypeMarkdown, value.TypeSelect, value.TypeTag, value.TypeReference: @@ -310,18 +308,3 @@ func determineTypeAndFormat(t value.Type) (string, string) { return "string", "" } } - -func buildGroupSchemaMap(ctx context.Context, sch *schema.Schema, uc *interfaces.Container) map[id.GroupID]*schema.Schema { - groupSchemaMap := make(map[id.GroupID]*schema.Schema) - for _, field := range sch.Fields() { - field.TypeProperty().Match(schema.TypePropertyMatch{ - Group: func(fg *schema.FieldGroup) { - groupSchema, err := uc.Schema.FindByGroup(ctx, fg.Group(), nil) - if err == nil { - groupSchemaMap[fg.Group()] = groupSchema - } - }, - }) - } - return groupSchemaMap -} diff --git a/server/internal/adapter/integration/schema_export_test.go b/server/internal/adapter/integration/schema_export_test.go index a5599599ee..d6139bf689 100644 --- a/server/internal/adapter/integration/schema_export_test.go +++ b/server/internal/adapter/integration/schema_export_test.go @@ -1,8 +1,12 @@ package integration import ( + "context" "testing" + "github.com/reearth/reearth-cms/server/internal/infrastructure/memory" + "github.com/reearth/reearth-cms/server/internal/usecase/interactor" + "github.com/reearth/reearth-cms/server/internal/usecase/interfaces" "github.com/reearth/reearth-cms/server/pkg/group" "github.com/reearth/reearth-cms/server/pkg/id" "github.com/reearth/reearth-cms/server/pkg/schema" @@ -13,6 +17,10 @@ import ( ) func TestBuildProperties(t *testing.T) { + ctx := context.Background() + r := memory.New() + uc := &interfaces.Container{Schema: interactor.NewSchema(r, nil)} + wid := accountdomain.NewWorkspaceID() pid := id.NewProjectID() @@ -35,12 +43,13 @@ func TestBuildProperties(t *testing.T) { // group schema gs := schema.New().ID(id.NewSchemaID()).Workspace(wid).Project(pid).Fields([]*schema.Field{gsf}).MustBuild() + lo.Must0(r.Schema.Save(ctx, gs)) // group gid := id.NewGroupID() gkey := id.RandomKey() g := group.New().ID(gid).Name("group").Project(pid).Key(gkey).Schema(gs.ID()).MustBuild() - gsMap := map[id.GroupID]*schema.Schema{g.ID(): gs} + lo.Must0(r.Group.Save(ctx, g)) // group field fId3 := id.NewFieldID() @@ -63,6 +72,8 @@ func TestBuildProperties(t *testing.T) { sf6 := schema.NewField(schema.NewURL().TypeProperty()).ID(fId6).Key(sfKey6).MustBuild() fieldList := schema.FieldList{sf1, sf2, sf3, sf4, sf5, sf6} + s1 := schema.New().NewID().Workspace(wid).Project(pid).Fields(schema.FieldList{sf2}).MustBuild() + lo.Must0(r.Schema.Save(ctx, s1)) expectedProperties := &map[string]interface{}{ sfKey1.String(): map[string]interface{}{ @@ -110,7 +121,7 @@ func TestBuildProperties(t *testing.T) { }, } - properties := buildProperties(fieldList, gsMap) + properties := buildProperties(uc, fieldList, ctx) assert.Equal(t, expectedProperties, properties) } diff --git a/server/internal/adapter/publicapi/schema_export.go b/server/internal/adapter/publicapi/schema_export.go index 29ca10213b..7c3af4c2ed 100644 --- a/server/internal/adapter/publicapi/schema_export.go +++ b/server/internal/adapter/publicapi/schema_export.go @@ -4,7 +4,6 @@ import ( "context" "github.com/reearth/reearth-cms/server/internal/usecase/interfaces" - "github.com/reearth/reearth-cms/server/pkg/id" "github.com/reearth/reearth-cms/server/pkg/model" "github.com/reearth/reearth-cms/server/pkg/schema" "github.com/reearth/reearth-cms/server/pkg/value" @@ -27,13 +26,12 @@ func (c *Controller) GetSchemaJSON(ctx context.Context, pKey, mKey string) (Sche return SchemaJSON{}, rerror.ErrNotFound } - gsMap := buildGroupSchemaMap(ctx, sp.Schema(), c.usecases) - return NewSchemaJSON(m, buildProperties(sp.Schema().Fields(), gsMap)), nil + return NewSchemaJSON(m, buildProperties(c.usecases, sp.Schema().Fields(), ctx)), nil } -func buildProperties(fields schema.FieldList, gsMap map[id.GroupID]*schema.Schema) *map[string]interface{} { +func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.Context) *map[string]interface{} { properties := make(map[string]interface{}) - for _, field := range fields { + for _, field := range f { fieldType, format := determineTypeAndFormat(field.Type()) fieldSchema := map[string]interface{}{ "type": fieldType, @@ -43,55 +41,58 @@ func buildProperties(fields schema.FieldList, gsMap map[id.GroupID]*schema.Schem if format != "" { fieldSchema["format"] = format } + + var maxLength *int field.TypeProperty().Match(schema.TypePropertyMatch{ - Text: func(f *schema.FieldText) { addMaxLength(fieldSchema, f.MaxLength()) }, - TextArea: func(f *schema.FieldTextArea) { addMaxLength(fieldSchema, f.MaxLength()) }, - RichText: func(f *schema.FieldRichText) { addMaxLength(fieldSchema, f.MaxLength()) }, - Markdown: func(f *schema.FieldMarkdown) { addMaxLength(fieldSchema, f.MaxLength()) }, - Integer: func(f *schema.FieldInteger) { addMinMax(fieldSchema, f.Min(), f.Max()) }, - Number: func(f *schema.FieldNumber) { addMinMax(fieldSchema, f.Min(), f.Max()) }, - Group: func(f *schema.FieldGroup) { addGroupItems(fieldSchema, gsMap[f.Group()]) }, + Text: func(f *schema.FieldText) { + if maxLength = f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + TextArea: func(f *schema.FieldTextArea) { + if maxLength = f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + RichText: func(f *schema.FieldRichText) { + if maxLength = f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + Markdown: func(f *schema.FieldMarkdown) { + if maxLength = f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + Integer: func(f *schema.FieldInteger) { + if min := f.Min(); min != nil { + fieldSchema["minimum"] = *min + } + if max := f.Max(); max != nil { + fieldSchema["maximum"] = *max + } + }, + Number: func(f *schema.FieldNumber) { + if min := f.Min(); min != nil { + fieldSchema["minimum"] = *min + } + if max := f.Max(); max != nil { + fieldSchema["maximum"] = *max + } + }, + Group: func(f *schema.FieldGroup) { + gs, _ := uc.Schema.FindByGroup(ctx, f.Group(), nil) + if gs != nil { + fieldSchema["items"] = buildProperties(uc, gs.Fields(), ctx) + } + }, }) + properties[field.Key().String()] = fieldSchema } return &properties } -func addMaxLength(schemaMap map[string]interface{}, maxLength *int) { - if maxLength != nil { - schemaMap["maxLength"] = *maxLength - } -} - -func addMinMax(schemaMap map[string]interface{}, min, max interface{}) { - switch minVal := min.(type) { - case *int64: - if minVal != nil { - schemaMap["minimum"] = *minVal - } - case *float64: - if minVal != nil { - schemaMap["minimum"] = *minVal - } - } - switch maxVal := max.(type) { - case *int64: - if maxVal != nil { - schemaMap["maximum"] = *maxVal - } - case *float64: - if maxVal != nil { - schemaMap["maximum"] = *maxVal - } - } -} - -func addGroupItems(fieldSchema map[string]interface{}, gs *schema.Schema) { - if gs != nil { - fieldSchema["items"] = buildProperties(gs.Fields(), nil) - } -} - func determineTypeAndFormat(t value.Type) (string, string) { switch t { case value.TypeText, value.TypeTextArea, value.TypeRichText, value.TypeMarkdown, value.TypeSelect, value.TypeTag, value.TypeReference: @@ -116,18 +117,3 @@ func determineTypeAndFormat(t value.Type) (string, string) { return "string", "" } } - -func buildGroupSchemaMap(ctx context.Context, sch *schema.Schema, uc *interfaces.Container) map[id.GroupID]*schema.Schema { - groupSchemaMap := make(map[id.GroupID]*schema.Schema) - for _, field := range sch.Fields() { - field.TypeProperty().Match(schema.TypePropertyMatch{ - Group: func(fg *schema.FieldGroup) { - groupSchema, err := uc.Schema.FindByGroup(ctx, fg.Group(), nil) - if err == nil { - groupSchemaMap[fg.Group()] = groupSchema - } - }, - }) - } - return groupSchemaMap -} diff --git a/server/internal/adapter/publicapi/schema_export_test.go b/server/internal/adapter/publicapi/schema_export_test.go index 4f407fce13..a34c51fb13 100644 --- a/server/internal/adapter/publicapi/schema_export_test.go +++ b/server/internal/adapter/publicapi/schema_export_test.go @@ -1,8 +1,12 @@ package publicapi import ( + "context" "testing" + "github.com/reearth/reearth-cms/server/internal/infrastructure/memory" + "github.com/reearth/reearth-cms/server/internal/usecase/interactor" + "github.com/reearth/reearth-cms/server/internal/usecase/interfaces" "github.com/reearth/reearth-cms/server/pkg/group" "github.com/reearth/reearth-cms/server/pkg/id" "github.com/reearth/reearth-cms/server/pkg/schema" @@ -13,6 +17,10 @@ import ( ) func TestBuildProperties(t *testing.T) { + ctx := context.Background() + r := memory.New() + uc := &interfaces.Container{Schema: interactor.NewSchema(r, nil)} + wid := accountdomain.NewWorkspaceID() pid := id.NewProjectID() @@ -35,12 +43,13 @@ func TestBuildProperties(t *testing.T) { // group schema gs := schema.New().ID(id.NewSchemaID()).Workspace(wid).Project(pid).Fields([]*schema.Field{gsf}).MustBuild() + lo.Must0(r.Schema.Save(ctx, gs)) // group gid := id.NewGroupID() gkey := id.RandomKey() g := group.New().ID(gid).Name("group").Project(pid).Key(gkey).Schema(gs.ID()).MustBuild() - gsMap := map[id.GroupID]*schema.Schema{g.ID(): gs} + lo.Must0(r.Group.Save(ctx, g)) // group field fId3 := id.NewFieldID() @@ -63,6 +72,8 @@ func TestBuildProperties(t *testing.T) { sf6 := schema.NewField(schema.NewURL().TypeProperty()).ID(fId6).Key(sfKey6).MustBuild() fieldList := schema.FieldList{sf1, sf2, sf3, sf4, sf5, sf6} + s1 := schema.New().NewID().Workspace(wid).Project(pid).Fields(schema.FieldList{sf2}).MustBuild() + lo.Must0(r.Schema.Save(ctx, s1)) expectedProperties := &map[string]interface{}{ sfKey1.String(): map[string]interface{}{ @@ -110,7 +121,7 @@ func TestBuildProperties(t *testing.T) { }, } - properties := buildProperties(fieldList, gsMap) + properties := buildProperties(uc, fieldList, ctx) assert.Equal(t, expectedProperties, properties) } From 4fee3ebc6102846d96ae88e40b461b4d92b4f8a7 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Tue, 26 Nov 2024 13:11:43 +0900 Subject: [PATCH 30/39] requested changes --- .../adapter/integration/schema_export.go | 38 ++--- .../adapter/integration/server.gen.go | 138 +++++++++--------- .../adapter/publicapi/schema_export.go | 16 +- .../adapter/publicapi/schema_export_test.go | 4 +- server/internal/adapter/publicapi/types.go | 25 ++-- server/pkg/integrationapi/types.gen.go | 12 +- server/schemas/integration.yml | 1 + 7 files changed, 112 insertions(+), 122 deletions(-) diff --git a/server/internal/adapter/integration/schema_export.go b/server/internal/adapter/integration/schema_export.go index 11c50ae665..25159d3fab 100644 --- a/server/internal/adapter/integration/schema_export.go +++ b/server/internal/adapter/integration/schema_export.go @@ -7,7 +7,6 @@ import ( "github.com/reearth/reearth-cms/server/internal/adapter" "github.com/reearth/reearth-cms/server/internal/usecase/interfaces" "github.com/reearth/reearth-cms/server/pkg/integrationapi" - "github.com/reearth/reearth-cms/server/pkg/model" "github.com/reearth/reearth-cms/server/pkg/schema" "github.com/reearth/reearth-cms/server/pkg/value" "github.com/reearth/reearthx/rerror" @@ -16,22 +15,13 @@ import ( const defaultJSONSchemaVersion = "https://json-schema.org/draft/2020-12/schema" -func NewSchemaJSON(s *schema.Schema, pp *map[string]interface{}) integrationapi.SchemaJSON { +func NewSchemaJSON(id string, title, description *string, pp map[string]interface{}) integrationapi.SchemaJSON { return integrationapi.SchemaJSON{ - Schema: lo.ToPtr(defaultJSONSchemaVersion), - Id: s.ID().Ref().StringRef(), - Type: lo.ToPtr("object"), - Properties: pp, - } -} - -func NewSchemaJSONWitModel(m *model.Model, pp *map[string]interface{}) integrationapi.SchemaJSON { - return integrationapi.SchemaJSON{ - Schema: lo.ToPtr(defaultJSONSchemaVersion), - Id: m.ID().Ref().StringRef(), - Title: lo.ToPtr(m.Name()), - Description: lo.ToPtr(m.Description()), - Type: lo.ToPtr("object"), + Schema: defaultJSONSchemaVersion, + Id: id, + Title: title, + Description: description, + Type: "object", Properties: pp, } } @@ -53,7 +43,7 @@ func (s *Server) SchemaByModelAsJSON(ctx context.Context, request SchemaByModelA return SchemaByModelAsJSON404Response{}, err } - res := NewSchemaJSONWitModel(m, buildProperties(uc, sp.Schema().Fields(), ctx)) + res := NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), buildProperties(uc, sp.Schema().Fields(), ctx)) return SchemaByModelAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -81,7 +71,7 @@ func (s *Server) MetadataSchemaByModelAsJSON(ctx context.Context, request Metada return MetadataSchemaByModelAsJSON404Response{}, err } - res := NewSchemaJSONWitModel(m, buildProperties(uc, sp.MetaSchema().Fields(), ctx)) + res := NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), buildProperties(uc, sp.MetaSchema().Fields(), ctx)) return MetadataSchemaByModelAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -120,7 +110,7 @@ func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request Sch return SchemaByModelWithProjectAsJSON400Response{}, err } - res := NewSchemaJSONWitModel(m, buildProperties(uc, sch.Schema().Fields(), ctx)) + res := NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), buildProperties(uc, sch.Schema().Fields(), ctx)) return SchemaByModelWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -159,7 +149,7 @@ func (s *Server) MetadataSchemaByModelWithProjectAsJSON(ctx context.Context, req return MetadataSchemaByModelWithProjectAsJSON400Response{}, err } - res := NewSchemaJSONWitModel(m, buildProperties(uc, sch.MetaSchema().Fields(), ctx)) + res := NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), buildProperties(uc, sch.MetaSchema().Fields(), ctx)) return MetadataSchemaByModelWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -182,7 +172,7 @@ func (s *Server) SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONR return SchemaByIDAsJSON400Response{}, err } - res := NewSchemaJSON(sch, buildProperties(uc, sch.Fields(), ctx)) + res := NewSchemaJSON(sch.ID().String(), nil, nil, buildProperties(uc, sch.Fields(), ctx)) return SchemaByIDAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -211,7 +201,7 @@ func (s *Server) SchemaByIDWithProjectAsJSON(ctx context.Context, request Schema return SchemaByIDWithProjectAsJSON400Response{}, err } - res := NewSchemaJSON(sch, buildProperties(uc, sch.Fields(), ctx)) + res := NewSchemaJSON(sch.ID().String(), nil, nil, buildProperties(uc, sch.Fields(), ctx)) return SchemaByIDWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -220,7 +210,7 @@ func (s *Server) SchemaByIDWithProjectAsJSON(ctx context.Context, request Schema }, nil } -func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.Context) *map[string]interface{} { +func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.Context) map[string]interface{} { properties := make(map[string]interface{}) for _, field := range f { fieldType, format := determineTypeAndFormat(field.Type()) @@ -281,7 +271,7 @@ func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.C properties[field.Key().String()] = fieldSchema } - return &properties + return properties } func determineTypeAndFormat(t value.Type) (string, string) { diff --git a/server/internal/adapter/integration/server.gen.go b/server/internal/adapter/integration/server.gen.go index 556932b725..d2bfd512d0 100644 --- a/server/internal/adapter/integration/server.gen.go +++ b/server/internal/adapter/integration/server.gen.go @@ -5183,78 +5183,78 @@ func (sh *strictHandler) ProjectFilter(ctx echo.Context, workspaceId WorkspaceId // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "zbXlWH91KWnGixzhslwu/xcAAP//gROObT6wAAA=", + "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/server/internal/adapter/publicapi/schema_export.go b/server/internal/adapter/publicapi/schema_export.go index 7c3af4c2ed..f362dfda90 100644 --- a/server/internal/adapter/publicapi/schema_export.go +++ b/server/internal/adapter/publicapi/schema_export.go @@ -8,6 +8,7 @@ import ( "github.com/reearth/reearth-cms/server/pkg/schema" "github.com/reearth/reearth-cms/server/pkg/value" "github.com/reearth/reearthx/rerror" + "github.com/samber/lo" ) func (c *Controller) GetSchemaJSON(ctx context.Context, pKey, mKey string) (SchemaJSON, error) { @@ -26,10 +27,10 @@ func (c *Controller) GetSchemaJSON(ctx context.Context, pKey, mKey string) (Sche return SchemaJSON{}, rerror.ErrNotFound } - return NewSchemaJSON(m, buildProperties(c.usecases, sp.Schema().Fields(), ctx)), nil + return NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), buildProperties(c.usecases, sp.Schema().Fields(), ctx)), nil } -func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.Context) *map[string]interface{} { +func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.Context) map[string]interface{} { properties := make(map[string]interface{}) for _, field := range f { fieldType, format := determineTypeAndFormat(field.Type()) @@ -42,25 +43,24 @@ func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.C fieldSchema["format"] = format } - var maxLength *int field.TypeProperty().Match(schema.TypePropertyMatch{ Text: func(f *schema.FieldText) { - if maxLength = f.MaxLength(); maxLength != nil { + if maxLength := f.MaxLength(); maxLength != nil { fieldSchema["maxLength"] = *maxLength } }, TextArea: func(f *schema.FieldTextArea) { - if maxLength = f.MaxLength(); maxLength != nil { + if maxLength := f.MaxLength(); maxLength != nil { fieldSchema["maxLength"] = *maxLength } }, RichText: func(f *schema.FieldRichText) { - if maxLength = f.MaxLength(); maxLength != nil { + if maxLength := f.MaxLength(); maxLength != nil { fieldSchema["maxLength"] = *maxLength } }, Markdown: func(f *schema.FieldMarkdown) { - if maxLength = f.MaxLength(); maxLength != nil { + if maxLength := f.MaxLength(); maxLength != nil { fieldSchema["maxLength"] = *maxLength } }, @@ -90,7 +90,7 @@ func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.C properties[field.Key().String()] = fieldSchema } - return &properties + return properties } func determineTypeAndFormat(t value.Type) (string, string) { diff --git a/server/internal/adapter/publicapi/schema_export_test.go b/server/internal/adapter/publicapi/schema_export_test.go index a34c51fb13..0af24fdcb4 100644 --- a/server/internal/adapter/publicapi/schema_export_test.go +++ b/server/internal/adapter/publicapi/schema_export_test.go @@ -75,7 +75,7 @@ func TestBuildProperties(t *testing.T) { s1 := schema.New().NewID().Workspace(wid).Project(pid).Fields(schema.FieldList{sf2}).MustBuild() lo.Must0(r.Schema.Save(ctx, s1)) - expectedProperties := &map[string]interface{}{ + expectedProperties := map[string]interface{}{ sfKey1.String(): map[string]interface{}{ "type": "string", "title": "", @@ -93,7 +93,7 @@ func TestBuildProperties(t *testing.T) { "title": "", "type": "array", "description": "", - "items": &map[string]interface{}{ + "items": map[string]interface{}{ "asset-key": map[string]interface{}{ "description": "", "format": "binary", diff --git a/server/internal/adapter/publicapi/types.go b/server/internal/adapter/publicapi/types.go index 929419770f..4b156e4dc7 100644 --- a/server/internal/adapter/publicapi/types.go +++ b/server/internal/adapter/publicapi/types.go @@ -8,7 +8,6 @@ import ( "github.com/reearth/reearth-cms/server/pkg/asset" "github.com/reearth/reearth-cms/server/pkg/item" - "github.com/reearth/reearth-cms/server/pkg/model" "github.com/reearth/reearth-cms/server/pkg/schema" "github.com/reearth/reearth-cms/server/pkg/value" "github.com/reearth/reearthx/usecasex" @@ -216,21 +215,21 @@ func NewItemAsset(a *asset.Asset, urlResolver asset.URLResolver) ItemAsset { const defaultJSONSchemaVersion = "https://json-schema.org/draft/2020-12/schema" type SchemaJSON struct { - Schema *string `json:"schema,omitempty"` - Id *string `json:"id,omitempty"` - Title *string `json:"title,omitempty"` - Description *string `json:"description,omitempty"` - Type *string `json:"type,omitempty"` - Properties *map[string]interface{} `json:"properties,omitempty"` + Schema string `json:"schema"` + Id string `json:"id"` + Title *string `json:"title,omitempty"` + Description *string `json:"description,omitempty"` + Type string `json:"type"` + Properties map[string]interface{} `json:"properties"` } -func NewSchemaJSON(m *model.Model, pp *map[string]interface{}) SchemaJSON { +func NewSchemaJSON(id string, title, description *string, pp map[string]interface{}) SchemaJSON { return SchemaJSON{ - Schema: lo.ToPtr(defaultJSONSchemaVersion), - Id: m.ID().Ref().StringRef(), - Title: lo.ToPtr(m.Name()), - Description: lo.ToPtr(m.Description()), - Type: lo.ToPtr("object"), + Schema: defaultJSONSchemaVersion, + Id: id, + Title: title, + Description: description, + Type: "object", Properties: pp, } } diff --git a/server/pkg/integrationapi/types.gen.go b/server/pkg/integrationapi/types.gen.go index 884ce58cb1..927ba39051 100644 --- a/server/pkg/integrationapi/types.gen.go +++ b/server/pkg/integrationapi/types.gen.go @@ -553,12 +553,12 @@ type SchemaField struct { // SchemaJSON defines model for schemaJSON. type SchemaJSON struct { - Id *string `json:"$id,omitempty"` - Schema *string `json:"$schema,omitempty"` - Description *string `json:"description,omitempty"` - Properties *map[string]interface{} `json:"properties,omitempty"` - Title *string `json:"title,omitempty"` - Type *string `json:"type,omitempty"` + Id string `json:"$id"` + Schema string `json:"$schema"` + Description *string `json:"description,omitempty"` + Properties map[string]interface{} `json:"properties"` + Title *string `json:"title,omitempty"` + Type string `json:"type"` } // TagResponse defines model for tagResponse. diff --git a/server/schemas/integration.yml b/server/schemas/integration.yml index 28fa760735..58384157b9 100644 --- a/server/schemas/integration.yml +++ b/server/schemas/integration.yml @@ -1831,6 +1831,7 @@ components: format: date-time schemaJSON: type: object + required: ["$schema", "$id", "type", "properties"] properties: $schema: type: string From 24bb268480a6ceec446b6548b30db117812ec196 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Tue, 26 Nov 2024 13:17:44 +0900 Subject: [PATCH 31/39] fix ci --- server/internal/adapter/integration/schema_export_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/internal/adapter/integration/schema_export_test.go b/server/internal/adapter/integration/schema_export_test.go index d6139bf689..699fbd9528 100644 --- a/server/internal/adapter/integration/schema_export_test.go +++ b/server/internal/adapter/integration/schema_export_test.go @@ -75,7 +75,7 @@ func TestBuildProperties(t *testing.T) { s1 := schema.New().NewID().Workspace(wid).Project(pid).Fields(schema.FieldList{sf2}).MustBuild() lo.Must0(r.Schema.Save(ctx, s1)) - expectedProperties := &map[string]interface{}{ + expectedProperties := map[string]interface{}{ sfKey1.String(): map[string]interface{}{ "type": "string", "title": "", @@ -93,7 +93,7 @@ func TestBuildProperties(t *testing.T) { "title": "", "type": "array", "description": "", - "items": &map[string]interface{}{ + "items": map[string]interface{}{ "asset-key": map[string]interface{}{ "description": "", "format": "binary", From 57550de9cc9a08ab8a03bd46b3718815b9d74e10 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Tue, 26 Nov 2024 14:53:44 +0900 Subject: [PATCH 32/39] unify the logic for integration and publicapi --- .../adapter/integration/schema_export.go | 123 +++----------- .../adapter/integration/schema_export_test.go | 160 ------------------ .../adapter/publicapi/schema_export.go | 107 +++--------- server/pkg/exporters/schema_json.go | 121 +++++++++++++ .../exporters/schema_json_test.go} | 16 +- 5 files changed, 171 insertions(+), 356 deletions(-) delete mode 100644 server/internal/adapter/integration/schema_export_test.go create mode 100644 server/pkg/exporters/schema_json.go rename server/{internal/adapter/publicapi/schema_export_test.go => pkg/exporters/schema_json_test.go} (88%) diff --git a/server/internal/adapter/integration/schema_export.go b/server/internal/adapter/integration/schema_export.go index 25159d3fab..ea81cf81ec 100644 --- a/server/internal/adapter/integration/schema_export.go +++ b/server/internal/adapter/integration/schema_export.go @@ -6,26 +6,13 @@ import ( "github.com/reearth/reearth-cms/server/internal/adapter" "github.com/reearth/reearth-cms/server/internal/usecase/interfaces" - "github.com/reearth/reearth-cms/server/pkg/integrationapi" + "github.com/reearth/reearth-cms/server/pkg/exporters" + "github.com/reearth/reearth-cms/server/pkg/id" "github.com/reearth/reearth-cms/server/pkg/schema" - "github.com/reearth/reearth-cms/server/pkg/value" "github.com/reearth/reearthx/rerror" "github.com/samber/lo" ) -const defaultJSONSchemaVersion = "https://json-schema.org/draft/2020-12/schema" - -func NewSchemaJSON(id string, title, description *string, pp map[string]interface{}) integrationapi.SchemaJSON { - return integrationapi.SchemaJSON{ - Schema: defaultJSONSchemaVersion, - Id: id, - Title: title, - Description: description, - Type: "object", - Properties: pp, - } -} - func (s *Server) SchemaByModelAsJSON(ctx context.Context, request SchemaByModelAsJSONRequestObject) (SchemaByModelAsJSONResponseObject, error) { op := adapter.Operator(ctx) uc := adapter.Usecases(ctx) @@ -43,7 +30,8 @@ func (s *Server) SchemaByModelAsJSON(ctx context.Context, request SchemaByModelA return SchemaByModelAsJSON404Response{}, err } - res := NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), buildProperties(uc, sp.Schema().Fields(), ctx)) + gsMap := buildGroupSchemaMap(ctx, sp.Schema(), uc) + res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(ctx, sp.Schema().Fields(), gsMap)) return SchemaByModelAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -71,7 +59,7 @@ func (s *Server) MetadataSchemaByModelAsJSON(ctx context.Context, request Metada return MetadataSchemaByModelAsJSON404Response{}, err } - res := NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), buildProperties(uc, sp.MetaSchema().Fields(), ctx)) + res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(ctx, sp.MetaSchema().Fields(), nil)) return MetadataSchemaByModelAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -110,7 +98,8 @@ func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request Sch return SchemaByModelWithProjectAsJSON400Response{}, err } - res := NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), buildProperties(uc, sch.Schema().Fields(), ctx)) + gsMap := buildGroupSchemaMap(ctx, sch.Schema(), uc) + res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(ctx, sch.Schema().Fields(), gsMap)) return SchemaByModelWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -149,7 +138,7 @@ func (s *Server) MetadataSchemaByModelWithProjectAsJSON(ctx context.Context, req return MetadataSchemaByModelWithProjectAsJSON400Response{}, err } - res := NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), buildProperties(uc, sch.MetaSchema().Fields(), ctx)) + res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(ctx, sch.MetaSchema().Fields(), nil)) return MetadataSchemaByModelWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -172,7 +161,8 @@ func (s *Server) SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONR return SchemaByIDAsJSON400Response{}, err } - res := NewSchemaJSON(sch.ID().String(), nil, nil, buildProperties(uc, sch.Fields(), ctx)) + gsMap := buildGroupSchemaMap(ctx, sch, uc) + res := exporters.NewSchemaJSON(sch.ID().String(), nil, nil, exporters.BuildProperties(ctx, sch.Fields(), gsMap)) return SchemaByIDAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -201,7 +191,8 @@ func (s *Server) SchemaByIDWithProjectAsJSON(ctx context.Context, request Schema return SchemaByIDWithProjectAsJSON400Response{}, err } - res := NewSchemaJSON(sch.ID().String(), nil, nil, buildProperties(uc, sch.Fields(), ctx)) + gsMap := buildGroupSchemaMap(ctx, sch, uc) + res := exporters.NewSchemaJSON(sch.ID().String(), nil, nil, exporters.BuildProperties(ctx, sch.Fields(), gsMap)) return SchemaByIDWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -210,91 +201,17 @@ func (s *Server) SchemaByIDWithProjectAsJSON(ctx context.Context, request Schema }, nil } -func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.Context) map[string]interface{} { - properties := make(map[string]interface{}) - for _, field := range f { - fieldType, format := determineTypeAndFormat(field.Type()) - fieldSchema := map[string]interface{}{ - "type": fieldType, - "title": field.Name(), - "description": field.Description(), - } - if format != "" { - fieldSchema["format"] = format - } - - var maxLength *int +func buildGroupSchemaMap(ctx context.Context, sch *schema.Schema, uc *interfaces.Container) map[id.GroupID]*schema.Schema { + groupSchemaMap := make(map[id.GroupID]*schema.Schema) + for _, field := range sch.Fields() { field.TypeProperty().Match(schema.TypePropertyMatch{ - Text: func(f *schema.FieldText) { - if maxLength = f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength - } - }, - TextArea: func(f *schema.FieldTextArea) { - if maxLength = f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength - } - }, - RichText: func(f *schema.FieldRichText) { - if maxLength = f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength - } - }, - Markdown: func(f *schema.FieldMarkdown) { - if maxLength = f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength - } - }, - Integer: func(f *schema.FieldInteger) { - if min := f.Min(); min != nil { - fieldSchema["minimum"] = *min - } - if max := f.Max(); max != nil { - fieldSchema["maximum"] = *max - } - }, - Number: func(f *schema.FieldNumber) { - if min := f.Min(); min != nil { - fieldSchema["minimum"] = *min - } - if max := f.Max(); max != nil { - fieldSchema["maximum"] = *max - } - }, - Group: func(f *schema.FieldGroup) { - gs, _ := uc.Schema.FindByGroup(ctx, f.Group(), nil) - if gs != nil { - fieldSchema["items"] = buildProperties(uc, gs.Fields(), ctx) + Group: func(fg *schema.FieldGroup) { + groupSchema, err := uc.Schema.FindByGroup(ctx, fg.Group(), nil) + if err == nil { + groupSchemaMap[fg.Group()] = groupSchema } }, }) - - properties[field.Key().String()] = fieldSchema - } - return properties -} - -func determineTypeAndFormat(t value.Type) (string, string) { - switch t { - case value.TypeText, value.TypeTextArea, value.TypeRichText, value.TypeMarkdown, value.TypeSelect, value.TypeTag, value.TypeReference: - return "string", "" - case value.TypeInteger: - return "integer", "" - case value.TypeNumber: - return "number", "" - case value.TypeBool, value.TypeCheckbox: - return "boolean", "" - case value.TypeDateTime: - return "string", "date-time" - case value.TypeURL: - return "string", "uri" - case value.TypeAsset: - return "string", "binary" - case value.TypeGroup: - return "array", "" - case value.TypeGeometryObject, value.TypeGeometryEditor: - return "object", "" - default: - return "string", "" } + return groupSchemaMap } diff --git a/server/internal/adapter/integration/schema_export_test.go b/server/internal/adapter/integration/schema_export_test.go deleted file mode 100644 index 699fbd9528..0000000000 --- a/server/internal/adapter/integration/schema_export_test.go +++ /dev/null @@ -1,160 +0,0 @@ -package integration - -import ( - "context" - "testing" - - "github.com/reearth/reearth-cms/server/internal/infrastructure/memory" - "github.com/reearth/reearth-cms/server/internal/usecase/interactor" - "github.com/reearth/reearth-cms/server/internal/usecase/interfaces" - "github.com/reearth/reearth-cms/server/pkg/group" - "github.com/reearth/reearth-cms/server/pkg/id" - "github.com/reearth/reearth-cms/server/pkg/schema" - "github.com/reearth/reearth-cms/server/pkg/value" - "github.com/reearth/reearthx/account/accountdomain" - "github.com/samber/lo" - "github.com/stretchr/testify/assert" -) - -func TestBuildProperties(t *testing.T) { - ctx := context.Background() - r := memory.New() - uc := &interfaces.Container{Schema: interactor.NewSchema(r, nil)} - - wid := accountdomain.NewWorkspaceID() - pid := id.NewProjectID() - - // text field - fId1 := id.NewFieldID() - sfKey1 := id.RandomKey() - sf1 := schema.NewField(schema.NewText(lo.ToPtr(100)).TypeProperty()).ID(fId1).Key(sfKey1).MustBuild() - - // number field - fId2 := id.NewFieldID() - sfKey2 := id.RandomKey() - intField, err := schema.NewInteger(lo.ToPtr(int64(1)), lo.ToPtr(int64(100))) - assert.NoError(t, err) - sf2 := schema.NewField(intField.TypeProperty()).ID(fId2).Key(sfKey2).MustBuild() - - // asset field - gsfKey := id.NewKey("asset-key") - gsfId2 := id.NewFieldID() - gsf := schema.NewField(schema.NewAsset().TypeProperty()).ID(gsfId2).Key(gsfKey).Multiple(true).MustBuild() - - // group schema - gs := schema.New().ID(id.NewSchemaID()).Workspace(wid).Project(pid).Fields([]*schema.Field{gsf}).MustBuild() - lo.Must0(r.Schema.Save(ctx, gs)) - - // group - gid := id.NewGroupID() - gkey := id.RandomKey() - g := group.New().ID(gid).Name("group").Project(pid).Key(gkey).Schema(gs.ID()).MustBuild() - lo.Must0(r.Group.Save(ctx, g)) - - // group field - fId3 := id.NewFieldID() - sfKey3 := id.NewKey("group-key") - sf3 := schema.NewField(schema.NewGroup(g.ID()).TypeProperty()).ID(fId3).Key(sfKey3).Multiple(true).MustBuild() - - // bool field - fId4 := id.NewFieldID() - sfKey4 := id.RandomKey() - sf4 := schema.NewField(schema.NewBool().TypeProperty()).ID(fId4).Key(sfKey4).MustBuild() - - // date field - fId5 := id.NewFieldID() - sfKey5 := id.RandomKey() - sf5 := schema.NewField(schema.NewDateTime().TypeProperty()).ID(fId5).Key(sfKey5).MustBuild() - - // url field - fId6 := id.NewFieldID() - sfKey6 := id.RandomKey() - sf6 := schema.NewField(schema.NewURL().TypeProperty()).ID(fId6).Key(sfKey6).MustBuild() - - fieldList := schema.FieldList{sf1, sf2, sf3, sf4, sf5, sf6} - s1 := schema.New().NewID().Workspace(wid).Project(pid).Fields(schema.FieldList{sf2}).MustBuild() - lo.Must0(r.Schema.Save(ctx, s1)) - - expectedProperties := map[string]interface{}{ - sfKey1.String(): map[string]interface{}{ - "type": "string", - "title": "", - "description": "", - "maxLength": 100, - }, - sfKey2.String(): map[string]interface{}{ - "type": "integer", - "title": "", - "description": "", - "minimum": int64(1), - "maximum": int64(100), - }, - sfKey3.String(): map[string]interface{}{ - "title": "", - "type": "array", - "description": "", - "items": map[string]interface{}{ - "asset-key": map[string]interface{}{ - "description": "", - "format": "binary", - "title": "", - "type": "string", - }, - }, - }, - sfKey4.String(): map[string]interface{}{ - "type": "boolean", - "title": "", - "description": "", - }, - sfKey5.String(): map[string]interface{}{ - "type": "string", - "title": "", - "description": "", - "format": "date-time", - }, - sfKey6.String(): map[string]interface{}{ - "type": "string", - "title": "", - "description": "", - "format": "uri", - }, - } - - properties := buildProperties(uc, fieldList, ctx) - assert.Equal(t, expectedProperties, properties) -} - -func TestDetermineTypeAndFormat(t *testing.T) { - tests := []struct { - input value.Type - wantType string - wantFmt string - }{ - {value.TypeText, "string", ""}, - {value.TypeTextArea, "string", ""}, - {value.TypeRichText, "string", ""}, - {value.TypeMarkdown, "string", ""}, - {value.TypeSelect, "string", ""}, - {value.TypeTag, "string", ""}, - {value.TypeReference, "string", ""}, - {value.TypeInteger, "integer", ""}, - {value.TypeNumber, "number", ""}, - {value.TypeBool, "boolean", ""}, - {value.TypeDateTime, "string", "date-time"}, - {value.TypeURL, "string", "uri"}, - {value.TypeAsset, "string", "binary"}, - {value.TypeGroup, "array", ""}, - {value.TypeGeometryObject, "object", ""}, - {value.TypeGeometryEditor, "object", ""}, - {"unknown", "string", ""}, - } - - for _, tt := range tests { - t.Run(string(tt.input), func(t *testing.T) { - gotType, gotFmt := determineTypeAndFormat(tt.input) - assert.Equal(t, tt.wantType, gotType) - assert.Equal(t, tt.wantFmt, gotFmt) - }) - } -} diff --git a/server/internal/adapter/publicapi/schema_export.go b/server/internal/adapter/publicapi/schema_export.go index f362dfda90..54fa3a9b6b 100644 --- a/server/internal/adapter/publicapi/schema_export.go +++ b/server/internal/adapter/publicapi/schema_export.go @@ -4,9 +4,10 @@ import ( "context" "github.com/reearth/reearth-cms/server/internal/usecase/interfaces" + "github.com/reearth/reearth-cms/server/pkg/exporters" + "github.com/reearth/reearth-cms/server/pkg/id" "github.com/reearth/reearth-cms/server/pkg/model" "github.com/reearth/reearth-cms/server/pkg/schema" - "github.com/reearth/reearth-cms/server/pkg/value" "github.com/reearth/reearthx/rerror" "github.com/samber/lo" ) @@ -27,93 +28,35 @@ func (c *Controller) GetSchemaJSON(ctx context.Context, pKey, mKey string) (Sche return SchemaJSON{}, rerror.ErrNotFound } - return NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), buildProperties(c.usecases, sp.Schema().Fields(), ctx)), nil + gsMap := buildGroupSchemaMap(ctx, sp.Schema(), c.usecases) + res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(ctx, sp.Schema().Fields(), gsMap)) + + return toSchemaJSON(res), nil +} + +func toSchemaJSON(s exporters.SchemaJSON) SchemaJSON { + return SchemaJSON{ + Schema: s.Schema, + Id: s.Id, + Title: s.Title, + Description: s.Description, + Type: s.Type, + Properties: s.Properties, + } } -func buildProperties(uc *interfaces.Container, f schema.FieldList, ctx context.Context) map[string]interface{} { - properties := make(map[string]interface{}) - for _, field := range f { - fieldType, format := determineTypeAndFormat(field.Type()) - fieldSchema := map[string]interface{}{ - "type": fieldType, - "title": field.Name(), - "description": field.Description(), - } - if format != "" { - fieldSchema["format"] = format - } +func buildGroupSchemaMap(ctx context.Context, sch *schema.Schema, uc *interfaces.Container) map[id.GroupID]*schema.Schema { + groupSchemaMap := make(map[id.GroupID]*schema.Schema) + for _, field := range sch.Fields() { field.TypeProperty().Match(schema.TypePropertyMatch{ - Text: func(f *schema.FieldText) { - if maxLength := f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength - } - }, - TextArea: func(f *schema.FieldTextArea) { - if maxLength := f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength - } - }, - RichText: func(f *schema.FieldRichText) { - if maxLength := f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength - } - }, - Markdown: func(f *schema.FieldMarkdown) { - if maxLength := f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength - } - }, - Integer: func(f *schema.FieldInteger) { - if min := f.Min(); min != nil { - fieldSchema["minimum"] = *min - } - if max := f.Max(); max != nil { - fieldSchema["maximum"] = *max - } - }, - Number: func(f *schema.FieldNumber) { - if min := f.Min(); min != nil { - fieldSchema["minimum"] = *min - } - if max := f.Max(); max != nil { - fieldSchema["maximum"] = *max - } - }, - Group: func(f *schema.FieldGroup) { - gs, _ := uc.Schema.FindByGroup(ctx, f.Group(), nil) - if gs != nil { - fieldSchema["items"] = buildProperties(uc, gs.Fields(), ctx) + Group: func(fg *schema.FieldGroup) { + groupSchema, err := uc.Schema.FindByGroup(ctx, fg.Group(), nil) + if err == nil { + groupSchemaMap[fg.Group()] = groupSchema } }, }) - - properties[field.Key().String()] = fieldSchema - } - return properties -} - -func determineTypeAndFormat(t value.Type) (string, string) { - switch t { - case value.TypeText, value.TypeTextArea, value.TypeRichText, value.TypeMarkdown, value.TypeSelect, value.TypeTag, value.TypeReference: - return "string", "" - case value.TypeInteger: - return "integer", "" - case value.TypeNumber: - return "number", "" - case value.TypeBool, value.TypeCheckbox: - return "boolean", "" - case value.TypeDateTime: - return "string", "date-time" - case value.TypeURL: - return "string", "uri" - case value.TypeAsset: - return "string", "binary" - case value.TypeGroup: - return "array", "" - case value.TypeGeometryObject, value.TypeGeometryEditor: - return "object", "" - default: - return "string", "" } + return groupSchemaMap } diff --git a/server/pkg/exporters/schema_json.go b/server/pkg/exporters/schema_json.go new file mode 100644 index 0000000000..6449ceb4f5 --- /dev/null +++ b/server/pkg/exporters/schema_json.go @@ -0,0 +1,121 @@ +package exporters + +import ( + "context" + + "github.com/reearth/reearth-cms/server/pkg/id" + "github.com/reearth/reearth-cms/server/pkg/schema" + "github.com/reearth/reearth-cms/server/pkg/value" +) + +const defaultJSONSchemaVersion = "https://json-schema.org/draft/2020-12/schema" + +type SchemaJSON struct { + Schema string `json:"schema"` + Id string `json:"id"` + Title *string `json:"title,omitempty"` + Description *string `json:"description,omitempty"` + Type string `json:"type"` + Properties map[string]interface{} `json:"properties"` +} + +func NewSchemaJSON(id string, title, description *string, pp map[string]interface{}) SchemaJSON { + return SchemaJSON{ + Schema: defaultJSONSchemaVersion, + Id: id, + Title: title, + Description: description, + Type: "object", + Properties: pp, + } +} + +func BuildProperties(ctx context.Context, f schema.FieldList, gsMap map[id.GroupID]*schema.Schema) map[string]interface{} { + properties := make(map[string]interface{}) + for _, field := range f { + fieldType, format := determineTypeAndFormat(field.Type()) + fieldSchema := map[string]interface{}{ + "type": fieldType, + "title": field.Name(), + "description": field.Description(), + } + if format != "" { + fieldSchema["format"] = format + } + + field.TypeProperty().Match(schema.TypePropertyMatch{ + Text: func(f *schema.FieldText) { + if maxLength := f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + TextArea: func(f *schema.FieldTextArea) { + if maxLength := f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + RichText: func(f *schema.FieldRichText) { + if maxLength := f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + Markdown: func(f *schema.FieldMarkdown) { + if maxLength := f.MaxLength(); maxLength != nil { + fieldSchema["maxLength"] = *maxLength + } + }, + Integer: func(f *schema.FieldInteger) { + if min := f.Min(); min != nil { + fieldSchema["minimum"] = *min + } + if max := f.Max(); max != nil { + fieldSchema["maximum"] = *max + } + }, + Number: func(f *schema.FieldNumber) { + if min := f.Min(); min != nil { + fieldSchema["minimum"] = *min + } + if max := f.Max(); max != nil { + fieldSchema["maximum"] = *max + } + }, + Group: func(f *schema.FieldGroup) { + if gsMap != nil { + gs := gsMap[f.Group()] + if gs != nil { + fieldSchema["items"] = BuildProperties(ctx, gs.Fields(), nil) + } + } + }, + }) + + properties[field.Key().String()] = fieldSchema + } + return properties +} + +func determineTypeAndFormat(t value.Type) (string, string) { + switch t { + case value.TypeText, value.TypeTextArea, value.TypeRichText, value.TypeMarkdown, value.TypeSelect, value.TypeTag, value.TypeReference: + return "string", "" + case value.TypeInteger: + return "integer", "" + case value.TypeNumber: + return "number", "" + case value.TypeBool, value.TypeCheckbox: + return "boolean", "" + case value.TypeDateTime: + return "string", "date-time" + case value.TypeURL: + return "string", "uri" + case value.TypeAsset: + return "string", "binary" + case value.TypeGroup: + return "array", "" + case value.TypeGeometryObject, value.TypeGeometryEditor: + return "object", "" + default: + return "string", "" + } +} diff --git a/server/internal/adapter/publicapi/schema_export_test.go b/server/pkg/exporters/schema_json_test.go similarity index 88% rename from server/internal/adapter/publicapi/schema_export_test.go rename to server/pkg/exporters/schema_json_test.go index 0af24fdcb4..f5e8cf4b6f 100644 --- a/server/internal/adapter/publicapi/schema_export_test.go +++ b/server/pkg/exporters/schema_json_test.go @@ -1,12 +1,9 @@ -package publicapi +package exporters import ( "context" "testing" - "github.com/reearth/reearth-cms/server/internal/infrastructure/memory" - "github.com/reearth/reearth-cms/server/internal/usecase/interactor" - "github.com/reearth/reearth-cms/server/internal/usecase/interfaces" "github.com/reearth/reearth-cms/server/pkg/group" "github.com/reearth/reearth-cms/server/pkg/id" "github.com/reearth/reearth-cms/server/pkg/schema" @@ -18,8 +15,6 @@ import ( func TestBuildProperties(t *testing.T) { ctx := context.Background() - r := memory.New() - uc := &interfaces.Container{Schema: interactor.NewSchema(r, nil)} wid := accountdomain.NewWorkspaceID() pid := id.NewProjectID() @@ -43,13 +38,11 @@ func TestBuildProperties(t *testing.T) { // group schema gs := schema.New().ID(id.NewSchemaID()).Workspace(wid).Project(pid).Fields([]*schema.Field{gsf}).MustBuild() - lo.Must0(r.Schema.Save(ctx, gs)) // group gid := id.NewGroupID() gkey := id.RandomKey() g := group.New().ID(gid).Name("group").Project(pid).Key(gkey).Schema(gs.ID()).MustBuild() - lo.Must0(r.Group.Save(ctx, g)) // group field fId3 := id.NewFieldID() @@ -72,8 +65,7 @@ func TestBuildProperties(t *testing.T) { sf6 := schema.NewField(schema.NewURL().TypeProperty()).ID(fId6).Key(sfKey6).MustBuild() fieldList := schema.FieldList{sf1, sf2, sf3, sf4, sf5, sf6} - s1 := schema.New().NewID().Workspace(wid).Project(pid).Fields(schema.FieldList{sf2}).MustBuild() - lo.Must0(r.Schema.Save(ctx, s1)) + gsMap := map[id.GroupID]*schema.Schema{gid: gs} expectedProperties := map[string]interface{}{ sfKey1.String(): map[string]interface{}{ @@ -121,7 +113,9 @@ func TestBuildProperties(t *testing.T) { }, } - properties := buildProperties(uc, fieldList, ctx) + + + properties := BuildProperties(ctx, fieldList, gsMap) assert.Equal(t, expectedProperties, properties) } From 3a6e589315805c5aa2bfc6a74415c9b4562b723e Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Tue, 26 Nov 2024 17:40:38 +0900 Subject: [PATCH 33/39] requested changes 2 --- .../adapter/integration/schema_export.go | 60 +++++++++---------- .../adapter/publicapi/schema_export.go | 24 +------- server/internal/usecase/interactor/schema.go | 12 ---- server/internal/usecase/interfaces/schema.go | 1 - server/pkg/exporters/schema_json.go | 21 +++++-- server/pkg/exporters/schema_json_test.go | 47 ++++++++++++--- 6 files changed, 88 insertions(+), 77 deletions(-) diff --git a/server/internal/adapter/integration/schema_export.go b/server/internal/adapter/integration/schema_export.go index ea81cf81ec..22100d95de 100644 --- a/server/internal/adapter/integration/schema_export.go +++ b/server/internal/adapter/integration/schema_export.go @@ -5,10 +5,7 @@ import ( "errors" "github.com/reearth/reearth-cms/server/internal/adapter" - "github.com/reearth/reearth-cms/server/internal/usecase/interfaces" "github.com/reearth/reearth-cms/server/pkg/exporters" - "github.com/reearth/reearth-cms/server/pkg/id" - "github.com/reearth/reearth-cms/server/pkg/schema" "github.com/reearth/reearthx/rerror" "github.com/samber/lo" ) @@ -30,8 +27,8 @@ func (s *Server) SchemaByModelAsJSON(ctx context.Context, request SchemaByModelA return SchemaByModelAsJSON404Response{}, err } - gsMap := buildGroupSchemaMap(ctx, sp.Schema(), uc) - res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(ctx, sp.Schema().Fields(), gsMap)) + gsMap := exporters.BuildGroupSchemaMap(sp) + res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(sp.Schema().Fields(), gsMap)) return SchemaByModelAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -59,7 +56,7 @@ func (s *Server) MetadataSchemaByModelAsJSON(ctx context.Context, request Metada return MetadataSchemaByModelAsJSON404Response{}, err } - res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(ctx, sp.MetaSchema().Fields(), nil)) + res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(sp.MetaSchema().Fields(), nil)) return MetadataSchemaByModelAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -90,7 +87,7 @@ func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request Sch return SchemaByModelWithProjectAsJSON400Response{}, err } - sch, err := uc.Schema.FindByModel(ctx, m.ID(), op) + sp, err := uc.Schema.FindByModel(ctx, m.ID(), op) if err != nil { if errors.Is(err, rerror.ErrNotFound) { return SchemaByModelWithProjectAsJSON404Response{}, err @@ -98,8 +95,8 @@ func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request Sch return SchemaByModelWithProjectAsJSON400Response{}, err } - gsMap := buildGroupSchemaMap(ctx, sch.Schema(), uc) - res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(ctx, sch.Schema().Fields(), gsMap)) + gsMap := exporters.BuildGroupSchemaMap(sp) + res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(sp.Schema().Fields(), gsMap)) return SchemaByModelWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -138,7 +135,7 @@ func (s *Server) MetadataSchemaByModelWithProjectAsJSON(ctx context.Context, req return MetadataSchemaByModelWithProjectAsJSON400Response{}, err } - res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(ctx, sch.MetaSchema().Fields(), nil)) + res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(sch.MetaSchema().Fields(), nil)) return MetadataSchemaByModelWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -153,7 +150,7 @@ func (s *Server) SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONR uc := adapter.Usecases(ctx) op := adapter.Operator(ctx) - sch, err := uc.Schema.FindByID(ctx, request.SchemaId, op) + m, err := uc.Model.FindBySchema(ctx, request.SchemaId, op) if err != nil { if errors.Is(err, rerror.ErrNotFound) { return SchemaByIDAsJSON404Response{}, err @@ -161,8 +158,16 @@ func (s *Server) SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONR return SchemaByIDAsJSON400Response{}, err } - gsMap := buildGroupSchemaMap(ctx, sch, uc) - res := exporters.NewSchemaJSON(sch.ID().String(), nil, nil, exporters.BuildProperties(ctx, sch.Fields(), gsMap)) + sp, err := uc.Schema.FindByModel(ctx, m.ID(), op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return SchemaByIDAsJSON404Response{}, err + } + return SchemaByIDAsJSON400Response{}, err + } + + gsMap := exporters.BuildGroupSchemaMap(sp) + res := exporters.NewSchemaJSON(sp.Schema().ID().String(), nil, nil, exporters.BuildProperties(sp.Schema().Fields(), gsMap)) return SchemaByIDAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -183,7 +188,7 @@ func (s *Server) SchemaByIDWithProjectAsJSON(ctx context.Context, request Schema return SchemaByIDWithProjectAsJSON400Response{}, err } - sch, err := uc.Schema.FindByID(ctx, request.SchemaId, op) + m, err := uc.Model.FindBySchema(ctx, request.SchemaId, op) if err != nil { if errors.Is(err, rerror.ErrNotFound) { return SchemaByIDWithProjectAsJSON404Response{}, err @@ -191,8 +196,16 @@ func (s *Server) SchemaByIDWithProjectAsJSON(ctx context.Context, request Schema return SchemaByIDWithProjectAsJSON400Response{}, err } - gsMap := buildGroupSchemaMap(ctx, sch, uc) - res := exporters.NewSchemaJSON(sch.ID().String(), nil, nil, exporters.BuildProperties(ctx, sch.Fields(), gsMap)) + sp, err := uc.Schema.FindByModel(ctx, m.ID(), op) + if err != nil { + if errors.Is(err, rerror.ErrNotFound) { + return SchemaByIDWithProjectAsJSON404Response{}, err + } + return SchemaByIDWithProjectAsJSON400Response{}, err + } + + gsMap := exporters.BuildGroupSchemaMap(sp) + res := exporters.NewSchemaJSON(sp.Schema().ID().String(), nil, nil, exporters.BuildProperties(sp.Schema().Fields(), gsMap)) return SchemaByIDWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, @@ -200,18 +213,3 @@ func (s *Server) SchemaByIDWithProjectAsJSON(ctx context.Context, request Schema Properties: res.Properties, }, nil } - -func buildGroupSchemaMap(ctx context.Context, sch *schema.Schema, uc *interfaces.Container) map[id.GroupID]*schema.Schema { - groupSchemaMap := make(map[id.GroupID]*schema.Schema) - for _, field := range sch.Fields() { - field.TypeProperty().Match(schema.TypePropertyMatch{ - Group: func(fg *schema.FieldGroup) { - groupSchema, err := uc.Schema.FindByGroup(ctx, fg.Group(), nil) - if err == nil { - groupSchemaMap[fg.Group()] = groupSchema - } - }, - }) - } - return groupSchemaMap -} diff --git a/server/internal/adapter/publicapi/schema_export.go b/server/internal/adapter/publicapi/schema_export.go index 54fa3a9b6b..b905e1dee7 100644 --- a/server/internal/adapter/publicapi/schema_export.go +++ b/server/internal/adapter/publicapi/schema_export.go @@ -3,11 +3,8 @@ package publicapi import ( "context" - "github.com/reearth/reearth-cms/server/internal/usecase/interfaces" "github.com/reearth/reearth-cms/server/pkg/exporters" - "github.com/reearth/reearth-cms/server/pkg/id" "github.com/reearth/reearth-cms/server/pkg/model" - "github.com/reearth/reearth-cms/server/pkg/schema" "github.com/reearth/reearthx/rerror" "github.com/samber/lo" ) @@ -28,9 +25,8 @@ func (c *Controller) GetSchemaJSON(ctx context.Context, pKey, mKey string) (Sche return SchemaJSON{}, rerror.ErrNotFound } - gsMap := buildGroupSchemaMap(ctx, sp.Schema(), c.usecases) - res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(ctx, sp.Schema().Fields(), gsMap)) - + gsMap := exporters.BuildGroupSchemaMap(sp) + res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(sp.Schema().Fields(), gsMap)) return toSchemaJSON(res), nil } @@ -44,19 +40,3 @@ func toSchemaJSON(s exporters.SchemaJSON) SchemaJSON { Properties: s.Properties, } } - -func buildGroupSchemaMap(ctx context.Context, sch *schema.Schema, uc *interfaces.Container) map[id.GroupID]*schema.Schema { - groupSchemaMap := make(map[id.GroupID]*schema.Schema) - - for _, field := range sch.Fields() { - field.TypeProperty().Match(schema.TypePropertyMatch{ - Group: func(fg *schema.FieldGroup) { - groupSchema, err := uc.Schema.FindByGroup(ctx, fg.Group(), nil) - if err == nil { - groupSchemaMap[fg.Group()] = groupSchema - } - }, - }) - } - return groupSchemaMap -} diff --git a/server/internal/usecase/interactor/schema.go b/server/internal/usecase/interactor/schema.go index b631f09440..b472a791f0 100644 --- a/server/internal/usecase/interactor/schema.go +++ b/server/internal/usecase/interactor/schema.go @@ -72,18 +72,6 @@ func (i Schema) FindByModel(ctx context.Context, mID id.ModelID, _ *usecase.Oper return schema.NewPackage(s, sList.Schema(m.Metadata()), gsm, rs), nil } -func (i Schema) FindByGroup(ctx context.Context, gID id.GroupID, _ *usecase.Operator) (*schema.Schema, error) { - g, err := i.repos.Group.FindByID(ctx, gID) - if err != nil { - return nil, err - } - s, err := i.repos.Schema.FindByID(ctx, g.Schema()) - if err != nil { - return nil, err - } - return s, nil -} - func (i Schema) CreateField(ctx context.Context, param interfaces.CreateFieldParam, op *usecase.Operator) (*schema.Field, error) { return Run1(ctx, op, i.repos, Usecase().Transaction(), func(ctx context.Context) (*schema.Field, error) { s, err := i.repos.Schema.FindByID(ctx, param.SchemaID) diff --git a/server/internal/usecase/interfaces/schema.go b/server/internal/usecase/interfaces/schema.go index eee847dc44..4e29eb2d2d 100644 --- a/server/internal/usecase/interfaces/schema.go +++ b/server/internal/usecase/interfaces/schema.go @@ -56,7 +56,6 @@ type Schema interface { FindByID(context.Context, id.SchemaID, *usecase.Operator) (*schema.Schema, error) FindByIDs(context.Context, []id.SchemaID, *usecase.Operator) (schema.List, error) FindByModel(context.Context, id.ModelID, *usecase.Operator) (*schema.Package, error) - FindByGroup(context.Context, id.GroupID, *usecase.Operator) (*schema.Schema, error) CreateField(context.Context, CreateFieldParam, *usecase.Operator) (*schema.Field, error) UpdateField(context.Context, UpdateFieldParam, *usecase.Operator) (*schema.Field, error) UpdateFields(context.Context, id.SchemaID, []UpdateFieldParam, *usecase.Operator) (schema.FieldList, error) diff --git a/server/pkg/exporters/schema_json.go b/server/pkg/exporters/schema_json.go index 6449ceb4f5..3d2761626a 100644 --- a/server/pkg/exporters/schema_json.go +++ b/server/pkg/exporters/schema_json.go @@ -1,8 +1,6 @@ package exporters import ( - "context" - "github.com/reearth/reearth-cms/server/pkg/id" "github.com/reearth/reearth-cms/server/pkg/schema" "github.com/reearth/reearth-cms/server/pkg/value" @@ -30,7 +28,7 @@ func NewSchemaJSON(id string, title, description *string, pp map[string]interfac } } -func BuildProperties(ctx context.Context, f schema.FieldList, gsMap map[id.GroupID]*schema.Schema) map[string]interface{} { +func BuildProperties(f schema.FieldList, gsMap map[id.GroupID]*schema.Schema) map[string]interface{} { properties := make(map[string]interface{}) for _, field := range f { fieldType, format := determineTypeAndFormat(field.Type()) @@ -84,7 +82,7 @@ func BuildProperties(ctx context.Context, f schema.FieldList, gsMap map[id.Group if gsMap != nil { gs := gsMap[f.Group()] if gs != nil { - fieldSchema["items"] = BuildProperties(ctx, gs.Fields(), nil) + fieldSchema["items"] = BuildProperties(gs.Fields(), nil) } } }, @@ -119,3 +117,18 @@ func determineTypeAndFormat(t value.Type) (string, string) { return "string", "" } } + +func BuildGroupSchemaMap(sp *schema.Package) map[id.GroupID]*schema.Schema { + groupSchemaMap := make(map[id.GroupID]*schema.Schema) + for _, field := range sp.Schema().Fields() { + field.TypeProperty().Match(schema.TypePropertyMatch{ + Group: func(fg *schema.FieldGroup) { + groupSchema := sp.GroupSchema(fg.Group()) + if groupSchema != nil { + groupSchemaMap[fg.Group()] = groupSchema + } + }, + }) + } + return groupSchemaMap +} diff --git a/server/pkg/exporters/schema_json_test.go b/server/pkg/exporters/schema_json_test.go index f5e8cf4b6f..c9754b9ec7 100644 --- a/server/pkg/exporters/schema_json_test.go +++ b/server/pkg/exporters/schema_json_test.go @@ -1,7 +1,6 @@ package exporters import ( - "context" "testing" "github.com/reearth/reearth-cms/server/pkg/group" @@ -14,8 +13,6 @@ import ( ) func TestBuildProperties(t *testing.T) { - ctx := context.Background() - wid := accountdomain.NewWorkspaceID() pid := id.NewProjectID() @@ -65,7 +62,7 @@ func TestBuildProperties(t *testing.T) { sf6 := schema.NewField(schema.NewURL().TypeProperty()).ID(fId6).Key(sfKey6).MustBuild() fieldList := schema.FieldList{sf1, sf2, sf3, sf4, sf5, sf6} - gsMap := map[id.GroupID]*schema.Schema{gid: gs} + gsMap := map[id.GroupID]*schema.Schema{gid: gs} expectedProperties := map[string]interface{}{ sfKey1.String(): map[string]interface{}{ @@ -113,9 +110,7 @@ func TestBuildProperties(t *testing.T) { }, } - - - properties := BuildProperties(ctx, fieldList, gsMap) + properties := BuildProperties(fieldList, gsMap) assert.Equal(t, expectedProperties, properties) } @@ -152,3 +147,41 @@ func TestDetermineTypeAndFormat(t *testing.T) { }) } } + +func TestBuildGroupSchemaMap(t *testing.T) { + wid := accountdomain.NewWorkspaceID() + pid := id.NewProjectID() + + textFieldID := id.NewFieldID() + textFieldKey := id.RandomKey() + textField := schema.NewField(schema.NewText(lo.ToPtr(100)).TypeProperty()).ID(textFieldID).Key(textFieldKey).MustBuild() + + assetField1 := schema.NewField(schema.NewAsset().TypeProperty()).ID(id.NewFieldID()).Key(id.NewKey("asset-key-1")).Multiple(true).MustBuild() + groupSchema1 := schema.New().ID(id.NewSchemaID()).Workspace(wid).Project(pid).Fields([]*schema.Field{assetField1}).MustBuild() + + groupID1 := id.NewGroupID() + groupKey1 := id.RandomKey() + group1 := group.New().ID(groupID1).Name("group-1").Project(pid).Key(groupKey1).Schema(groupSchema1.ID()).MustBuild() + + groupFieldID1 := id.NewFieldID() + groupFieldKey1 := id.NewKey("group-key-1") + groupField1 := schema.NewField(schema.NewGroup(group1.ID()).TypeProperty()).ID(groupFieldID1).Key(groupFieldKey1).Multiple(true).MustBuild() + + textField2 := schema.NewField(schema.NewText(nil).TypeProperty()).ID(id.NewFieldID()).Key(id.NewKey("text-key-2")).Multiple(false).MustBuild() + groupSchema2 := schema.New().ID(id.NewSchemaID()).Workspace(wid).Project(pid).Fields([]*schema.Field{textField2}).MustBuild() + + groupID2 := id.NewGroupID() + groupKey2 := id.RandomKey() + group2 := group.New().ID(groupID2).Name("group-2").Project(pid).Key(groupKey2).Schema(groupSchema2.ID()).MustBuild() + + groupFieldID2 := id.NewFieldID() + groupFieldKey2 := id.NewKey("group-key-2") + groupField2 := schema.NewField(schema.NewGroup(group2.ID()).TypeProperty()).ID(groupFieldID2).Key(groupFieldKey2).Multiple(false).MustBuild() + + mainSchema := schema.New().ID(id.NewSchemaID()).Workspace(wid).Project(pid).Fields([]*schema.Field{textField, groupField1, groupField2}).MustBuild() + schemaPackage := schema.NewPackage(mainSchema, nil, map[id.GroupID]*schema.Schema{groupID1: groupSchema1, groupID2: groupSchema2}, nil) + + expected := map[id.GroupID]*schema.Schema{groupID1: groupSchema1, groupID2: groupSchema2} + result := BuildGroupSchemaMap(schemaPackage) + assert.Equal(t, expected, result) +} From b2002f98c7e8dce26a24e222541fe00525be8c02 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 27 Nov 2024 15:09:52 +0900 Subject: [PATCH 34/39] add type to properties --- .../adapter/integration/schema_export.go | 52 +++++-- .../adapter/integration/server.gen.go | 145 +++++++++--------- .../adapter/publicapi/schema_export.go | 31 +++- server/internal/adapter/publicapi/types.go | 27 +++- server/pkg/exporters/schema_json.go | 128 +++++++++++++--- server/pkg/exporters/schema_json_test.go | 78 +++++----- server/pkg/integrationapi/types.gen.go | 24 ++- server/schemas/integration.yml | 27 +++- 8 files changed, 348 insertions(+), 164 deletions(-) diff --git a/server/internal/adapter/integration/schema_export.go b/server/internal/adapter/integration/schema_export.go index 22100d95de..b27c509b40 100644 --- a/server/internal/adapter/integration/schema_export.go +++ b/server/internal/adapter/integration/schema_export.go @@ -6,6 +6,7 @@ import ( "github.com/reearth/reearth-cms/server/internal/adapter" "github.com/reearth/reearth-cms/server/pkg/exporters" + "github.com/reearth/reearth-cms/server/pkg/integrationapi" "github.com/reearth/reearthx/rerror" "github.com/samber/lo" ) @@ -28,14 +29,14 @@ func (s *Server) SchemaByModelAsJSON(ctx context.Context, request SchemaByModelA } gsMap := exporters.BuildGroupSchemaMap(sp) - res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(sp.Schema().Fields(), gsMap)) + res := exporters.NewSchemaJSON(m.ID().Ref().StringRef(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(sp.Schema().Fields(), gsMap)) return SchemaByModelAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, Title: res.Title, Description: res.Description, Type: res.Type, - Properties: res.Properties, + Properties: toSchemaJSONProperties(res.Properties), }, nil } @@ -56,14 +57,14 @@ func (s *Server) MetadataSchemaByModelAsJSON(ctx context.Context, request Metada return MetadataSchemaByModelAsJSON404Response{}, err } - res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(sp.MetaSchema().Fields(), nil)) + res := exporters.NewSchemaJSON(m.ID().Ref().StringRef(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(sp.MetaSchema().Fields(), nil)) return MetadataSchemaByModelAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, Title: res.Title, Description: res.Description, Type: res.Type, - Properties: res.Properties, + Properties: toSchemaJSONProperties(res.Properties), }, nil } @@ -96,14 +97,14 @@ func (s *Server) SchemaByModelWithProjectAsJSON(ctx context.Context, request Sch } gsMap := exporters.BuildGroupSchemaMap(sp) - res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(sp.Schema().Fields(), gsMap)) + res := exporters.NewSchemaJSON(m.ID().Ref().StringRef(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(sp.Schema().Fields(), gsMap)) return SchemaByModelWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, Title: res.Title, Description: res.Description, Type: res.Type, - Properties: res.Properties, + Properties: toSchemaJSONProperties(res.Properties), }, nil } @@ -135,14 +136,14 @@ func (s *Server) MetadataSchemaByModelWithProjectAsJSON(ctx context.Context, req return MetadataSchemaByModelWithProjectAsJSON400Response{}, err } - res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(sch.MetaSchema().Fields(), nil)) + res := exporters.NewSchemaJSON(m.ID().Ref().StringRef(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(sch.MetaSchema().Fields(), nil)) return MetadataSchemaByModelWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, Title: res.Title, Description: res.Description, Type: res.Type, - Properties: res.Properties, + Properties: toSchemaJSONProperties(res.Properties), }, nil } @@ -167,12 +168,12 @@ func (s *Server) SchemaByIDAsJSON(ctx context.Context, request SchemaByIDAsJSONR } gsMap := exporters.BuildGroupSchemaMap(sp) - res := exporters.NewSchemaJSON(sp.Schema().ID().String(), nil, nil, exporters.BuildProperties(sp.Schema().Fields(), gsMap)) + res := exporters.NewSchemaJSON(sp.Schema().ID().Ref().StringRef(), nil, nil, exporters.BuildProperties(sp.Schema().Fields(), gsMap)) return SchemaByIDAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, Type: res.Type, - Properties: res.Properties, + Properties: toSchemaJSONProperties(res.Properties), }, nil } @@ -205,11 +206,38 @@ func (s *Server) SchemaByIDWithProjectAsJSON(ctx context.Context, request Schema } gsMap := exporters.BuildGroupSchemaMap(sp) - res := exporters.NewSchemaJSON(sp.Schema().ID().String(), nil, nil, exporters.BuildProperties(sp.Schema().Fields(), gsMap)) + res := exporters.NewSchemaJSON(sp.Schema().ID().Ref().StringRef(), nil, nil, exporters.BuildProperties(sp.Schema().Fields(), gsMap)) return SchemaByIDWithProjectAsJSON200JSONResponse{ Schema: res.Schema, Id: res.Id, Type: res.Type, - Properties: res.Properties, + Properties: toSchemaJSONProperties(res.Properties), }, nil } + +func toSchemaJSONProperties(pp map[string]exporters.SchemaJSONProperties) map[string]integrationapi.SchemaJSONProperties { + res := map[string]integrationapi.SchemaJSONProperties{} + for k, v := range pp { + res[k] = integrationapi.SchemaJSONProperties{ + Type: v.Type, + Title: v.Title, + Description: v.Description, + Format: v.Format, + Minimum: v.Minimum, + Maximum: v.Maximum, + MaxLength: v.MaxLength, + Items: toSchemaJSONItems(v.Items), + } + } + return res +} + +func toSchemaJSONItems(pp *exporters.SchemaJSON) *integrationapi.SchemaJSON { + if pp == nil { + return nil + } + return &integrationapi.SchemaJSON{ + Type: pp.Type, + Properties: toSchemaJSONProperties(pp.Properties), + } +} diff --git a/server/internal/adapter/integration/server.gen.go b/server/internal/adapter/integration/server.gen.go index d2bfd512d0..3f010f7d53 100644 --- a/server/internal/adapter/integration/server.gen.go +++ b/server/internal/adapter/integration/server.gen.go @@ -5183,78 +5183,79 @@ func (sh *strictHandler) ProjectFilter(ctx echo.Context, workspaceId WorkspaceId // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", + "WS6X/wsAAP//hHQYUfexAAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/server/internal/adapter/publicapi/schema_export.go b/server/internal/adapter/publicapi/schema_export.go index b905e1dee7..fd58d04df9 100644 --- a/server/internal/adapter/publicapi/schema_export.go +++ b/server/internal/adapter/publicapi/schema_export.go @@ -26,7 +26,7 @@ func (c *Controller) GetSchemaJSON(ctx context.Context, pKey, mKey string) (Sche } gsMap := exporters.BuildGroupSchemaMap(sp) - res := exporters.NewSchemaJSON(m.ID().String(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(sp.Schema().Fields(), gsMap)) + res := exporters.NewSchemaJSON(m.ID().Ref().StringRef(), lo.ToPtr(m.Name()), lo.ToPtr(m.Description()), exporters.BuildProperties(sp.Schema().Fields(), gsMap)) return toSchemaJSON(res), nil } @@ -37,6 +37,33 @@ func toSchemaJSON(s exporters.SchemaJSON) SchemaJSON { Title: s.Title, Description: s.Description, Type: s.Type, - Properties: s.Properties, + Properties: toSchemaJSONProperties(s.Properties), + } +} + +func toSchemaJSONProperties(pp map[string]exporters.SchemaJSONProperties) map[string]SchemaJSONProperties { + res := map[string]SchemaJSONProperties{} + for k, v := range pp { + res[k] = SchemaJSONProperties{ + Type: v.Type, + Title: v.Title, + Description: v.Description, + Format: v.Format, + Minimum: v.Minimum, + Maximum: v.Maximum, + MaxLength: v.MaxLength, + Items: toSchemaJSONItems(v.Items), + } + } + return res +} + +func toSchemaJSONItems(pp *exporters.SchemaJSON) *SchemaJSON { + if pp == nil { + return nil + } + return &SchemaJSON{ + Type: pp.Type, + Properties: toSchemaJSONProperties(pp.Properties), } } diff --git a/server/internal/adapter/publicapi/types.go b/server/internal/adapter/publicapi/types.go index 4b156e4dc7..84af75eeea 100644 --- a/server/internal/adapter/publicapi/types.go +++ b/server/internal/adapter/publicapi/types.go @@ -215,17 +215,28 @@ func NewItemAsset(a *asset.Asset, urlResolver asset.URLResolver) ItemAsset { const defaultJSONSchemaVersion = "https://json-schema.org/draft/2020-12/schema" type SchemaJSON struct { - Schema string `json:"schema"` - Id string `json:"id"` - Title *string `json:"title,omitempty"` - Description *string `json:"description,omitempty"` - Type string `json:"type"` - Properties map[string]interface{} `json:"properties"` + Id *string `json:"id,omitempty"` + Schema *string `json:"schema,omitempty"` + Description *string `json:"description,omitempty"` + Properties map[string]SchemaJSONProperties `json:"properties"` + Title *string `json:"title,omitempty"` + Type string `json:"type"` } -func NewSchemaJSON(id string, title, description *string, pp map[string]interface{}) SchemaJSON { +type SchemaJSONProperties struct { + Description *string `json:"description,omitempty"` + Format *string `json:"format,omitempty"` + Items *SchemaJSON `json:"items,omitempty"` + MaxLength *int `json:"maxLength,omitempty"` + Maximum *float64 `json:"maximum,omitempty"` + Minimum *float64 `json:"minimum,omitempty"` + Title *string `json:"title,omitempty"` + Type string `json:"type"` +} + +func NewSchemaJSON(id, title, description *string, pp map[string]SchemaJSONProperties) SchemaJSON { return SchemaJSON{ - Schema: defaultJSONSchemaVersion, + Schema: lo.ToPtr(defaultJSONSchemaVersion), Id: id, Title: title, Description: description, diff --git a/server/pkg/exporters/schema_json.go b/server/pkg/exporters/schema_json.go index 3d2761626a..9ef87fb1d3 100644 --- a/server/pkg/exporters/schema_json.go +++ b/server/pkg/exporters/schema_json.go @@ -4,22 +4,34 @@ import ( "github.com/reearth/reearth-cms/server/pkg/id" "github.com/reearth/reearth-cms/server/pkg/schema" "github.com/reearth/reearth-cms/server/pkg/value" + "github.com/samber/lo" ) const defaultJSONSchemaVersion = "https://json-schema.org/draft/2020-12/schema" type SchemaJSON struct { - Schema string `json:"schema"` - Id string `json:"id"` - Title *string `json:"title,omitempty"` - Description *string `json:"description,omitempty"` - Type string `json:"type"` - Properties map[string]interface{} `json:"properties"` + Id *string `json:"$id"` + Schema *string `json:"$schema"` + Description *string `json:"description,omitempty"` + Properties map[string]SchemaJSONProperties `json:"properties"` + Title *string `json:"title,omitempty"` + Type string `json:"type"` } -func NewSchemaJSON(id string, title, description *string, pp map[string]interface{}) SchemaJSON { +type SchemaJSONProperties struct { + Description *string `json:"description,omitempty"` + Format *string `json:"format,omitempty"` + Items *SchemaJSON `json:"items,omitempty"` + MaxLength *int `json:"maxLength,omitempty"` + Maximum *float64 `json:"maximum,omitempty"` + Minimum *float64 `json:"minimum,omitempty"` + Title *string `json:"title,omitempty"` + Type string `json:"type"` +} + +func NewSchemaJSON(id, title, description *string, pp map[string]SchemaJSONProperties) SchemaJSON { return SchemaJSON{ - Schema: defaultJSONSchemaVersion, + Schema: lo.ToPtr(defaultJSONSchemaVersion), Id: id, Title: title, Description: description, @@ -28,61 +40,62 @@ func NewSchemaJSON(id string, title, description *string, pp map[string]interfac } } -func BuildProperties(f schema.FieldList, gsMap map[id.GroupID]*schema.Schema) map[string]interface{} { - properties := make(map[string]interface{}) +func BuildProperties(f schema.FieldList, gsMap map[id.GroupID]*schema.Schema) map[string]SchemaJSONProperties { + properties := make(map[string]SchemaJSONProperties) for _, field := range f { fieldType, format := determineTypeAndFormat(field.Type()) - fieldSchema := map[string]interface{}{ - "type": fieldType, - "title": field.Name(), - "description": field.Description(), + fieldSchema := SchemaJSONProperties{ + Type: fieldType, + Title: lo.ToPtr(field.Name()), + Description: lo.ToPtr(field.Description()), } if format != "" { - fieldSchema["format"] = format + fieldSchema.Format = lo.ToPtr(format) } field.TypeProperty().Match(schema.TypePropertyMatch{ Text: func(f *schema.FieldText) { if maxLength := f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength + fieldSchema.MaxLength = maxLength + properties[field.Key().String()] = fieldSchema } }, TextArea: func(f *schema.FieldTextArea) { if maxLength := f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength + fieldSchema.MaxLength = maxLength } }, RichText: func(f *schema.FieldRichText) { if maxLength := f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength + fieldSchema.MaxLength = maxLength } }, Markdown: func(f *schema.FieldMarkdown) { if maxLength := f.MaxLength(); maxLength != nil { - fieldSchema["maxLength"] = *maxLength + fieldSchema.MaxLength = maxLength } }, Integer: func(f *schema.FieldInteger) { if min := f.Min(); min != nil { - fieldSchema["minimum"] = *min + fieldSchema.Minimum = Int64ToFloat64(min) } if max := f.Max(); max != nil { - fieldSchema["maximum"] = *max + fieldSchema.Maximum = Int64ToFloat64(max) } }, Number: func(f *schema.FieldNumber) { if min := f.Min(); min != nil { - fieldSchema["minimum"] = *min + fieldSchema.Minimum = min } if max := f.Max(); max != nil { - fieldSchema["maximum"] = *max + fieldSchema.Maximum = max } }, Group: func(f *schema.FieldGroup) { if gsMap != nil { gs := gsMap[f.Group()] if gs != nil { - fieldSchema["items"] = BuildProperties(gs.Fields(), nil) + fieldSchema.Items = BuildItems(gs.Fields()) } } }, @@ -93,6 +106,73 @@ func BuildProperties(f schema.FieldList, gsMap map[id.GroupID]*schema.Schema) ma return properties } +func BuildItems(f schema.FieldList) *SchemaJSON { + properties := make(map[string]SchemaJSONProperties) + for _, field := range f { + fieldType, format := determineTypeAndFormat(field.Type()) + fieldSchema := SchemaJSONProperties{} + fieldSchema.Type = fieldType + fieldSchema.Title = lo.ToPtr(field.Name()) + fieldSchema.Description = lo.ToPtr(field.Description()) + if format != "" { + fieldSchema.Format = lo.ToPtr(format) + } + + field.TypeProperty().Match(schema.TypePropertyMatch{ + Text: func(f *schema.FieldText) { + if maxLength := f.MaxLength(); maxLength != nil { + fieldSchema.MaxLength = maxLength + properties[field.Key().String()] = fieldSchema + } + }, + TextArea: func(f *schema.FieldTextArea) { + if maxLength := f.MaxLength(); maxLength != nil { + fieldSchema.MaxLength = maxLength + } + }, + RichText: func(f *schema.FieldRichText) { + if maxLength := f.MaxLength(); maxLength != nil { + fieldSchema.MaxLength = maxLength + } + }, + Markdown: func(f *schema.FieldMarkdown) { + if maxLength := f.MaxLength(); maxLength != nil { + fieldSchema.MaxLength = maxLength + } + }, + Integer: func(f *schema.FieldInteger) { + if min := f.Min(); min != nil { + fieldSchema.Minimum = Int64ToFloat64(min) + } + if max := f.Max(); max != nil { + fieldSchema.Maximum = Int64ToFloat64(max) + } + }, + Number: func(f *schema.FieldNumber) { + if min := f.Min(); min != nil { + fieldSchema.Minimum = min + } + if max := f.Max(); max != nil { + fieldSchema.Maximum = max + } + }, + }) + properties[field.Key().String()] = fieldSchema + } + return &SchemaJSON{ + Type: "object", + Properties: properties, + } +} + +func Int64ToFloat64(input *int64) *float64 { + if input == nil { + return nil + } + value := float64(*input) + return &value +} + func determineTypeAndFormat(t value.Type) (string, string) { switch t { case value.TypeText, value.TypeTextArea, value.TypeRichText, value.TypeMarkdown, value.TypeSelect, value.TypeTag, value.TypeReference: diff --git a/server/pkg/exporters/schema_json_test.go b/server/pkg/exporters/schema_json_test.go index c9754b9ec7..cdbd6a8d82 100644 --- a/server/pkg/exporters/schema_json_test.go +++ b/server/pkg/exporters/schema_json_test.go @@ -64,49 +64,51 @@ func TestBuildProperties(t *testing.T) { fieldList := schema.FieldList{sf1, sf2, sf3, sf4, sf5, sf6} gsMap := map[id.GroupID]*schema.Schema{gid: gs} - expectedProperties := map[string]interface{}{ - sfKey1.String(): map[string]interface{}{ - "type": "string", - "title": "", - "description": "", - "maxLength": 100, + expectedProperties := map[string]SchemaJSONProperties{ + sfKey1.String(): { + Type: "string", + Title: lo.ToPtr(""), + Description: lo.ToPtr(""), + MaxLength: lo.ToPtr(100), }, - sfKey2.String(): map[string]interface{}{ - "type": "integer", - "title": "", - "description": "", - "minimum": int64(1), - "maximum": int64(100), + sfKey2.String(): { + Type: "integer", + Title: lo.ToPtr(""), + Description: lo.ToPtr(""), + Minimum: lo.ToPtr(float64(1)), + Maximum: lo.ToPtr(float64(100)), }, - sfKey3.String(): map[string]interface{}{ - "title": "", - "type": "array", - "description": "", - "items": map[string]interface{}{ - "asset-key": map[string]interface{}{ - "description": "", - "format": "binary", - "title": "", - "type": "string", - }, - }, + sfKey3.String(): { + Title: lo.ToPtr(""), + Type: "array", + Description: lo.ToPtr(""), + Items: &SchemaJSON{ + Type: "object", + Properties: map[string]SchemaJSONProperties{ + "asset-key": { + Description: lo.ToPtr(""), + Format: lo.ToPtr("binary"), + Title: lo.ToPtr(""), + Type: "string", + }, + }}, }, - sfKey4.String(): map[string]interface{}{ - "type": "boolean", - "title": "", - "description": "", + sfKey4.String(): { + Type: "boolean", + Title: lo.ToPtr(""), + Description: lo.ToPtr(""), }, - sfKey5.String(): map[string]interface{}{ - "type": "string", - "title": "", - "description": "", - "format": "date-time", + sfKey5.String(): { + Type: "string", + Title: lo.ToPtr(""), + Description: lo.ToPtr(""), + Format: lo.ToPtr("date-time"), }, - sfKey6.String(): map[string]interface{}{ - "type": "string", - "title": "", - "description": "", - "format": "uri", + sfKey6.String(): { + Type: "string", + Title: lo.ToPtr(""), + Description: lo.ToPtr(""), + Format: lo.ToPtr("uri"), }, } diff --git a/server/pkg/integrationapi/types.gen.go b/server/pkg/integrationapi/types.gen.go index 927ba39051..ac4daf94f9 100644 --- a/server/pkg/integrationapi/types.gen.go +++ b/server/pkg/integrationapi/types.gen.go @@ -553,12 +553,24 @@ type SchemaField struct { // SchemaJSON defines model for schemaJSON. type SchemaJSON struct { - Id string `json:"$id"` - Schema string `json:"$schema"` - Description *string `json:"description,omitempty"` - Properties map[string]interface{} `json:"properties"` - Title *string `json:"title,omitempty"` - Type string `json:"type"` + Id *string `json:"$id,omitempty"` + Schema *string `json:"$schema,omitempty"` + Description *string `json:"description,omitempty"` + Properties map[string]SchemaJSONProperties `json:"properties"` + Title *string `json:"title,omitempty"` + Type string `json:"type"` +} + +// SchemaJSONProperties defines model for schemaJSONProperties. +type SchemaJSONProperties struct { + Description *string `json:"description,omitempty"` + Format *string `json:"format,omitempty"` + Items *SchemaJSON `json:"items,omitempty"` + MaxLength *int `json:"maxLength,omitempty"` + Maximum *float64 `json:"maximum,omitempty"` + Minimum *float64 `json:"minimum,omitempty"` + Title *string `json:"title,omitempty"` + Type string `json:"type"` } // TagResponse defines model for tagResponse. diff --git a/server/schemas/integration.yml b/server/schemas/integration.yml index 58384157b9..5f62f94e7a 100644 --- a/server/schemas/integration.yml +++ b/server/schemas/integration.yml @@ -1831,7 +1831,7 @@ components: format: date-time schemaJSON: type: object - required: ["$schema", "$id", "type", "properties"] + required: ["type", "properties"] properties: $schema: type: string @@ -1845,7 +1845,30 @@ components: type: string properties: type: object - additionalProperties: true + additionalProperties: + $ref: '#/components/schemas/schemaJSONProperties' + schemaJSONProperties: + type: object + required: ["type"] + properties: + type: + type: string + title: + type: string + description: + type: string + format: + type: string + minimum: + type: number + format: double + maximum: + type: number + format: double + maxLength: + type: integer + items: + $ref: '#/components/schemas/schemaJSON' valueType: type: string enum: From 17e8a12f682f390fd09f1341863b869ab0286fb0 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 27 Nov 2024 15:29:45 +0900 Subject: [PATCH 35/39] fix types --- server/e2e/publicapi_test.go | 4 ++-- server/internal/adapter/publicapi/types.go | 4 ++-- server/pkg/exporters/schema_json.go | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/server/e2e/publicapi_test.go b/server/e2e/publicapi_test.go index 689f7250c8..a1c2e74af0 100644 --- a/server/e2e/publicapi_test.go +++ b/server/e2e/publicapi_test.go @@ -366,7 +366,7 @@ func TestPublicAPI(t *testing.T) { JSON(). IsEqual(map[string]any{ "description": "", - "id": publicAPIModelID, + "$id": publicAPIModelID, "properties": map[string]any{ "asset": map[string]any{ "description": "", @@ -401,7 +401,7 @@ func TestPublicAPI(t *testing.T) { "type": "string", }, }, - "schema": "https://json-schema.org/draft/2020-12/schema", + "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "", "type": "object", }) diff --git a/server/internal/adapter/publicapi/types.go b/server/internal/adapter/publicapi/types.go index 84af75eeea..b2aa82f4a6 100644 --- a/server/internal/adapter/publicapi/types.go +++ b/server/internal/adapter/publicapi/types.go @@ -215,8 +215,8 @@ func NewItemAsset(a *asset.Asset, urlResolver asset.URLResolver) ItemAsset { const defaultJSONSchemaVersion = "https://json-schema.org/draft/2020-12/schema" type SchemaJSON struct { - Id *string `json:"id,omitempty"` - Schema *string `json:"schema,omitempty"` + Id *string `json:"$id,omitempty"` + Schema *string `json:"$schema,omitempty"` Description *string `json:"description,omitempty"` Properties map[string]SchemaJSONProperties `json:"properties"` Title *string `json:"title,omitempty"` diff --git a/server/pkg/exporters/schema_json.go b/server/pkg/exporters/schema_json.go index 9ef87fb1d3..46a319a82b 100644 --- a/server/pkg/exporters/schema_json.go +++ b/server/pkg/exporters/schema_json.go @@ -10,8 +10,8 @@ import ( const defaultJSONSchemaVersion = "https://json-schema.org/draft/2020-12/schema" type SchemaJSON struct { - Id *string `json:"$id"` - Schema *string `json:"$schema"` + Id *string `json:"$id,omitempty"` + Schema *string `json:"$schema,omitempty"` Description *string `json:"description,omitempty"` Properties map[string]SchemaJSONProperties `json:"properties"` Title *string `json:"title,omitempty"` From f743f06aa19bbb61f08bc4d7117946435f91ed98 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 27 Nov 2024 15:57:51 +0900 Subject: [PATCH 36/39] fix empty values --- server/e2e/integration_schema_export_test.go | 48 ++++++-------------- server/e2e/publicapi_test.go | 40 +++++++--------- server/pkg/exporters/schema_json.go | 42 +++++++++++------ server/pkg/exporters/schema_json_test.go | 40 ++++++---------- 4 files changed, 70 insertions(+), 100 deletions(-) diff --git a/server/e2e/integration_schema_export_test.go b/server/e2e/integration_schema_export_test.go index c6b4fdeeed..3eae4d0a88 100644 --- a/server/e2e/integration_schema_export_test.go +++ b/server/e2e/integration_schema_export_test.go @@ -32,15 +32,11 @@ func TestIntegrationSchemaJSONExportAPI(t *testing.T) { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": map[string]any{ "asset": map[string]any{ - "description": "", - "title": "", - "type": "string", - "format": "binary", + "type": "string", + "format": "binary", }, sfKey1.String(): map[string]any{ - "description": "", - "title": "", - "type": "string", + "type": "string", }, }, "type": "object", @@ -67,15 +63,11 @@ func TestIntegrationSchemaJSONExportAPI(t *testing.T) { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": map[string]any{ "asset": map[string]any{ - "description": "", - "title": "", - "type": "string", - "format": "binary", + "type": "string", + "format": "binary", }, sfKey1.String(): map[string]any{ - "description": "", - "title": "", - "type": "string", + "type": "string", }, }, "type": "object", @@ -102,15 +94,11 @@ func TestIntegrationSchemaJSONExportAPI(t *testing.T) { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": map[string]any{ "asset": map[string]any{ - "description": "", - "title": "", - "type": "string", - "format": "binary", + "type": "string", + "format": "binary", }, sfKey1.String(): map[string]any{ - "description": "", - "title": "", - "type": "string", + "type": "string", }, }, "type": "object", @@ -139,9 +127,7 @@ func TestIntegrationSchemaJSONExportAPI(t *testing.T) { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": map[string]any{ sfKey4.String(): map[string]any{ - "description": "", - "title": "", - "type": "boolean", + "type": "boolean", }, }, "type": "object", @@ -170,15 +156,11 @@ func TestIntegrationSchemaJSONExportAPI(t *testing.T) { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": map[string]any{ "asset": map[string]any{ - "description": "", - "title": "", - "type": "string", - "format": "binary", + "type": "string", + "format": "binary", }, sfKey1.String(): map[string]any{ - "description": "", - "title": "", - "type": "string", + "type": "string", }, }, "type": "object", @@ -207,9 +189,7 @@ func TestIntegrationSchemaJSONExportAPI(t *testing.T) { "$schema": "https://json-schema.org/draft/2020-12/schema", "properties": map[string]any{ sfKey4.String(): map[string]any{ - "description": "", - "title": "", - "type": "boolean", + "type": "boolean", }, }, "type": "object", diff --git a/server/e2e/publicapi_test.go b/server/e2e/publicapi_test.go index a1c2e74af0..f943fdd459 100644 --- a/server/e2e/publicapi_test.go +++ b/server/e2e/publicapi_test.go @@ -365,45 +365,37 @@ func TestPublicAPI(t *testing.T) { Status(http.StatusOK). JSON(). IsEqual(map[string]any{ - "description": "", - "$id": publicAPIModelID, + "$id": publicAPIModelID, "properties": map[string]any{ "asset": map[string]any{ - "description": "", - "title": "asset", - "type": "string", - "format": "binary", + "title": "asset", + "type": "string", + "format": "binary", }, "asset2": map[string]any{ - "description": "", - "title": "asset2", - "type": "string", - "format": "binary", + "title": "asset2", + "type": "string", + "format": "binary", }, "geometry-editor": map[string]any{ - "description": "", - "title": "geometry-editor", - "type": "object", + "title": "geometry-editor", + "type": "object", }, "geometry-object": map[string]any{ - "description": "", - "title": "geometry-object", - "type": "object", + "title": "geometry-object", + "type": "object", }, "test-field-1": map[string]any{ - "description": "", - "title": "test-field-1", - "type": "string", + "title": "test-field-1", + "type": "string", }, "test-field-2": map[string]any{ - "description": "", - "title": "test-field-2", - "type": "string", + "title": "test-field-2", + "type": "string", }, }, "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "", - "type": "object", + "type": "object", }) // make the project private diff --git a/server/pkg/exporters/schema_json.go b/server/pkg/exporters/schema_json.go index 46a319a82b..6a0fcf5150 100644 --- a/server/pkg/exporters/schema_json.go +++ b/server/pkg/exporters/schema_json.go @@ -30,24 +30,33 @@ type SchemaJSONProperties struct { } func NewSchemaJSON(id, title, description *string, pp map[string]SchemaJSONProperties) SchemaJSON { - return SchemaJSON{ - Schema: lo.ToPtr(defaultJSONSchemaVersion), - Id: id, - Title: title, - Description: description, - Type: "object", - Properties: pp, + res := SchemaJSON{ + Schema: lo.ToPtr(defaultJSONSchemaVersion), + Type: "object", + Properties: pp, + } + if id != nil && *id != "" { + res.Id = id + } + if title != nil && *title != "" { + res.Title = title + } + if description != nil && *description != "" { + res.Description = description } + return res } func BuildProperties(f schema.FieldList, gsMap map[id.GroupID]*schema.Schema) map[string]SchemaJSONProperties { properties := make(map[string]SchemaJSONProperties) for _, field := range f { fieldType, format := determineTypeAndFormat(field.Type()) - fieldSchema := SchemaJSONProperties{ - Type: fieldType, - Title: lo.ToPtr(field.Name()), - Description: lo.ToPtr(field.Description()), + fieldSchema := SchemaJSONProperties{Type: fieldType} + if field.Name() != "" { + fieldSchema.Title = lo.ToPtr(field.Name()) + } + if field.Description() != "" { + fieldSchema.Description = lo.ToPtr(field.Description()) } if format != "" { fieldSchema.Format = lo.ToPtr(format) @@ -110,10 +119,13 @@ func BuildItems(f schema.FieldList) *SchemaJSON { properties := make(map[string]SchemaJSONProperties) for _, field := range f { fieldType, format := determineTypeAndFormat(field.Type()) - fieldSchema := SchemaJSONProperties{} - fieldSchema.Type = fieldType - fieldSchema.Title = lo.ToPtr(field.Name()) - fieldSchema.Description = lo.ToPtr(field.Description()) + fieldSchema := SchemaJSONProperties{Type: fieldType} + if field.Name() != "" { + fieldSchema.Title = lo.ToPtr(field.Name()) + } + if field.Description() != "" { + fieldSchema.Description = lo.ToPtr(field.Description()) + } if format != "" { fieldSchema.Format = lo.ToPtr(format) } diff --git a/server/pkg/exporters/schema_json_test.go b/server/pkg/exporters/schema_json_test.go index cdbd6a8d82..7da3265811 100644 --- a/server/pkg/exporters/schema_json_test.go +++ b/server/pkg/exporters/schema_json_test.go @@ -66,49 +66,35 @@ func TestBuildProperties(t *testing.T) { expectedProperties := map[string]SchemaJSONProperties{ sfKey1.String(): { - Type: "string", - Title: lo.ToPtr(""), - Description: lo.ToPtr(""), - MaxLength: lo.ToPtr(100), + Type: "string", + MaxLength: lo.ToPtr(100), }, sfKey2.String(): { - Type: "integer", - Title: lo.ToPtr(""), - Description: lo.ToPtr(""), - Minimum: lo.ToPtr(float64(1)), - Maximum: lo.ToPtr(float64(100)), + Type: "integer", + Minimum: lo.ToPtr(float64(1)), + Maximum: lo.ToPtr(float64(100)), }, sfKey3.String(): { - Title: lo.ToPtr(""), - Type: "array", - Description: lo.ToPtr(""), + Type: "array", Items: &SchemaJSON{ Type: "object", Properties: map[string]SchemaJSONProperties{ "asset-key": { - Description: lo.ToPtr(""), - Format: lo.ToPtr("binary"), - Title: lo.ToPtr(""), - Type: "string", + Format: lo.ToPtr("binary"), + Type: "string", }, }}, }, sfKey4.String(): { - Type: "boolean", - Title: lo.ToPtr(""), - Description: lo.ToPtr(""), + Type: "boolean", }, sfKey5.String(): { - Type: "string", - Title: lo.ToPtr(""), - Description: lo.ToPtr(""), - Format: lo.ToPtr("date-time"), + Type: "string", + Format: lo.ToPtr("date-time"), }, sfKey6.String(): { - Type: "string", - Title: lo.ToPtr(""), - Description: lo.ToPtr(""), - Format: lo.ToPtr("uri"), + Type: "string", + Format: lo.ToPtr("uri"), }, } From c262c242f2c4d7d764cfee776593a28a95ff3301 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 27 Nov 2024 18:48:12 +0900 Subject: [PATCH 37/39] remove useless function --- server/internal/adapter/publicapi/types.go | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/server/internal/adapter/publicapi/types.go b/server/internal/adapter/publicapi/types.go index b2aa82f4a6..664127d7e9 100644 --- a/server/internal/adapter/publicapi/types.go +++ b/server/internal/adapter/publicapi/types.go @@ -212,8 +212,6 @@ func NewItemAsset(a *asset.Asset, urlResolver asset.URLResolver) ItemAsset { } } -const defaultJSONSchemaVersion = "https://json-schema.org/draft/2020-12/schema" - type SchemaJSON struct { Id *string `json:"$id,omitempty"` Schema *string `json:"$schema,omitempty"` @@ -234,17 +232,6 @@ type SchemaJSONProperties struct { Type string `json:"type"` } -func NewSchemaJSON(id, title, description *string, pp map[string]SchemaJSONProperties) SchemaJSON { - return SchemaJSON{ - Schema: lo.ToPtr(defaultJSONSchemaVersion), - Id: id, - Title: title, - Description: description, - Type: "object", - Properties: pp, - } -} - // GeoJSON type GeoJSON = FeatureCollection From 6945f77e84cf248ff084e1ed40eec4bfbae2dab1 Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 27 Nov 2024 19:21:18 +0900 Subject: [PATCH 38/39] refactor --- server/pkg/exporters/schema_json.go | 63 +++-------------------------- 1 file changed, 6 insertions(+), 57 deletions(-) diff --git a/server/pkg/exporters/schema_json.go b/server/pkg/exporters/schema_json.go index 6a0fcf5150..c1a70d7bc6 100644 --- a/server/pkg/exporters/schema_json.go +++ b/server/pkg/exporters/schema_json.go @@ -47,7 +47,7 @@ func NewSchemaJSON(id, title, description *string, pp map[string]SchemaJSONPrope return res } -func BuildProperties(f schema.FieldList, gsMap map[id.GroupID]*schema.Schema) map[string]SchemaJSONProperties { +func buildPropertiesMap(f schema.FieldList, gsMap map[id.GroupID]*schema.Schema) map[string]SchemaJSONProperties { properties := make(map[string]SchemaJSONProperties) for _, field := range f { fieldType, format := determineTypeAndFormat(field.Type()) @@ -115,65 +115,14 @@ func BuildProperties(f schema.FieldList, gsMap map[id.GroupID]*schema.Schema) ma return properties } -func BuildItems(f schema.FieldList) *SchemaJSON { - properties := make(map[string]SchemaJSONProperties) - for _, field := range f { - fieldType, format := determineTypeAndFormat(field.Type()) - fieldSchema := SchemaJSONProperties{Type: fieldType} - if field.Name() != "" { - fieldSchema.Title = lo.ToPtr(field.Name()) - } - if field.Description() != "" { - fieldSchema.Description = lo.ToPtr(field.Description()) - } - if format != "" { - fieldSchema.Format = lo.ToPtr(format) - } +func BuildProperties(f schema.FieldList, gsMap map[id.GroupID]*schema.Schema) map[string]SchemaJSONProperties { + return buildPropertiesMap(f, gsMap) +} - field.TypeProperty().Match(schema.TypePropertyMatch{ - Text: func(f *schema.FieldText) { - if maxLength := f.MaxLength(); maxLength != nil { - fieldSchema.MaxLength = maxLength - properties[field.Key().String()] = fieldSchema - } - }, - TextArea: func(f *schema.FieldTextArea) { - if maxLength := f.MaxLength(); maxLength != nil { - fieldSchema.MaxLength = maxLength - } - }, - RichText: func(f *schema.FieldRichText) { - if maxLength := f.MaxLength(); maxLength != nil { - fieldSchema.MaxLength = maxLength - } - }, - Markdown: func(f *schema.FieldMarkdown) { - if maxLength := f.MaxLength(); maxLength != nil { - fieldSchema.MaxLength = maxLength - } - }, - Integer: func(f *schema.FieldInteger) { - if min := f.Min(); min != nil { - fieldSchema.Minimum = Int64ToFloat64(min) - } - if max := f.Max(); max != nil { - fieldSchema.Maximum = Int64ToFloat64(max) - } - }, - Number: func(f *schema.FieldNumber) { - if min := f.Min(); min != nil { - fieldSchema.Minimum = min - } - if max := f.Max(); max != nil { - fieldSchema.Maximum = max - } - }, - }) - properties[field.Key().String()] = fieldSchema - } +func BuildItems(f schema.FieldList) *SchemaJSON { return &SchemaJSON{ Type: "object", - Properties: properties, + Properties: buildPropertiesMap(f, nil), } } From f6c191a996cd2f0446c6d32c746c91f060c8e1aa Mon Sep 17 00:00:00 2001 From: nourbalaha Date: Wed, 27 Nov 2024 19:45:47 +0900 Subject: [PATCH 39/39] refactor --- server/pkg/exporters/schema_json.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/pkg/exporters/schema_json.go b/server/pkg/exporters/schema_json.go index c1a70d7bc6..8be4229217 100644 --- a/server/pkg/exporters/schema_json.go +++ b/server/pkg/exporters/schema_json.go @@ -86,10 +86,10 @@ func buildPropertiesMap(f schema.FieldList, gsMap map[id.GroupID]*schema.Schema) }, Integer: func(f *schema.FieldInteger) { if min := f.Min(); min != nil { - fieldSchema.Minimum = Int64ToFloat64(min) + fieldSchema.Minimum = int64ToFloat64(min) } if max := f.Max(); max != nil { - fieldSchema.Maximum = Int64ToFloat64(max) + fieldSchema.Maximum = int64ToFloat64(max) } }, Number: func(f *schema.FieldNumber) { @@ -126,7 +126,7 @@ func BuildItems(f schema.FieldList) *SchemaJSON { } } -func Int64ToFloat64(input *int64) *float64 { +func int64ToFloat64(input *int64) *float64 { if input == nil { return nil }