Compare commits
10 commits
d04359aa58
...
5e1149d1ff
| Author | SHA1 | Date | |
|---|---|---|---|
| 5e1149d1ff | |||
| df41b45905 | |||
| 79b7567627 | |||
| b09cb2aa54 | |||
| 0904448966 | |||
| 11cc2027b8 | |||
| 70ef8933a9 | |||
| 31a2fa9c9d | |||
| 68436545be | |||
| 72bcaf4b32 |
17 changed files with 208 additions and 54 deletions
|
|
@ -78,6 +78,7 @@ deploy:staging:
|
||||||
api ./deploy \
|
api ./deploy \
|
||||||
--values deploy/values.staging.yaml \
|
--values deploy/values.staging.yaml \
|
||||||
--set image.tag=$TAG \
|
--set image.tag=$TAG \
|
||||||
|
--set migrations.image.tag=$TAG \
|
||||||
--set imageCredentials.username=$REGISTRY_USERNAME \
|
--set imageCredentials.username=$REGISTRY_USERNAME \
|
||||||
--set imageCredentials.password=$REGISTRY_PASSWORD \
|
--set imageCredentials.password=$REGISTRY_PASSWORD \
|
||||||
--set config.database.url=$DATABASE_URL
|
--set config.database.url=$DATABASE_URL
|
||||||
|
|
|
||||||
5
Makefile
5
Makefile
|
|
@ -49,3 +49,8 @@ build-docker-httpserver:
|
||||||
.PHONY: build-docker-migrations
|
.PHONY: build-docker-migrations
|
||||||
build-docker-migrations:
|
build-docker-migrations:
|
||||||
docker build -t yggdrasil-migrations -f ./build/package/migrations/Dockerfile .
|
docker build -t yggdrasil-migrations -f ./build/package/migrations/Dockerfile .
|
||||||
|
|
||||||
|
.PHONY: helm-test
|
||||||
|
helm-test:
|
||||||
|
helm lint ./deploy
|
||||||
|
helm template api ./deploy --values ./deploy/values.test.yaml
|
||||||
|
|
|
||||||
|
|
@ -560,6 +560,9 @@ components:
|
||||||
$ref: "#/components/schemas/TrainingPrice"
|
$ref: "#/components/schemas/TrainingPrice"
|
||||||
slug:
|
slug:
|
||||||
type: string
|
type: string
|
||||||
|
published:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
- days
|
- days
|
||||||
|
|
@ -573,9 +576,13 @@ components:
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
$ref: "#/components/schemas/TrainingID"
|
$ref: "#/components/schemas/TrainingID"
|
||||||
|
retired:
|
||||||
|
type: boolean
|
||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
- slug
|
- slug
|
||||||
|
- published
|
||||||
|
- retired
|
||||||
|
|
||||||
TrainingID:
|
TrainingID:
|
||||||
type: integer
|
type: integer
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
ALTER TABLE training.trainings
|
||||||
|
DROP COLUMN published,
|
||||||
|
DROP COLUMN retired;
|
||||||
6
db/migrations/002_training-published-and-retired.up.sql
Normal file
6
db/migrations/002_training-published-and-retired.up.sql
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
ALTER TABLE training.trainings ADD COLUMN published BOOLEAN NOT NULL DEFAULT FALSE;
|
||||||
|
ALTER TABLE training.trainings ADD COLUMN retired BOOLEAN NOT NULL DEFAULT FALSE;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
|
@ -34,7 +34,7 @@ spec:
|
||||||
{{- toYaml . | nindent 8 }}
|
{{- toYaml . | nindent 8 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
containers:
|
containers:
|
||||||
- name: {{ .Chart.Name }}
|
- name: httpserver
|
||||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
ports:
|
ports:
|
||||||
|
|
|
||||||
46
deploy/templates/migration-job.yaml
Normal file
46
deploy/templates/migration-job.yaml
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: {{ .Release.Name }}-migrations-{{ now | unixEpoch }}
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: {{ .Chart.Name }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
app.kubernetes.io/component: "database-migrations"
|
||||||
|
batch.kubernetes.io/job-name: {{ .Release.Name }}-migrations-{{ now | unixEpoch }}
|
||||||
|
spec:
|
||||||
|
ttlSecondsAfterFinished: 604800 # 1 week in seconds
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: {{ .Chart.Name }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
app.kubernetes.io/component: "database-migrations"
|
||||||
|
batch.kubernetes.io/job-name: {{ .Release.Name }}-migrations-{{ now | unixEpoch }}
|
||||||
|
spec:
|
||||||
|
automountServiceAccountToken: false
|
||||||
|
{{- with .Values.migrations.image.pullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
containers:
|
||||||
|
- name: migrations
|
||||||
|
image: "{{ .Values.migrations.image.repository }}:{{ .Values.migrations.image.tag }}"
|
||||||
|
command: ["/bin/ash"]
|
||||||
|
args:
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
migrate -path /srv/migrations -database $(cat /etc/yggdrasil/secrets/database_url.txt) up
|
||||||
|
{{- with .Values.migrations.resources }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
volumeMounts:
|
||||||
|
- mountPath: /etc/yggdrasil/secrets
|
||||||
|
name: secrets
|
||||||
|
readOnly: true
|
||||||
|
volumes:
|
||||||
|
- name: secrets
|
||||||
|
secret:
|
||||||
|
secretName: {{ .Release.Name }}
|
||||||
|
restartPolicy: Never
|
||||||
|
backoffLimit: 0
|
||||||
|
|
@ -6,7 +6,7 @@ spec:
|
||||||
type: {{ .Values.service.type }}
|
type: {{ .Values.service.type }}
|
||||||
ports:
|
ports:
|
||||||
- port: {{ .Values.service.port.number }}
|
- port: {{ .Values.service.port.number }}
|
||||||
targetPort: {{ .Values.service.port.number }}
|
targetPort: {{ .Values.service.port.name }}
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
name: {{ .Values.service.port.name }}
|
name: {{ .Values.service.port.name }}
|
||||||
selector:
|
selector:
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,17 @@ ingress:
|
||||||
host: staging.yggdrasil.vmdevel.cz
|
host: staging.yggdrasil.vmdevel.cz
|
||||||
annotations:
|
annotations:
|
||||||
cert-manager.io/cluster-issuer: letsencrypt-dns-production
|
cert-manager.io/cluster-issuer: letsencrypt-dns-production
|
||||||
|
nginx.ingress.kubernetes.io/enable-cors: "true"
|
||||||
|
nginx.ingress.kubernetes.io/cors-allow-origin: "https://staging.midgard.vmdevel.cz,http://localhost:5173"
|
||||||
|
nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE"
|
||||||
|
|
||||||
replicas: 2
|
replicas: 2
|
||||||
|
|
||||||
image:
|
image:
|
||||||
pullSecrets:
|
pullSecrets:
|
||||||
- name: mareshq-gitlab-registry
|
- name: mareshq-gitlab-registry
|
||||||
|
|
||||||
|
migrations:
|
||||||
|
image:
|
||||||
|
pullSecrets:
|
||||||
|
- name: mareshq-gitlab-registry
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,7 @@ ingress:
|
||||||
enabled: true
|
enabled: true
|
||||||
host: yggdrasil.example.com
|
host: yggdrasil.example.com
|
||||||
annotations:
|
annotations:
|
||||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
cert-manager.io/cluster-issuer: letsencrypt-staging
|
||||||
cert-manager.io/issuer: letsencrypt-prod
|
|
||||||
|
|
||||||
replicas: 2
|
replicas: 2
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,3 +31,17 @@ config:
|
||||||
port: 8080
|
port: 8080
|
||||||
database:
|
database:
|
||||||
url:
|
url:
|
||||||
|
|
||||||
|
migrations:
|
||||||
|
image:
|
||||||
|
pullSecrets: []
|
||||||
|
repository: registry.mareshq.com/hq/yggdrasil/migrations
|
||||||
|
tag: latest
|
||||||
|
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 250m
|
||||||
|
memory: 512Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,31 @@ func NewFaker(trainingRepository training.Repository, trainingDateRepository tra
|
||||||
|
|
||||||
func (f *Faker) GenerateFakeData() error {
|
func (f *Faker) GenerateFakeData() error {
|
||||||
var trainings = []training.Training{
|
var trainings = []training.Training{
|
||||||
|
{
|
||||||
|
Name: "Kubernetes v1",
|
||||||
|
Days: 1,
|
||||||
|
Description: "Kubernetes-v1",
|
||||||
|
Published: false,
|
||||||
|
Retired: true,
|
||||||
|
Pricing: []training.Price{
|
||||||
|
{
|
||||||
|
Amount: decimal.NewFromInt(3900),
|
||||||
|
Currency: money.CZK,
|
||||||
|
Type: training.OpenTrainingPrice,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Amount: decimal.NewFromInt(24000),
|
||||||
|
Currency: money.CZK,
|
||||||
|
Type: training.CorporateTrainingPrice,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "Kubernetes",
|
Name: "Kubernetes",
|
||||||
Days: 2,
|
Days: 2,
|
||||||
Description: "Kubernetes",
|
Description: "Kubernetes",
|
||||||
|
Published: true,
|
||||||
|
Retired: false,
|
||||||
Pricing: []training.Price{
|
Pricing: []training.Price{
|
||||||
{
|
{
|
||||||
Amount: decimal.NewFromInt(450),
|
Amount: decimal.NewFromInt(450),
|
||||||
|
|
@ -54,6 +75,8 @@ func (f *Faker) GenerateFakeData() error {
|
||||||
Name: "Terraform",
|
Name: "Terraform",
|
||||||
Days: 1,
|
Days: 1,
|
||||||
Description: "Terraform",
|
Description: "Terraform",
|
||||||
|
Published: true,
|
||||||
|
Retired: false,
|
||||||
Pricing: []training.Price{
|
Pricing: []training.Price{
|
||||||
{
|
{
|
||||||
Amount: decimal.NewFromInt(200),
|
Amount: decimal.NewFromInt(200),
|
||||||
|
|
@ -81,6 +104,8 @@ func (f *Faker) GenerateFakeData() error {
|
||||||
Name: "RKE2",
|
Name: "RKE2",
|
||||||
Days: 1,
|
Days: 1,
|
||||||
Description: "RKE2",
|
Description: "RKE2",
|
||||||
|
Published: false,
|
||||||
|
Retired: false,
|
||||||
Pricing: []training.Price{
|
Pricing: []training.Price{
|
||||||
{
|
{
|
||||||
Amount: decimal.NewFromInt(200),
|
Amount: decimal.NewFromInt(200),
|
||||||
|
|
@ -108,6 +133,8 @@ func (f *Faker) GenerateFakeData() error {
|
||||||
Name: "GitHub Actions",
|
Name: "GitHub Actions",
|
||||||
Days: 1,
|
Days: 1,
|
||||||
Description: "GitHub Actions",
|
Description: "GitHub Actions",
|
||||||
|
Published: false,
|
||||||
|
Retired: false,
|
||||||
Pricing: []training.Price{
|
Pricing: []training.Price{
|
||||||
{
|
{
|
||||||
Amount: decimal.NewFromInt(200),
|
Amount: decimal.NewFromInt(200),
|
||||||
|
|
@ -135,6 +162,8 @@ func (f *Faker) GenerateFakeData() error {
|
||||||
Name: "GitLab CI",
|
Name: "GitLab CI",
|
||||||
Days: 1,
|
Days: 1,
|
||||||
Description: "GitLab CI",
|
Description: "GitLab CI",
|
||||||
|
Published: true,
|
||||||
|
Retired: false,
|
||||||
Pricing: []training.Price{
|
Pricing: []training.Price{
|
||||||
{
|
{
|
||||||
Amount: decimal.NewFromInt(200),
|
Amount: decimal.NewFromInt(200),
|
||||||
|
|
@ -162,6 +191,8 @@ func (f *Faker) GenerateFakeData() error {
|
||||||
Name: "Prometheus",
|
Name: "Prometheus",
|
||||||
Days: 2,
|
Days: 2,
|
||||||
Description: "Prometheus",
|
Description: "Prometheus",
|
||||||
|
Published: true,
|
||||||
|
Retired: false,
|
||||||
Pricing: []training.Price{
|
Pricing: []training.Price{
|
||||||
{
|
{
|
||||||
Amount: decimal.NewFromInt(450),
|
Amount: decimal.NewFromInt(450),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Package server provides primitives to interact with the openapi HTTP API.
|
// Package server provides primitives to interact with the openapi HTTP API.
|
||||||
//
|
//
|
||||||
// Code generated by github.com/deepmap/oapi-codegen/v2 version v2.2.0 DO NOT EDIT.
|
// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.3.0 DO NOT EDIT.
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -83,6 +83,7 @@ type NewTraining struct {
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Pricing []TrainingPrice `json:"pricing"`
|
Pricing []TrainingPrice `json:"pricing"`
|
||||||
|
Published *bool `json:"published,omitempty"`
|
||||||
Slug *string `json:"slug,omitempty"`
|
Slug *string `json:"slug,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -139,6 +140,8 @@ type Training struct {
|
||||||
Id TrainingID `json:"id"`
|
Id TrainingID `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Pricing []TrainingPrice `json:"pricing"`
|
Pricing []TrainingPrice `json:"pricing"`
|
||||||
|
Published bool `json:"published"`
|
||||||
|
Retired bool `json:"retired"`
|
||||||
Slug string `json:"slug"`
|
Slug string `json:"slug"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2431,45 +2434,46 @@ func (sh *strictHandler) ListTrainingUpcomingDates(ctx *fiber.Ctx, trainingID Tr
|
||||||
// Base64 encoded, gzipped, json marshaled Swagger object
|
// Base64 encoded, gzipped, json marshaled Swagger object
|
||||||
var swaggerSpec = []string{
|
var swaggerSpec = []string{
|
||||||
|
|
||||||
"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",
|
||||||
|
"rUcw74lf4Jvfz38LAAD//+HPwchvWQAA",
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSwagger returns the content of the embedded swagger specification file
|
// GetSwagger returns the content of the embedded swagger specification file
|
||||||
|
|
|
||||||
|
|
@ -85,11 +85,18 @@ func (h *APIHandlers) CreateTraining(ctx context.Context, req CreateTrainingRequ
|
||||||
slug = *req.Body.Slug
|
slug = *req.Body.Slug
|
||||||
}
|
}
|
||||||
|
|
||||||
|
published := false
|
||||||
|
if req.Body.Published != nil {
|
||||||
|
published = *req.Body.Published
|
||||||
|
}
|
||||||
|
|
||||||
t := training.Training{
|
t := training.Training{
|
||||||
Name: req.Body.Name,
|
Name: req.Body.Name,
|
||||||
Slug: slug,
|
Slug: slug,
|
||||||
Days: req.Body.Days,
|
Days: req.Body.Days,
|
||||||
Description: req.Body.Description,
|
Description: req.Body.Description,
|
||||||
|
Published: published,
|
||||||
|
Retired: false,
|
||||||
Pricing: pricing,
|
Pricing: pricing,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,6 +125,8 @@ func (h *APIHandlers) CreateTraining(ctx context.Context, req CreateTrainingRequ
|
||||||
Slug: t.Slug,
|
Slug: t.Slug,
|
||||||
Days: t.Days,
|
Days: t.Days,
|
||||||
Description: t.Description,
|
Description: t.Description,
|
||||||
|
Published: t.Published,
|
||||||
|
Retired: t.Retired,
|
||||||
Pricing: responsePricing,
|
Pricing: responsePricing,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
@ -173,6 +182,8 @@ func (h *APIHandlers) GetTraining(ctx context.Context, req GetTrainingRequestObj
|
||||||
Slug: t.Slug,
|
Slug: t.Slug,
|
||||||
Days: t.Days,
|
Days: t.Days,
|
||||||
Description: t.Description,
|
Description: t.Description,
|
||||||
|
Published: t.Published,
|
||||||
|
Retired: t.Retired,
|
||||||
Pricing: pricing,
|
Pricing: pricing,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
@ -208,6 +219,8 @@ func (h *APIHandlers) GetTrainingBySlug(ctx context.Context, req GetTrainingBySl
|
||||||
Slug: t.Slug,
|
Slug: t.Slug,
|
||||||
Days: t.Days,
|
Days: t.Days,
|
||||||
Description: t.Description,
|
Description: t.Description,
|
||||||
|
Published: t.Published,
|
||||||
|
Retired: t.Retired,
|
||||||
Pricing: pricing,
|
Pricing: pricing,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
@ -237,12 +250,19 @@ func (h *APIHandlers) UpdateTraining(ctx context.Context, req UpdateTrainingRequ
|
||||||
slug = *req.Body.Slug
|
slug = *req.Body.Slug
|
||||||
}
|
}
|
||||||
|
|
||||||
|
published := false
|
||||||
|
if req.Body.Published != nil {
|
||||||
|
published = *req.Body.Published
|
||||||
|
}
|
||||||
|
|
||||||
t := training.Training{
|
t := training.Training{
|
||||||
ID: req.TrainingID,
|
ID: req.TrainingID,
|
||||||
Name: req.Body.Name,
|
Name: req.Body.Name,
|
||||||
Slug: slug,
|
Slug: slug,
|
||||||
Days: req.Body.Days,
|
Days: req.Body.Days,
|
||||||
Description: req.Body.Description,
|
Description: req.Body.Description,
|
||||||
|
Published: published,
|
||||||
|
Retired: false,
|
||||||
Pricing: pricing,
|
Pricing: pricing,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -262,6 +282,8 @@ func (h *APIHandlers) UpdateTraining(ctx context.Context, req UpdateTrainingRequ
|
||||||
Slug: t.Slug,
|
Slug: t.Slug,
|
||||||
Days: t.Days,
|
Days: t.Days,
|
||||||
Description: t.Description,
|
Description: t.Description,
|
||||||
|
Published: t.Published,
|
||||||
|
Retired: t.Retired,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,8 @@ func TestServer(t *testing.T) {
|
||||||
assert.Equal(t, tr.Name, trr.Name)
|
assert.Equal(t, tr.Name, trr.Name)
|
||||||
assert.Equal(t, tr.ID, trr.Id)
|
assert.Equal(t, tr.ID, trr.Id)
|
||||||
assert.Equal(t, tr.Slug, trr.Slug)
|
assert.Equal(t, tr.Slug, trr.Slug)
|
||||||
|
assert.Equal(t, false, trr.Published)
|
||||||
|
assert.Equal(t, false, trr.Retired)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("List all trainings", func(t *testing.T) {
|
t.Run("List all trainings", func(t *testing.T) {
|
||||||
|
|
@ -202,6 +204,8 @@ func TestServer(t *testing.T) {
|
||||||
assert.NotEmpty(t, trr.Slug)
|
assert.NotEmpty(t, trr.Slug)
|
||||||
assert.NotEmpty(t, trr.Description)
|
assert.NotEmpty(t, trr.Description)
|
||||||
assert.NotEmpty(t, trr.Days)
|
assert.NotEmpty(t, trr.Days)
|
||||||
|
assert.False(t, trr.Published)
|
||||||
|
assert.False(t, trr.Retired)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -246,6 +250,8 @@ func TestServer(t *testing.T) {
|
||||||
assert.NoError(t, err, "error unmarshalling response")
|
assert.NoError(t, err, "error unmarshalling response")
|
||||||
assert.Equal(t, updTr.Name, trr.Name)
|
assert.Equal(t, updTr.Name, trr.Name)
|
||||||
assert.Equal(t, updatedSlug, trr.Slug)
|
assert.Equal(t, updatedSlug, trr.Slug)
|
||||||
|
assert.Equal(t, false, trr.Published)
|
||||||
|
assert.Equal(t, false, trr.Retired)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Delete training", func(t *testing.T) {
|
t.Run("Delete training", func(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ type Training struct {
|
||||||
Slug string
|
Slug string
|
||||||
Days int8
|
Days int8
|
||||||
Description string
|
Description string
|
||||||
|
Published bool
|
||||||
|
Retired bool
|
||||||
Pricing []Price `db:"-"`
|
Pricing []Price `db:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,10 @@ func (r *PostgresTrainingRepository) Create(training *Training) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
queryErr := tx.QueryRow(ctx, `
|
queryErr := tx.QueryRow(ctx, `
|
||||||
INSERT INTO training.trainings (name, slug, description, days)
|
INSERT INTO training.trainings (name, slug, description, days, published)
|
||||||
VALUES ($1, $2, $3, $4)
|
VALUES ($1, $2, $3, $4, $5)
|
||||||
RETURNING id
|
RETURNING id
|
||||||
`, training.Name, training.Slug, training.Description, training.Days).Scan(&training.ID)
|
`, training.Name, training.Slug, training.Description, training.Days, training.Published).Scan(&training.ID)
|
||||||
if queryErr != nil {
|
if queryErr != nil {
|
||||||
return queryErr
|
return queryErr
|
||||||
}
|
}
|
||||||
|
|
@ -77,10 +77,10 @@ func (r *PostgresTrainingRepository) FindByID(id ID) (*Training, error) {
|
||||||
|
|
||||||
var training Training
|
var training Training
|
||||||
err := r.pg.QueryRow(ctx, `
|
err := r.pg.QueryRow(ctx, `
|
||||||
SELECT id, name, slug, description, days
|
SELECT id, name, slug, description, days, published, retired
|
||||||
FROM training.trainings
|
FROM training.trainings
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`, id).Scan(&training.ID, &training.Name, &training.Slug, &training.Description, &training.Days)
|
`, id).Scan(&training.ID, &training.Name, &training.Slug, &training.Description, &training.Days, &training.Published, &training.Retired)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -122,10 +122,10 @@ func (r *PostgresTrainingRepository) FindBySlug(slug string) (*Training, error)
|
||||||
|
|
||||||
var training Training
|
var training Training
|
||||||
err := r.pg.QueryRow(ctx, `
|
err := r.pg.QueryRow(ctx, `
|
||||||
SELECT id, name, slug, description, days
|
SELECT id, name, slug, description, days, published, retired
|
||||||
FROM training.trainings
|
FROM training.trainings
|
||||||
WHERE slug = $1
|
WHERE slug = $1
|
||||||
`, slug).Scan(&training.ID, &training.Name, &training.Slug, &training.Description, &training.Days)
|
`, slug).Scan(&training.ID, &training.Name, &training.Slug, &training.Description, &training.Days, &training.Published, &training.Retired)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -172,7 +172,7 @@ func (r *PostgresTrainingRepository) FindAll() ([]Training, error) {
|
||||||
|
|
||||||
trainings, err := pgx.CollectRows(rows, func(row pgx.CollectableRow) (Training, error) {
|
trainings, err := pgx.CollectRows(rows, func(row pgx.CollectableRow) (Training, error) {
|
||||||
var training Training
|
var training Training
|
||||||
scanErr := row.Scan(&training.ID, &training.Name, &training.Slug, &training.Description, &training.Days)
|
scanErr := row.Scan(&training.ID, &training.Name, &training.Slug, &training.Description, &training.Days, &training.Published, &training.Retired)
|
||||||
if scanErr != nil {
|
if scanErr != nil {
|
||||||
return Training{}, scanErr
|
return Training{}, scanErr
|
||||||
}
|
}
|
||||||
|
|
@ -217,9 +217,9 @@ func (r *PostgresTrainingRepository) Update(training *Training) error {
|
||||||
|
|
||||||
_, err = tx.Exec(ctx, `
|
_, err = tx.Exec(ctx, `
|
||||||
UPDATE training.trainings
|
UPDATE training.trainings
|
||||||
SET name = $1, slug = $2, description = $3, days = $4
|
SET name = $1, slug = $2, description = $3, days = $4, published = $5, retired = $6
|
||||||
WHERE id = $4
|
WHERE id = $4
|
||||||
`, training.Name, training.Slug, training.Description, training.Days, training.ID)
|
`, training.Name, training.Slug, training.Description, training.Days, training.ID, training.Published, training.Retired)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
Reference in a new issue