init api implementations

This commit is contained in:
2025-03-24 21:41:33 +01:00
parent d9d565e0ee
commit 267285c356
46 changed files with 1047 additions and 679 deletions

View File

@@ -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"
}
}

View File

@@ -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<string, never>;
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<string, never>;
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;
};
};
};
};
};
}

View File

@@ -1,3 +1,3 @@
MEMGRAPH_URI="bolt://localhost:7687"
MEMGRAPH_USER="memgraph"
MEMGRAPH_PASSWORD="memgraph"
MEMGRAPH_PASSWORD="memgraph"5

View File

@@ -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

View File

@@ -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" ]
CMD [ "/app/db-adapter" ]

View File

@@ -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
)

View File

@@ -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=

View File

@@ -0,0 +1 @@
package api

View File

@@ -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()})
}
}

View File

@@ -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()})
}
}

View File

@@ -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()})
}
}

View File

@@ -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"})
}
}

View File

@@ -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"})
}
}

View File

@@ -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) {}

View File

@@ -0,0 +1,6 @@
package api
import "github.com/gin-gonic/gin"
func (srv *server) CreatePersonAndRelationship(c *gin.Context, id int, params CreatePersonAndRelationshipParams) {
}

View File

@@ -0,0 +1,5 @@
package api
import "github.com/gin-gonic/gin"
func (srv *server) GetFamilyTreeById(c *gin.Context, id int) {}

View File

@@ -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) {}

View File

@@ -0,0 +1,5 @@
package api
import "github.com/gin-gonic/gin"
func (srv *server) GetRecipesByPersonId(c *gin.Context, id int, params GetRecipesByPersonIdParams) {}

View File

@@ -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) {
}

View File

@@ -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) {}

View File

@@ -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) {}

View File

@@ -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)
}

View File

@@ -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)
})
}

View File

@@ -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()})
}
}

View File

@@ -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()})
}
}

View File

@@ -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)
}
}

View File

@@ -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"])
}
}

View File

@@ -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")
}

View File

@@ -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(),
})
}
}

View File

@@ -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()

View File

@@ -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)
}