diff --git a/api/openapi.json b/api/openapi.json index f69b1b1..332b068 100644 --- a/api/openapi.json +++ b/api/openapi.json @@ -19,16 +19,40 @@ } ], "paths": { - "/health":{ - "get":{ + "/health": { + "get": { "summary": "Check the health of the server", "operationId": "healthCheck", "responses": { "200": { - "description": "Server is healthy" + "description": "Server is healthy", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } }, "503": { - "description": "Server is unhealthy" + "description": "Server is unhealthy", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } } } } @@ -133,16 +157,6 @@ "post": { "summary": "Create a new person", "operationId": "createPerson", - "parameters": [ - { - "name": "X-User-ID", - "in": "header", - "required": true, - "schema": { - "type": "integer" - } - } - ], "requestBody": { "required": true, "content": { @@ -218,7 +232,6 @@ "type": "integer" } } - ], "requestBody": { "required": true, @@ -472,6 +485,65 @@ } } }, + "patch": { + "summary": "Create a new person by Google ID with invite code", + "operationId": "createPersonByGoogleIdAndInviteCode", + "parameters": [ + { + "name": "google_id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "invite_code": { + "type": "string" + }, + "person": { + "$ref": "#/components/schemas/PersonRegistration" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Person created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Person" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + } + } + }, "get": { "summary": "Get a person by Google ID", "operationId": "getPersonByGoogleId", @@ -572,8 +644,8 @@ } } }, - "/person/{id}/recipes":{ - "get":{ + "/person/{id}/recipes": { + "get": { "summary": "Get recipes by person ID", "operationId": "getRecipesByPersonId", "parameters": [ @@ -602,12 +674,10 @@ "schema": { "type": "object", "properties": { - "recipeRelations":{ + "recipeRelations": { "type": "array", "items": { - - "$ref": "#/components/schemas/Likes" - + "$ref": "#/components/schemas/Likes" } }, "recipes": { @@ -617,12 +687,11 @@ } } } - } } } }, - "400":{ + "400": { "description": "Bad request", "content": { "application/json": { @@ -1860,7 +1929,7 @@ "type": "string", "nullable": true }, - "allow_admin_access":{ + "allow_admin_access": { "type": "array", "items": { "type": "object", @@ -1909,10 +1978,10 @@ "type": "string", "nullable": true }, - "others_said":{ + "others_said": { "nullable": true, "type": "array", - "items":{ + "items": { "type": "object", "properties": { "id": { @@ -1921,7 +1990,7 @@ "name": { "type": "string" }, - "said":{ + "said": { "type": "string" } } diff --git a/apps/app/src/lib/api/api.gen.ts b/apps/app/src/lib/api/api.gen.ts index bcc77f2..5d08eec 100644 --- a/apps/app/src/lib/api/api.gen.ts +++ b/apps/app/src/lib/api/api.gen.ts @@ -4,7 +4,24 @@ */ export interface paths { - "/person_and_relationship": { + "/health": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Check the health of the server */ + get: operations["healthCheck"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/person_and_relationship/{id}": { parameters: { query?: never; header?: never; @@ -46,14 +63,14 @@ export interface paths { cookie?: never; }; get?: never; - /** Update a person by ID */ - put: operations["updatePerson"]; + put?: never; post?: never; /** Soft delete a person by ID */ delete: operations["softDeletePerson"]; options?: never; head?: never; - patch?: never; + /** Update a person by ID */ + patch: operations["updatePerson"]; trace?: never; }; "/person/{id}/hard-delete": { @@ -108,6 +125,23 @@ export interface paths { patch?: never; trace?: never; }; + "/person/{id}/recipes": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get recipes by person ID */ + get: operations["getRecipesByPersonId"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/relationship": { parameters: { query?: never; @@ -150,14 +184,14 @@ export interface paths { cookie?: never; }; get?: never; - /** Update a recipe by ID */ - put: operations["updateRecipe"]; + put?: never; post?: never; /** Soft delete a recipe by ID */ delete: operations["softDeleteRecipe"]; options?: never; head?: never; - patch?: never; + /** Update a recipe by ID */ + patch: operations["updateRecipe"]; trace?: never; }; "/recipe/{id}/hard-delete": { @@ -200,7 +234,10 @@ export type webhooks = Record; export interface components { schemas: { PersonProperties: { - allow_admin_access?: boolean | null; + allow_admin_access?: { + id?: number; + name?: string; + }[] | null; invite_code?: string | null; google_id?: string | null; first_name?: string | null; @@ -360,6 +397,10 @@ export interface components { RecipeProperties: { name?: string | null; origin?: string | null; + allow_admin_access?: { + id?: number; + name?: string; + }[]; category?: string | null; /** Format: date */ first_recorded?: string | null; @@ -368,6 +409,11 @@ export interface components { instructions?: string[] | null; photo?: string | null; notes?: string | null; + others_said?: { + id?: number; + name?: string; + said?: string; + }[] | null; }; Recipe: { id?: number; @@ -395,13 +441,42 @@ export interface components { } export type $defs = Record; export interface operations { - createPersonAndRelationship: { + healthCheck: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; + requestBody?: never; + responses: { + /** @description Server is healthy */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Server is unhealthy */ + 503: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + createPersonAndRelationship: { + parameters: { + query?: never; + header: { + "X-User-ID": number; + }; + path: { + id: number; + }; + cookie?: never; + }; requestBody: { content: { "application/json": { @@ -423,12 +498,36 @@ export interface operations { }; }; }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; }; }; createPerson: { parameters: { query?: never; - header?: never; + header: { + "X-User-ID": number; + }; path?: never; cookie?: never; }; @@ -447,12 +546,91 @@ export interface operations { "application/json": components["schemas"]["Person"]; }; }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + }; + }; + softDeletePerson: { + parameters: { + query?: never; + header: { + "X-User-ID": number; + }; + path: { + id: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Person soft deleted */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; }; }; updatePerson: { parameters: { query?: never; - header?: never; + header: { + "X-User-ID": number; + }; path: { id: number; }; @@ -484,12 +662,36 @@ export interface operations { }; }; }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; }; }; - softDeletePerson: { + hardDeletePerson: { parameters: { query?: never; - header?: never; + header: { + "X-User-ID": number; + }; path: { id: number; }; @@ -497,7 +699,7 @@ export interface operations { }; requestBody?: never; responses: { - /** @description Person soft deleted */ + /** @description Person hard deleted */ 200: { headers: { [name: string]: unknown; @@ -515,28 +717,8 @@ export interface operations { }; }; }; - }; - }; - hardDeletePerson: { - parameters: { - query?: never; - header?: never; - path: { - id: number; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Person hard deleted */ - 200: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Bad request */ - 400: { + /** @description Internal server error */ + 500: { headers: { [name: string]: unknown; }; @@ -649,12 +831,85 @@ export interface operations { }; }; }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + }; + }; + getRecipesByPersonId: { + parameters: { + query?: never; + header: { + "X-User-ID": number; + }; + path: { + id: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Recipes retrieved */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + recipeRelations?: components["schemas"]["Likes"][]; + recipes?: components["schemas"]["Recipe"][]; + }; + }; + }; + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; }; }; createRelationship: { parameters: { query?: never; - header?: never; + header: { + "X-User-ID": number; + }; path?: never; cookie?: never; }; @@ -677,12 +932,36 @@ export interface operations { "application/json": components["schemas"]["Relationship"]; }; }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; }; }; getRelationship: { parameters: { query?: never; - header?: never; + header: { + "X-User-ID": number; + }; path: { id1: number; id2: number; @@ -711,12 +990,91 @@ export interface operations { }; }; }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + }; + }; + softDeleteRecipe: { + parameters: { + query?: never; + header: { + "X-User-ID": number; + }; + path: { + id: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Recipe soft deleted */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; }; }; updateRecipe: { parameters: { query?: never; - header?: never; + header: { + "X-User-ID": number; + }; path: { id: number; }; @@ -748,28 +1106,19 @@ export interface operations { }; }; }; - }; - }; - softDeleteRecipe: { - parameters: { - query?: never; - header?: never; - path: { - id: number; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Recipe soft deleted */ - 200: { + /** @description Unauthorized */ + 401: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": { + msg?: string; + }; + }; }; - /** @description Bad request */ - 400: { + /** @description Internal server error */ + 500: { headers: { [name: string]: unknown; }; @@ -784,7 +1133,9 @@ export interface operations { hardDeleteRecipe: { parameters: { query?: never; - header?: never; + header: { + "X-User-ID": number; + }; path: { id: number; }; @@ -810,12 +1161,36 @@ export interface operations { }; }; }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; }; }; createRecipeRelationship: { parameters: { query?: never; - header?: never; + header: { + "X-User-ID": number; + }; path: { recipeId: number; }; @@ -852,6 +1227,28 @@ export interface operations { }; }; }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; }; }; deleteRecipeRelationship: { @@ -859,7 +1256,9 @@ export interface operations { query: { personId: number; }; - header?: never; + header: { + "X-User-ID": number; + }; path: { recipeId: number; }; @@ -885,6 +1284,28 @@ export interface operations { }; }; }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; }; }; } diff --git a/apps/db-handler/.env.example b/apps/db-handler/.env.example index a3cabe5..a6f62e5 100644 --- a/apps/db-handler/.env.example +++ b/apps/db-handler/.env.example @@ -1,3 +1,3 @@ MEMGRAPH_URI="bolt://localhost:7687" MEMGRAPH_USER="memgraph" -MEMGRAPH_PASSWORD="memgraph" \ No newline at end of file +MEMGRAPH_PASSWORD="memgraph"5 \ No newline at end of file diff --git a/apps/db-handler/.golangci.yml b/apps/db-handler/.golangci.yml index 3d78eb9..7d41257 100644 --- a/apps/db-handler/.golangci.yml +++ b/apps/db-handler/.golangci.yml @@ -1,92 +1,30 @@ -linters-settings: - depguard: - rules: - logger: - deny: - # logging is allowed only by logutils.Log, - # logrus is allowed to use only in logutils package. - - pkg: "github.com/sirupsen/logrus" - desc: logging is allowed only by logutils.Log. - - pkg: "github.com/pkg/errors" - desc: Should be replaced by standard lib errors package. - - pkg: "github.com/instana/testify" - desc: It's a fork of github.com/stretchr/testify. - dupl: - threshold: 100 - funlen: - lines: -1 # the number of lines (code + empty lines) is not a right metric and leads to code without empty line or one-liner. - statements: 50 - goconst: - min-len: 2 - min-occurrences: 3 - gocritic: - enabled-tags: - - diagnostic - - experimental - - opinionated - - performance - - style - disabled-checks: - - dupImport # https://github.com/go-critic/go-critic/issues/845 - - ifElseChain - - octalLiteral - - whyNoLint - gocyclo: - min-complexity: 15 - gofmt: - rewrite-rules: - - pattern: 'interface{}' - replacement: 'any' - govet: - settings: - printf: - funcs: - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf - - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf - enable: - - nilness - - shadow - errorlint: - asserts: false - lll: - line-length: 140 - misspell: - locale: US - nolintlint: - allow-unused: false # report any unused nolint directives - require-explanation: false # don't require an explanation for nolint directives - require-specific: false # don't require nolint directives to be specific about which linter is being skipped - revive: - rules: - - name: unexported-return - disabled: true - - name: unused-parameter +version: "2" linters: - disable-all: true + default: none + # This list of linters is not a recommendation (same thing for all this configuration file). + # We intentionally use a limited set of linters. + # See the comment on top of this file. enable: - bodyclose + - copyloopvar - depguard - dogsled - dupl - errcheck - errorlint - - exportloopref - funlen - gocheckcompilerdirectives - gochecknoinits - goconst - gocritic - gocyclo - - gofmt - - goimports - - gomnd + - godox + - mnd - goprintffuncname - gosec - - gosimple - govet + - intrange - ineffassign - lll - misspell @@ -95,24 +33,114 @@ linters: - nolintlint - revive - staticcheck - - stylecheck - - typecheck + - testifylint - unconvert - unparam - unused - whitespace - # don't enable: - # - asciicheck - # - gochecknoglobals - # - gocognit - # - godot - # - godox - # - goerr113 - # - nestif - # - prealloc - # - testpackage - # - wsl + settings: + depguard: + rules: + logger: + deny: + # logging is allowed only by zap.Logger., + - pkg: "github.com/sirupsen/logrus" + desc: logging is allowed only by zap.Logger. + - pkg: "github.com/pkg/errors" + desc: Should be replaced by standard lib errors package. + - pkg: "github.com/instana/testify" + desc: It's a fork of github.com/stretchr/testify. -run: - timeout: 5m + dupl: + threshold: 100 + funlen: + lines: -1 # the number of lines (code + empty lines) is not a right metric and leads to code without empty line or one-liner. + statements: 60 + goconst: + min-len: 2 + min-occurrences: 3 + gocritic: + enabled-tags: + - diagnostic + - experimental + - opinionated + - performance + - style + disabled-checks: + - dupImport # https://github.com/go-critic/go-critic/issues/845 + - ifElseChain + - octalLiteral + - whyNoLint + gocyclo: + min-complexity: 15 + godox: + keywords: + - FIXME + mnd: + # don't include the "operation" and "assign" + checks: + - argument + - case + - condition + - return + ignored-numbers: + - '0' + - '1' + - '2' + - '3' + ignored-functions: + - strings.SplitN + govet: + enable-all: true + errorlint: + asserts: false + lll: + line-length: 140 + misspell: + locale: US + ignore-rules: + - "importas" # linter name + nolintlint: + allow-unused: false # report any unused nolint directives + require-explanation: true # require an explanation for nolint directives + require-specific: true # require nolint directives to be specific about which linter is being skipped + revive: + rules: + - name: indent-error-flow + - name: unexported-return + disabled: true + - name: unused-parameter + - name: unused-receiver + + exclusions: + presets: + - comments + - std-error-handling + - common-false-positives + - legacy + paths: + - internal/api/api.gen.go # generated code + + rules: + - path: (.+)_test\.go + linters: + - dupl + - mnd + - lll + +formatters: + enable: + - gofmt + - goimports + settings: + gofmt: + rewrite-rules: + - pattern: 'interface{}' + replacement: 'any' + goimports: + local-prefixes: + - github.com/golangci/golangci-lint/v2 + exclusions: + paths: + - internal/api/api.gen.go # generated code diff --git a/apps/db-handler/dockerfile b/apps/db-handler/dockerfile index a34b672..b9145aa 100644 --- a/apps/db-handler/dockerfile +++ b/apps/db-handler/dockerfile @@ -6,13 +6,15 @@ COPY . . RUN go get ./... -RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o backend +RUN go generate ./... + +RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o db-adapter RUN apk update && apk add ca-certificates && update-ca-certificates FROM --platform=$TARGETPLATFORM busybox:1.36.1 COPY --from=build /etc/ssl/certs /etc/ssl/certs -COPY --from=build /app/backend /app/ +COPY --from=build /app/db-adapter /app/ -CMD [ "/app/backend" ] \ No newline at end of file +CMD [ "/app/db-adapter" ] \ No newline at end of file diff --git a/apps/db-handler/go.mod b/apps/db-handler/go.mod index 0da6f9d..7a6ee0a 100644 --- a/apps/db-handler/go.mod +++ b/apps/db-handler/go.mod @@ -3,35 +3,41 @@ module github.com/vcscsvcscs/GenerationsHeritage/apps/db-adapter go 1.24 require ( - github.com/gin-contrib/cors v1.7.2 + github.com/gin-contrib/cors v1.7.4 + github.com/gin-contrib/zap v1.1.4 github.com/gin-gonic/gin v1.10.0 github.com/google/uuid v1.6.0 - github.com/neo4j/neo4j-go-driver/v5 v5.27.0 + github.com/neo4j/neo4j-go-driver/v5 v5.28.0 github.com/oapi-codegen/runtime v1.1.1 - github.com/vcscsvcscs/GenerationsHeritage v0.0.0-20241228130259-47dca8ed3d6f + github.com/spf13/viper v1.20.0 + github.com/stretchr/testify v1.10.0 + go.uber.org/zap v1.27.0 golang.org/x/net v0.37.0 ) require ( github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect - github.com/bytedance/sonic v1.12.6 // indirect - github.com/bytedance/sonic/loader v0.2.1 // indirect - github.com/cloudwego/base64x v0.1.4 // indirect + github.com/bytedance/sonic v1.13.2 // indirect + github.com/bytedance/sonic/loader v0.2.4 // indirect + github.com/cloudwego/base64x v0.1.5 // indirect github.com/cloudwego/iasm v0.2.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect - github.com/gabriel-vasile/mimetype v1.4.7 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/getkin/kin-openapi v0.127.0 // indirect - github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-contrib/sse v1.0.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.23.0 // indirect - github.com/goccy/go-json v0.10.4 // indirect + github.com/go-playground/validator/v10 v10.25.0 // indirect + github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/goccy/go-json v0.10.5 // indirect github.com/invopop/yaml v0.3.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -41,20 +47,28 @@ require ( github.com/oapi-codegen/oapi-codegen/v2 v2.4.1 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect + github.com/sagikazarmark/locafero v0.8.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect - github.com/stretchr/testify v1.10.0 // indirect + github.com/spf13/afero v1.14.0 // indirect + github.com/spf13/cast v1.7.1 // indirect + github.com/spf13/pflag v1.0.6 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect - golang.org/x/arch v0.12.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/arch v0.15.0 // indirect golang.org/x/crypto v0.36.0 // indirect golang.org/x/mod v0.24.0 // indirect golang.org/x/sync v0.12.0 // indirect golang.org/x/sys v0.31.0 // indirect golang.org/x/text v0.23.0 // indirect golang.org/x/tools v0.31.0 // indirect - google.golang.org/protobuf v1.36.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/apps/db-handler/go.sum b/apps/db-handler/go.sum index b110959..c909a4d 100644 --- a/apps/db-handler/go.sum +++ b/apps/db-handler/go.sum @@ -4,14 +4,20 @@ github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/bytedance/sonic v1.12.6 h1:/isNmCUF2x3Sh8RAp/4mh4ZGkcFAX/hLrzrK3AvpRzk= github.com/bytedance/sonic v1.12.6/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= +github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= +github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E= github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY= +github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4= +github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -20,17 +26,28 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58= github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 h1:PRxIJD8XjimM5aTknUK9w6DHLDox2r2M3DI4i2pnd3w= github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5qlB+mlV1okblJqcSMtR4c52UKxDiX9GRBS8+Q= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA= github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU= +github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= github.com/getkin/kin-openapi v0.127.0 h1:Mghqi3Dhryf3F8vR370nN67pAERW+3a95vomb3MAREY= github.com/getkin/kin-openapi v0.127.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= github.com/gin-contrib/cors v1.7.2 h1:oLDHxdg8W/XDoN/8zamqk/Drgt4oVZDvaV0YmvVICQw= github.com/gin-contrib/cors v1.7.2/go.mod h1:SUJVARKgQ40dmrzgXEVxj2m7Ig1v1qIboQkPDTQ9t2E= +github.com/gin-contrib/cors v1.7.4 h1:/fC6/wk7rCRtqKqki8lLr2Xq+hnV49aXDLIuSek9g4k= +github.com/gin-contrib/cors v1.7.4/go.mod h1:vGc/APSgLMlQfEJV5NAzkrAHb0C8DetL3K6QZuvGii0= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E= +github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0= +github.com/gin-contrib/zap v1.1.4 h1:xvxTybg6XBdNtcQLH3Tf0lFr4vhDkwzgLLrIGlNTqIo= +github.com/gin-contrib/zap v1.1.4/go.mod h1:7lgEpe91kLbeJkwBTPgtVBy4zMa6oSBEcvj662diqKQ= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= @@ -45,11 +62,17 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o= github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8= +github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -81,6 +104,8 @@ github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPci github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -102,8 +127,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/neo4j/neo4j-go-driver/v5 v5.27.0 h1:YdsIxDjAQbjlP/4Ha9B/gF8Y39UdgdTwCyihSxy8qTw= -github.com/neo4j/neo4j-go-driver/v5 v5.27.0/go.mod h1:Vff8OwT7QpLm7L2yYr85XNWe9Rbqlbeb9asNXJTHO4k= +github.com/neo4j/neo4j-go-driver/v5 v5.28.0 h1:chDT68PHNa8JZRmjSkGzAbk1weLWo4rMtDvccvpobg0= +github.com/neo4j/neo4j-go-driver/v5 v5.28.0/go.mod h1:Vff8OwT7QpLm7L2yYr85XNWe9Rbqlbeb9asNXJTHO4k= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -132,14 +157,32 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= +github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= +github.com/sagikazarmark/locafero v0.8.0 h1:mXaMVw7IqxNBxfv3LdWt9MDmcWDQ1fagDH918lOdVaQ= +github.com/sagikazarmark/locafero v0.8.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/speakeasy-api/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= +github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= +github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= +github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= +github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.20.0 h1:zrxIyR3RQIOsarIrgL8+sAvALXul9jeEPa06Y0Ph6vY= +github.com/spf13/viper v1.20.0/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -147,19 +190,28 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/vcscsvcscs/GenerationsHeritage v0.0.0-20241228130259-47dca8ed3d6f h1:guHwv0Ae4YTYLKnhhMYhuUrM/bYpEVcIxU/DVvVZvrQ= -github.com/vcscsvcscs/GenerationsHeritage v0.0.0-20241228130259-47dca8ed3d6f/go.mod h1:13vdMuVr8qc2tPTH2mO1hedv1fb++3PuBm41YMWffak= github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg= golang.org/x/arch v0.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw= +golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -224,8 +276,10 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ= -google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/apps/db-handler/internal/api/authorization_by_id.go b/apps/db-handler/internal/api/authorization_by_id.go new file mode 100644 index 0000000..778f64e --- /dev/null +++ b/apps/db-handler/internal/api/authorization_by_id.go @@ -0,0 +1 @@ +package api diff --git a/apps/db-handler/internal/api/createPerson.go b/apps/db-handler/internal/api/createPerson.go deleted file mode 100644 index 9481b9b..0000000 --- a/apps/db-handler/internal/api/createPerson.go +++ /dev/null @@ -1,49 +0,0 @@ -package handlers - -import ( - "encoding/json" - "log" - "net/http" - - "github.com/gin-gonic/gin" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/vcscsvcscs/GenerationsHeritage/pkg/memgraph" -) - -func CreatePerson(driver neo4j.DriverWithContext) gin.HandlerFunc { - return func(c *gin.Context) { - if c.Request.Body == nil || c.ContentType() != "application/json" { - log.Printf("ip: %s error: request body is empty or content type is not application/json", c.ClientIP()) - c.JSON(http.StatusBadRequest, gin.H{"error": "content type must be application/json and request body must not be empty"}) - - return - } - - var person memgraph.Person - err := json.NewDecoder(c.Request.Body).Decode(&person) - if err != nil { - log.Printf("ip: %s error: %s", c.ClientIP(), err.Error()) - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"}) - - return - } - - if err := person.Verify(); err != nil { - log.Printf("ip: %s error: %s", c.ClientIP(), err.Error()) - c.JSON(http.StatusBadRequest, gin.H{"error": "contains-forbidden-characters"}) - - return - } - - person.ID = c.GetString("id") - rec, err := person.CreatePerson(driver) - if err != nil { - log.Printf("ip: %s error: %s", c.ClientIP(), err.Error()) - c.JSON(http.StatusBadRequest, gin.H{"error": "already-exists"}) - - return - } - - c.JSON(http.StatusCreated, gin.H{"person": rec.AsMap()}) - } -} diff --git a/apps/db-handler/internal/api/createRelationship.go b/apps/db-handler/internal/api/createRelationship.go deleted file mode 100644 index c80c783..0000000 --- a/apps/db-handler/internal/api/createRelationship.go +++ /dev/null @@ -1,32 +0,0 @@ -package handlers - -import ( - "log" - "net/http" - - "github.com/gin-gonic/gin" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/vcscsvcscs/GenerationsHeritage/pkg/memgraph" -) - -func CreateRelationship(driver neo4j.DriverWithContext) gin.HandlerFunc { - return func(c *gin.Context) { - var relationship memgraph.Relationship - if err := c.ShouldBindJSON(&relationship); err != nil { - log.Printf("ip: %s error: %s", c.ClientIP(), err) - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - - return - } - - rec, err := relationship.CreateRelationship(driver) - if err != nil { - log.Printf("ip: %s error: %s", c.ClientIP(), err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "internal server error"}) - - return - } - - c.JSON(http.StatusCreated, gin.H{"relationship": rec.AsMap()}) - } -} diff --git a/apps/db-handler/internal/api/create_relationship_and_person.go b/apps/db-handler/internal/api/create_relationship_and_person.go deleted file mode 100644 index fbc570c..0000000 --- a/apps/db-handler/internal/api/create_relationship_and_person.go +++ /dev/null @@ -1,32 +0,0 @@ -package handlers - -import ( - "log" - "net/http" - - "github.com/gin-gonic/gin" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/vcscsvcscs/GenerationsHeritage/pkg/memgraph" -) - -func CreateRelationshipAndPerson(driver neo4j.DriverWithContext) gin.HandlerFunc { - return func(c *gin.Context) { - var rp memgraph.RelationshipAndPerson - if err := c.ShouldBindJSON(&rp); err != nil { - log.Printf("ip: %s error: %s", c.ClientIP(), err) - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - - return - } - - rec, err := rp.CreateRelationshipAndPerson(driver) - if err != nil { - log.Printf("ip: %s error: %s", c.ClientIP(), err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "internal server error"}) - - return - } - - c.JSON(http.StatusCreated, gin.H{"relationship": rec.AsMap()}) - } -} diff --git a/apps/db-handler/internal/api/deletePerson.go b/apps/db-handler/internal/api/deletePerson.go deleted file mode 100644 index df9ef99..0000000 --- a/apps/db-handler/internal/api/deletePerson.go +++ /dev/null @@ -1,48 +0,0 @@ -package handlers - -import ( - "encoding/json" - "log" - "net/http" - - "github.com/gin-gonic/gin" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/vcscsvcscs/GenerationsHeritage/pkg/memgraph" -) - -func DeletePerson(driver neo4j.DriverWithContext) gin.HandlerFunc { - return func(c *gin.Context) { - if c.Request.Body == nil || c.ContentType() != "application/json" { - log.Printf("ip: %s error: request body is empty or content type is not application/json", c.ClientIP()) - c.JSON(http.StatusBadRequest, gin.H{"error": "content type must be application/json and request body must not be empty"}) - - return - } - - var person memgraph.Person - err := json.NewDecoder(c.Request.Body).Decode(&person) - if err != nil { - log.Printf("ip: %s error: %s", c.ClientIP(), err) - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"}) - - return - } - - if person.ID != "" { - log.Printf("ip: %s error: %s", c.ClientIP(), err) - c.JSON(http.StatusBadRequest, gin.H{"error": "no person ID provided"}) - - return - } - - err = person.DeletePerson(driver) - if err != nil { - log.Printf("ip: %s error: %s", c.ClientIP(), err) - c.JSON(http.StatusNotFound, gin.H{"error": "could not delete person with ID provided"}) - - return - } - - c.JSON(http.StatusOK, gin.H{"status": "person deleted successfully"}) - } -} diff --git a/apps/db-handler/internal/api/deleteRelationship.go b/apps/db-handler/internal/api/deleteRelationship.go deleted file mode 100644 index e1cf576..0000000 --- a/apps/db-handler/internal/api/deleteRelationship.go +++ /dev/null @@ -1,32 +0,0 @@ -package handlers - -import ( - "log" - "net/http" - - "github.com/gin-gonic/gin" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/vcscsvcscs/GenerationsHeritage/pkg/memgraph" -) - -func DeleteRelationship(driver neo4j.DriverWithContext) gin.HandlerFunc { - return func(c *gin.Context) { - var relationship memgraph.Relationship - if err := c.ShouldBindJSON(&relationship); err != nil { - log.Printf("ip: %s error: %s", c.ClientIP(), err) - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - - return - } - - err := relationship.DeleteRelationship(driver) - if err != nil { - log.Printf("ip: %s error: %s", c.ClientIP(), err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "internal server error"}) - - return - } - - c.JSON(http.StatusAccepted, gin.H{"status": "relationship deleted successfully"}) - } -} diff --git a/apps/db-handler/internal/api/person.go b/apps/db-handler/internal/api/person.go new file mode 100644 index 0000000..7c52956 --- /dev/null +++ b/apps/db-handler/internal/api/person.go @@ -0,0 +1,11 @@ +package api + +import "github.com/gin-gonic/gin" + +func (srv *server) CreatePerson(c *gin.Context) {} + +func (srv *server) SoftDeletePerson(c *gin.Context, id int, params SoftDeletePersonParams) {} + +func (srv *server) UpdatePerson(c *gin.Context, id int, params UpdatePersonParams) {} + +func (srv *server) HardDeletePerson(c *gin.Context, id int, params HardDeletePersonParams) {} diff --git a/apps/db-handler/internal/api/person_and_relationship.go b/apps/db-handler/internal/api/person_and_relationship.go new file mode 100644 index 0000000..d44229d --- /dev/null +++ b/apps/db-handler/internal/api/person_and_relationship.go @@ -0,0 +1,6 @@ +package api + +import "github.com/gin-gonic/gin" + +func (srv *server) CreatePersonAndRelationship(c *gin.Context, id int, params CreatePersonAndRelationshipParams) { +} diff --git a/apps/db-handler/internal/api/person_family_tree.go b/apps/db-handler/internal/api/person_family_tree.go new file mode 100644 index 0000000..4a0f130 --- /dev/null +++ b/apps/db-handler/internal/api/person_family_tree.go @@ -0,0 +1,5 @@ +package api + +import "github.com/gin-gonic/gin" + +func (srv *server) GetFamilyTreeById(c *gin.Context, id int) {} diff --git a/apps/db-handler/internal/api/person_google.go b/apps/db-handler/internal/api/person_google.go new file mode 100644 index 0000000..f981ec8 --- /dev/null +++ b/apps/db-handler/internal/api/person_google.go @@ -0,0 +1,9 @@ +package api + +import "github.com/gin-gonic/gin" + +func (srv *server) GetPersonByGoogleId(c *gin.Context, googleId string) {} + +func (srv *server) CreatePersonByGoogleIdAndInviteCode(c *gin.Context, googleId string) {} + +func (srv *server) CreatePersonByGoogleId(c *gin.Context, googleId string) {} diff --git a/apps/db-handler/internal/api/person_recipes.go b/apps/db-handler/internal/api/person_recipes.go new file mode 100644 index 0000000..4ceb0f6 --- /dev/null +++ b/apps/db-handler/internal/api/person_recipes.go @@ -0,0 +1,5 @@ +package api + +import "github.com/gin-gonic/gin" + +func (srv *server) GetRecipesByPersonId(c *gin.Context, id int, params GetRecipesByPersonIdParams) {} diff --git a/apps/db-handler/internal/api/recipe_relationship.go b/apps/db-handler/internal/api/recipe_relationship.go new file mode 100644 index 0000000..a0e8813 --- /dev/null +++ b/apps/db-handler/internal/api/recipe_relationship.go @@ -0,0 +1,9 @@ +package api + +import "github.com/gin-gonic/gin" + +func (srv *server) DeleteRecipeRelationship(c *gin.Context, recipeId int, params DeleteRecipeRelationshipParams) { +} + +func (srv *server) CreateRecipeRelationship(c *gin.Context, recipeId int, params CreateRecipeRelationshipParams) { +} diff --git a/apps/db-handler/internal/api/recipes.go b/apps/db-handler/internal/api/recipes.go new file mode 100644 index 0000000..4f0cb07 --- /dev/null +++ b/apps/db-handler/internal/api/recipes.go @@ -0,0 +1,9 @@ +package api + +import "github.com/gin-gonic/gin" + +func (srv *server) SoftDeleteRecipe(c *gin.Context, id int, params SoftDeleteRecipeParams) {} + +func (srv *server) UpdateRecipe(c *gin.Context, id int, params UpdateRecipeParams) {} + +func (srv *server) HardDeleteRecipe(c *gin.Context, id int, params HardDeleteRecipeParams) {} diff --git a/apps/db-handler/internal/api/relationship.go b/apps/db-handler/internal/api/relationship.go new file mode 100644 index 0000000..12579c6 --- /dev/null +++ b/apps/db-handler/internal/api/relationship.go @@ -0,0 +1,7 @@ +package api + +import "github.com/gin-gonic/gin" + +func (srv *server) CreateRelationship(c *gin.Context, params CreateRelationshipParams) {} + +func (srv *server) GetRelationship(c *gin.Context, id1 int, id2 int, params GetRelationshipParams) {} diff --git a/apps/db-handler/internal/api/server.go b/apps/db-handler/internal/api/server.go new file mode 100644 index 0000000..9788854 --- /dev/null +++ b/apps/db-handler/internal/api/server.go @@ -0,0 +1,34 @@ +package api + +import ( + "github.com/gin-gonic/gin" + "github.com/neo4j/neo4j-go-driver/v5/neo4j" + "github.com/vcscsvcscs/GenerationsHeritage/apps/db-adapter/pkg/gin/healthcheck" + "go.uber.org/zap" +) + +type server struct { + db neo4j.DriverWithContext + health healthcheck.HealthCheck + logger *zap.Logger +} + +func New(logger *zap.Logger, drv neo4j.DriverWithContext, healthcheck healthcheck.HealthCheck) ServerInterface { + if logger == nil { + panic("logger is required") + } + + if drv == nil { + panic("neo4j driver is required") + } + + if healthcheck == nil { + panic("healthcheck is required") + } + + return &server{db: drv, health: healthcheck, logger: logger} +} + +func (srv *server) HealthCheck(c *gin.Context) { + srv.health.HealthCheckHandler(c) +} diff --git a/apps/db-handler/internal/api/server_test.go b/apps/db-handler/internal/api/server_test.go new file mode 100644 index 0000000..0b08be9 --- /dev/null +++ b/apps/db-handler/internal/api/server_test.go @@ -0,0 +1,77 @@ +package api + +import ( + "testing" + + "github.com/gin-gonic/gin" + "github.com/neo4j/neo4j-go-driver/v5/neo4j" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "go.uber.org/zap" +) + +type mockHealthCheck struct { + mock.Mock +} + +func (m *mockHealthCheck) HealthCheckHandler(c *gin.Context) { + m.Called(c) +} + +func (m *mockHealthCheck) SetStatus(status string) { + m.Called(status) +} + +func (m *mockHealthCheck) GetStatus() string { + args := m.Called() + + return args.String(0) +} + +func TestNewServer(t *testing.T) { + logger := zap.NewNop() + mockDriver, err := neo4j.NewDriverWithContext("bolt+ssc://memgraph:7687", nil) + assert.NoError(t, err) + mockHealth := &mockHealthCheck{} + + t.Run("should create a new server instance", func(t *testing.T) { + t.Parallel() + srv := New(logger, mockDriver, mockHealth) + assert.NotNil(t, srv) + }) + + t.Run("should panic if logger is nil", func(t *testing.T) { + t.Parallel() + assert.Panics(t, func() { + New(nil, mockDriver, mockHealth) + }) + }) + + t.Run("should panic if driver is nil", func(t *testing.T) { + t.Parallel() + assert.Panics(t, func() { + New(logger, nil, mockHealth) + }) + }) + + t.Run("should panic if healthcheck is nil", func(t *testing.T) { + t.Parallel() + assert.Panics(t, func() { + New(logger, mockDriver, nil) + }) + }) +} + +func TestHealthCheck(t *testing.T) { + mockHealth := &mockHealthCheck{} + srv := &server{health: mockHealth} + + t.Run("should call HealthCheckHandler", func(t *testing.T) { + mockHealth.On("HealthCheckHandler", mock.Anything).Once() + + c, _ := gin.CreateTestContext(nil) + srv.HealthCheck(c) + + mockHealth.AssertCalled(t, "HealthCheckHandler", c) + }) +} diff --git a/apps/db-handler/internal/api/updatePerson.go b/apps/db-handler/internal/api/updatePerson.go deleted file mode 100644 index f413643..0000000 --- a/apps/db-handler/internal/api/updatePerson.go +++ /dev/null @@ -1,48 +0,0 @@ -package handlers - -import ( - "encoding/json" - "log" - "net/http" - - "github.com/gin-gonic/gin" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/vcscsvcscs/GenerationsHeritage/pkg/memgraph" -) - -func UpdatePerson(driver neo4j.DriverWithContext) gin.HandlerFunc { - return func(c *gin.Context) { - if c.Request.Body == nil || c.ContentType() != "application/json" { - log.Printf("ip: %s error: request body is empty or content type is not application/json", c.ClientIP()) - c.JSON(http.StatusBadRequest, gin.H{"error": "content type must be application/json and request body must not be empty"}) - - return - } - - var person memgraph.Person - err := json.NewDecoder(c.Request.Body).Decode(&person) - if err != nil { - log.Printf("ip: %s error: %s", c.ClientIP(), err) - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"}) - - return - } - - if person.ID == "" { - log.Printf("ip: %s error: %s", c.ClientIP(), err) - c.JSON(http.StatusBadRequest, gin.H{"error": "No ID provided"}) - - return - } - - rec, err := person.UpdatePerson(driver) - if err != nil { - log.Printf("ip: %s error: %s", c.ClientIP(), err) - c.JSON(http.StatusNotFound, gin.H{"error": "could not update person with information provided"}) - - return - } - - c.JSON(http.StatusOK, gin.H{"person": rec.AsMap()}) - } -} diff --git a/apps/db-handler/internal/api/verifyRelationship.go b/apps/db-handler/internal/api/verifyRelationship.go deleted file mode 100644 index 5b3e9f9..0000000 --- a/apps/db-handler/internal/api/verifyRelationship.go +++ /dev/null @@ -1,32 +0,0 @@ -package handlers - -import ( - "log" - "net/http" - - "github.com/gin-gonic/gin" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/vcscsvcscs/GenerationsHeritage/pkg/memgraph" -) - -func VerifyRelationship(driver neo4j.DriverWithContext) gin.HandlerFunc { - return func(c *gin.Context) { - var relationship memgraph.Relationship - if err := c.ShouldBindJSON(&relationship); err != nil { - log.Printf("ip: %s error: %s", c.ClientIP(), err) - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - - return - } - - rec, err := relationship.VerifyRelationship(driver) - if err != nil { - log.Printf("ip: %s error: %s", c.ClientIP(), err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "internal server error"}) - - return - } - - c.JSON(http.StatusOK, gin.H{"relationship": rec.AsMap()}) - } -} diff --git a/apps/db-handler/internal/api/viewFamilyTree.go b/apps/db-handler/internal/api/viewFamilyTree.go deleted file mode 100644 index a9775c4..0000000 --- a/apps/db-handler/internal/api/viewFamilyTree.go +++ /dev/null @@ -1,55 +0,0 @@ -package handlers - -import ( - "context" - "log" - "net/http" - "time" - - "github.com/gin-gonic/gin" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" -) - -func ViewFamiliyTree(driver neo4j.DriverWithContext) gin.HandlerFunc { - return func(c *gin.Context) { - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close(ctx) - - id := c.GetString("id") - if id == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "id is required"}) - - return - } - - query := ` - MATCH (n:Person {id: $person_id})-[p:Parent*1..]->(family:Person) - OPTIONAL MATCH (family)-[c:Child]->(children:Person) - WITH family, p, children, c, n - OPTIONAL MATCH (children)<-[p2:Parent]-(OtherParents:Person) - WITH family, p, children, c, OtherParents, p2,n - OPTIONAL MATCH (family)-[s:Spouse]-(spouse:Person) - RETURN family, p, children, c, OtherParents, p2, spouse, s, n;` - - result, err := session.Run(ctx, query, map[string]any{"person_id": id}) - if err != nil { - log.Printf("ip: %s error: %s", c.ClientIP(), err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "internal server error"}) - - return - } - - rec, err := result.Collect(ctx) - if err != nil { - log.Printf("ip: %s error: %s", c.ClientIP(), err) - c.JSON(http.StatusNotFound, gin.H{"error": "could not find family tree for person with id: " + id}) - - return - } - - c.JSON(200, rec) - } -} diff --git a/apps/db-handler/internal/api/viewPerson.go b/apps/db-handler/internal/api/viewPerson.go deleted file mode 100644 index d15c16a..0000000 --- a/apps/db-handler/internal/api/viewPerson.go +++ /dev/null @@ -1,50 +0,0 @@ -package handlers - -import ( - "context" - "log" - "net/http" - "time" - - "github.com/gin-gonic/gin" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" -) - -func ViewPerson(driver neo4j.DriverWithContext) gin.HandlerFunc { - return func(c *gin.Context) { - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) - defer session.Close(ctx) - - id := c.Query("id") - if id == "" { - id = c.GetString("id") - } - - if id == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "id is required"}) - - return - } - - result, err := session.Run(ctx, "MATCH (n:Person) WHERE n.id = $person_id RETURN n;", map[string]any{"person_id": id}) - if err != nil { - log.Printf("ip: %s error: %s", c.ClientIP(), err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "internal server error"}) - - return - } - - rec, err := result.Single(ctx) - if err != nil { - log.Printf("ip: %s error: %s", c.ClientIP(), err) - c.JSON(http.StatusNotFound, gin.H{"error": "could not find person with information provided"}) - - return - } - - c.JSON(200, rec.AsMap()["n"]) - } -} diff --git a/apps/db-handler/main.go b/apps/db-handler/main.go index a6491f8..8dbd7e3 100644 --- a/apps/db-handler/main.go +++ b/apps/db-handler/main.go @@ -2,87 +2,94 @@ package main import ( "context" - "flag" - "log" + "errors" + "net/http" "os" "os/signal" "syscall" "time" "github.com/gin-contrib/cors" + ginzap "github.com/gin-contrib/zap" "github.com/gin-gonic/gin" - "github.com/vcscsvcscs/GenerationsHeritage/cmd/backend/handlers" - utilities "github.com/vcscsvcscs/GenerationsHeritage/pkg" - "github.com/vcscsvcscs/GenerationsHeritage/pkg/gin/healthcheck" - "github.com/vcscsvcscs/GenerationsHeritage/pkg/memgraph" - //"github.com/zitadel/zitadel-go/v3/pkg/authorization" - //"github.com/zitadel/zitadel-go/v3/pkg/authorization/oauth" - //"github.com/zitadel/zitadel-go/v3/pkg/zitadel" + "github.com/vcscsvcscs/GenerationsHeritage/apps/db-adapter/internal/api" + "github.com/vcscsvcscs/GenerationsHeritage/apps/db-adapter/pkg/gin/healthcheck" + "github.com/vcscsvcscs/GenerationsHeritage/apps/db-adapter/pkg/memgraph" + + "github.com/spf13/viper" + "go.uber.org/zap" ) var ( - cert = flag.String("cert", "/etc/gh-backend/ssl/tls.crt", "Specify the path of TLS cert") - key = flag.String("key", "/etc/gh-backend/ssl/tls.key", "Specify the path of TLS key") - httpsPort = flag.String("https", ":443", "Specify port for http secure hosting(example for format :443)") - httpPort = flag.String("http", ":80", "Specify port for http hosting(example for format :80)") - // zitadelAccessKey = flag.String("zitadel-access-key", "/etc/gh-backend/zitadel/api-key.json", "Specify the path of Zitadel access key") - // zitadelURI = flag.String("zitadel-uri", "zitadel.varghacsongor.hu", "Specify the Zitadel URI") - memgraphURI = flag.String("memgraph", "bolt+ssc://memgraph:7687", "Specify the Memgraph database URI") - memgraphUser = flag.String("memgraph-user", "", "Specify the Memgraph database user") - memgraphPass = flag.String("memgraph-pass", "", "Specify the Memgraph database password") - release = flag.Bool("release", false, "Set true to release build") - logToFile = flag.Bool("log-to-file", false, "Set true to log to file") - logToFileAndStd = flag.Bool("log-to-file-and-std", false, "Set true to log to file and std") - requestTimeout = time.Duration(*flag.Int("request-timeout", 20, "Set request timeout in seconds")) + httpPort string + memgraphURI string + memgraphUser string + memgraphPass string + production bool + requestTimeout time.Duration ) +func init() { + viper.AutomaticEnv() + + viper.SetDefault("HTTP_PORT", ":80") + viper.SetDefault("MEMGRAPH_URI", "bolt+ssc://memgraph:7687") + viper.SetDefault("MEMGRAPH_USER", "") + viper.SetDefault("MEMGRAPH_PASS", "") + viper.SetDefault("PRODUCTION", false) + viper.SetDefault("REQUEST_TIMEOUT", 20) + + httpPort = viper.GetString("HTTP_PORT") + memgraphURI = viper.GetString("MEMGRAPH_URI") + memgraphUser = viper.GetString("MEMGRAPH_USER") + memgraphPass = viper.GetString("MEMGRAPH_PASS") + production = viper.GetBool("PRODUCTION") + requestTimeout = time.Duration(viper.GetInt("REQUEST_TIMEOUT")) * time.Second +} + func main() { - flag.Parse() - if *release { - gin.SetMode(gin.ReleaseMode) + var logger *zap.Logger + var err error + if production { + logger, err = zap.NewProduction() + } else { + logger, _ = zap.NewDevelopment() } - utilities.SetupLogger(*logToFileAndStd, *logToFile) + if err != nil { + panic(err) + } hc := healthcheck.New() - memgraphDriver := memgraph.InitDatabase(*memgraphURI, *memgraphUser, *memgraphPass) + memgraphDriver := memgraph.InitDatabase(memgraphURI, memgraphUser, memgraphPass) router := gin.Default() router.Use(cors.New(cors.Config{ - AllowOrigins: []string{"http://localhost:5173", "http://localhost", "https://heritagebackend.varghacsongor.hu", "https://feature-add-frontend.generationsheritage.pages.dev/", "https://csalad.varghacsongor.hu/"}, + AllowOrigins: []string{"http://localhost:5173", "http://localhost"}, AllowCredentials: true, - AllowHeaders: []string{"Authorization", "id", "Content-Type"}, + AllowHeaders: []string{"X-User-ID", "Content-Type"}, MaxAge: 12 * time.Hour, })) - router.Use(gin.Recovery()) - //ctx := context.Background() + router.Use(ginzap.Ginzap(logger, time.RFC3339, true)) + router.Use(ginzap.RecoveryWithZap(logger, true)) - // Initiate the authorization by providing a zitadel configuration and a verifier. - // This example will use OAuth2 Introspection for this, therefore you will also need to provide the downloaded api key.json - //authZ, err := authorization.New(ctx, zitadel.New(*zitadelURI), oauth.DefaultAuthorization(*zitadelAccessKey)) - //if err != nil { - // log.Println("zitadel sdk could not initialize", "error", err) - // os.Exit(1) - //} + sApi := api.New(logger, memgraphDriver, hc) + api.RegisterHandlersWithOptions(router, sApi, api.GinServerOptions{}) - // Initialize the HTTP middleware by providing the authorization - //mw := middleware.New(authZ) - - //router.Use(auth(mw)) - router.GET("/health", hc.HealthCheckHandler()) - router.GET("/person", handlers.ViewPerson(memgraphDriver)) - router.POST("/person", handlers.CreatePerson(memgraphDriver)) - router.DELETE("/person", handlers.DeletePerson(memgraphDriver)) - router.PUT("/person", handlers.UpdatePerson(memgraphDriver)) - router.POST("/relationship", handlers.CreateRelationship(memgraphDriver)) - router.DELETE("/relationship", handlers.DeleteRelationship(memgraphDriver)) - router.PUT("/relationship", handlers.VerifyRelationship(memgraphDriver)) - router.POST("/createRelationshipAndPerson", handlers.CreateRelationshipAndPerson(memgraphDriver)) - router.GET("/familyTree", handlers.ViewFamiliyTree(memgraphDriver)) - - server := utilities.SetupHttpsServer(router, *cert, *key, *httpsPort, *httpPort, requestTimeout) + server := &http.Server{ + Addr: httpPort, + Handler: router, + ReadTimeout: requestTimeout * time.Second, + WriteTimeout: requestTimeout * time.Second, + } + go func() { + logger.Info("Starting server", zap.String("port", httpPort)) + if err := server.ListenAndServe(); err != nil && errors.Is(err, http.ErrServerClosed) { + logger.Fatal(err.Error()) + } + }() // Wait for interrupt signal to gracefully shutdown the server with some time to finish requests. quit := make(chan os.Signal, 1) @@ -91,16 +98,22 @@ func main() { // kill -9 is syscall.SIGKILL but can't be caught, so don't need to add it signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-quit - log.Println("Shutting down server...") + logger.Info("Shutting down server...") // The context is used to inform the server it has some seconds to finish // the request it is currently handling ctx, cancel := context.WithTimeout(context.Background(), requestTimeout*time.Second) defer cancel() + go func() { + if err := memgraphDriver.Close(context.WithoutCancel(ctx)); err != nil { + logger.Error("Memgraph driver forced to shutdown", zap.Error(err)) + } + }() + if err := server.Shutdown(ctx); err != nil { - log.Fatal("Server forced to shutdown:", err) + logger.Error("Server forced to shutdown", zap.Error(err)) } - log.Println("Server exiting") + logger.Info("Server exited") } diff --git a/apps/db-handler/pkg/fileExists.go b/apps/db-handler/pkg/file_exists.go similarity index 100% rename from apps/db-handler/pkg/fileExists.go rename to apps/db-handler/pkg/file_exists.go diff --git a/apps/db-handler/pkg/fileExists_test.go b/apps/db-handler/pkg/file_exists_test.go similarity index 100% rename from apps/db-handler/pkg/fileExists_test.go rename to apps/db-handler/pkg/file_exists_test.go diff --git a/apps/db-handler/pkg/gin/healthcheck/health_check.go b/apps/db-handler/pkg/gin/healthcheck/health_check.go index 1ebbe65..5f9fe34 100644 --- a/apps/db-handler/pkg/gin/healthcheck/health_check.go +++ b/apps/db-handler/pkg/gin/healthcheck/health_check.go @@ -10,7 +10,7 @@ import ( type HealthCheck interface { SetStatus(status string) GetStatus() string - HealthCheckHandler() gin.HandlerFunc + HealthCheckHandler(c *gin.Context) } type healthCheck struct { @@ -38,17 +38,15 @@ func (hc *healthCheck) GetStatus() string { return hc.status } -func (hc *healthCheck) HealthCheckHandler() gin.HandlerFunc { - return func(c *gin.Context) { - switch hc.GetStatus() { - case "nok": - c.JSON(http.StatusInternalServerError, gin.H{ - "status": hc.GetStatus(), - }) - default: - c.JSON(http.StatusOK, gin.H{ - "status": hc.GetStatus(), - }) - } +func (hc *healthCheck) HealthCheckHandler(c *gin.Context) { + switch hc.GetStatus() { + case "nok": + c.JSON(http.StatusServiceUnavailable, gin.H{ + "msg": hc.GetStatus(), + }) + default: + c.JSON(http.StatusOK, gin.H{ + "msg": hc.GetStatus(), + }) } } diff --git a/apps/db-handler/pkg/gin/healthcheck/health_check_test.go b/apps/db-handler/pkg/gin/healthcheck/health_check_test.go index 92dd268..3eea4fc 100644 --- a/apps/db-handler/pkg/gin/healthcheck/health_check_test.go +++ b/apps/db-handler/pkg/gin/healthcheck/health_check_test.go @@ -83,9 +83,11 @@ func TestHealthCheck_SetStatus(t *testing.T) { } func TestHealthCheck_HealthCheckHandler(t *testing.T) { + t.Parallel() + r := gin.Default() hc := New() - r.GET("/health", hc.HealthCheckHandler()) + r.GET("/health", hc.HealthCheckHandler) type args struct { status string } @@ -100,7 +102,7 @@ func TestHealthCheck_HealthCheckHandler(t *testing.T) { args: args{ status: "ok", }, - want: `{"status":"ok"}`, + want: `{"msg":"ok"}`, statusCode: http.StatusOK, }, { @@ -108,12 +110,13 @@ func TestHealthCheck_HealthCheckHandler(t *testing.T) { args: args{ status: "nok", }, - want: `{"status":"nok"}`, - statusCode: http.StatusInternalServerError, + want: `{"msg":"nok"}`, + statusCode: http.StatusServiceUnavailable, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + t.Parallel() hc.SetStatus(tt.args.status) w := httptest.NewRecorder() diff --git a/apps/db-handler/internal/api/queries/create_directed_relationship.cypher b/apps/db-handler/pkg/memgraph/queries/create_directed_relationship.cypher similarity index 100% rename from apps/db-handler/internal/api/queries/create_directed_relationship.cypher rename to apps/db-handler/pkg/memgraph/queries/create_directed_relationship.cypher diff --git a/apps/db-handler/internal/api/queries/create_person.cypher b/apps/db-handler/pkg/memgraph/queries/create_person.cypher similarity index 100% rename from apps/db-handler/internal/api/queries/create_person.cypher rename to apps/db-handler/pkg/memgraph/queries/create_person.cypher diff --git a/apps/db-handler/internal/api/queries/create_relationship.cypher b/apps/db-handler/pkg/memgraph/queries/create_relationship.cypher similarity index 100% rename from apps/db-handler/internal/api/queries/create_relationship.cypher rename to apps/db-handler/pkg/memgraph/queries/create_relationship.cypher diff --git a/apps/db-handler/internal/api/queries/create_two_directed_relationships.cypher b/apps/db-handler/pkg/memgraph/queries/create_two_directed_relationships.cypher similarity index 100% rename from apps/db-handler/internal/api/queries/create_two_directed_relationships.cypher rename to apps/db-handler/pkg/memgraph/queries/create_two_directed_relationships.cypher diff --git a/apps/db-handler/internal/api/queries/get_family_tree_by_id.cypher b/apps/db-handler/pkg/memgraph/queries/get_family_tree_by_id.cypher similarity index 100% rename from apps/db-handler/internal/api/queries/get_family_tree_by_id.cypher rename to apps/db-handler/pkg/memgraph/queries/get_family_tree_by_id.cypher diff --git a/apps/db-handler/internal/api/queries/get_people_by_properties.cypher b/apps/db-handler/pkg/memgraph/queries/get_people_by_properties.cypher similarity index 100% rename from apps/db-handler/internal/api/queries/get_people_by_properties.cypher rename to apps/db-handler/pkg/memgraph/queries/get_people_by_properties.cypher diff --git a/apps/db-handler/internal/api/queries/get_person_by_google_id.cypher b/apps/db-handler/pkg/memgraph/queries/get_person_by_google_id.cypher similarity index 100% rename from apps/db-handler/internal/api/queries/get_person_by_google_id.cypher rename to apps/db-handler/pkg/memgraph/queries/get_person_by_google_id.cypher diff --git a/apps/db-handler/internal/api/queries/get_person_by_id.cypher b/apps/db-handler/pkg/memgraph/queries/get_person_by_id.cypher similarity index 100% rename from apps/db-handler/internal/api/queries/get_person_by_id.cypher rename to apps/db-handler/pkg/memgraph/queries/get_person_by_id.cypher diff --git a/apps/db-handler/internal/api/queries/get_relationship.cypher b/apps/db-handler/pkg/memgraph/queries/get_relationship.cypher similarity index 100% rename from apps/db-handler/internal/api/queries/get_relationship.cypher rename to apps/db-handler/pkg/memgraph/queries/get_relationship.cypher diff --git a/apps/db-handler/internal/api/queries/hard_delete_person_by_id.cypher b/apps/db-handler/pkg/memgraph/queries/hard_delete_person_by_id.cypher similarity index 100% rename from apps/db-handler/internal/api/queries/hard_delete_person_by_id.cypher rename to apps/db-handler/pkg/memgraph/queries/hard_delete_person_by_id.cypher diff --git a/apps/db-handler/internal/api/queries/schema.cypher b/apps/db-handler/pkg/memgraph/queries/schema.cypher similarity index 100% rename from apps/db-handler/internal/api/queries/schema.cypher rename to apps/db-handler/pkg/memgraph/queries/schema.cypher diff --git a/apps/db-handler/internal/api/queries/soft_delete_person_by_id.cypher b/apps/db-handler/pkg/memgraph/queries/soft_delete_person_by_id.cypher similarity index 100% rename from apps/db-handler/internal/api/queries/soft_delete_person_by_id.cypher rename to apps/db-handler/pkg/memgraph/queries/soft_delete_person_by_id.cypher diff --git a/apps/db-handler/internal/api/queries/update_person.cypher b/apps/db-handler/pkg/memgraph/queries/update_person.cypher similarity index 100% rename from apps/db-handler/internal/api/queries/update_person.cypher rename to apps/db-handler/pkg/memgraph/queries/update_person.cypher diff --git a/apps/db-handler/pkg/setup_logger.go b/apps/db-handler/pkg/setup_logger.go deleted file mode 100644 index f0a9ce4..0000000 --- a/apps/db-handler/pkg/setup_logger.go +++ /dev/null @@ -1,29 +0,0 @@ -package pkg - -import ( - "fmt" - "io" - "log" - "os" - "time" - - "github.com/gin-gonic/gin" -) - -func SetupLogger(logToFileAndStd bool, logToFile bool) { - if logToFileAndStd || logToFile { - gin.DisableConsoleColor() // Disable Console Color, you don't need console color when writing the logs to file. - path := fmt.Sprintf("private/logs/%02dy_%02dm_%02dd_%02dh_%02dm_%02ds.log", time.Now().Year(), time.Now().Month(), time.Now().Day(), time.Now().Hour(), time.Now().Minute(), time.Now().Second()) - logerror1 := os.MkdirAll("private/logs/", 0755) - f, logerror2 := os.Create(path) - if logerror1 != nil || logerror2 != nil { - log.Println("Cant log to file") - } else if logToFileAndStd { - gin.DefaultWriter = io.MultiWriter(f, os.Stdout) - } else { - gin.DefaultWriter = io.MultiWriter(f) - } - } - log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) - log.SetOutput(gin.DefaultErrorWriter) -}