From 7b0392237446c9b546e7a3aa88c6ebc49fc75752 Mon Sep 17 00:00:00 2001 From: kandrusyak Date: Fri, 14 Jul 2023 14:54:41 +0300 Subject: [PATCH] first commit --- .gitignore | 3 + .gitlab-ci.yml | 4 ++ Dockerfile | 24 +++++++ config/config.go | 41 ++++++++++++ deploy/.helmignore | 23 +++++++ deploy/Chart.yaml | 24 +++++++ deploy/templates/NOTES.txt | 1 + deploy/templates/_helpers.tpl | 62 ++++++++++++++++++ deploy/templates/deployment.yaml | 39 ++++++++++++ deploy/templates/hpa.yaml | 28 +++++++++ deploy/templates/ingress.yaml | 61 ++++++++++++++++++ deploy/templates/service.yaml | 16 +++++ deploy/values.template.yaml | 16 +++++ go.mod | 23 +++++++ go.sum | 51 +++++++++++++++ handler/event.go | 71 +++++++++++++++++++++ handler/handler.go | 7 +++ main.go | 46 ++++++++++++++ model/card.go | 7 +++ model/event.go | 32 ++++++++++ model/events_services.go | 9 +++ model/pd.go | 7 +++ model/service.go | 7 +++ model/user.go | 20 ++++++ pkg/api/apiCall.go | 105 +++++++++++++++++++++++++++++++ pkg/utils/query.go | 27 ++++++++ pkg/utils/url.go | 52 +++++++++++++++ services/users.go | 33 ++++++++++ test.db | Bin 0 -> 20480 bytes 29 files changed, 839 insertions(+) create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 Dockerfile create mode 100644 config/config.go create mode 100644 deploy/.helmignore create mode 100644 deploy/Chart.yaml create mode 100644 deploy/templates/NOTES.txt create mode 100644 deploy/templates/_helpers.tpl create mode 100644 deploy/templates/deployment.yaml create mode 100644 deploy/templates/hpa.yaml create mode 100644 deploy/templates/ingress.yaml create mode 100644 deploy/templates/service.yaml create mode 100644 deploy/values.template.yaml create mode 100644 go.mod create mode 100644 go.sum create mode 100644 handler/event.go create mode 100644 handler/handler.go create mode 100644 main.go create mode 100644 model/card.go create mode 100644 model/event.go create mode 100644 model/events_services.go create mode 100644 model/pd.go create mode 100644 model/service.go create mode 100644 model/user.go create mode 100644 pkg/api/apiCall.go create mode 100644 pkg/utils/query.go create mode 100644 pkg/utils/url.go create mode 100644 services/users.go create mode 100644 test.db diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..89c472d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea +build +.env \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..25571c3 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,4 @@ +include: + - project: 'astra/microservice-ci' + ref: main + file: '/templates/microservice.yaml' diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ddd2eb1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +FROM kandrusyak/go-build as build +LABEL authors="andrusyakka@dopcore.com" + +WORKDIR /app + +ENV CGO_ENABLED 1 + +COPY go.mod ./ + +RUN go mod download + +COPY . ./ + +RUN go build -o ./app + +FROM alpine:edge + +WORKDIR / + +COPY --from=build /app /app + +EXPOSE 8080 + +CMD ["/app/app"] \ No newline at end of file diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..ced4785 --- /dev/null +++ b/config/config.go @@ -0,0 +1,41 @@ +package config + +import ( + "os" +) + +type ServerConfig struct { + Port string + ConnectionString string +} + +type MSHosts struct { + UsersHost string +} + +type Config struct { + Server ServerConfig + MSHosts MSHosts +} + +func New() *Config { + return &Config{ + Server: ServerConfig{ + Port: getEnv("PORT", "8080"), + ConnectionString: getEnv("CONNECTION_STRING", "test.db"), + }, + MSHosts: MSHosts{ + UsersHost: getEnv("ASTRA-USERS", "http://localhost:8082"), + }, + } +} + +func getEnv(key string, defaultVal string) string { + if value, exists := os.LookupEnv(key); exists { + return value + } + + return defaultVal +} + +var Env = New() diff --git a/deploy/.helmignore b/deploy/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/deploy/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/deploy/Chart.yaml b/deploy/Chart.yaml new file mode 100644 index 0000000..3ef0dc0 --- /dev/null +++ b/deploy/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: astra-users +appVersion: latest +description: A Helm chart to deploy app - astra + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +engine: gotpl + +maintainers: +- name: DOP diff --git a/deploy/templates/NOTES.txt b/deploy/templates/NOTES.txt new file mode 100644 index 0000000..483dc61 --- /dev/null +++ b/deploy/templates/NOTES.txt @@ -0,0 +1 @@ +192.168.1.112:8888 diff --git a/deploy/templates/_helpers.tpl b/deploy/templates/_helpers.tpl new file mode 100644 index 0000000..3d14643 --- /dev/null +++ b/deploy/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "astra-frontend.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "astra-frontend.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "astra-frontend.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "astra-frontend.labels" -}} +helm.sh/chart: {{ include "astra-frontend.chart" . }} +{{ include "astra-frontend.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "astra-frontend.selectorLabels" -}} +app.kubernetes.io/name: {{ include "astra-frontend.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "astra-frontend.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "astra-frontend.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/deploy/templates/deployment.yaml b/deploy/templates/deployment.yaml new file mode 100644 index 0000000..7eb0aba --- /dev/null +++ b/deploy/templates/deployment.yaml @@ -0,0 +1,39 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.app.fullName }} +spec: + replicas: {{ .Values.replicas }} + revisionHistoryLimit: 10 + selector: + matchLabels: + app: {{ .Values.app.fullName }} + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate + template: + metadata: + labels: + app: {{ .Values.app.fullName }} + spec: + imagePullSecrets: + - name: {{ .Values.images.pullSecret }} + containers: + - name: {{ .Values.app.fullName }} + env: + - name: TZ + value: Europe/Moscow + - name: PORT + value: {{ .Values.app.server.port | quote }} + - name: CONNECTION_STRING + value: /app/test.db + {{- .Values.envs | toYaml | nindent 12 }} + + image: {{ .Values.app.image }}:{{ .Chart.AppVersion }} + imagePullPolicy: Always + ports: + - name: http + containerPort: {{ .Values.app.server.port }} + protocol: TCP \ No newline at end of file diff --git a/deploy/templates/hpa.yaml b/deploy/templates/hpa.yaml new file mode 100644 index 0000000..cc40f06 --- /dev/null +++ b/deploy/templates/hpa.yaml @@ -0,0 +1,28 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include ".Values.app.fullName" . }} + labels: + app: {{ include ".Values.app.fullName" . }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include ".Values.app.fullName" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/deploy/templates/ingress.yaml b/deploy/templates/ingress.yaml new file mode 100644 index 0000000..516515e --- /dev/null +++ b/deploy/templates/ingress.yaml @@ -0,0 +1,61 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include ".Values.app.fullName" . -}} +{{- $svcPort := .Values.app.server.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + app: {{ $fullName }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/deploy/templates/service.yaml b/deploy/templates/service.yaml new file mode 100644 index 0000000..eff85e3 --- /dev/null +++ b/deploy/templates/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.app.fullName }} + namespace: default +spec: + ports: + - port: {{ .Values.app.server.port }} + protocol: TCP + targetPort: {{ .Values.app.server.port }} + selector: + app: {{ .Values.app.fullName }} + sessionAffinity: None + type: ClusterIP +status: + loadBalancer: {} \ No newline at end of file diff --git a/deploy/values.template.yaml b/deploy/values.template.yaml new file mode 100644 index 0000000..0adf226 --- /dev/null +++ b/deploy/values.template.yaml @@ -0,0 +1,16 @@ +app: + fullName: ${CI_PROJECT_TITLE} + image: docker-registry.dopcore.com/${CI_PROJECT_PATH} + server: + port: ${SERVICE_PORT} + +replicas: ${SERVICE_REPLICAS} + +images: + pullSecret: regcred + +ingress: + enabled: false + +autoscaling: + enabled: false diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..5ca5fa1 --- /dev/null +++ b/go.mod @@ -0,0 +1,23 @@ +module astra-events + +go 1.21rc1 + +require ( + github.com/golang-jwt/jwt v3.2.2+incompatible // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/labstack/echo/v4 v4.10.2 // indirect + github.com/labstack/gommon v0.4.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-sqlite3 v1.14.17 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.7.0 // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/text v0.7.0 // indirect + golang.org/x/time v0.3.0 // indirect + gorm.io/driver/sqlite v1.5.2 // indirect + gorm.io/gorm v1.25.2 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..4f6a759 --- /dev/null +++ b/go.sum @@ -0,0 +1,51 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M= +github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= +github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= +github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= +github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= +github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/sqlite v1.5.2 h1:TpQ+/dqCY4uCigCFyrfnrJnrW9zjpelWVoEVNy5qJkc= +gorm.io/driver/sqlite v1.5.2/go.mod h1:qxAuCol+2r6PannQDpOP1FP6ag3mKi4esLnB/jHed+4= +gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho= +gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= diff --git a/handler/event.go b/handler/event.go new file mode 100644 index 0000000..5e12a4c --- /dev/null +++ b/handler/event.go @@ -0,0 +1,71 @@ +package handler + +import ( + "astra-events/model" + "astra-events/services" + "github.com/labstack/echo/v4" + "net/http" + "strconv" +) + +func (h *Handler) CreateEvent(c echo.Context) (err error) { + newEvent := new(model.Event) + event := new(model.CreateEvent) + authorId, err := strconv.Atoi(c.Request().Header.Get("UserId")) + + if err != nil { + return c.NoContent(http.StatusUnauthorized) + } + + if err = c.Bind(event); err != nil { + return c.NoContent(http.StatusBadRequest) + } + + // TODO: Add gorutine + employee, err := services.GetUser(event.EmployeeId, c.Request().Header) + if err != nil { + return c.HTML(http.StatusBadGateway, err.Error()) + } + author, err := services.GetUser(uint(authorId), c.Request().Header) + if err != nil { + return c.HTML(http.StatusBadGateway, err.Error()) + } + + newEvent.Start = event.Start + newEvent.End = event.End + newEvent.AuthorId = uint(authorId) + newEvent.EmployeeId = event.EmployeeId + newEvent.MemberId = event.MemberId + newEvent.MedicalCardId = event.MedicalCardId + newEvent.Status = event.Status + + h.DB.Begin() + + tx := h.DB.Create(&newEvent) + + if tx.RowsAffected == 0 { + h.DB.Rollback() + return c.NoContent(http.StatusBadGateway) + } + + eventsServices := []model.EventsServices{} + + for _, service := range event.Services { + eventsServices = append(eventsServices, model.EventsServices{EventId: newEvent.ID, ServiceId: service}) + } + + tx = h.DB.Create(eventsServices) + + if tx.RowsAffected == 0 { + h.DB.Rollback() + return c.NoContent(http.StatusBadGateway) + } + + h.DB.Commit() + + newEvent.Services = event.Services + newEvent.Author = *author + newEvent.Employee = *employee + + return c.JSON(http.StatusCreated, newEvent) +} diff --git a/handler/handler.go b/handler/handler.go new file mode 100644 index 0000000..83a7019 --- /dev/null +++ b/handler/handler.go @@ -0,0 +1,7 @@ +package handler + +import "gorm.io/gorm" + +type Handler struct { + DB *gorm.DB +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..c077e0c --- /dev/null +++ b/main.go @@ -0,0 +1,46 @@ +package main + +import ( + "astra-events/config" + "astra-events/handler" + "astra-events/model" + "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4/middleware" + "gorm.io/driver/sqlite" + "gorm.io/gorm" + "gorm.io/gorm/logger" + "log" + "os" + "time" +) + +func main() { + newLogger := logger.New( + log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer + logger.Config{ + SlowThreshold: time.Second, // Slow SQL threshold + LogLevel: logger.Info, // Log level + IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger + ParameterizedQueries: true, // Don't include params in the SQL log + Colorful: false, // Disable color + }, + ) + + db, err := gorm.Open(sqlite.Open(config.Env.Server.ConnectionString), &gorm.Config{ + Logger: newLogger, + }) + if err != nil { + panic("failed to connect database") + } + e := echo.New() + + e.Use(middleware.Logger()) + + db.AutoMigrate(&model.Event{}, &model.EventsServices{}) + + var h = &handler.Handler{DB: db} + + e.POST("/", h.CreateEvent) + + e.Logger.Fatal(e.Start(":" + config.Env.Server.Port)) +} diff --git a/model/card.go b/model/card.go new file mode 100644 index 0000000..4300d7b --- /dev/null +++ b/model/card.go @@ -0,0 +1,7 @@ +package model + +import "gorm.io/gorm" + +type Card struct { + gorm.Model +} diff --git a/model/event.go b/model/event.go new file mode 100644 index 0000000..8dea2f4 --- /dev/null +++ b/model/event.go @@ -0,0 +1,32 @@ +package model + +import ( + "gorm.io/gorm" + "time" +) + +type Event struct { + gorm.Model + Start time.Time `json:"start"` + End time.Time `json:"end"` + Author User `json:"author" gorm:"-"` + AuthorId uint `json:"-"` + Employee User `json:"employee" gorm:"-"` + EmployeeId uint `json:"-"` + Member PD `json:"member" gorm:"-"` + MemberId uint `json:"-"` + Status string `json:"status"` + MedicalCard Card `json:"medicalCard" gorm:"-"` + MedicalCardId uint `json:"-"` + Services []uint `json:"services" gorm:"-"` +} + +type CreateEvent struct { + Start time.Time `json:"start"` + End time.Time `json:"end"` + EmployeeId uint `json:"employee_id"` + MemberId uint `json:"member_id"` + Status string `json:"status"` + MedicalCardId uint `json:"medical_card_id"` + Services []uint `json:"services"` +} diff --git a/model/events_services.go b/model/events_services.go new file mode 100644 index 0000000..d5f698e --- /dev/null +++ b/model/events_services.go @@ -0,0 +1,9 @@ +package model + +import "gorm.io/gorm" + +type EventsServices struct { + gorm.Model + EventId uint + ServiceId uint +} diff --git a/model/pd.go b/model/pd.go new file mode 100644 index 0000000..9eda0ac --- /dev/null +++ b/model/pd.go @@ -0,0 +1,7 @@ +package model + +import "gorm.io/gorm" + +type PD struct { + gorm.Model +} diff --git a/model/service.go b/model/service.go new file mode 100644 index 0000000..a714e65 --- /dev/null +++ b/model/service.go @@ -0,0 +1,7 @@ +package model + +import "gorm.io/gorm" + +type Service struct { + gorm.Model +} diff --git a/model/user.go b/model/user.go new file mode 100644 index 0000000..9484519 --- /dev/null +++ b/model/user.go @@ -0,0 +1,20 @@ +package model + +import "gorm.io/gorm" + +type ( + User struct { + gorm.Model + UserName string `json:"userName" gorm:"unique"` + Password string `json:"password,omitempty"` + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + } +) + +type APIUser struct { + UserName string `json:"userName" gorm:"unique"` + Password string `json:"password,omitempty"` + FirstName string `json:"firstName"` + LastName string `json:"lastName"` +} diff --git a/pkg/api/apiCall.go b/pkg/api/apiCall.go new file mode 100644 index 0000000..d8ab5a1 --- /dev/null +++ b/pkg/api/apiCall.go @@ -0,0 +1,105 @@ +package api + +import ( + "bytes" + "encoding/json" + "io" + "net/http" +) + +func PostRequest(url string, model any, header http.Header) ([]byte, error) { + uJson, err := json.Marshal(model) + + if err != nil { + return nil, err + } + + client := http.Client{} + req, err := http.NewRequest("POST", url, bytes.NewReader(uJson)) + req.Header = header + req.Header.Set("Content-Type", "application/json") + + resp, err := client.Do(req) + + if err != nil { + return nil, err + } + + data, err := io.ReadAll(resp.Body) + + if err != nil { + return nil, err + } + + return data, nil +} + +func GetRequest(url string, header http.Header, args ...string) ([]byte, error, *http.Response) { + client := http.Client{} + req, err := http.NewRequest("GET", url, nil) + if len(args) > 0 { + req.URL.RawQuery = args[0] + } + req.Header = header + req.Header.Set("Content-Type", "application/json") + resp, err := client.Do(req) + + if err != nil { + return nil, err, nil + } + + data, err := io.ReadAll(resp.Body) + + if err != nil { + return nil, err, nil + } + + return data, nil, resp +} + +func PatchRequest(url string, model any, header http.Header) ([]byte, error) { + uJson, err := json.Marshal(model) + + if err != nil { + return nil, err + } + + client := http.Client{} + req, err := http.NewRequest("PATCH", url, bytes.NewReader(uJson)) + req.Header = header + req.Header.Set("Content-Type", "application/json") + + resp, err := client.Do(req) + + if err != nil { + return nil, err + } + + data, err := io.ReadAll(resp.Body) + + if err != nil { + return nil, err + } + + return data, nil +} + +func DeleteRequest(url string, header http.Header) ([]byte, error) { + client := http.Client{} + req, err := http.NewRequest("DELETE", url, nil) + req.Header = header + req.Header.Set("Content-Type", "application/json") + resp, err := client.Do(req) + + if err != nil { + return nil, err + } + + data, err := io.ReadAll(resp.Body) + + if err != nil { + return nil, err + } + + return data, nil +} diff --git a/pkg/utils/query.go b/pkg/utils/query.go new file mode 100644 index 0000000..eedf5b9 --- /dev/null +++ b/pkg/utils/query.go @@ -0,0 +1,27 @@ +package utils + +import ( + "github.com/labstack/echo/v4" + "gorm.io/gorm" + "gorm.io/gorm/clause" +) + +func ApplySort(tx *gorm.DB, column string, isDesc bool) { + tx.Order(clause.OrderByColumn{ + Column: clause.Column{Name: column}, + Desc: isDesc, + }) +} + +func ApplyFilters(tx *gorm.DB, column string, value string) { + if column != "" && value != "" { + tx.Where(column + " LIKE '%" + value + "%'") + } +} + +func ApplyIdFilter(c echo.Context, tx *gorm.DB) { + id := c.Param("id") + if id != "" { + tx.Where("id = ?", id) + } +} diff --git a/pkg/utils/url.go b/pkg/utils/url.go new file mode 100644 index 0000000..330e69d --- /dev/null +++ b/pkg/utils/url.go @@ -0,0 +1,52 @@ +package utils + +import ( + "net/url" + "strconv" + "strings" +) + +func GetQueryParam(query url.Values, key string, defaultVal string) string { + data := query.Get(key) + + if data == "" { + return defaultVal + } + + return data +} + +func GetPaginationParams(query url.Values) (int, int) { + offset := GetQueryParam(query, "offset", "0") + limit := GetQueryParam(query, "limit", "10") + + limitInt, err := strconv.Atoi(limit) + + if err != nil { + limitInt = 10 + } + + offsetInt, err := strconv.Atoi(offset) + + if err != nil { + offsetInt = 0 + } + + return limitInt, offsetInt +} + +func GetFilterParams(query url.Values) (string, bool, string, string) { + sort := GetQueryParam(query, "sort", "id:asc") + filter := GetQueryParam(query, "filter", ":") + + filters := strings.Split(filter, ":") + sorts := strings.Split(sort, ":") + + isDesc := false + + if sorts[1] == "desc" { + isDesc = true + } + + return sorts[0], isDesc, filters[0], filters[1] +} diff --git a/services/users.go b/services/users.go new file mode 100644 index 0000000..2176925 --- /dev/null +++ b/services/users.go @@ -0,0 +1,33 @@ +package services + +import ( + "astra-events/config" + "astra-events/model" + "astra-events/pkg/api" + "encoding/json" + "errors" + "net/http" + "strconv" +) + +func GetUser(ID uint, header http.Header) (*model.User, error) { + id := strconv.Itoa(int(ID)) + + data, err, _ := api.GetRequest( + config.Env.MSHosts.UsersHost+"/"+id, + header) + + if err != nil { + return nil, errors.New("Error Request to Users Service") + } + + u := new(model.User) + + err = json.Unmarshal(data, &u) + + if err != nil { + return nil, errors.New("Bad Response from Users Service") + } + + return u, nil +} diff --git a/test.db b/test.db new file mode 100644 index 0000000000000000000000000000000000000000..fb12d1210bd169d72551d51b0ca25a64fb8a7853 GIT binary patch literal 20480 zcmeI&&vMd090%}SLS>-R^hP;2vlnN|@Ml7RcHkr`)1lU)SZC}ho03K25MaW#g9i_E zd=($T_wXfr0WV%WxREkIq&SW}IQ9FRge=J~zfC?lg&!}TAGuPn?!fnK$x39KP)Z&! zMhHo$bwjPQh^j%b&VtScYqkkec>6i25~9f+vh`)_ee$CkARqt%2tWV=5P$##AOHaf z{6hkhL^PIaX6YpF_8l>Hov|e@L|=}qk?=3vju=^v=m{wt%a)-d8;{zJ`bmQ|j~_Q) zF~0s>&RWNehbr)0KCjL*lb2d7mCe#iTiRzm5lRkyjb6=uQh#{V__Z?IRTspW+n3_C z@N>N53v~m*U2x{8k#s$g*n*3D%PSk>c z00bZa0SG_<0uX=z1Rwwb2teQ#3TPUM2mOCdzen^>x~nz_2tWV=5P$##AOHafKmY;| zfWZGJaHz$Cu6_KPhJ9tPTCT2Z*e@j9IgH#`t!R@@YsFXpPher%-zEh8e@*|Y`v3Yj mwLw4t0uX=z1Rwwb2tWV=5P$##AaE-Lq8g!E@DU06|33hg