diff --git a/go.mod b/go.mod index e90793b..369a1c5 100644 --- a/go.mod +++ b/go.mod @@ -2,39 +2,122 @@ module git.golem15.com/jakub/sm-bm-plugin go 1.27.0 -toolchain go1.27.0 - require ( + git.golem15.com/golem15/sm-user-plugin v0.0.0 git.golem15.com/golem15/summercms v0.0.0 github.com/go-gormigrate/gormigrate/v2 v2.1.7 + github.com/jackc/pgx/v5 v5.10.0 + github.com/testcontainers/testcontainers-go v0.44.0 + github.com/testcontainers/testcontainers-go/modules/postgres v0.44.0 + gorm.io/gorm v1.31.2 ) require ( + dario.cat/mergo v1.0.2 // indirect + github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/containerd/errdefs v1.0.0 // indirect + github.com/containerd/errdefs/pkg v0.3.0 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/containerd/platforms v0.2.1 // indirect + github.com/cpuguy83/dockercfg v0.3.2 // indirect + github.com/disintegration/imaging v1.6.2 // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/go-connections v0.7.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/ebitengine/purego v0.10.1 // indirect + github.com/felixge/httpsnoop v1.1.0 // indirect github.com/fsnotify/fsnotify v1.10.1 // indirect + github.com/gabriel-vasile/mimetype v1.4.15 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.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.30.4 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/goccy/go-yaml v1.19.2 // indirect + github.com/golang-jwt/jwt/v5 v5.3.1 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/googleapis/gax-go/v2 v2.19.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/klauspost/compress v1.18.6 // indirect github.com/knadh/koanf/maps v0.1.2 // indirect github.com/knadh/koanf/parsers/yaml v1.1.1 // indirect github.com/knadh/koanf/providers/confmap v1.0.1 // indirect github.com/knadh/koanf/providers/env/v2 v2.0.1 // indirect github.com/knadh/koanf/providers/file v1.2.1 // indirect github.com/knadh/koanf/v2 v2.3.6 // indirect + github.com/leodido/go-urn v1.5.0 // indirect + github.com/lib/pq v1.12.3 // indirect + github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e // indirect + github.com/magiconair/properties v1.8.10 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/go-archive v0.2.0 // indirect + github.com/moby/moby/api v1.55.0 // indirect + github.com/moby/moby/client v0.5.0 // indirect + github.com/moby/patternmatcher v0.6.1 // indirect + github.com/moby/sys/sequential v0.7.0 // indirect + github.com/moby/sys/user v0.4.0 // indirect + github.com/moby/sys/userns v0.1.0 // indirect + github.com/moby/term v0.5.2 // indirect github.com/nicksnyder/go-i18n/v2 v2.6.1 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect + github.com/riverqueue/river v0.47.0 // indirect + github.com/riverqueue/river/riverdriver v0.47.0 // indirect + github.com/riverqueue/river/riverdriver/riverdatabasesql v0.47.0 // indirect + github.com/riverqueue/river/riverdriver/riverpgxv5 v0.47.0 // indirect + github.com/riverqueue/river/rivershared v0.47.0 // indirect + github.com/riverqueue/river/rivertype v0.47.0 // indirect + github.com/shirou/gopsutil/v4 v4.26.6 // indirect + github.com/sirupsen/logrus v1.9.4 // indirect github.com/spf13/cobra v1.10.2 // indirect github.com/spf13/pflag v1.0.9 // indirect + github.com/stretchr/testify v1.12.1 // indirect + github.com/tidwall/gjson v1.19.0 // indirect + github.com/tidwall/match v1.2.0 // indirect + github.com/tidwall/pretty v1.2.1 // indirect + github.com/tidwall/sjson v1.2.5 // indirect + github.com/tklauser/go-sysconf v0.4.0 // indirect + github.com/tklauser/numcpus v0.12.0 // indirect github.com/wneessen/go-mail v0.8.1 // indirect github.com/yuin/goldmark v1.8.6 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect + go.opentelemetry.io/otel v1.44.0 // indirect + go.opentelemetry.io/otel/metric v1.44.0 // indirect + go.opentelemetry.io/otel/sdk v1.44.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.44.0 // indirect + go.opentelemetry.io/otel/trace v1.44.0 // indirect go.yaml.in/yaml/v3 v3.0.5 // indirect + gocloud.dev v0.46.0 // indirect golang.org/x/crypto v0.57.0 // indirect + golang.org/x/image v0.46.0 // indirect + golang.org/x/net v0.58.0 // indirect + golang.org/x/sync v0.23.0 // indirect golang.org/x/sys v0.48.0 // indirect golang.org/x/term v0.46.0 // indirect golang.org/x/text v0.42.0 // indirect - gorm.io/gorm v1.31.2 // indirect + golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect + google.golang.org/api v0.272.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 // indirect + google.golang.org/grpc v1.79.3 // indirect + google.golang.org/protobuf v1.36.11 // indirect + gorm.io/driver/postgres v1.6.3 // indirect ) replace git.golem15.com/golem15/summercms => ../../../../summercms.go + +replace git.golem15.com/golem15/sm-user-plugin => ../../golem15/user diff --git a/go.sum b/go.sum index 4776d15..ecad56f 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,79 @@ +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= +cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= +cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= +cloud.google.com/go/auth v0.18.2 h1:+Nbt5Ev0xEqxlNjd6c+yYUeosQ5TtEUaNcN/3FozlaM= +cloud.google.com/go/auth v0.18.2/go.mod h1:xD+oY7gcahcu7G2SG2DsBerfFxgPAJz17zz2joOFF3M= +cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= +cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= +cloud.google.com/go/iam v1.5.3 h1:+vMINPiDF2ognBJ97ABAYYwRgsaqxPbQDlMnbHMjolc= +cloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU= +cloud.google.com/go/monitoring v1.24.3 h1:dde+gMNc0UhPZD1Azu6at2e79bfdztVDS5lvhOdsgaE= +cloud.google.com/go/monitoring v1.24.3/go.mod h1:nYP6W0tm3N9H/bOw8am7t62YTzZY+zUeQ+Bi6+2eonI= +cloud.google.com/go/storage v1.61.3 h1:VS//ZfBuPGDvakfD9xyPW1RGF1Vy3BWUoVZXgW1KMOg= +cloud.google.com/go/storage v1.61.3/go.mod h1:JtqK8BBB7TWv0HVGHubtUdzYYrakOQIsMLffZ2Z/HWk= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 h1:DHa2U07rk8syqvCge0QIGMCE1WxGj9njT44GH7zNJLQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 h1:UnDZ/zFfG1JhH/DqxIZYU/1CUAlTUScoXD/LcM2Ykk8= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0/go.mod h1:IA1C1U7jO/ENqm/vhi7V9YYpBsp+IMyqNrEN94N7tVc= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 h1:0s6TxfCu2KHkkZPnBfsQ2y5qia0jl3MMrmBhu3nCOYk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/aws/aws-sdk-go-v2 v1.41.9 h1:/rYeyO2+HrMztAmxAq9++XJtFMqSIpSsNA0yDGALYq4= +github.com/aws/aws-sdk-go-v2 v1.41.9/go.mod h1:+HsoOEX80qAVUitj1A2DhCNTjmb3edVyuDypb6LNEeo= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.11 h1:h5+3VT69KUBK24grGuuA5saDJTj2IIjLb9au668Fo5I= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.11/go.mod h1:dnakxebH6UwFvcvujL0LVggYQ8nEvBGjU4G/V79Nv94= +github.com/aws/aws-sdk-go-v2/config v1.32.20 h1:8VMDnWc/kEzxsI/1ngGM9mG81a8IGmIHD8KLcYGwagc= +github.com/aws/aws-sdk-go-v2/config v1.32.20/go.mod h1:PuwEpciweIXGULWeOeSTXtSbH4CW9mWdWrhdCKQI1sM= +github.com/aws/aws-sdk-go-v2/credentials v1.19.19 h1:yuFzSV1U0aRNYCQGVaTY2zW2M/L93pYHnXnrJUphYhU= +github.com/aws/aws-sdk-go-v2/credentials v1.19.19/go.mod h1:7y63L1kGzeoDlJaQ3Z578KrnmfBut96JjvJUzGwR+YE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.25 h1:0w6dCiO8iez+YKwRhRBlL1CH/E3GTfdkuzrwj1by8vo= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.25/go.mod h1:9FDWUothyr5RCRAHc45XOiVCzUR8n/IhCYX+uVqw6vk= +github.com/aws/aws-sdk-go-v2/feature/s3/transfermanager v0.2.3 h1:w5OoDiMN6x53ROmiIImGzmVcxXv2q1GXY+aKV4WAJYM= +github.com/aws/aws-sdk-go-v2/feature/s3/transfermanager v0.2.3/go.mod h1:dAhgYp776bX3LuWvnSCFwQEjNs6fuFg7YXIy5PXcP3Q= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.25 h1:Uii3frf9ztec/ABM2/FSH9/z7PLzxfpG8h4RpkUFflQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.25/go.mod h1:G6kntsA2GorAxDPbap6xgB2F+amSLUF8GJTi7PUoX44= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.25 h1:r1+/l6m+WaUJF9HISEsNOLHSNj5EXYQxK8VX6Cz9NlA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.25/go.mod h1:cKf+D+NMDK1LndD7BowHbBZPgR9V0/5HubH0PFWvA+c= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.26 h1:A1PmWU2zfkIm9EyFlJncFXL4W4phML+h8KjltUsCvNQ= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.26/go.mod h1:dY4MRzXEizrD4hqtpKvWVGPX7QleSGGVY+EBolo1RmM= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.10 h1:d5/908OJ4bXg8lyjeMPvXetEKqoDoLi5Owy1zNue3yg= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.10/go.mod h1:a57l7Hwh+FWI+we50g5NPJHYUKeJKfXbc4w8SyXu8Ig= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.18 h1:W/EyPFl9A5rXrtoilfwHYEvzHER+K4SpBPtMXi24Mos= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.18/go.mod h1:UG50K+pvd/uy6xExbobg0rjqFBFZe6I3l75EPDZw4tg= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.25 h1:dD3dhHNglpd98gs72my22Ndqi1hqQGllFFg1F+twfxg= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.25/go.mod h1:0yAbjPfd64gG7mj85RW+fMEYdfBgCRZw8g/oWcL1pjc= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.25 h1:2pQEbwf+/6EDbiit/GcBE2K4IUpMZymaA0kOz3xK978= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.25/go.mod h1:KvT6NCcQ0EZ+ZkVRrlBMt04Po3ok23YELEp7WimhLhM= +github.com/aws/aws-sdk-go-v2/service/s3 v1.102.2 h1:ie4ElCmUKS26pzrZcIk/lmt4yWjAqLLcawstyQCh298= +github.com/aws/aws-sdk-go-v2/service/s3 v1.102.2/go.mod h1:zjsomFeX5duj+4PlMB+o4JoWTIx+G0XMyzjYrUbQkN0= +github.com/aws/aws-sdk-go-v2/service/signin v1.1.1 h1:1VwbP3qMNfxUDEXWki4rCE5iA+44VA1lokTz9HasGzw= +github.com/aws/aws-sdk-go-v2/service/signin v1.1.1/go.mod h1:vUtyoSj0OPji3kjIVSc/GlKuWEiL33f/WFxl6dmpy/A= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.19 h1:N6pIsdFOW1Kd9S4KyFKXdGRBojPPxkP32+uHFWLv4Hc= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.19/go.mod h1:3gt5WJArFooNmyLONS+h/R4J+o86II8du38IgCwj9dE= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.2 h1:hc+lBYiiTr8Zk4MTzIsQ92MeDWCIDvWGmzKUWOaBcOg= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.2/go.mod h1:hU6fqB3OJA6/ePheD47LQnxvjYk6br6PtQxs+Q9ojvk= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.3 h1:ErklX/7uhSbkAAeyQD/Y1OoQ9hO3SJXQNEgksORW3Js= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.3/go.mod h1:ULe4HCzfKPiR6R3HEurE3b1upEkuk8AkMrOKtaOxKO8= +github.com/aws/smithy-go v1.26.0 h1:9ouqbi+NyKP7fV3Te7UElCwdAb6Y8uk7LGwPE5tVe/s= +github.com/aws/smithy-go v1.26.0/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os8IaYg++6uMOdKK83QtkkvJik= +github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= @@ -21,6 +85,11 @@ github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7np github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= +github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= +github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c= @@ -29,26 +98,69 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/ebitengine/purego v0.10.1 h1:dewVBCBT2GaMu1SrNTYxQhgQBethzfhiwvZiLGP/qyY= github.com/ebitengine/purego v0.10.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= +github.com/envoyproxy/go-control-plane/envoy v1.37.0 h1:u3riX6BoYRfF4Dr7dwSOroNfdSbEPe9Yyl09/B6wBrQ= +github.com/envoyproxy/go-control-plane/envoy v1.37.0/go.mod h1:DReE9MMrmecPy+YvQOAOHNYMALuowAnbjjEMkkWOi6A= +github.com/envoyproxy/protoc-gen-validate v1.3.3 h1:MVQghNeW+LZcmXe7SY1V36Z+WFMDjpqGAGacLe2T0ds= +github.com/envoyproxy/protoc-gen-validate v1.3.3/go.mod h1:TsndJ/ngyIdQRhMcVVGDDHINPLWB7C82oDArY51KfB0= github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeORc= github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE= github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho= github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= +github.com/gabriel-vasile/mimetype v1.4.15 h1:05iP/CYtZ/w455R/KZM6rZ5ieAdh99UPtd+d3YzLmaI= +github.com/gabriel-vasile/mimetype v1.4.15/go.mod h1:azpTcoLcDZRNgFou5j+APrqQx9HqVPWa6ijYQIIVswQ= github.com/go-gormigrate/gormigrate/v2 v2.1.7 h1:PdT4jVPbRb4R+0Ey2R0yJOdctVf4Whiq1Qi4necaZdg= github.com/go-gormigrate/gormigrate/v2 v2.1.7/go.mod h1:3ouXglTuPrKF5+7cQyVGfvAXTU4vLMaYh9+EPl03uog= +github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= +github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.30.4 h1:9Rcod2ZPO6mOEG6b4GqyoHE/H6//Ze0RuhOo1hT1x0w= +github.com/go-playground/validator/v10 v10.30.4/go.mod h1:numpT+RPLE91R9oYWMY/R9zRgJBewr3IXHko4OISPpk= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= +github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4= +github.com/google/wire v0.7.0/go.mod h1:n6YbUQD9cPKTnHXEBN2DXlOp/mVADhVErcMFb0v3J18= +github.com/googleapis/enterprise-certificate-proxy v0.3.14 h1:yh8ncqsbUY4shRD5dA6RlzjJaT4hi3kII+zYw8wmLb8= +github.com/googleapis/enterprise-certificate-proxy v0.3.14/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg= +github.com/googleapis/gax-go/v2 v2.19.0 h1:fYQaUOiGwll0cGj7jmHT/0nPlcrZDFPrZRhTsoCr8hE= +github.com/googleapis/gax-go/v2 v2.19.0/go.mod h1:w2ROXVdfGEVFXzmlciUU4EdjHgWvB5h2n6x/8XSTTJA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438 h1:Dj0L5fhJ9F82ZJyVOmBx6msDp/kfd1t9GRfny/mfJA0= +github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.10.0 h1:VhSvgU2jSli8o3AqIEOTJr7rZwAEUVo4E4XhR94Zfr0= +github.com/jackc/pgx/v5 v5.10.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= 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= @@ -67,12 +179,18 @@ github.com/knadh/koanf/providers/file v1.2.1 h1:bEWbtQwYrA+W2DtdBrQWyXqJaJSG3KrP github.com/knadh/koanf/providers/file v1.2.1/go.mod h1:bp1PM5f83Q+TOUu10J/0ApLBd9uIzg+n9UgthfY+nRA= github.com/knadh/koanf/v2 v2.3.6 h1:JoQPSJmvS4aP0xNc8xMDr5tcrkSEInL23/Il7pITAKo= github.com/knadh/koanf/v2 v2.3.6/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28= +github.com/leodido/go-urn v1.5.0 h1:pLqT2kq1zpHW/1D18QMjMpdtX7cekxqtJJjg5ANyWw0= +github.com/leodido/go-urn v1.5.0/go.mod h1:9BORnCDhdPBJNDEX+w1bJisa8yOKYi116VeO96s4ifE= +github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ= +github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e h1:Q6MvJtQK/iRcRtzAscm/zF23XxJlbECiGPyRicsX+Ak= github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mdelapenya/tlscert v0.2.0 h1:7H81W6Z/4weDvZBNOfQte5GpIMo0lGYEeWbkGp5LJHI= +github.com/mdelapenya/tlscert v0.2.0/go.mod h1:O4njj3ELLnJjGdkN7M/vIVCpZ+Cf0L6muqOG4tLSl8o= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= @@ -101,8 +219,25 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/riverqueue/river v0.47.0 h1:j8HOEyiOE8gRRhVS2wllKams372TH1WWiH6xCakXHqc= +github.com/riverqueue/river v0.47.0/go.mod h1:Wgmwx475ZBd8lQnNrJgyG2DWH7BfyNiSAtv0rC9bJBQ= +github.com/riverqueue/river/riverdriver v0.47.0 h1:qU8VkjdMl9plqeRg57SxsDUM/i/eECaSYejZ7HynC60= +github.com/riverqueue/river/riverdriver v0.47.0/go.mod h1:NOXl0fUiF1AT/TaQOjdx2A/c0Davn+SKbW8nAXWjfC4= +github.com/riverqueue/river/riverdriver/riverdatabasesql v0.47.0 h1:4wckhMlLN08F76/GWxGF6vlrbs5HCMuV01dpUnvOGI4= +github.com/riverqueue/river/riverdriver/riverdatabasesql v0.47.0/go.mod h1:EME1EGr7RU/vMUf61mpf9YXhsZJ+GlFk4AHrIHT+YdE= +github.com/riverqueue/river/riverdriver/riverpgxv5 v0.47.0 h1:5N9nvemhQwbUElMxASw4oEaYJ/v6hiS5Y9VcOQfdC5g= +github.com/riverqueue/river/riverdriver/riverpgxv5 v0.47.0/go.mod h1:ZboiXXZKC4+fTkxBxGRVmAsCuUu0NPYliqbWYuQAZyw= +github.com/riverqueue/river/rivershared v0.47.0 h1:jdtFsBexCvLqTXf8wnDnGXvB/eeOtPKQZAmThkjFpLs= +github.com/riverqueue/river/rivershared v0.47.0/go.mod h1:w8Pi1T+6ypyko5/hs9Mv7IIIKo4fAL9eXYnkVV/Y418= +github.com/riverqueue/river/rivertype v0.47.0 h1:SzNavtLGR4nMT1QkrEYQ7n96OMatYsn/z3aJWhewmv0= +github.com/riverqueue/river/rivertype v0.47.0/go.mod h1:XKkcRQR6zm8RR/JQa1Q2ywpj8uXQu21quPa4Lpw1Xhw= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shirou/gopsutil/v4 v4.26.6 h1:Mzr/npDtQC/xpeEuQKHZt8Zo9CmPvhTj8nkR8w5TLDs= github.com/shirou/gopsutil/v4 v4.26.6/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= @@ -112,10 +247,30 @@ github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= +github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= +github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE= github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg= github.com/testcontainers/testcontainers-go v0.44.0 h1:/Fwh6HY1mIikhnm9e7HwoxGycx0lzRAE0f5VQpjFxzI= github.com/testcontainers/testcontainers-go v0.44.0/go.mod h1:IcnwQrYTO86xHXu5bvMaBH7ATlbS3Qn1M1QWW3c66rE= +github.com/testcontainers/testcontainers-go/modules/postgres v0.44.0 h1:8fdv/9y3JMxjQ+ULAcOG8RtgeNu5t9XF9LolSXDuTwM= +github.com/testcontainers/testcontainers-go/modules/postgres v0.44.0/go.mod h1:CFr2LncGYokw+OKjXcr8ARCKG1SaC2UEnGxFBovE86g= +github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.19.0 h1:xwxm7n691Uf3u5OFjzngavjGTh55KX5q/9w9xHW88JU= +github.com/tidwall/gjson v1.19.0/go.mod h1:V37/opeE/JbLUOfH0QTXiNez2l0RUjYUhpT4szFQAfc= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM= +github.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/tklauser/go-sysconf v0.4.0 h1:7H0uAN+7RkwWRaxhYXDLqa5V3LPrJeV8wmD9dRUgPQU= github.com/tklauser/go-sysconf v0.4.0/go.mod h1:8mTNWyog7H+MpKijp4VmKJAd2bbYQ2zuUwkYRbUArPI= github.com/tklauser/numcpus v0.12.0 h1:NR85qdvHA9pFse3x3weVZ0r0ST8R6l5RHbZrlRaqob4= @@ -128,27 +283,80 @@ github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/detectors/gcp v1.42.0 h1:kpt2PEJuOuqYkPcktfJqWWDjTEd/FNgrxcniL7kQrXQ= +go.opentelemetry.io/contrib/detectors/gcp v1.42.0/go.mod h1:W9zQ439utxymRrXsUOzZbFX4JhLxXU4+ZnCt8GG7yA8= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0 h1:yI1/OhfEPy7J9eoa6Sj051C7n5dvpj0QX8g4sRchg04= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0/go.mod h1:NoUCKYWK+3ecatC4HjkRktREheMeEtrXoQxrqYFeHSc= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI= go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= +go.opentelemetry.io/otel/metric/x v0.66.0 h1:YkCrx1zLOChi9ZcZ6euupOcsgzbVlec7D/xoEU1+cTA= +go.opentelemetry.io/otel/metric/x v0.66.0/go.mod h1:d1+BDj9t96do0/1LoU1ayfCv79ZgNE41qbhBvnMOBZk= +go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= +go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= +go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= +go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= +gocloud.dev v0.46.0 h1:niIuZwSjMtBx8K+ITB2s5kZullB13PGOS2ZoQPZxQ4Q= +gocloud.dev v0.46.0/go.mod h1:ACQe+2qO+hEO+pdcvvsM+RB63r8TyGD1W3ESCLFyzvM= golang.org/x/crypto v0.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M= golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA= +golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.46.0 h1:b1+oYj0Jbp6K5MDT4i4/eZpYlk3V8SJhhDKh6LBHAyQ= +golang.org/x/image v0.46.0/go.mod h1:3B3W05VGVQyuXucLINLjXKrqISASfi4Xj+iCVkLMwew= +golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= +golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= +golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk= +golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo= golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= golang.org/x/term v0.46.0 h1:3+OXuTbaKDgwk8jTi3aSLHRlmWqHEUDUtxnbFigO4YE= golang.org/x/term v0.46.0/go.mod h1:+K02xbkittuwc0Am4abfA3Fc+XRGXkvBXNO88NCXPoc= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI= golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/api v0.272.0 h1:eLUQZGnAS3OHn31URRf9sAmRk3w2JjMx37d2k8AjJmA= +google.golang.org/api v0.272.0/go.mod h1:wKjowi5LNJc5qarNvDCvNQBn3rVK8nSy6jg2SwRwzIA= +google.golang.org/genproto v0.0.0-20260316180232-0b37fe3546d5 h1:JNfk58HZ8lfmXbYK2vx/UvsqIL59TzByCxPIX4TDmsE= +google.golang.org/genproto v0.0.0-20260316180232-0b37fe3546d5/go.mod h1:x5julN69+ED4PcFk/XWayw35O0lf/nGa4aNgODCmNmw= +google.golang.org/genproto/googleapis/api v0.0.0-20260316180232-0b37fe3546d5 h1:CogIeEXn4qWYzzQU0QqvYBM8yDF9cFYzDq9ojSpv0Js= +google.golang.org/genproto/googleapis/api v0.0.0-20260316180232-0b37fe3546d5/go.mod h1:EIQZ5bFCfRQDV4MhRle7+OgjNtZ6P1PiZBgAKuxXu/Y= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5 h1:aJmi6DVGGIStN9Mobk/tZOOQUBbj0BPjZjjnOdoZKts= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260316180232-0b37fe3546d5/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= +google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= 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= +gorm.io/driver/postgres v1.6.3 h1:bAn6O2pUa8LtpWEvL5NFU4+52Tfx8Ut7IVaIacCLcI0= +gorm.io/driver/postgres v1.6.3/go.mod h1:0c4fQA44XhOklXDkgtuKqysHCycTa5i9e3EIpDGCwXk= gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ= gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8= gorm.io/gorm v1.31.2 h1:3o8FXNo9v9S858gil+3LlZA1LkCOzgb4g5BL64FgaCo= gorm.io/gorm v1.31.2/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= +pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk= +pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= diff --git a/models/class_session.go b/models/class_session.go new file mode 100644 index 0000000..10dbf59 --- /dev/null +++ b/models/class_session.go @@ -0,0 +1,63 @@ +// Code generated by summer make. DO NOT EDIT. + +package models + +import ( + "time" + + "gorm.io/gorm" +) + +// ClassSession is one block of classes (zajęcia) of a course. +type ClassSession struct { + ID uint `gorm:"column:id;primaryKey"` + CourseID uint `gorm:"column:course_id"` + Course *Course `gorm:"foreignKey:CourseID"` + MeetingID *uint `gorm:"column:meeting_id"` + Meeting *Meeting `gorm:"foreignKey:MeetingID"` + StartsAt DateTime `gorm:"column:starts_at"` + EndsAt DateTime `gorm:"column:ends_at"` + Room *string `gorm:"column:room"` + Kind *string `gorm:"column:kind"` + Notes *string `gorm:"column:notes"` + IsOnline bool `gorm:"column:is_online"` + CreatedAt time.Time `gorm:"column:created_at"` + UpdatedAt time.Time `gorm:"column:updated_at"` +} + +// TableName is the plugin table. +func (ClassSession) TableName() string { return "jz_bm_class_sessions" } + +// Fillable lists the columns mass assignment may set. course_id and +// meeting_id are set through the admin relation pickers. +func (ClassSession) Fillable() []string { + return []string{"course_id", "meeting_id", "starts_at", "ends_at", "room", "kind", "notes", "is_online"} +} + +// Rules are checked by the admin API on every save. +func (ClassSession) Rules() map[string]string { + return map[string]string{ + "starts_at": "required", + "ends_at": "required", + "room": "nullable|max:100", + "kind": "nullable|max:100", + "is_online": "boolean", + } +} + +// TemporalErrors checks the timestamps, which lagoon.Validate cannot. +func (s *ClassSession) TemporalErrors() map[string][]string { + e := temporalErrors{} + e.dateTime("starts_at", s.StartsAt, true) + e.dateTime("ends_at", s.EndsAt, true) + if len(e) == 0 && !s.EndsAt.MustTime().After(s.StartsAt.MustTime()) { + e.add("ends_at", "The ends at must be a date after starts at.") + } + return e.result() +} + +// BeforeSave stores NULL for empty optional text. +func (s *ClassSession) BeforeSave(*gorm.DB) error { + blank(&s.Room, &s.Kind, &s.Notes) + return nil +} diff --git a/models/course.go b/models/course.go new file mode 100644 index 0000000..d43847b --- /dev/null +++ b/models/course.go @@ -0,0 +1,72 @@ +// Code generated by summer make. DO NOT EDIT. + +package models + +import ( + "time" + + "gorm.io/gorm" +) + +// Course forms, the values of Course.Form. +const ( + FormWyklad = "wyklad" + FormCwiczenia = "cwiczenia" + FormKonwersatorium = "konwersatorium" + FormSeminarium = "seminarium" + FormInne = "inne" +) + +// CourseForms lists the allowed Course.Form values. +var CourseForms = []string{FormWyklad, FormCwiczenia, FormKonwersatorium, FormSeminarium, FormInne} + +// Course is one przedmiot of the programme in one form (a lecture and its +// tutorial are two courses). +type Course struct { + ID uint `gorm:"column:id;primaryKey"` + Code *string `gorm:"column:code"` + Name string `gorm:"column:name"` + Form string `gorm:"column:form"` + Lecturer *string `gorm:"column:lecturer"` + Semester int `gorm:"column:semester"` + ECTS *float64 `gorm:"column:ects"` + Assessment *string `gorm:"column:assessment"` + // ElectiveGroup marks alternatives ("do wyboru"): courses that share a + // value are options of one choice, such as "specjalnosc". + ElectiveGroup *string `gorm:"column:elective_group"` + Description *string `gorm:"column:description"` + SyllabusURL *string `gorm:"column:syllabus_url"` + SortOrder int `gorm:"column:sort_order"` + CreatedAt time.Time `gorm:"column:created_at"` + UpdatedAt time.Time `gorm:"column:updated_at"` +} + +// TableName is the plugin table. +func (Course) TableName() string { return "jz_bm_courses" } + +// Fillable lists the columns mass assignment may set. +func (Course) Fillable() []string { + return []string{"code", "name", "form", "lecturer", "semester", "ects", "assessment", "elective_group", "description", "syllabus_url", "sort_order"} +} + +// Rules are checked by the admin API on every save. +func (Course) Rules() map[string]string { + return map[string]string{ + "code": "nullable|max:50", + "name": "required|max:255", + "form": "required|in:wyklad,cwiczenia,konwersatorium,seminarium,inne", + "lecturer": "nullable|max:255", + "semester": "required|integer|between:1,4", + "ects": "nullable|numeric|between:0,60", + "assessment": "nullable|max:100", + "elective_group": "nullable|max:100", + "syllabus_url": "nullable|max:2048", + "sort_order": "nullable|integer", + } +} + +// BeforeSave stores NULL for empty optional text. +func (c *Course) BeforeSave(*gorm.DB) error { + blank(&c.Code, &c.Lecturer, &c.Assessment, &c.ElectiveGroup, &c.Description, &c.SyllabusURL) + return nil +} diff --git a/models/deadline.go b/models/deadline.go new file mode 100644 index 0000000..fa8f119 --- /dev/null +++ b/models/deadline.go @@ -0,0 +1,56 @@ +// Code generated by summer make. DO NOT EDIT. + +package models + +import ( + "time" + + "gorm.io/gorm" +) + +// DeadlineKinds lists the allowed Deadline.Kind values. +var DeadlineKinds = []string{"zaliczenie", "egzamin", "praca", "organizacyjne", "inne"} + +// Deadline is one entry of the terminarz: an exam, a submission or an +// administrative date, optionally tied to a course. +type Deadline struct { + ID uint `gorm:"column:id;primaryKey"` + Title string `gorm:"column:title"` + DueAt DateTime `gorm:"column:due_at"` + CourseID *uint `gorm:"column:course_id"` + Course *Course `gorm:"foreignKey:CourseID"` + Kind string `gorm:"column:kind"` + Description *string `gorm:"column:description"` + CreatedAt time.Time `gorm:"column:created_at"` + UpdatedAt time.Time `gorm:"column:updated_at"` +} + +// TableName is the plugin table. +func (Deadline) TableName() string { return "jz_bm_deadlines" } + +// Fillable lists the columns mass assignment may set. +func (Deadline) Fillable() []string { + return []string{"title", "due_at", "course_id", "kind", "description"} +} + +// Rules are checked by the admin API on every save. +func (Deadline) Rules() map[string]string { + return map[string]string{ + "title": "required|max:255", + "due_at": "required", + "kind": "required|in:zaliczenie,egzamin,praca,organizacyjne,inne", + } +} + +// TemporalErrors checks the due time, which lagoon.Validate cannot. +func (d *Deadline) TemporalErrors() map[string][]string { + e := temporalErrors{} + e.dateTime("due_at", d.DueAt, true) + return e.result() +} + +// BeforeSave stores NULL for empty optional text. +func (d *Deadline) BeforeSave(*gorm.DB) error { + blank(&d.Description) + return nil +} diff --git a/models/material.go b/models/material.go new file mode 100644 index 0000000..f2c0a7e --- /dev/null +++ b/models/material.go @@ -0,0 +1,75 @@ +// Code generated by summer make. DO NOT EDIT. + +package models + +import ( + "time" + + "gorm.io/gorm" +) + +// MaterialTypes lists the allowed Material.Type values. +var MaterialTypes = []string{"pdf", "notatka", "link", "inne"} + +// MaterialFilesField is the system_files field of a material's attachments +// (attachMany "files"). +const MaterialFilesField = "files" + +// Material is a study material: a note, a link or uploaded files, optionally +// tied to a course. A material without published_at is a draft and is not +// served by the API. +type Material struct { + ID uint `gorm:"column:id;primaryKey"` + CourseID *uint `gorm:"column:course_id"` + Course *Course `gorm:"foreignKey:CourseID"` + Title string `gorm:"column:title"` + Type string `gorm:"column:type"` + Body *string `gorm:"column:body"` + Source *string `gorm:"column:source"` + URL *string `gorm:"column:url"` + PublishedAt *DateTime `gorm:"column:published_at"` + CreatedAt time.Time `gorm:"column:created_at"` + UpdatedAt time.Time `gorm:"column:updated_at"` + + Tags []Tag `gorm:"many2many:jz_bm_material_tag;joinForeignKey:material_id;joinReferences:tag_id"` +} + +// TableName is the plugin table. +func (Material) TableName() string { return "jz_bm_materials" } + +// MorphName is the attachment_type of the material's system_files rows. +func (Material) MorphName() string { return `Jz\Bm\Models\Material` } + +// Fillable lists the columns mass assignment may set. +func (Material) Fillable() []string { + return []string{"course_id", "title", "type", "body", "source", "url", "published_at"} +} + +// Rules are checked by the admin API on every save. +func (Material) Rules() map[string]string { + return map[string]string{ + "title": "required|max:255", + "type": "required|in:pdf,notatka,link,inne", + "source": "nullable|max:500", + "url": "nullable|max:2048", + } +} + +// TemporalErrors checks published_at, which lagoon.Validate cannot. +func (m *Material) TemporalErrors() map[string][]string { + e := temporalErrors{} + if m.PublishedAt != nil { + e.dateTime("published_at", *m.PublishedAt, false) + } + return e.result() +} + +// BeforeSave stores NULL for empty optional text and an empty publication +// time. +func (m *Material) BeforeSave(*gorm.DB) error { + blank(&m.Body, &m.Source, &m.URL) + if m.PublishedAt != nil && *m.PublishedAt == "" { + m.PublishedAt = nil + } + return nil +} diff --git a/models/material_tag.go b/models/material_tag.go new file mode 100644 index 0000000..dc10535 --- /dev/null +++ b/models/material_tag.go @@ -0,0 +1,12 @@ +// Code generated by summer make. DO NOT EDIT. + +package models + +// MaterialTag is the pivot row between a material and a tag. +type MaterialTag struct { + MaterialID uint `gorm:"column:material_id;primaryKey"` + TagID uint `gorm:"column:tag_id;primaryKey"` +} + +// TableName is the pivot table. +func (MaterialTag) TableName() string { return "jz_bm_material_tag" } diff --git a/models/meeting.go b/models/meeting.go new file mode 100644 index 0000000..2cff79f --- /dev/null +++ b/models/meeting.go @@ -0,0 +1,52 @@ +// Code generated by summer make. DO NOT EDIT. + +package models + +import ( + "time" + + "gorm.io/gorm" +) + +// Meeting is one zjazd: a weekend of classes of the part-time programme. +type Meeting struct { + ID uint `gorm:"column:id;primaryKey"` + Number int `gorm:"column:number"` + StartsOn Date `gorm:"column:starts_on"` + EndsOn Date `gorm:"column:ends_on"` + Notes *string `gorm:"column:notes"` + CreatedAt time.Time `gorm:"column:created_at"` + UpdatedAt time.Time `gorm:"column:updated_at"` +} + +// TableName is the plugin table. +func (Meeting) TableName() string { return "jz_bm_meetings" } + +// Fillable lists the columns mass assignment may set. +func (Meeting) Fillable() []string { return []string{"number", "starts_on", "ends_on", "notes"} } + +// Rules are checked by the admin API on every save. +func (Meeting) Rules() map[string]string { + return map[string]string{ + "number": "required|integer|min:1|unique:jz_bm_meetings", + "starts_on": "required", + "ends_on": "required", + } +} + +// TemporalErrors checks the dates, which lagoon.Validate cannot. +func (m *Meeting) TemporalErrors() map[string][]string { + e := temporalErrors{} + e.date("starts_on", m.StartsOn, true) + e.date("ends_on", m.EndsOn, true) + if len(e) == 0 && m.EndsOn < m.StartsOn { + e.add("ends_on", "The ends on must be a date after or equal to starts on.") + } + return e.result() +} + +// BeforeSave stores NULL for empty optional text. +func (m *Meeting) BeforeSave(*gorm.DB) error { + blank(&m.Notes) + return nil +} diff --git a/models/nullable.go b/models/nullable.go new file mode 100644 index 0000000..fd708c6 --- /dev/null +++ b/models/nullable.go @@ -0,0 +1,50 @@ +package models + +import "strings" + +// blank clears each optional text column whose value is empty or only +// whitespace, so an emptied admin text input stores NULL rather than "". +func blank(fields ...**string) { + for _, f := range fields { + if *f != nil && strings.TrimSpace(**f) == "" { + *f = nil + } + } +} + +// temporalErrors is a field-to-messages map in the shape of lagoon.Validate. +type temporalErrors map[string][]string + +func (e temporalErrors) add(field, msg string) { e[field] = append(e[field], msg) } + +func (e temporalErrors) dateTime(field string, v DateTime, required bool) { + switch { + case v == "" && required: + e.add(field, "The "+strings.ReplaceAll(field, "_", " ")+" field is required.") + case v != "" && !v.Valid(): + e.add(field, "The "+strings.ReplaceAll(field, "_", " ")+" must be a date and time such as 2026-10-03 08:00.") + } +} + +func (e temporalErrors) date(field string, v Date, required bool) { + switch { + case v == "" && required: + e.add(field, "The "+strings.ReplaceAll(field, "_", " ")+" field is required.") + case v != "" && !v.Valid(): + e.add(field, "The "+strings.ReplaceAll(field, "_", " ")+" must be a date in the YYYY-MM-DD form.") + } +} + +func (e temporalErrors) result() map[string][]string { + if len(e) == 0 { + return nil + } + return e +} + +// TemporalValidator is implemented by models with Date or DateTime columns. +// The admin controllers call it before a save, because lagoon.Validate has +// no date rules. +type TemporalValidator interface { + TemporalErrors() map[string][]string +} diff --git a/models/reading.go b/models/reading.go new file mode 100644 index 0000000..f00d216 --- /dev/null +++ b/models/reading.go @@ -0,0 +1,50 @@ +// Code generated by summer make. DO NOT EDIT. + +package models + +import ( + "time" + + "gorm.io/gorm" +) + +// Reading is one lektura on a course's reading list. +type Reading struct { + ID uint `gorm:"column:id;primaryKey"` + CourseID uint `gorm:"column:course_id"` + Course *Course `gorm:"foreignKey:CourseID"` + Title string `gorm:"column:title"` + Author *string `gorm:"column:author"` + Source *string `gorm:"column:source"` + URL *string `gorm:"column:url"` + IsRequired bool `gorm:"column:is_required"` + SortOrder int `gorm:"column:sort_order"` + CreatedAt time.Time `gorm:"column:created_at"` + UpdatedAt time.Time `gorm:"column:updated_at"` +} + +// TableName is the plugin table. +func (Reading) TableName() string { return "jz_bm_readings" } + +// Fillable lists the columns mass assignment may set. +func (Reading) Fillable() []string { + return []string{"course_id", "title", "author", "source", "url", "is_required", "sort_order"} +} + +// Rules are checked by the admin API on every save. +func (Reading) Rules() map[string]string { + return map[string]string{ + "title": "required|max:500", + "author": "nullable|max:255", + "source": "nullable|max:500", + "url": "nullable|max:2048", + "is_required": "boolean", + "sort_order": "nullable|integer", + } +} + +// BeforeSave stores NULL for empty optional text. +func (r *Reading) BeforeSave(*gorm.DB) error { + blank(&r.Author, &r.Source, &r.URL) + return nil +} diff --git a/models/reading_progress.go b/models/reading_progress.go new file mode 100644 index 0000000..a0a79db --- /dev/null +++ b/models/reading_progress.go @@ -0,0 +1,17 @@ +// Code generated by summer make. DO NOT EDIT. + +package models + +import "time" + +// ReadingProgress records that a user (a golem15.user users row) has read a +// reading. One row per reading and user. +type ReadingProgress struct { + ID uint `gorm:"column:id;primaryKey"` + ReadingID uint `gorm:"column:reading_id"` + UserID uint `gorm:"column:user_id"` + ReadAt time.Time `gorm:"column:read_at"` +} + +// TableName is the plugin table. +func (ReadingProgress) TableName() string { return "jz_bm_reading_progress" } diff --git a/models/tag.go b/models/tag.go new file mode 100644 index 0000000..683e068 --- /dev/null +++ b/models/tag.go @@ -0,0 +1,28 @@ +// Code generated by summer make. DO NOT EDIT. + +package models + +import "time" + +// Tag labels materials. +type Tag struct { + ID uint `gorm:"column:id;primaryKey"` + Name string `gorm:"column:name"` + Slug string `gorm:"column:slug"` + CreatedAt time.Time `gorm:"column:created_at"` + UpdatedAt time.Time `gorm:"column:updated_at"` +} + +// TableName is the plugin table. +func (Tag) TableName() string { return "jz_bm_tags" } + +// Fillable lists the columns mass assignment may set. +func (Tag) Fillable() []string { return []string{"name", "slug"} } + +// Rules are checked by the admin API on every save. +func (Tag) Rules() map[string]string { + return map[string]string{ + "name": "required|max:100", + "slug": "required|max:100|unique:jz_bm_tags", + } +} diff --git a/models/temporal.go b/models/temporal.go new file mode 100644 index 0000000..8009bf8 --- /dev/null +++ b/models/temporal.go @@ -0,0 +1,186 @@ +package models + +import ( + "database/sql/driver" + "fmt" + "strings" + "time" + _ "time/tzdata" // Europe/Warsaw must resolve on hosts without zoneinfo. +) + +// Location is the time zone the programme runs in. Timestamps are stored in +// UTC (TIMESTAMPTZ) and shown in this zone; a date or time typed without an +// offset is read in it. +var Location = mustLoadLocation("Europe/Warsaw") + +func mustLoadLocation(name string) *time.Location { + loc, err := time.LoadLocation(name) + if err != nil { + panic(fmt.Sprintf("jz.bm: load location %s: %v", name, err)) + } + return loc +} + +// DateLayout is the textual form of a Date. +const DateLayout = "2006-01-02" + +// dateTimeLayouts are the forms ParseDateTime accepts. RFC 3339 carries its +// own offset; the others are wall-clock times in Location. +var dateTimeLayouts = []string{ + "2006-01-02T15:04", + "2006-01-02 15:04", + "2006-01-02T15:04:05", + "2006-01-02 15:04:05", +} + +// ParseDateTime reads an RFC 3339 timestamp, or a wall-clock time +// ("2026-10-03 08:00") in Location. +func ParseDateTime(s string) (time.Time, error) { + s = strings.TrimSpace(s) + if t, err := time.Parse(time.RFC3339, s); err == nil { + return t, nil + } + for _, layout := range dateTimeLayouts { + if t, err := time.ParseInLocation(layout, s, Location); err == nil { + return t, nil + } + } + return time.Time{}, fmt.Errorf("jz.bm: %q is not a date and time", s) +} + +// ParseDate reads a YYYY-MM-DD calendar date. +func ParseDate(s string) (time.Time, error) { + t, err := time.ParseInLocation(DateLayout, strings.TrimSpace(s), Location) + if err != nil { + return time.Time{}, fmt.Errorf("jz.bm: %q is not a YYYY-MM-DD date", s) + } + return t, nil +} + +// DateTime is a TIMESTAMPTZ column held as RFC 3339 text in Location +// ("2026-10-03T08:00:00+02:00"). +// +// It is a string type rather than time.Time because the admin form has no +// date picker and lagoon.Fill cannot write text into a time.Time field, while +// cabana treats any struct-typed field as a relation. A string type is filled +// from the form's text input, and Value checks and normalises it. +// TODO: requires SummerCMS change (a datetime form field type and Fill +// support for time.Time) to use time.Time here. +type DateTime string + +// NewDateTime returns t as a DateTime in Location. +func NewDateTime(t time.Time) DateTime { + return DateTime(t.In(Location).Format(time.RFC3339)) +} + +// Time parses the value. +func (d DateTime) Time() (time.Time, error) { return ParseDateTime(string(d)) } + +// MustTime parses the value and returns the zero time when it does not parse. +// Values read from the database always parse. +func (d DateTime) MustTime() time.Time { + t, _ := d.Time() + return t +} + +// Valid reports whether the value parses. +func (d DateTime) Valid() bool { + _, err := d.Time() + return err == nil +} + +// Value stores the instant in UTC. An empty value is SQL NULL. +func (d DateTime) Value() (driver.Value, error) { + if strings.TrimSpace(string(d)) == "" { + return nil, nil + } + t, err := d.Time() + if err != nil { + return nil, err + } + return t.UTC(), nil +} + +// Scan reads a TIMESTAMPTZ (or its text) and normalises it to Location. +func (d *DateTime) Scan(src any) error { + switch v := src.(type) { + case nil: + *d = "" + case time.Time: + *d = NewDateTime(v) + case string: + return d.scanText(v) + case []byte: + return d.scanText(string(v)) + default: + return fmt.Errorf("jz.bm: cannot scan %T into DateTime", src) + } + return nil +} + +func (d *DateTime) scanText(s string) error { + if strings.TrimSpace(s) == "" { + *d = "" + return nil + } + t, err := ParseDateTime(s) + if err != nil { + // Postgres text output: "2026-10-03 06:00:00+00". + t, err = time.Parse("2006-01-02 15:04:05-07", s) + if err != nil { + return err + } + } + *d = NewDateTime(t) + return nil +} + +// Date is a DATE column held as YYYY-MM-DD text, for the same reason as +// DateTime. +type Date string + +// NewDate returns the calendar date of t in Location. +func NewDate(t time.Time) Date { return Date(t.In(Location).Format(DateLayout)) } + +// Time returns midnight of the date in Location. +func (d Date) Time() (time.Time, error) { return ParseDate(string(d)) } + +// Valid reports whether the value is a YYYY-MM-DD date. +func (d Date) Valid() bool { + _, err := d.Time() + return err == nil +} + +// Value stores the date as text; Postgres casts it to DATE. An empty value is +// SQL NULL. +func (d Date) Value() (driver.Value, error) { + if strings.TrimSpace(string(d)) == "" { + return nil, nil + } + t, err := d.Time() + if err != nil { + return nil, err + } + return t.Format(DateLayout), nil +} + +// Scan reads a DATE. The driver hands it over as midnight UTC, so the +// calendar fields are taken as they are, without a zone conversion. +func (d *Date) Scan(src any) error { + switch v := src.(type) { + case nil: + *d = "" + case time.Time: + *d = Date(v.Format(DateLayout)) + case string: + *d = Date(strings.TrimSpace(v)) + if len(*d) > len(DateLayout) { + *d = (*d)[:len(DateLayout)] + } + case []byte: + return d.Scan(string(v)) + default: + return fmt.Errorf("jz.bm: cannot scan %T into Date", src) + } + return nil +} diff --git a/models/temporal_test.go b/models/temporal_test.go new file mode 100644 index 0000000..1f057ea --- /dev/null +++ b/models/temporal_test.go @@ -0,0 +1,136 @@ +package models_test + +import ( + "testing" + "time" + + "git.golem15.com/jakub/sm-bm-plugin/models" +) + +func TestParseDateTimeForms(t *testing.T) { + want := time.Date(2026, 10, 3, 6, 0, 0, 0, time.UTC) + for _, in := range []string{ + "2026-10-03T08:00:00+02:00", + "2026-10-03T06:00:00Z", + "2026-10-03 08:00", + "2026-10-03T08:00", + " 2026-10-03 08:00:00 ", + } { + got, err := models.ParseDateTime(in) + if err != nil { + t.Errorf("ParseDateTime(%q): %v", in, err) + continue + } + if !got.Equal(want) { + t.Errorf("ParseDateTime(%q) = %v, want %v", in, got, want) + } + } + // Winter time: a wall-clock time in December is UTC+1. + got, err := models.ParseDateTime("2026-12-01 08:00") + if err != nil || !got.Equal(time.Date(2026, 12, 1, 7, 0, 0, 0, time.UTC)) { + t.Errorf("winter wall clock = %v, %v", got, err) + } + for _, bad := range []string{"", "tomorrow", "2026-13-01 08:00", "2026-10-03"} { + if _, err := models.ParseDateTime(bad); err == nil { + t.Errorf("ParseDateTime(%q) accepted", bad) + } + } +} + +func TestDateTimeRoundTrip(t *testing.T) { + d := models.DateTime("2026-10-03 08:00") + v, err := d.Value() + if err != nil { + t.Fatal(err) + } + stored, ok := v.(time.Time) + if !ok || stored.Location() != time.UTC || stored.Hour() != 6 { + t.Fatalf("Value = %#v, want 06:00 UTC", v) + } + var read models.DateTime + if err := read.Scan(stored); err != nil { + t.Fatal(err) + } + if read != "2026-10-03T08:00:00+02:00" { + t.Errorf("Scan = %q, want the Warsaw RFC 3339 form", read) + } + if err := read.Scan("2026-10-03 06:00:00+00"); err != nil || read != "2026-10-03T08:00:00+02:00" { + t.Errorf("Scan(postgres text) = %q, %v", read, err) + } + if err := read.Scan(nil); err != nil || read != "" { + t.Errorf("Scan(nil) = %q, %v", read, err) + } + if v, err := models.DateTime("").Value(); err != nil || v != nil { + t.Errorf("empty Value = %v, %v; want NULL", v, err) + } + if _, err := models.DateTime("soon").Value(); err == nil { + t.Error("an unparsable DateTime was stored") + } + if err := read.Scan(42); err == nil { + t.Error("Scan(int) succeeded") + } +} + +func TestDateRoundTrip(t *testing.T) { + var d models.Date + if err := d.Scan(time.Date(2026, 10, 3, 0, 0, 0, 0, time.UTC)); err != nil || d != "2026-10-03" { + t.Errorf("Scan(time) = %q, %v", d, err) + } + if err := d.Scan([]byte("2026-10-04")); err != nil || d != "2026-10-04" { + t.Errorf("Scan(bytes) = %q, %v", d, err) + } + if v, err := models.Date("2026-10-03").Value(); err != nil || v != "2026-10-03" { + t.Errorf("Value = %v, %v", v, err) + } + if _, err := models.Date("03.10.2026").Value(); err == nil { + t.Error("a non-ISO date was stored") + } + if models.NewDate(time.Date(2026, 10, 2, 23, 30, 0, 0, time.UTC)) != "2026-10-03" { + t.Error("NewDate does not use the Warsaw calendar day") + } +} + +func TestTemporalErrors(t *testing.T) { + s := &models.ClassSession{StartsAt: "2026-10-03 10:00", EndsAt: "2026-10-03 09:00"} + if errs := s.TemporalErrors(); len(errs["ends_at"]) != 1 { + t.Errorf("end before start: %v", errs) + } + s = &models.ClassSession{StartsAt: "bad"} + errs := s.TemporalErrors() + if len(errs["starts_at"]) != 1 || len(errs["ends_at"]) != 1 { + t.Errorf("bad and missing: %v", errs) + } + m := &models.Meeting{StartsOn: "2026-10-04", EndsOn: "2026-10-03"} + if errs := m.TemporalErrors(); len(errs["ends_on"]) != 1 { + t.Errorf("meeting order: %v", errs) + } + ok := &models.Meeting{StartsOn: "2026-10-03", EndsOn: "2026-10-04"} + if errs := ok.TemporalErrors(); errs != nil { + t.Errorf("valid meeting: %v", errs) + } + draft := &models.Material{} + if errs := draft.TemporalErrors(); errs != nil { + t.Errorf("draft material: %v", errs) + } + bad := models.DateTime("yesterday") + if errs := (&models.Material{PublishedAt: &bad}).TemporalErrors(); len(errs["published_at"]) != 1 { + t.Errorf("bad published_at: %v", errs) + } +} + +func TestBeforeSaveBlanksOptionalText(t *testing.T) { + empty, space := "", " " + c := &models.Course{Code: &empty, Lecturer: &space} + if err := c.BeforeSave(nil); err != nil { + t.Fatal(err) + } + if c.Code != nil || c.Lecturer != nil { + t.Errorf("blank text kept: %v %v", c.Code, c.Lecturer) + } + pub := models.DateTime("") + m := &models.Material{PublishedAt: &pub} + _ = m.BeforeSave(nil) + if m.PublishedAt != nil { + t.Error("an empty published_at was not cleared to a draft") + } +} diff --git a/updates/20261002120154_create_jz_bm_meetings.go b/updates/20261002120154_create_jz_bm_meetings.go new file mode 100644 index 0000000..f65ad85 --- /dev/null +++ b/updates/20261002120154_create_jz_bm_meetings.go @@ -0,0 +1,31 @@ +// Code generated by summer make. DO NOT EDIT. + +package updates + +import ( + "github.com/go-gormigrate/gormigrate/v2" + "gorm.io/gorm" +) + +// CreateMeetings returns the 20261002120154_create_jz_bm_meetings gormigrate entry: +// the zjazdy. +func CreateMeetings() *gormigrate.Migration { + return &gormigrate.Migration{ + ID: "20261002120154_create_jz_bm_meetings", + Migrate: func(tx *gorm.DB) error { + return execAll(tx, `CREATE TABLE jz_bm_meetings ( + id BIGSERIAL PRIMARY KEY, + number INTEGER NOT NULL UNIQUE CHECK (number > 0), + starts_on DATE NOT NULL, + ends_on DATE NOT NULL, + notes TEXT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + CHECK (ends_on >= starts_on) +)`) + }, + Rollback: func(tx *gorm.DB) error { + return tx.Exec("DROP TABLE IF EXISTS jz_bm_meetings").Error + }, + } +} diff --git a/updates/20261002120203_create_jz_bm_courses.go b/updates/20261002120203_create_jz_bm_courses.go new file mode 100644 index 0000000..c767d2e --- /dev/null +++ b/updates/20261002120203_create_jz_bm_courses.go @@ -0,0 +1,38 @@ +// Code generated by summer make. DO NOT EDIT. + +package updates + +import ( + "github.com/go-gormigrate/gormigrate/v2" + "gorm.io/gorm" +) + +// CreateCourses returns the 20261002120203_create_jz_bm_courses gormigrate entry: +// the przedmioty, one row per course and form. +func CreateCourses() *gormigrate.Migration { + return &gormigrate.Migration{ + ID: "20261002120203_create_jz_bm_courses", + Migrate: func(tx *gorm.DB) error { + return execAll(tx, `CREATE TABLE jz_bm_courses ( + id BIGSERIAL PRIMARY KEY, + code VARCHAR(50) NULL, + name VARCHAR(255) NOT NULL, + form VARCHAR(20) NOT NULL CHECK (form IN ('wyklad', 'cwiczenia', 'konwersatorium', 'seminarium', 'inne')), + lecturer VARCHAR(255) NULL, + semester INTEGER NOT NULL CHECK (semester > 0), + ects NUMERIC(4,1) NULL, + assessment VARCHAR(100) NULL, + description TEXT NULL, + syllabus_url VARCHAR(2048) NULL, + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + UNIQUE (name, form, semester) +); +CREATE INDEX jz_bm_courses_semester_sort_index ON jz_bm_courses (semester, sort_order)`) + }, + Rollback: func(tx *gorm.DB) error { + return tx.Exec("DROP TABLE IF EXISTS jz_bm_courses").Error + }, + } +} diff --git a/updates/20261002120204_create_jz_bm_class_sessions.go b/updates/20261002120204_create_jz_bm_class_sessions.go new file mode 100644 index 0000000..70ed9f7 --- /dev/null +++ b/updates/20261002120204_create_jz_bm_class_sessions.go @@ -0,0 +1,38 @@ +// Code generated by summer make. DO NOT EDIT. + +package updates + +import ( + "github.com/go-gormigrate/gormigrate/v2" + "gorm.io/gorm" +) + +// CreateClassSessions returns the 20261002120204_create_jz_bm_class_sessions gormigrate entry: +// the zajęcia. Deleting a course deletes its sessions; deleting a meeting keeps them. +func CreateClassSessions() *gormigrate.Migration { + return &gormigrate.Migration{ + ID: "20261002120204_create_jz_bm_class_sessions", + Migrate: func(tx *gorm.DB) error { + return execAll(tx, `CREATE TABLE jz_bm_class_sessions ( + id BIGSERIAL PRIMARY KEY, + course_id BIGINT NOT NULL REFERENCES jz_bm_courses (id) ON DELETE CASCADE, + meeting_id BIGINT NULL REFERENCES jz_bm_meetings (id) ON DELETE SET NULL, + starts_at TIMESTAMPTZ NOT NULL, + ends_at TIMESTAMPTZ NOT NULL, + room VARCHAR(100) NULL, + kind VARCHAR(100) NULL, + notes TEXT NULL, + is_online BOOLEAN NOT NULL DEFAULT FALSE, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + CHECK (ends_at > starts_at), + UNIQUE (course_id, starts_at) +); +CREATE INDEX jz_bm_class_sessions_starts_at_index ON jz_bm_class_sessions (starts_at); +CREATE INDEX jz_bm_class_sessions_meeting_id_index ON jz_bm_class_sessions (meeting_id)`) + }, + Rollback: func(tx *gorm.DB) error { + return tx.Exec("DROP TABLE IF EXISTS jz_bm_class_sessions").Error + }, + } +} diff --git a/updates/20261002120205_create_jz_bm_deadlines.go b/updates/20261002120205_create_jz_bm_deadlines.go new file mode 100644 index 0000000..89ffb69 --- /dev/null +++ b/updates/20261002120205_create_jz_bm_deadlines.go @@ -0,0 +1,33 @@ +// Code generated by summer make. DO NOT EDIT. + +package updates + +import ( + "github.com/go-gormigrate/gormigrate/v2" + "gorm.io/gorm" +) + +// CreateDeadlines returns the 20261002120205_create_jz_bm_deadlines gormigrate entry: +// the terminarz. Deleting a course keeps its deadlines, unlinked. +func CreateDeadlines() *gormigrate.Migration { + return &gormigrate.Migration{ + ID: "20261002120205_create_jz_bm_deadlines", + Migrate: func(tx *gorm.DB) error { + return execAll(tx, `CREATE TABLE jz_bm_deadlines ( + id BIGSERIAL PRIMARY KEY, + title VARCHAR(255) NOT NULL, + due_at TIMESTAMPTZ NOT NULL, + course_id BIGINT NULL REFERENCES jz_bm_courses (id) ON DELETE SET NULL, + kind VARCHAR(20) NOT NULL CHECK (kind IN ('zaliczenie', 'egzamin', 'praca', 'organizacyjne', 'inne')), + description TEXT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); +CREATE INDEX jz_bm_deadlines_due_at_index ON jz_bm_deadlines (due_at); +CREATE INDEX jz_bm_deadlines_course_id_index ON jz_bm_deadlines (course_id)`) + }, + Rollback: func(tx *gorm.DB) error { + return tx.Exec("DROP TABLE IF EXISTS jz_bm_deadlines").Error + }, + } +} diff --git a/updates/20261002120206_create_jz_bm_readings.go b/updates/20261002120206_create_jz_bm_readings.go new file mode 100644 index 0000000..25f3dc1 --- /dev/null +++ b/updates/20261002120206_create_jz_bm_readings.go @@ -0,0 +1,34 @@ +// Code generated by summer make. DO NOT EDIT. + +package updates + +import ( + "github.com/go-gormigrate/gormigrate/v2" + "gorm.io/gorm" +) + +// CreateReadings returns the 20261002120206_create_jz_bm_readings gormigrate entry: +// the lektury. Deleting a course deletes its readings. +func CreateReadings() *gormigrate.Migration { + return &gormigrate.Migration{ + ID: "20261002120206_create_jz_bm_readings", + Migrate: func(tx *gorm.DB) error { + return execAll(tx, `CREATE TABLE jz_bm_readings ( + id BIGSERIAL PRIMARY KEY, + course_id BIGINT NOT NULL REFERENCES jz_bm_courses (id) ON DELETE CASCADE, + title VARCHAR(500) NOT NULL, + author VARCHAR(255) NULL, + source VARCHAR(500) NULL, + url VARCHAR(2048) NULL, + is_required BOOLEAN NOT NULL DEFAULT FALSE, + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + UNIQUE (course_id, title) +)`) + }, + Rollback: func(tx *gorm.DB) error { + return tx.Exec("DROP TABLE IF EXISTS jz_bm_readings").Error + }, + } +} diff --git a/updates/20261002120207_create_jz_bm_reading_progress.go b/updates/20261002120207_create_jz_bm_reading_progress.go new file mode 100644 index 0000000..696be33 --- /dev/null +++ b/updates/20261002120207_create_jz_bm_reading_progress.go @@ -0,0 +1,29 @@ +// Code generated by summer make. DO NOT EDIT. + +package updates + +import ( + "github.com/go-gormigrate/gormigrate/v2" + "gorm.io/gorm" +) + +// CreateReadingProgress returns the 20261002120207_create_jz_bm_reading_progress gormigrate entry: +// who has read which reading. The rows go with the reading or the golem15.user user. +func CreateReadingProgress() *gormigrate.Migration { + return &gormigrate.Migration{ + ID: "20261002120207_create_jz_bm_reading_progress", + Migrate: func(tx *gorm.DB) error { + return execAll(tx, `CREATE TABLE jz_bm_reading_progress ( + id BIGSERIAL PRIMARY KEY, + reading_id BIGINT NOT NULL REFERENCES jz_bm_readings (id) ON DELETE CASCADE, + user_id INTEGER NOT NULL REFERENCES users (id) ON DELETE CASCADE, + read_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + UNIQUE (reading_id, user_id) +); +CREATE INDEX jz_bm_reading_progress_user_id_index ON jz_bm_reading_progress (user_id)`) + }, + Rollback: func(tx *gorm.DB) error { + return tx.Exec("DROP TABLE IF EXISTS jz_bm_reading_progress").Error + }, + } +} diff --git a/updates/20261002120208_create_jz_bm_tags.go b/updates/20261002120208_create_jz_bm_tags.go new file mode 100644 index 0000000..497c166 --- /dev/null +++ b/updates/20261002120208_create_jz_bm_tags.go @@ -0,0 +1,28 @@ +// Code generated by summer make. DO NOT EDIT. + +package updates + +import ( + "github.com/go-gormigrate/gormigrate/v2" + "gorm.io/gorm" +) + +// CreateTags returns the 20261002120208_create_jz_bm_tags gormigrate entry: +// the material tags. +func CreateTags() *gormigrate.Migration { + return &gormigrate.Migration{ + ID: "20261002120208_create_jz_bm_tags", + Migrate: func(tx *gorm.DB) error { + return execAll(tx, `CREATE TABLE jz_bm_tags ( + id BIGSERIAL PRIMARY KEY, + name VARCHAR(100) NOT NULL, + slug VARCHAR(100) NOT NULL UNIQUE, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +)`) + }, + Rollback: func(tx *gorm.DB) error { + return tx.Exec("DROP TABLE IF EXISTS jz_bm_tags").Error + }, + } +} diff --git a/updates/20261002120209_create_jz_bm_materials.go b/updates/20261002120209_create_jz_bm_materials.go new file mode 100644 index 0000000..e920baf --- /dev/null +++ b/updates/20261002120209_create_jz_bm_materials.go @@ -0,0 +1,35 @@ +// Code generated by summer make. DO NOT EDIT. + +package updates + +import ( + "github.com/go-gormigrate/gormigrate/v2" + "gorm.io/gorm" +) + +// CreateMaterials returns the 20261002120209_create_jz_bm_materials gormigrate entry: +// the study materials; a NULL published_at is a draft. Deleting a course keeps its materials, unlinked. +func CreateMaterials() *gormigrate.Migration { + return &gormigrate.Migration{ + ID: "20261002120209_create_jz_bm_materials", + Migrate: func(tx *gorm.DB) error { + return execAll(tx, `CREATE TABLE jz_bm_materials ( + id BIGSERIAL PRIMARY KEY, + course_id BIGINT NULL REFERENCES jz_bm_courses (id) ON DELETE SET NULL, + title VARCHAR(255) NOT NULL, + type VARCHAR(20) NOT NULL CHECK (type IN ('pdf', 'notatka', 'link', 'inne')), + body TEXT NULL, + source VARCHAR(500) NULL, + url VARCHAR(2048) NULL, + published_at TIMESTAMPTZ NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); +CREATE INDEX jz_bm_materials_published_at_index ON jz_bm_materials (published_at); +CREATE INDEX jz_bm_materials_course_id_index ON jz_bm_materials (course_id)`) + }, + Rollback: func(tx *gorm.DB) error { + return tx.Exec("DROP TABLE IF EXISTS jz_bm_materials").Error + }, + } +} diff --git a/updates/20261002120210_create_jz_bm_material_tag.go b/updates/20261002120210_create_jz_bm_material_tag.go new file mode 100644 index 0000000..a35e4dd --- /dev/null +++ b/updates/20261002120210_create_jz_bm_material_tag.go @@ -0,0 +1,27 @@ +// Code generated by summer make. DO NOT EDIT. + +package updates + +import ( + "github.com/go-gormigrate/gormigrate/v2" + "gorm.io/gorm" +) + +// CreateMaterialTag returns the 20261002120210_create_jz_bm_material_tag gormigrate entry: +// the material-tag pivot. +func CreateMaterialTag() *gormigrate.Migration { + return &gormigrate.Migration{ + ID: "20261002120210_create_jz_bm_material_tag", + Migrate: func(tx *gorm.DB) error { + return execAll(tx, `CREATE TABLE jz_bm_material_tag ( + material_id BIGINT NOT NULL REFERENCES jz_bm_materials (id) ON DELETE CASCADE, + tag_id BIGINT NOT NULL REFERENCES jz_bm_tags (id) ON DELETE CASCADE, + PRIMARY KEY (material_id, tag_id) +); +CREATE INDEX jz_bm_material_tag_tag_id_index ON jz_bm_material_tag (tag_id)`) + }, + Rollback: func(tx *gorm.DB) error { + return tx.Exec("DROP TABLE IF EXISTS jz_bm_material_tag").Error + }, + } +} diff --git a/updates/20261002121227_add_elective_group_to_courses.go b/updates/20261002121227_add_elective_group_to_courses.go new file mode 100644 index 0000000..f808dbf --- /dev/null +++ b/updates/20261002121227_add_elective_group_to_courses.go @@ -0,0 +1,22 @@ +// Code generated by summer make. DO NOT EDIT. + +package updates + +import ( + "github.com/go-gormigrate/gormigrate/v2" + "gorm.io/gorm" +) + +// AddElectiveGroupToCourses returns the 20261002121227_add_elective_group_to_courses gormigrate entry: +// courses that share an elective_group are alternatives ("do wyboru"). +func AddElectiveGroupToCourses() *gormigrate.Migration { + return &gormigrate.Migration{ + ID: "20261002121227_add_elective_group_to_courses", + Migrate: func(tx *gorm.DB) error { + return tx.Exec("ALTER TABLE jz_bm_courses ADD COLUMN elective_group VARCHAR(100) NULL").Error + }, + Rollback: func(tx *gorm.DB) error { + return tx.Exec("ALTER TABLE jz_bm_courses DROP COLUMN IF EXISTS elective_group").Error + }, + } +} diff --git a/updates/exec.go b/updates/exec.go new file mode 100644 index 0000000..ba37c19 --- /dev/null +++ b/updates/exec.go @@ -0,0 +1,21 @@ +package updates + +import ( + "strings" + + "gorm.io/gorm" +) + +// execAll runs each semicolon-separated statement of sql in order. The +// statements hold no semicolons of their own. +func execAll(tx *gorm.DB, sql string) error { + for _, stmt := range strings.Split(sql, ";") { + if strings.TrimSpace(stmt) == "" { + continue + } + if err := tx.Exec(stmt).Error; err != nil { + return err + } + } + return nil +}