From f287af2913e193a594301cfc7b8cbe1bebc74eca Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Thu, 31 Oct 2024 12:08:13 -0700 Subject: [PATCH 01/21] CORE-2016: enable the use of direnv for development testing --- .env.sample | 4 ++++ .envrc | 19 +++++++++++++++++++ .gitignore | 1 + 3 files changed, 24 insertions(+) create mode 100755 .env.sample create mode 100755 .envrc diff --git a/.env.sample b/.env.sample new file mode 100755 index 0000000..e4d2b62 --- /dev/null +++ b/.env.sample @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +QMS_DATABASE_URI=postgres://de@localhost/qms?sslmode=disable +QMS_USERNAME_SUFFIX=iplantcollaborative.org +QMS_NATS_CLUSTER=nats://localhost:4222 diff --git a/.envrc b/.envrc new file mode 100755 index 0000000..e84a999 --- /dev/null +++ b/.envrc @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +_PWD=$(pwd) +_APP=`echo $_PWD | grep -Eo -i '([[:alnum:]-]*)$'` +echo "Starting $_APP environment..." +export PATH="$_PWD/bin:$PATH" + +export PRJ_ROOT_DIR=$(realpath "$_PWD") + +[ -f ${PRJ_ROOT_DIR}/.env ] && source ${PRJ_ROOT_DIR}/.env || { echo "Missing ${PRJ_ROOT_DIR}/.env!"; exit 1; } +## Export all VARS in .env +ALL_ENV_PRJ_VARS=($(grep -E '^[[:space:]]*[A-Z_][A-Z0-9_]*[[:space:]]*=' ${PRJ_ROOT_DIR}/.env | cut -f1 -d"=" | tr '\n' ' ')) +for idx in "${!ALL_ENV_PRJ_VARS[@]}"; do + # echo "idx: $idx :: ${ALL_ENV_PRJ_VARS[idx]}=${!ALL_ENV_PRJ_VARS[idx]}" + eval "export ${ALL_ENV_PRJ_VARS[idx]}='${!ALL_ENV_PRJ_VARS[idx]}'" +done + +## GOPRIVATE="gitlab.com/cyverse*,github.com/cyverse*,bitbucket.org/cyverse*" +export GOPRIVATE="gitlab.com/cyverse*" diff --git a/.gitignore b/.gitignore index 7c27451..5f28fc0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ configs/local.yml configs/local.yaml **/dotenv dev-test/ +.env From 636c0033a71d7908656d52fb66b07e29bd1fa1e6 Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Fri, 1 Nov 2024 17:14:37 -0700 Subject: [PATCH 02/21] CORE-2016: upgraded dependencies --- go.mod | 60 ++++++++++++++++++++++++++++++---------------------- go.sum | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index 9fa7ed4..0cf589d 100644 --- a/go.mod +++ b/go.mod @@ -1,15 +1,17 @@ module github.com/cyverse-de/subscriptions -go 1.22 +go 1.22.0 + +toolchain go1.23.2 require ( github.com/cyverse-de/go-mod/cfg v0.0.2 - github.com/cyverse-de/go-mod/gotelnats v0.0.11 - github.com/cyverse-de/go-mod/logging v0.0.2 - github.com/cyverse-de/go-mod/otelutils v0.0.3 - github.com/cyverse-de/go-mod/pbinit v0.1.11 - github.com/cyverse-de/go-mod/protobufjson v0.0.3 - github.com/cyverse-de/go-mod/subjects v0.1.4 + github.com/cyverse-de/go-mod/gotelnats v0.0.12 + github.com/cyverse-de/go-mod/logging v0.0.3 + github.com/cyverse-de/go-mod/otelutils v0.0.4 + github.com/cyverse-de/go-mod/pbinit v0.1.12 + github.com/cyverse-de/go-mod/protobufjson v0.0.4 + github.com/cyverse-de/go-mod/subjects v0.1.5 github.com/cyverse-de/p/go/qms v0.1.13 github.com/cyverse-de/p/go/requests v0.0.3 github.com/cyverse-de/p/go/svcerror v0.0.8 @@ -18,29 +20,31 @@ require ( github.com/knadh/koanf v1.5.0 github.com/labstack/echo/v4 v4.12.0 github.com/lib/pq v1.10.9 - github.com/nats-io/nats.go v1.34.1 + github.com/nats-io/nats.go v1.37.0 github.com/pkg/errors v0.9.1 - github.com/samber/lo v1.39.0 + github.com/samber/lo v1.47.0 github.com/sirupsen/logrus v1.9.3 - github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.4 - github.com/uptrace/opentelemetry-go-extra/otelsqlx v0.2.4 - go.opentelemetry.io/otel v1.26.0 - google.golang.org/protobuf v1.34.1 + github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2 + github.com/uptrace/opentelemetry-go-extra/otelsqlx v0.3.2 + go.opentelemetry.io/otel v1.31.0 + google.golang.org/protobuf v1.35.1 ) require ( - github.com/cyverse-de/p v0.0.0-20240228001927-426a6bd80191 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cyverse-de/p v0.0.0-20241022195522-7109f3ff6072 // indirect github.com/cyverse-de/p/go/analysis v0.0.16 // indirect github.com/cyverse-de/p/go/containers v0.0.2 // indirect github.com/cyverse-de/p/go/header v0.0.4 // indirect github.com/cyverse-de/p/go/monitoring v0.0.5 // indirect github.com/cyverse-de/p/go/user v0.0.11 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 // indirect github.com/joho/godotenv v1.5.1 // indirect - github.com/klauspost/compress v1.17.8 // indirect + github.com/klauspost/compress v1.17.11 // indirect github.com/labstack/gommon v0.4.2 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -53,13 +57,19 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect - go.opentelemetry.io/otel/metric v1.26.0 // indirect - go.opentelemetry.io/otel/sdk v1.26.0 // indirect - go.opentelemetry.io/otel/trace v1.26.0 // indirect - golang.org/x/crypto v0.23.0 // indirect - golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/text v0.15.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.31.0 // indirect + go.opentelemetry.io/otel/metric v1.31.0 // indirect + go.opentelemetry.io/otel/sdk v1.31.0 // indirect + go.opentelemetry.io/otel/trace v1.31.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect + golang.org/x/crypto v0.28.0 // indirect + golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect + golang.org/x/net v0.30.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/text v0.19.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect + google.golang.org/grpc v1.67.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 8480946..20f700e 100644 --- a/go.sum +++ b/go.sum @@ -29,6 +29,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -40,18 +42,32 @@ github.com/cyverse-de/go-mod/cfg v0.0.2 h1:evHNKqLwOPWHhxxzF498/Rtac7LZb1zxnHAjZ github.com/cyverse-de/go-mod/cfg v0.0.2/go.mod h1:jjn1fZJRwqKiYgiS5AcXg9Dzxp2QOiLyrWVWCcq9Dw0= github.com/cyverse-de/go-mod/gotelnats v0.0.11 h1:jpnnGrCUnBq1oUow6vujXaW3oiqusViqFUGpJD4njB0= github.com/cyverse-de/go-mod/gotelnats v0.0.11/go.mod h1:UDIqvtSCeOKvjV+gZ+DrcPoTHPYkQjIuFxw7IlcbAI0= +github.com/cyverse-de/go-mod/gotelnats v0.0.12 h1:oq24rRC2Tsc2z/5d0cso9QqrSRq6ce+e0vfHlk+wtPA= +github.com/cyverse-de/go-mod/gotelnats v0.0.12/go.mod h1:n9+Qw8jV5z+w476xk3RRPBQzJQbA/fehv4UiXtL+Zqk= github.com/cyverse-de/go-mod/logging v0.0.2 h1:MhmyAXl1UgxwXUgP2C5/jl7QAsF+Bs+r7Cs0SSZYLlI= github.com/cyverse-de/go-mod/logging v0.0.2/go.mod h1:KkvW+/cMUdkfsJAD3uqMxHEb5naX8bwnO6z8znqHILQ= +github.com/cyverse-de/go-mod/logging v0.0.3 h1:sbehQImEP5cYusWVN1sDvo3lqwEfaZSCZLmrhFaI8xI= +github.com/cyverse-de/go-mod/logging v0.0.3/go.mod h1:KRRtiAvsBZlnR9qxXLFYaFdvJAJZKGYAIhRnjuORpIQ= github.com/cyverse-de/go-mod/otelutils v0.0.3 h1:4DAxvkZhf7YRUJeHaCyodbWv7t+tLzFchw6B4GrDsZ0= github.com/cyverse-de/go-mod/otelutils v0.0.3/go.mod h1:h75ZnGtwiwGwHgqpxFQL0912bnHMrcOKfyGAv2+q2Vw= +github.com/cyverse-de/go-mod/otelutils v0.0.4 h1:MHTf9VSeW+463BR1mpbE9lhgEflW9Cb1Tnu8Efj3Nhw= +github.com/cyverse-de/go-mod/otelutils v0.0.4/go.mod h1:ImgwzJFUE3EObZGtbsxCbEXVQCk43IP7Q2qs1H847PU= github.com/cyverse-de/go-mod/pbinit v0.1.11 h1:HUGZ5Q0yOwkp8vnGjJzmKX7FweX96f68IrZe/lfpKT0= github.com/cyverse-de/go-mod/pbinit v0.1.11/go.mod h1:eC6iC5kAxbWvJgZcqK04qeQbioX6KYwBoBw/SzsuPak= +github.com/cyverse-de/go-mod/pbinit v0.1.12 h1:HA9q0ffLAzAbcEYJkhQigZXXl06juaAhuft/baIKbOg= +github.com/cyverse-de/go-mod/pbinit v0.1.12/go.mod h1:M5zde8HkoyViaCD1sT/8PNNiYCheCfwhktfaoI6lobA= github.com/cyverse-de/go-mod/protobufjson v0.0.3 h1:XTIZejY7EUbpF6ZdhRhiFX9PGYDkGGmPP760cDswGWM= github.com/cyverse-de/go-mod/protobufjson v0.0.3/go.mod h1:p/ASemjpl2GEFYb3Tt7N8RozViwonsK0fOm0LxYeCt8= +github.com/cyverse-de/go-mod/protobufjson v0.0.4 h1:UPZCpdg6zm30tNf/c8JCI+F/SewiqeF42Uwi13X8diU= +github.com/cyverse-de/go-mod/protobufjson v0.0.4/go.mod h1:SJuTgEbjy56L3QtVKiON/kAHM298Xd8F4Uq7kyU8nFo= github.com/cyverse-de/go-mod/subjects v0.1.4 h1:w2LSkQAQLjK054QW4c155HgcJww8nn3nwBknzlWU0BM= github.com/cyverse-de/go-mod/subjects v0.1.4/go.mod h1:x8P+TNVSXvehkWMAmrg1RQHc5CCGafqtTKUn0hklkFA= +github.com/cyverse-de/go-mod/subjects v0.1.5 h1:wuThkSyC+XbngIAHVD3+WecSz7ytGRyQBzEBzzr0agU= +github.com/cyverse-de/go-mod/subjects v0.1.5/go.mod h1:XjBoa1k2CovbxjNqQFP69eiXEstiV4bqxZWSBLizGjA= github.com/cyverse-de/p v0.0.0-20240228001927-426a6bd80191 h1:f0tJEoxQ9t5X9JhH6P160uQt+j1K0LqAwOS7Uy5qzgQ= github.com/cyverse-de/p v0.0.0-20240228001927-426a6bd80191/go.mod h1:JM04cBlOajBkOVfQOEbBD6QwmWyupji9J84wfUA+LTc= +github.com/cyverse-de/p v0.0.0-20241022195522-7109f3ff6072 h1:jLG5JQ9UUUV553CEgccOO+opsaAJkZr/ezPMFz3sRRQ= +github.com/cyverse-de/p v0.0.0-20241022195522-7109f3ff6072/go.mod h1:JM04cBlOajBkOVfQOEbBD6QwmWyupji9J84wfUA+LTc= github.com/cyverse-de/p/go/analysis v0.0.16 h1:E+SE/v3RE1znwnIzk4ugXiM0knVsBnTLmuv4fcvietc= github.com/cyverse-de/p/go/analysis v0.0.16/go.mod h1:SJi4jTyxhqOe2waLcHKbDIN6+CZdV6WAJI2JWIrpFIQ= github.com/cyverse-de/p/go/containers v0.0.2 h1:PIpw5KHC6A85KeloHms86zG5ADVAQXjsP05n8KEWeXE= @@ -86,6 +102,8 @@ github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -97,6 +115,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/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-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= @@ -142,7 +162,10 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ 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/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 h1:ad0vkEBuk23VJzZR9nkLVG0YAoN9coASF1GusYX6AlU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0/go.mod h1:igFoXX2ELCW06bol23DWPB5BEWfZISOzSP5K2sbLea0= github.com/hashicorp/consul/api v1.13.0/go.mod h1:ZlVrynguJKcYr54zGaDbaL3fOvKC9m72FhPvA8T35KQ= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -196,6 +219,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/knadh/koanf v1.5.0 h1:q2TSd/3Pyc/5yP9ldIrSdIz26MCcyNQzW0pEAugLPNs= github.com/knadh/koanf v1.5.0/go.mod h1:Hgyjp4y8v44hpZtPzs7JZfRAW5AhN7KfZcwv1RYggDs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -259,6 +284,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/nats.go v1.34.1 h1:syWey5xaNHZgicYBemv0nohUPPmaLteiBEUT6Q5+F/4= github.com/nats-io/nats.go v1.34.1/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= +github.com/nats-io/nats.go v1.37.0 h1:07rauXbVnnJvv1gfIyghFEo6lUcYRY0WXc3x7x0vUxE= +github.com/nats-io/nats.go v1.37.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= @@ -300,6 +327,8 @@ github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFo github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= +github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= +github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -321,8 +350,12 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.4 h1:x3omFAG2XkvWFg1hvXRinY2ExAL1Aacl7W9ZlYjo6gc= github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.4/go.mod h1:qMKJr5fTnY0p7hqCQMNrAk62bCARWR5rAbTrGUFRuh4= +github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2 h1:ZjUj9BLYf9PEqBn8W/OapxhPjVRdC6CsXTdULHsyk5c= +github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2/go.mod h1:O8bHQfyinKwTXKkiKNGmLQS7vRsqRxIQTFZpYpHK3IQ= github.com/uptrace/opentelemetry-go-extra/otelsqlx v0.2.4 h1:Pt/+CUTRusJb471SBXwkRCz+9pbOjNr80M6LlwqV07w= github.com/uptrace/opentelemetry-go-extra/otelsqlx v0.2.4/go.mod h1:kQgNoghy4K/wguxbOd/u0OJw/Y0maNPc7PF4JpEGeUc= +github.com/uptrace/opentelemetry-go-extra/otelsqlx v0.3.2 h1:zA9ZXfdtowo0EKt+t7uqXNlHxPeygrxuFSIroiBVgPU= +github.com/uptrace/opentelemetry-go-extra/otelsqlx v0.3.2/go.mod h1:ySXmuW9JLCm/TjsQksuMY/7MNiWqfHnhH2xeT34uOLU= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= @@ -335,14 +368,28 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3 go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs= go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4= +go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 h1:K0XaT3DwHAcV4nKLzcQvwAgSyisUghWoY20I7huthMk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0/go.mod h1:B5Ki776z/MBnVha1Nzwp5arlzBbE3+1jk+pGmaP5HME= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.31.0 h1:FFeLy03iVTXP6ffeN2iXrxfGsZGCjVx0/4KlizjyBwU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.31.0/go.mod h1:TMu73/k1CP8nBUpDLc71Wj/Kf7ZS9FK5b53VapRsP9o= go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30= go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4= +go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= +go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= go.opentelemetry.io/otel/sdk v1.26.0 h1:Y7bumHf5tAiDlRYFmGqetNcLaVUZmh4iYfmGxtmz7F8= go.opentelemetry.io/otel/sdk v1.26.0/go.mod h1:0p8MXpqLeJ0pzcszQQN4F0S5FVjBLgypeGSngLsmirs= +go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= +go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA= go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0= +go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= @@ -355,9 +402,13 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= +golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -385,6 +436,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -432,6 +485,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -441,6 +496,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -464,7 +521,12 @@ google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 h1:2oV8dfuIkM1Ti7DwXc0BJfnwr9csz4TDXI9EmiI+Rbw= +google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38/go.mod h1:vuAjtvlwkDKF6L1GQ0SokiRLCGFfeBUXWr/aFFkHACc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= @@ -473,6 +535,8 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -486,6 +550,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From c976fef939f71bbc1204944e08e1d9665c73de13 Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Fri, 1 Nov 2024 17:24:02 -0700 Subject: [PATCH 03/21] CORE-2016: use go-ts-mode and go-mod-ts-mode for Go development --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 5f28fc0..083423c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ configs/local.yaml **/dotenv dev-test/ .env +local.mod +local.sum From a7b42d25255f7baf5cdbf2ecf0e128b687e4bda0 Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Tue, 5 Nov 2024 17:50:02 -0700 Subject: [PATCH 04/21] CORE-2016: added support for plan quota default effective dates --- db/tables/tables.go | 1 + db/types.go | 29 ++++++++++------- db/userplans.go | 1 + go.mod | 11 ++++--- go.sum | 76 ++++++++------------------------------------- 5 files changed, 40 insertions(+), 78 deletions(-) diff --git a/db/tables/tables.go b/db/tables/tables.go index 2fd38c4..102e893 100644 --- a/db/tables/tables.go +++ b/db/tables/tables.go @@ -10,6 +10,7 @@ var ( SubscriptionAddons = goqu.T("subscription_addons") Plans = goqu.T("plans") PlanQuotaDefaults = goqu.T("plan_quota_defaults") + PlanRates = goqu.T("plan_rates") PQD = PlanQuotaDefaults ResourceTypes = goqu.T("resource_types") RT = ResourceTypes diff --git a/db/types.go b/db/types.go index 0fb369a..db04abb 100644 --- a/db/types.go +++ b/db/types.go @@ -223,26 +223,33 @@ func (p Plan) ToQMSPlan() *qms.Plan { } type PlanQuotaDefault struct { - ID string `db:"id" goqu:"defaultifempty"` - PlanID string `db:"plan_id"` - QuotaValue float64 `db:"quota_value"` - ResourceType ResourceType `db:"resource_types"` + ID string `db:"id" goqu:"defaultifempty"` + PlanID string `db:"plan_id"` + QuotaValue float64 `db:"quota_value"` + ResourceType ResourceType `db:"resource_types"` + EffectiveDate time.Time `db:"effective_date"` } func NewPlanQuotaDefaultFromQMS(q *qms.QuotaDefault, planID string) *PlanQuotaDefault { + var effectiveDate time.Time + if q.EffectiveDate != nil { + effectiveDate = q.EffectiveDate.AsTime() + } return &PlanQuotaDefault{ - ID: q.Uuid, - PlanID: planID, - QuotaValue: q.QuotaValue, - ResourceType: *NewResourceTypeFromQMS(q.ResourceType), + ID: q.Uuid, + PlanID: planID, + QuotaValue: q.QuotaValue, + ResourceType: *NewResourceTypeFromQMS(q.ResourceType), + EffectiveDate: effectiveDate, } } func (pqd PlanQuotaDefault) ToQMSQuotaDefault() *qms.QuotaDefault { return &qms.QuotaDefault{ - Uuid: pqd.ID, - QuotaValue: pqd.QuotaValue, - ResourceType: pqd.ResourceType.ToQMSResourceType(), + Uuid: pqd.ID, + QuotaValue: pqd.QuotaValue, + ResourceType: pqd.ResourceType.ToQMSResourceType(), + EffectiveDate: timestamppb.New(pqd.EffectiveDate), } } diff --git a/db/userplans.go b/db/userplans.go index 44e5d67..946b225 100644 --- a/db/userplans.go +++ b/db/userplans.go @@ -315,6 +315,7 @@ func (d *Database) SubscriptionQuotaDefaults(ctx context.Context, planID string, t.PQD.Col("id").As("id"), t.PQD.Col("quota_value").As("quota_value"), t.PQD.Col("plan_id").As("plan_id"), + t.PQD.Col("effective_date").As("effective_date"), t.RT.Col("id").As(goqu.C("resource_types.id")), t.RT.Col("name").As(goqu.C("resource_types.name")), t.RT.Col("unit").As(goqu.C("resource_types.unit")), diff --git a/go.mod b/go.mod index 0cf589d..3b2990c 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,12 @@ module github.com/cyverse-de/subscriptions -go 1.22.0 +go 1.23.2 -toolchain go1.23.2 +replace github.com/cyverse-de/p/go/qms => /Users/sarahr/src/de/libs/p/go/qms + +replace github.com/cyverse-de/p/go/requests => /Users/sarahr/src/de/libs/p/go/requests + +replace github.com/cyverse-de/p/go/svcerror => /Users/sarahr/src/de/libs/p/go/svcerror require ( github.com/cyverse-de/go-mod/cfg v0.0.2 @@ -54,9 +58,9 @@ require ( github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/nats-io/nkeys v0.4.7 // indirect github.com/nats-io/nuid v1.0.1 // indirect + github.com/stretchr/objx v0.5.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect - go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.31.0 // indirect go.opentelemetry.io/otel/metric v1.31.0 // indirect @@ -64,7 +68,6 @@ require ( go.opentelemetry.io/otel/trace v1.31.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect golang.org/x/crypto v0.28.0 // indirect - golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect golang.org/x/net v0.30.0 // indirect golang.org/x/sys v0.26.0 // indirect golang.org/x/text v0.19.0 // indirect diff --git a/go.sum b/go.sum index 20f700e..8e35ccc 100644 --- a/go.sum +++ b/go.sum @@ -40,32 +40,18 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cyverse-de/go-mod/cfg v0.0.2 h1:evHNKqLwOPWHhxxzF498/Rtac7LZb1zxnHAjZSuqiEo= github.com/cyverse-de/go-mod/cfg v0.0.2/go.mod h1:jjn1fZJRwqKiYgiS5AcXg9Dzxp2QOiLyrWVWCcq9Dw0= -github.com/cyverse-de/go-mod/gotelnats v0.0.11 h1:jpnnGrCUnBq1oUow6vujXaW3oiqusViqFUGpJD4njB0= -github.com/cyverse-de/go-mod/gotelnats v0.0.11/go.mod h1:UDIqvtSCeOKvjV+gZ+DrcPoTHPYkQjIuFxw7IlcbAI0= github.com/cyverse-de/go-mod/gotelnats v0.0.12 h1:oq24rRC2Tsc2z/5d0cso9QqrSRq6ce+e0vfHlk+wtPA= github.com/cyverse-de/go-mod/gotelnats v0.0.12/go.mod h1:n9+Qw8jV5z+w476xk3RRPBQzJQbA/fehv4UiXtL+Zqk= -github.com/cyverse-de/go-mod/logging v0.0.2 h1:MhmyAXl1UgxwXUgP2C5/jl7QAsF+Bs+r7Cs0SSZYLlI= -github.com/cyverse-de/go-mod/logging v0.0.2/go.mod h1:KkvW+/cMUdkfsJAD3uqMxHEb5naX8bwnO6z8znqHILQ= github.com/cyverse-de/go-mod/logging v0.0.3 h1:sbehQImEP5cYusWVN1sDvo3lqwEfaZSCZLmrhFaI8xI= github.com/cyverse-de/go-mod/logging v0.0.3/go.mod h1:KRRtiAvsBZlnR9qxXLFYaFdvJAJZKGYAIhRnjuORpIQ= -github.com/cyverse-de/go-mod/otelutils v0.0.3 h1:4DAxvkZhf7YRUJeHaCyodbWv7t+tLzFchw6B4GrDsZ0= -github.com/cyverse-de/go-mod/otelutils v0.0.3/go.mod h1:h75ZnGtwiwGwHgqpxFQL0912bnHMrcOKfyGAv2+q2Vw= github.com/cyverse-de/go-mod/otelutils v0.0.4 h1:MHTf9VSeW+463BR1mpbE9lhgEflW9Cb1Tnu8Efj3Nhw= github.com/cyverse-de/go-mod/otelutils v0.0.4/go.mod h1:ImgwzJFUE3EObZGtbsxCbEXVQCk43IP7Q2qs1H847PU= -github.com/cyverse-de/go-mod/pbinit v0.1.11 h1:HUGZ5Q0yOwkp8vnGjJzmKX7FweX96f68IrZe/lfpKT0= -github.com/cyverse-de/go-mod/pbinit v0.1.11/go.mod h1:eC6iC5kAxbWvJgZcqK04qeQbioX6KYwBoBw/SzsuPak= github.com/cyverse-de/go-mod/pbinit v0.1.12 h1:HA9q0ffLAzAbcEYJkhQigZXXl06juaAhuft/baIKbOg= github.com/cyverse-de/go-mod/pbinit v0.1.12/go.mod h1:M5zde8HkoyViaCD1sT/8PNNiYCheCfwhktfaoI6lobA= -github.com/cyverse-de/go-mod/protobufjson v0.0.3 h1:XTIZejY7EUbpF6ZdhRhiFX9PGYDkGGmPP760cDswGWM= -github.com/cyverse-de/go-mod/protobufjson v0.0.3/go.mod h1:p/ASemjpl2GEFYb3Tt7N8RozViwonsK0fOm0LxYeCt8= github.com/cyverse-de/go-mod/protobufjson v0.0.4 h1:UPZCpdg6zm30tNf/c8JCI+F/SewiqeF42Uwi13X8diU= github.com/cyverse-de/go-mod/protobufjson v0.0.4/go.mod h1:SJuTgEbjy56L3QtVKiON/kAHM298Xd8F4Uq7kyU8nFo= -github.com/cyverse-de/go-mod/subjects v0.1.4 h1:w2LSkQAQLjK054QW4c155HgcJww8nn3nwBknzlWU0BM= -github.com/cyverse-de/go-mod/subjects v0.1.4/go.mod h1:x8P+TNVSXvehkWMAmrg1RQHc5CCGafqtTKUn0hklkFA= github.com/cyverse-de/go-mod/subjects v0.1.5 h1:wuThkSyC+XbngIAHVD3+WecSz7ytGRyQBzEBzzr0agU= github.com/cyverse-de/go-mod/subjects v0.1.5/go.mod h1:XjBoa1k2CovbxjNqQFP69eiXEstiV4bqxZWSBLizGjA= -github.com/cyverse-de/p v0.0.0-20240228001927-426a6bd80191 h1:f0tJEoxQ9t5X9JhH6P160uQt+j1K0LqAwOS7Uy5qzgQ= -github.com/cyverse-de/p v0.0.0-20240228001927-426a6bd80191/go.mod h1:JM04cBlOajBkOVfQOEbBD6QwmWyupji9J84wfUA+LTc= github.com/cyverse-de/p v0.0.0-20241022195522-7109f3ff6072 h1:jLG5JQ9UUUV553CEgccOO+opsaAJkZr/ezPMFz3sRRQ= github.com/cyverse-de/p v0.0.0-20241022195522-7109f3ff6072/go.mod h1:JM04cBlOajBkOVfQOEbBD6QwmWyupji9J84wfUA+LTc= github.com/cyverse-de/p/go/analysis v0.0.16 h1:E+SE/v3RE1znwnIzk4ugXiM0knVsBnTLmuv4fcvietc= @@ -76,12 +62,6 @@ github.com/cyverse-de/p/go/header v0.0.4 h1:asY/uixi9rCqbDLq2G21CT7WJRaendBfr1z2 github.com/cyverse-de/p/go/header v0.0.4/go.mod h1:1j79PqvJyMRmXXKyW4KbZWGQNontm0B9smsaq5t5Ct8= github.com/cyverse-de/p/go/monitoring v0.0.5 h1:n+GdL9a3R1zM7L+18SIufrtmLxXU8L/cKX6DhOJ7IhY= github.com/cyverse-de/p/go/monitoring v0.0.5/go.mod h1:CB0aMpTRJvCFlGeL/75uX4Snj/OXj9wzKF5KQX4tASg= -github.com/cyverse-de/p/go/qms v0.1.13 h1:4pcBCETTKwCYo9L3zfbQy92TXbaH/wv/VVyc3LGMl9E= -github.com/cyverse-de/p/go/qms v0.1.13/go.mod h1:Uv07x99AFaFmFwIwa3xTrN6bRxr76J7wK6R3Fgt/UG4= -github.com/cyverse-de/p/go/requests v0.0.3 h1:aFe6XxKPNib0nJSfS8QUPSQc8EnvCMv2dWUqUDEUnBU= -github.com/cyverse-de/p/go/requests v0.0.3/go.mod h1:oS0KhADCAS7trkpQqcperoIl4+Bge9xMPqbOSYzO+bc= -github.com/cyverse-de/p/go/svcerror v0.0.8 h1:UE06rE31kk7OcciTQlZfrJTFlC9AMTfNf6JKll41u0U= -github.com/cyverse-de/p/go/svcerror v0.0.8/go.mod h1:0h/BngUR9cTV86LYqHMkdREFcxJuMyOJV6f3u6Un4LQ= github.com/cyverse-de/p/go/user v0.0.11 h1:VM2WGrdvcmDLwwjUJpCbrhC5te8xFY8f71ALFO2N7LI= github.com/cyverse-de/p/go/user v0.0.11/go.mod h1:g6Gl6+Zv0PlZMoydO2cBmLFTLwQs39gYauboxp769KE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -100,8 +80,6 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -113,8 +91,6 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -162,7 +138,6 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ 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/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 h1:ad0vkEBuk23VJzZR9nkLVG0YAoN9coASF1GusYX6AlU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0/go.mod h1:igFoXX2ELCW06bol23DWPB5BEWfZISOzSP5K2sbLea0= @@ -217,8 +192,6 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= -github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/knadh/koanf v1.5.0 h1:q2TSd/3Pyc/5yP9ldIrSdIz26MCcyNQzW0pEAugLPNs= @@ -227,11 +200,13 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0= github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM= github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= @@ -282,8 +257,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nats-io/nats.go v1.34.1 h1:syWey5xaNHZgicYBemv0nohUPPmaLteiBEUT6Q5+F/4= -github.com/nats-io/nats.go v1.34.1/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= github.com/nats-io/nats.go v1.37.0 h1:07rauXbVnnJvv1gfIyghFEo6lUcYRY0WXc3x7x0vUxE= github.com/nats-io/nats.go v1.37.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= @@ -322,11 +295,11 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= -github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= -github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -339,6 +312,7 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -346,14 +320,12 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.4 h1:x3omFAG2XkvWFg1hvXRinY2ExAL1Aacl7W9ZlYjo6gc= -github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.4/go.mod h1:qMKJr5fTnY0p7hqCQMNrAk62bCARWR5rAbTrGUFRuh4= github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2 h1:ZjUj9BLYf9PEqBn8W/OapxhPjVRdC6CsXTdULHsyk5c= github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2/go.mod h1:O8bHQfyinKwTXKkiKNGmLQS7vRsqRxIQTFZpYpHK3IQ= -github.com/uptrace/opentelemetry-go-extra/otelsqlx v0.2.4 h1:Pt/+CUTRusJb471SBXwkRCz+9pbOjNr80M6LlwqV07w= -github.com/uptrace/opentelemetry-go-extra/otelsqlx v0.2.4/go.mod h1:kQgNoghy4K/wguxbOd/u0OJw/Y0maNPc7PF4JpEGeUc= github.com/uptrace/opentelemetry-go-extra/otelsqlx v0.3.2 h1:zA9ZXfdtowo0EKt+t7uqXNlHxPeygrxuFSIroiBVgPU= github.com/uptrace/opentelemetry-go-extra/otelsqlx v0.3.2/go.mod h1:ySXmuW9JLCm/TjsQksuMY/7MNiWqfHnhH2xeT34uOLU= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= @@ -366,31 +338,23 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= -go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs= -go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4= go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= -go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= -go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 h1:K0XaT3DwHAcV4nKLzcQvwAgSyisUghWoY20I7huthMk= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0/go.mod h1:B5Ki776z/MBnVha1Nzwp5arlzBbE3+1jk+pGmaP5HME= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.31.0 h1:FFeLy03iVTXP6ffeN2iXrxfGsZGCjVx0/4KlizjyBwU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.31.0/go.mod h1:TMu73/k1CP8nBUpDLc71Wj/Kf7ZS9FK5b53VapRsP9o= -go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30= -go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4= go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= -go.opentelemetry.io/otel/sdk v1.26.0 h1:Y7bumHf5tAiDlRYFmGqetNcLaVUZmh4iYfmGxtmz7F8= -go.opentelemetry.io/otel/sdk v1.26.0/go.mod h1:0p8MXpqLeJ0pzcszQQN4F0S5FVjBLgypeGSngLsmirs= go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= -go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA= -go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0= go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -400,15 +364,9 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= -golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= -golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -434,8 +392,6 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -483,8 +439,6 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -494,8 +448,6 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -521,7 +473,6 @@ google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 h1:2oV8dfuIkM1Ti7DwXc0BJfnwr9csz4TDXI9EmiI+Rbw= google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38/go.mod h1:vuAjtvlwkDKF6L1GQ0SokiRLCGFfeBUXWr/aFFkHACc= @@ -548,15 +499,14 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= From fc5a46da1d9e1da73ed7cc77f5b7fda813b8cf3a Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Thu, 7 Nov 2024 15:19:07 -0700 Subject: [PATCH 05/21] CORE-2016: added support for plan rates --- db/types.go | 50 +++++++++++++++++++++++++++++++++++++++++++++---- db/userplans.go | 46 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 85 insertions(+), 11 deletions(-) diff --git a/db/types.go b/db/types.go index db04abb..8586278 100644 --- a/db/types.go +++ b/db/types.go @@ -132,6 +132,7 @@ type Subscription struct { LastModifiedBy string `db:"last_modified_by"` LastModifiedAt string `db:"last_modified_at" goqu:"defaultifempty"` Paid bool `db:"paid" goqu:"defaultifempty"` + Rate PlanRate `db:"plan_rates"` } func NewSubscriptionFromQMS(s *qms.Subscription) *Subscription { @@ -159,6 +160,7 @@ func NewSubscriptionFromQMS(s *qms.Subscription) *Subscription { CreatedBy: s.User.Username, LastModifiedBy: s.User.Username, Paid: s.Paid, + Rate: *NewPlanRateFromQMS(s.PlanRate, s.Plan.Uuid), } } @@ -169,7 +171,7 @@ func (up Subscription) ToQMSSubscription() *qms.Subscription { quotas[i] = quota.ToQMSQuota() } - // Convert th elist of usages. + // Convert the list of usages. usages := make([]*qms.Usage, len(up.Usages)) for i, usage := range up.Usages { usages[i] = usage.ToQMSUsage() @@ -184,6 +186,7 @@ func (up Subscription) ToQMSSubscription() *qms.Subscription { Quotas: quotas, Usages: usages, Paid: up.Paid, + PlanRate: up.Rate.ToQMSPlanRate(), } } @@ -192,18 +195,24 @@ type Plan struct { Name string `db:"name"` Description string `db:"description"` QuotaDefaults []PlanQuotaDefault `db:"-"` + Rates []PlanRate `db:"-"` } func NewPlanFromQMS(q *qms.Plan) *Plan { - pqd := make([]PlanQuotaDefault, 0) - for _, qd := range q.PlanQuotaDefaults { - pqd = append(pqd, *NewPlanQuotaDefaultFromQMS(qd, q.Uuid)) + pqd := make([]PlanQuotaDefault, len(q.PlanQuotaDefaults)) + for i, qd := range q.PlanQuotaDefaults { + pqd[i] = *NewPlanQuotaDefaultFromQMS(qd, q.Uuid) + } + pr := make([]PlanRate, len(q.PlanRates)) + for i, r := range q.PlanRates { + pr[i] = *NewPlanRateFromQMS(r, q.Uuid) } return &Plan{ ID: q.Uuid, Name: q.Name, Description: q.Description, QuotaDefaults: pqd, + Rates: pr, } } @@ -213,12 +222,17 @@ func (p Plan) ToQMSPlan() *qms.Plan { for i, quotaDefault := range p.QuotaDefaults { quotaDefaults[i] = quotaDefault.ToQMSQuotaDefault() } + rates := make([]*qms.PlanRate, len(p.Rates)) + for i, rate := range p.Rates { + rates[i] = rate.ToQMSPlanRate() + } return &qms.Plan{ Uuid: p.ID, Name: p.Name, Description: p.Description, PlanQuotaDefaults: quotaDefaults, + PlanRates: rates, } } @@ -253,6 +267,34 @@ func (pqd PlanQuotaDefault) ToQMSQuotaDefault() *qms.QuotaDefault { } } +type PlanRate struct { + ID string `db:"id" goqu:"defaultifempty"` + PlanID string `db:"plan_id"` + EffectiveDate time.Time `db:"effective_date"` + Rate float64 `db:"rate"` +} + +func NewPlanRateFromQMS(r *qms.PlanRate, planID string) *PlanRate { + var effectiveDate time.Time + if r.EffectiveDate != nil { + effectiveDate = r.EffectiveDate.AsTime() + } + return &PlanRate{ + ID: r.Uuid, + PlanID: planID, + EffectiveDate: effectiveDate, + Rate: r.Rate, + } +} + +func (pr PlanRate) ToQMSPlanRate() *qms.PlanRate { + return &qms.PlanRate{ + Uuid: pr.ID, + EffectiveDate: timestamppb.New(pr.EffectiveDate), + Rate: pr.Rate, + } +} + type Usage struct { ID string `db:"id" goqu:"defaultifempty"` Usage float64 `db:"usage"` diff --git a/db/userplans.go b/db/userplans.go index 946b225..5229319 100644 --- a/db/userplans.go +++ b/db/userplans.go @@ -44,9 +44,14 @@ func subscriptionDS(db GoquDatabase) *goqu.SelectDataset { t.Plans.Col("id").As(goqu.C("plans.id")), t.Plans.Col("name").As(goqu.C("plans.name")), t.Plans.Col("description").As(goqu.C("plans.description")), + + t.PlanRates.Col("id").As(goqu.C("plan_rates.id")), + t.PlanRates.Col("effective_date").As(goqu.C("plan_rates.effective_date")), + t.PlanRates.Col("rate").As(goqu.C("plan_rates.rate")), ). Join(t.Users, goqu.On(t.Subscriptions.Col("user_id").Eq(t.Users.Col("id")))). - Join(t.Plans, goqu.On(t.Subscriptions.Col("plan_id").Eq(t.Plans.Col("id")))) + Join(t.Plans, goqu.On(t.Subscriptions.Col("plan_id").Eq(t.Plans.Col("id")))). + Join(t.PlanRates, goqu.On(t.Subscriptions.Col("plan_rate_id").Eq(t.PlanRates.Col("id")))) } func (d *Database) GetSubscriptionByID(ctx context.Context, subscriptionID string, opts ...QueryOption) (*Subscription, error) { @@ -262,6 +267,33 @@ func (d *Database) SubscriptionUsages(ctx context.Context, subscriptionID string return usages, nil } +// SubscriptionPlanRates returns a list of rates assocaited with a user plan specified by the passed in UUID. Accepts a +// variable number of QueryOptions, though only WithTX is currently supported. +func (d *Database) SubscriptionPlanRates(ctx context.Context, planID string, opts ...QueryOption) ([]PlanRate, error) { + var ( + err error + db GoquDatabase + rates []PlanRate + ) + + _, db = d.querySettings(opts...) + + ratesQuery := db.From(t.PlanRates). + Select( + t.PlanRates.Col("id").As("id"), + t.PlanRates.Col("plan_id").As("plan_id"), + t.PlanRates.Col("effective_date").As("effective_date"), + t.PlanRates.Col("rate").As("rate"), + ). + Where(t.PlanRates.Col("plan_id").Eq(planID)) + d.LogSQL(ratesQuery) + + if err = ratesQuery.Executor().ScanStructsContext(ctx, &rates); err != nil { + return nil, err + } + return rates, nil +} + // SubscriptionQuotas returns a list of t.Quotas associated with the user plan specified // by the UUID passed in. Accepts a variable number of QueryOptions, though only // WithTX is currently supported. @@ -342,28 +374,28 @@ func (d *Database) LoadSubscriptionDetails(ctx context.Context, subscription *Su quotas []Quota ) - log.Debug("before getting user plan quota defaults") defaults, err = d.SubscriptionQuotaDefaults(ctx, subscription.Plan.ID, opts...) if err != nil { return err } - log.Debug("after getting user plan quota defaults") - log.Debug("before getting user plan t.Quotas") quotas, err = d.SubscriptionQuotas(ctx, subscription.ID, opts...) if err != nil { return err } - log.Debug("after getting user plan t.Quotas") - log.Debug("before getting user plan usages") usages, err = d.SubscriptionUsages(ctx, subscription.ID, opts...) if err != nil { return err } - log.Debug("after getting user plan usages") + + planRates, err := d.SubscriptionPlanRates(ctx, subscription.Plan.ID) + if err != nil { + return err + } subscription.Plan.QuotaDefaults = defaults + subscription.Plan.Rates = planRates subscription.Quotas = quotas subscription.Usages = usages From af62a70d95b81232163635407d7928cf8dda4595 Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Thu, 7 Nov 2024 16:52:03 -0700 Subject: [PATCH 06/21] CORE-2016: rates and effective quota default for the add-user handler --- db/plans.go | 58 +++++++++++++++++++++++++++++++++++++++------ db/tables/tables.go | 2 +- db/types.go | 35 +++++++++++++++++++++++++++ db/userplans.go | 10 +++++++- 4 files changed, 96 insertions(+), 9 deletions(-) diff --git a/db/plans.go b/db/plans.go index 8835369..f00dbe3 100644 --- a/db/plans.go +++ b/db/plans.go @@ -9,19 +9,32 @@ import ( "github.com/pkg/errors" ) -func planDetailsDS(db GoquDatabase, planID string) *goqu.SelectDataset { +func planQuotaDefaultsDS(db GoquDatabase, planID string) *goqu.SelectDataset { return db.From(t.PQD). Select( t.PQD.Col("id"), t.PQD.Col("plan_id"), t.PQD.Col("quota_value"), + t.PQD.Col("effective_date"), t.RT.Col("id").As(goqu.C("resource_types.id")), t.RT.Col("name").As(goqu.C("resource_types.name")), t.RT.Col("unit").As(goqu.C("resource_types.unit")), ). Join(t.RT, goqu.On(t.PQD.Col("resource_type_id").Eq(t.RT.Col("id")))). - Where(t.PQD.Col("plan_id").Eq(planID)) + Where(t.PQD.Col("plan_id").Eq(planID)). + Order(t.PQD.Col("effective_date").Asc(), t.RT.Col("name").Asc()) +} + +func planRatesDS(db GoquDatabase, planID string) *goqu.SelectDataset { + return db.From(t.PlanRates). + Select( + t.PlanRates.Col("id"), + t.PlanRates.Col("effective_date"), + t.PlanRates.Col("rate"), + ). + Where(t.PlanRates.Col("plan_id").Eq(planID)). + Order(t.PlanRates.Col("effective_date").Asc()) } func (d *Database) getPlanList(ctx context.Context, opts ...QueryOption) ([]Plan, error) { @@ -41,12 +54,12 @@ func (d *Database) getPlanList(ctx context.Context, opts ...QueryOption) ([]Plan return plans, nil } -func (d *Database) loadPlanDetails(ctx context.Context, plan *Plan, opts ...QueryOption) error { - wrapMsg := fmt.Sprintf("unable to load details for plan ID %s", plan.ID) +func (d *Database) loadPlanQuotaDefaults(ctx context.Context, plan *Plan, opts ...QueryOption) error { + wrapMsg := fmt.Sprintf("unable to load the plan quota defaults for plan ID %s", plan.ID) _, db := d.querySettings(opts...) // Build the query. - query := planDetailsDS(db, plan.ID) + query := planQuotaDefaultsDS(db, plan.ID) d.LogSQL(query) // Execute the query and scan the results. @@ -57,6 +70,37 @@ func (d *Database) loadPlanDetails(ctx context.Context, plan *Plan, opts ...Quer return nil } +func (d *Database) loadPlanRates(ctx context.Context, plan *Plan, opts ...QueryOption) error { + wrapMsg := fmt.Sprintf("unable to load the plan rates for plan ID %s", plan.ID) + _, db := d.querySettings(opts...) + + // Build the query. + query := planRatesDS(db, plan.ID) + d.LogSQL(query) + + // Execute the query and scan the results. + err := query.ScanStructsContext(ctx, &plan.Rates) + if err != nil { + return errors.Wrap(err, wrapMsg) + } + + return nil +} + +func (d *Database) loadPlanDetails(ctx context.Context, plan *Plan, opts ...QueryOption) error { + err := d.loadPlanQuotaDefaults(ctx, plan, opts...) + if err != nil { + return err + } + + err = d.loadPlanRates(ctx, plan, opts...) + if err != nil { + return err + } + + return nil +} + func (d *Database) ListPlans(ctx context.Context, opts ...QueryOption) ([]Plan, error) { // Get the list of plans. plans, err := d.getPlanList(ctx, opts...) @@ -66,7 +110,7 @@ func (d *Database) ListPlans(ctx context.Context, opts ...QueryOption) ([]Plan, // Load the details for each plan in the list. for i := range plans { - err = d.loadPlanDetails(ctx, &plans[i], opts...) + err = d.loadPlanQuotaDefaults(ctx, &plans[i], opts...) if err != nil { return nil, err } @@ -94,7 +138,7 @@ func (d *Database) GetPlanByID(ctx context.Context, planID string, opts ...Query } // Load the plan details. - err = d.loadPlanDetails(ctx, &plan, opts...) + err = d.loadPlanQuotaDefaults(ctx, &plan, opts...) if err != nil { return nil, errors.Wrap(err, wrapMsg) } diff --git a/db/tables/tables.go b/db/tables/tables.go index 102e893..14806c1 100644 --- a/db/tables/tables.go +++ b/db/tables/tables.go @@ -10,7 +10,6 @@ var ( SubscriptionAddons = goqu.T("subscription_addons") Plans = goqu.T("plans") PlanQuotaDefaults = goqu.T("plan_quota_defaults") - PlanRates = goqu.T("plan_rates") PQD = PlanQuotaDefaults ResourceTypes = goqu.T("resource_types") RT = ResourceTypes @@ -18,4 +17,5 @@ var ( Usages = goqu.T("usages") Updates = goqu.T("updates") Addons = goqu.T("addons") + PlanRates = goqu.T("plan_rates") ) diff --git a/db/types.go b/db/types.go index 8586278..7d18ac0 100644 --- a/db/types.go +++ b/db/types.go @@ -236,6 +236,41 @@ func (p Plan) ToQMSPlan() *qms.Plan { } } +func (p Plan) GetActiveRate() *PlanRate { + now := time.Now() + + var effectiveRate *PlanRate + for _, pr := range p.Rates { + if pr.EffectiveDate.After(now) { + break + } + effectiveRate = &pr + } + + return effectiveRate +} + +func (p Plan) GetActiveQuotaDefaults() []*PlanQuotaDefault { + now := time.Now() + + pqdMap := make(map[string]*PlanQuotaDefault) + for _, pqd := range p.QuotaDefaults { + if pqd.EffectiveDate.After(now) { + break + } + pqdMap[pqd.ResourceType.Name] = &pqd + } + + index := 0 + pqds := make([]*PlanQuotaDefault, len(pqdMap)) + for _, pqd := range pqdMap { + pqds[index] = pqd + index++ + } + + return pqds +} + type PlanQuotaDefault struct { ID string `db:"id" goqu:"defaultifempty"` PlanID string `db:"plan_id"` diff --git a/db/userplans.go b/db/userplans.go index 5229319..b6b85a5 100644 --- a/db/userplans.go +++ b/db/userplans.go @@ -2,6 +2,7 @@ package db import ( "context" + "fmt" "time" t "github.com/cyverse-de/subscriptions/db/tables" @@ -120,6 +121,12 @@ func (d *Database) SetActiveSubscription( n := time.Now() e := subscriptionOpts.EndDate + // Get the active plan rate. + activePlanRate := plan.GetActiveRate() + if activePlanRate == nil { + return "", fmt.Errorf("the %s subscription plan has no effective rate", plan.Name) + } + query := db.Insert(t.Subscriptions). Rows( goqu.Record{ @@ -130,6 +137,7 @@ func (d *Database) SetActiveSubscription( "created_by": "de", "last_modified_by": "de", "paid": subscriptionOpts.Paid, + "plan_rate_id": activePlanRate.ID, }, ). Returning(t.Subscriptions.Col("id")) @@ -141,7 +149,7 @@ func (d *Database) SetActiveSubscription( } // Add the quota defaults as the t.Quotas for the user plan. - for _, quotaDefault := range plan.QuotaDefaults { + for _, quotaDefault := range plan.GetActiveQuotaDefaults() { quotaValue := quotaDefault.QuotaValue * float64(subscriptionOpts.Periods) if quotaDefault.ResourceType.Consumable { quotaValue *= float64(subscriptionOpts.Periods) From 191e75a0732633c9f49da2526003bfe6d2b8a46a Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Thu, 7 Nov 2024 17:03:00 -0700 Subject: [PATCH 07/21] CORE-2016: plan rates and quota default effective dates for the list plans handler --- app/plans.go | 24 +++--------------------- db/plans.go | 4 ++-- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/app/plans.go b/app/plans.go index 8fa81bb..616f75a 100644 --- a/app/plans.go +++ b/app/plans.go @@ -22,27 +22,9 @@ func (a *App) listPlans(ctx context.Context) *qms.PlanList { return response } - for _, p := range plans { - newP := &qms.Plan{ - Uuid: p.ID, - Name: p.Name, - Description: p.Description, - PlanQuotaDefaults: []*qms.QuotaDefault{}, - } - - for _, q := range p.QuotaDefaults { - newP.PlanQuotaDefaults = append(newP.PlanQuotaDefaults, &qms.QuotaDefault{ - Uuid: q.ID, - QuotaValue: q.QuotaValue, - ResourceType: &qms.ResourceType{ - Uuid: q.ResourceType.ID, - Name: q.ResourceType.Name, - Unit: q.ResourceType.Unit, - }, - }) - } - - response.Plans = append(response.Plans, newP) + response.Plans = make([]*qms.Plan, len(plans)) + for i, p := range plans { + response.Plans[i] = p.ToQMSPlan() } return response diff --git a/db/plans.go b/db/plans.go index f00dbe3..ea1cbc2 100644 --- a/db/plans.go +++ b/db/plans.go @@ -110,7 +110,7 @@ func (d *Database) ListPlans(ctx context.Context, opts ...QueryOption) ([]Plan, // Load the details for each plan in the list. for i := range plans { - err = d.loadPlanQuotaDefaults(ctx, &plans[i], opts...) + err = d.loadPlanDetails(ctx, &plans[i], opts...) if err != nil { return nil, err } @@ -138,7 +138,7 @@ func (d *Database) GetPlanByID(ctx context.Context, planID string, opts ...Query } // Load the plan details. - err = d.loadPlanQuotaDefaults(ctx, &plan, opts...) + err = d.loadPlanDetails(ctx, &plan, opts...) if err != nil { return nil, errors.Wrap(err, wrapMsg) } From a1724e87af3363e9ac421cfd5d908e4333297a93 Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Thu, 7 Nov 2024 17:43:21 -0700 Subject: [PATCH 08/21] WIP CORE-2016: began adding support for plan rates and effective dates on quota defaults to the add plans handler --- app/plans.go | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/app/plans.go b/app/plans.go index 616f75a..7ed64e1 100644 --- a/app/plans.go +++ b/app/plans.go @@ -65,34 +65,24 @@ func (a *App) addPlan(ctx context.Context, request *qms.AddPlanRequest) *qms.Pla d := db.New(a.db) - var qd []db.PlanQuotaDefault - var newPlanID string tx, err := d.Begin() if err != nil { response.Error = errors.NatsError(ctx, err) return response } err = tx.Wrap(func() error { - var err error - - for _, pqd := range request.Plan.PlanQuotaDefaults { - qd = append(qd, db.PlanQuotaDefault{ - QuotaValue: float64(pqd.QuotaValue), - ResourceType: db.ResourceType{ - ID: pqd.ResourceType.Uuid, - Name: pqd.ResourceType.Name, - Unit: pqd.ResourceType.Unit, - }, - }) + newPlanID, err := d.AddPlan(ctx, db.NewPlanFromQMS(request.Plan)) + if err != nil { + return err } - newPlanID, err = d.AddPlan(ctx, &db.Plan{ - Name: request.Plan.Name, - Description: request.Plan.Description, - QuotaDefaults: qd, - }, db.WithTX(tx)) + plan, err := d.GetPlanByID(ctx, newPlanID) + if err != nil { + return err + } - return err + response.Plan = plan.ToQMSPlan() + return nil }) if err != nil { @@ -100,9 +90,6 @@ func (a *App) addPlan(ctx context.Context, request *qms.AddPlanRequest) *qms.Pla return response } - response.Plan = request.Plan - response.Plan.Uuid = newPlanID - return response } From 9e9e3174013c58e034b63731c5172d435cd44a92 Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Fri, 8 Nov 2024 17:18:30 -0700 Subject: [PATCH 09/21] CORE-2016: added some additional request validation to the handler for adding user plans --- app/plans.go | 15 +++++++- db/types.go | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 1 deletion(-) diff --git a/app/plans.go b/app/plans.go index 7ed64e1..5691e84 100644 --- a/app/plans.go +++ b/app/plans.go @@ -71,7 +71,20 @@ func (a *App) addPlan(ctx context.Context, request *qms.AddPlanRequest) *qms.Pla return response } err = tx.Wrap(func() error { - newPlanID, err := d.AddPlan(ctx, db.NewPlanFromQMS(request.Plan)) + incomingPlan := db.NewPlanFromQMS(request.Plan) + err := incomingPlan.Validate() + if err != nil { + return err + } + + existingPlan, err := d.GetPlanByName(ctx, incomingPlan.Name) + if err != nil { + return err + } else if existingPlan != nil { + return fmt.Errorf("a plan named %s already exists", incomingPlan.Name) + } + + newPlanID, err := d.AddPlan(ctx, incomingPlan) if err != nil { return err } diff --git a/db/types.go b/db/types.go index 7d18ac0..674e417 100644 --- a/db/types.go +++ b/db/types.go @@ -3,6 +3,7 @@ package db import ( "context" "database/sql" + "fmt" "time" "github.com/cyverse-de/p/go/qms" @@ -48,6 +49,11 @@ const QuotasTrackedMetric = "quotas" const DefaultPlanName = "Basic" +type PlanQuotaDefaultKey struct { + ResourceTypeID string + EffectiveDate int64 +} + type UpdateOperation struct { ID string `db:"id" goqu:"defaultifempty"` Name string `db:"name"` @@ -90,6 +96,16 @@ func NewResourceTypeFromQMS(q *qms.ResourceType) *ResourceType { } } +func (rt ResourceType) ValidateForPlan() error { + + // The resource type ID is required. + if rt.ID == "" { + return fmt.Errorf("a resource type ID is required") + } + + return nil +} + var ResourceTypeNames = []string{ "cpu.hours", "data.size", @@ -271,6 +287,55 @@ func (p Plan) GetActiveQuotaDefaults() []*PlanQuotaDefault { return pqds } +func (p Plan) Validate() error { + + // The plan name and description are both required. + if p.Name == "" { + return fmt.Errorf("a plan name is required") + } + if p.Description == "" { + return fmt.Errorf("a plan description is required") + } + + // Validate the quota defaults. + for _, qd := range p.QuotaDefaults { + if err := qd.ValidateForPlan(); err != nil { + return err + } + } + + // Verify that there's only one quota default per resource type and effective date. + uniquePlanQuotaDefaults := make(map[PlanQuotaDefaultKey]bool) + for _, qd := range p.QuotaDefaults { + key := qd.Key() + if uniquePlanQuotaDefaults[key] { + return fmt.Errorf("there can only be one quota default for each resource type and effective date") + } else { + uniquePlanQuotaDefaults[key] = true + } + } + + // Validate the plan rates. + for _, r := range p.Rates { + if err := r.ValidateForPlan(); err != nil { + return err + } + } + + // Verify that there's only one rate per effective date. + uniquePlanRates := make(map[int64]bool) + for _, r := range p.Rates { + key := r.EffectiveDate.UnixMicro() + if uniquePlanRates[key] { + return fmt.Errorf("there can only be one plan rate for each effective date") + } else { + uniquePlanRates[key] = true + } + } + + return nil +} + type PlanQuotaDefault struct { ID string `db:"id" goqu:"defaultifempty"` PlanID string `db:"plan_id"` @@ -302,6 +367,28 @@ func (pqd PlanQuotaDefault) ToQMSQuotaDefault() *qms.QuotaDefault { } } +func (pqd PlanQuotaDefault) ValidateForPlan() error { + + // The default quota value must be specified and greater than zero. + if pqd.QuotaValue <= 0 { + return fmt.Errorf("plan quota default values must be specified and greater than zero") + } + + // The effective date must be specified. + if pqd.EffectiveDate.IsZero() { + return fmt.Errorf("all plan quota defaults must have an effective date") + } + + return pqd.ResourceType.ValidateForPlan() +} + +func (pqd PlanQuotaDefault) Key() PlanQuotaDefaultKey { + return PlanQuotaDefaultKey{ + ResourceTypeID: pqd.ResourceType.ID, + EffectiveDate: pqd.EffectiveDate.UnixMicro(), + } +} + type PlanRate struct { ID string `db:"id" goqu:"defaultifempty"` PlanID string `db:"plan_id"` @@ -330,6 +417,25 @@ func (pr PlanRate) ToQMSPlanRate() *qms.PlanRate { } } +func (pr PlanRate) Validate() error { + + // The rate can't be negative. + if pr.Rate < 0 { + return fmt.Errorf("the plan rate must not be less than zero") + } + + // The effective date has to be specified. + if pr.EffectiveDate.IsZero() { + return fmt.Errorf("the effective date of the plan rate must be specified") + } + + return nil +} + +func (pr PlanRate) ValidateForPlan() error { + return pr.Validate() +} + type Usage struct { ID string `db:"id" goqu:"defaultifempty"` Usage float64 `db:"usage"` From 07c20477ec9b26f624739a974173fe58d8e2fc36 Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Tue, 12 Nov 2024 17:38:33 -0700 Subject: [PATCH 10/21] CORE-2016: updated the code to save new plans in the add plan handler --- app/plans.go | 6 +++--- db/plans.go | 21 ++++++++++++++++++--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/app/plans.go b/app/plans.go index 5691e84..e3a910a 100644 --- a/app/plans.go +++ b/app/plans.go @@ -77,19 +77,19 @@ func (a *App) addPlan(ctx context.Context, request *qms.AddPlanRequest) *qms.Pla return err } - existingPlan, err := d.GetPlanByName(ctx, incomingPlan.Name) + existingPlan, err := d.GetPlanByName(ctx, incomingPlan.Name, db.WithTX(tx)) if err != nil { return err } else if existingPlan != nil { return fmt.Errorf("a plan named %s already exists", incomingPlan.Name) } - newPlanID, err := d.AddPlan(ctx, incomingPlan) + newPlanID, err := d.AddPlan(ctx, incomingPlan, db.WithTX(tx)) if err != nil { return err } - plan, err := d.GetPlanByID(ctx, newPlanID) + plan, err := d.GetPlanByID(ctx, newPlanID, db.WithTX(tx)) if err != nil { return err } diff --git a/db/plans.go b/db/plans.go index ea1cbc2..d5e406f 100644 --- a/db/plans.go +++ b/db/plans.go @@ -191,20 +191,35 @@ func (d *Database) AddPlan(ctx context.Context, plan *Plan, opts ...QueryOption) } for _, pqd := range plan.QuotaDefaults { - newDS := db.Insert(t.PQD). + pqdDS := db.Insert(t.PQD). Rows( goqu.Record{ "plan_id": newPlanID, "resource_type_id": pqd.ResourceType.ID, "quota_value": pqd.QuotaValue, + "effective_date": pqd.EffectiveDate, }, ).Executor() - if _, err := newDS.ExecContext(ctx); err != - nil { + if _, err := pqdDS.ExecContext(ctx); err != nil { return "", errors.Wrap(err, "unable to add plan quota defaults") } } + for _, pr := range plan.Rates { + prDS := db.Insert(t.PlanRates). + Rows( + goqu.Record{ + "plan_id": newPlanID, + "effective_date": pr.EffectiveDate, + "rate": pr.Rate, + }, + ).Executor() + + if _, err := prDS.ExecContext(ctx); err != nil { + return "", errors.Wrap(err, "unable to add plan rates") + } + } + return newPlanID, nil } From 9bc10af7c2a36ccf1d3002057540e97048004b99 Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Thu, 14 Nov 2024 12:39:19 -0700 Subject: [PATCH 11/21] CORE-2016: updated the `cyverse.qms.addon.list` handler to include addon rates --- db/addons.go | 31 ++++++++++++++++++++++++++++++- db/tables/tables.go | 1 + db/types.go | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/db/addons.go b/db/addons.go index e5282a2..1416f9a 100644 --- a/db/addons.go +++ b/db/addons.go @@ -67,6 +67,7 @@ func (d *Database) GetAddonByID(ctx context.Context, addonID string, opts ...Que } func (d *Database) ListAddons(ctx context.Context, opts ...QueryOption) ([]Addon, error) { + wrapMsg := "unable to list addons" _, db := d.querySettings(opts...) ds := db.From(t.Addons). @@ -86,12 +87,40 @@ func (d *Database) ListAddons(ctx context.Context, opts ...QueryOption) ([]Addon var addons []Addon if err := ds.ScanStructsContext(ctx, &addons); err != nil { - return nil, errors.Wrap(err, "unable to list addons") + return nil, errors.Wrap(err, wrapMsg) + } + + for i, addon := range addons { + addonRates, err := d.ListRatesForAddon(ctx, addon.ID, opts...) + if err != nil { + return nil, errors.Wrap(err, wrapMsg) + } + addons[i].AddonRates = addonRates } return addons, nil } +func (d *Database) ListRatesForAddon(ctx context.Context, addonID string, opts ...QueryOption) ([]AddonRate, error) { + _, db := d.querySettings(opts...) + + ds := db.From(t.AddonRates). + Select( + t.AddonRates.Col("id"), + t.AddonRates.Col("addon_id"), + t.AddonRates.Col("effective_date"), + t.AddonRates.Col("rate"), + ) + d.LogSQL(ds) + + var addonRates []AddonRate + if err := ds.ScanStructsContext(ctx, &addonRates); err != nil { + return nil, errors.Wrapf(err, "unable to list rates for addon ID %s", addonID) + } + + return addonRates, nil +} + func (d *Database) ToggleAddonPaid(ctx context.Context, addonID string, opts ...QueryOption) (*Addon, error) { tx, err := d.Begin() if err != nil { diff --git a/db/tables/tables.go b/db/tables/tables.go index 14806c1..b19009a 100644 --- a/db/tables/tables.go +++ b/db/tables/tables.go @@ -18,4 +18,5 @@ var ( Updates = goqu.T("updates") Addons = goqu.T("addons") PlanRates = goqu.T("plan_rates") + AddonRates = goqu.T("addon_rates") ) diff --git a/db/types.go b/db/types.go index 674e417..cdd5cf7 100644 --- a/db/types.go +++ b/db/types.go @@ -526,19 +526,29 @@ type Addon struct { ResourceType ResourceType `db:"resource_types"` DefaultAmount float64 `db:"default_amount"` DefaultPaid bool `db:"default_paid"` + AddonRates []AddonRate `db:"-"` } func NewAddonFromQMS(q *qms.Addon) *Addon { + addonRates := make([]AddonRate, len(q.AddonRates)) + for i, r := range q.AddonRates { + addonRates[i] = *NewAddonRateFromQMS(r, q.Uuid) + } return &Addon{ Name: q.Name, Description: q.Description, DefaultAmount: q.DefaultAmount, DefaultPaid: q.DefaultPaid, ResourceType: *NewResourceTypeFromQMS(q.ResourceType), + AddonRates: addonRates, } } func (a *Addon) ToQMSType() *qms.Addon { + addonRates := make([]*qms.AddonRate, len(a.AddonRates)) + for i, r := range a.AddonRates { + addonRates[i] = r.ToQMSType() + } return &qms.Addon{ Uuid: a.ID, Name: a.Name, @@ -550,6 +560,35 @@ func (a *Addon) ToQMSType() *qms.Addon { Name: a.ResourceType.Name, Unit: a.ResourceType.Unit, }, + AddonRates: addonRates, + } +} + +type AddonRate struct { + ID string `db:"id" goqu:"defaultifempty,skipupdate"` + AddonID string `db:"addon_id"` + EffectiveDate time.Time `db:"effective_date"` + Rate float64 `db:"rate"` +} + +func NewAddonRateFromQMS(r *qms.AddonRate, addonID string) *AddonRate { + var effectiveDate time.Time + if r.EffectiveDate != nil { + effectiveDate = r.EffectiveDate.AsTime() + } + return &AddonRate{ + ID: r.Uuid, + AddonID: addonID, + EffectiveDate: effectiveDate, + Rate: r.Rate, + } +} + +func (r *AddonRate) ToQMSType() *qms.AddonRate { + return &qms.AddonRate{ + Uuid: r.ID, + EffectiveDate: timestamppb.New(r.EffectiveDate), + Rate: r.Rate, } } From 18b489d410cb2fc87e58c30073951a0cc1a886e9 Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Thu, 14 Nov 2024 17:59:20 -0700 Subject: [PATCH 12/21] CORE-2016: updated the `cyverse.qms.addon.add` handler --- app/addons.go | 67 ++++++++++++++---------------------- app/plans.go | 18 ++++++++++ db/addons.go | 16 +++++++++ db/resourcetypes.go | 17 ++++++++++ db/types.go | 83 ++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 150 insertions(+), 51 deletions(-) diff --git a/app/addons.go b/app/addons.go index 711c992..10dfe1f 100644 --- a/app/addons.go +++ b/app/addons.go @@ -17,72 +17,55 @@ import ( ) func (a *App) addAddon(ctx context.Context, request *qms.AddAddonRequest) *qms.AddonResponse { + var newAddon *db.Addon d := db.New(a.db) - - reqAddon := request.Addon response := qmsinit.NewAddonResponse() - if reqAddon.Name == "" { - response.Error = serrors.NatsError(ctx, errors.New("name must be set")) - return response - } - - if reqAddon.Description == "" { - response.Error = serrors.NatsError(ctx, errors.New("descriptions must be set")) - return response - } - - if reqAddon.DefaultAmount <= 0.0 { - response.Error = serrors.NatsError(ctx, errors.New("default_amount must be greater than 0.0")) - return response + // Validate the incoming request. + requestedAddon := db.NewAddonFromQMS(request.Addon) + if err := requestedAddon.Validate(); err != nil { + response.Error = serrors.NatsError(ctx, err) } - - if reqAddon.ResourceType.Name == "" && reqAddon.ResourceType.Uuid == "" { - response.Error = serrors.NatsError(ctx, errors.New("resource_type.name or resource_type.uuid must be set")) - return response + if err := requestedAddon.ValidateAddonRateUniqueness(); err != nil { + response.Error = serrors.NatsError(ctx, err) } - var lookupRT *db.ResourceType - + // Start a transaction. tx, err := d.Begin() if err != nil { response.Error = serrors.NatsError(ctx, err) return response } - defer func() { - _ = tx.Rollback() - }() + err = tx.Wrap(func() error { - if reqAddon.ResourceType.Name != "" && reqAddon.ResourceType.Uuid == "" { - lookupRT, err = d.GetResourceTypeByName(ctx, reqAddon.ResourceType.Name, db.WithTX(tx)) + // Look up the resource type. + resourceType, err := d.LookupResoureType(ctx, &requestedAddon.ResourceType, db.WithTX(tx)) if err != nil { - response.Error = serrors.NatsError(ctx, err) - return response + return err } - } else { - lookupRT, err = d.GetResourceType(ctx, reqAddon.ResourceType.Uuid, db.WithTX(tx)) + requestedAddon.ResourceType = *resourceType + + // Add the addon to the database. + addonID, err := d.AddAddon(ctx, requestedAddon, db.WithTX(tx)) if err != nil { - response.Error = serrors.NatsError(ctx, err) - return response + return err } - } - newAddon := db.NewAddonFromQMS(request.Addon) - newAddon.ResourceType = *lookupRT + // Retrieve the addon from the database. + newAddon, err = d.GetAddonByID(ctx, addonID, db.WithTX(tx)) + if err != nil { + return err + } - newID, err := d.AddAddon(ctx, newAddon, db.WithTX(tx)) + return nil + }) if err != nil { response.Error = serrors.NatsError(ctx, err) return response } - if err = tx.Commit(); err != nil { - response.Error = serrors.NatsError(ctx, err) - return response - } - + // Return the inserted addon. response.Addon = newAddon.ToQMSType() - response.Addon.Uuid = newID return response } diff --git a/app/plans.go b/app/plans.go index e3a910a..91c17e3 100644 --- a/app/plans.go +++ b/app/plans.go @@ -84,6 +84,24 @@ func (a *App) addPlan(ctx context.Context, request *qms.AddPlanRequest) *qms.Pla return fmt.Errorf("a plan named %s already exists", incomingPlan.Name) } + for i, pqd := range incomingPlan.QuotaDefaults { + rt, err := d.LookupResoureType(ctx, &pqd.ResourceType, db.WithTX(tx)) + if err != nil { + return err + } + incomingPlan.QuotaDefaults[i].ResourceType = *rt + } + + err = incomingPlan.ValidateQuotaDefaultUniqueness() + if err != nil { + return err + } + + err = incomingPlan.ValidatePlanRateUniqueness() + if err != nil { + return err + } + newPlanID, err := d.AddPlan(ctx, incomingPlan, db.WithTX(tx)) if err != nil { return err diff --git a/db/addons.go b/db/addons.go index 1416f9a..317b63c 100644 --- a/db/addons.go +++ b/db/addons.go @@ -29,6 +29,22 @@ func (d *Database) AddAddon(ctx context.Context, addon *Addon, opts ...QueryOpti return "", err } + // Add the addon rates. + addonRateRows := make([]interface{}, len(addon.AddonRates)) + for i, r := range addon.AddonRates { + addonRateRows[i] = goqu.Record{ + "addon_id": newAddonID, + "effective_date": r.EffectiveDate, + "rate": r.Rate, + } + } + addonRateDS := db.Insert(t.AddonRates). + Rows(addonRateRows...). + Executor() + if _, err := addonRateDS.ExecContext(ctx); err != nil { + return "", err + } + return newAddonID, nil } diff --git a/db/resourcetypes.go b/db/resourcetypes.go index babda8b..6145141 100644 --- a/db/resourcetypes.go +++ b/db/resourcetypes.go @@ -2,6 +2,7 @@ package db import ( "context" + "fmt" t "github.com/cyverse-de/subscriptions/db/tables" "github.com/doug-martin/goqu/v9" @@ -110,3 +111,19 @@ func (d *Database) GetResourceTypeByName(ctx context.Context, name string, opts return &resourceType, nil } + +// LookupResourceType attempts to look up a resource type using either its ID or name in that order. It's an error to +// attempt a lookup with no ID or name specified. +func (d *Database) LookupResoureType( + ctx context.Context, + lookup *ResourceType, + opts ...QueryOption, +) (*ResourceType, error) { + if lookup.ID != "" { + return d.GetResourceType(ctx, lookup.ID, opts...) + } else if lookup.Name != "" { + return d.GetResourceTypeByName(ctx, lookup.Name, opts...) + } else { + return nil, fmt.Errorf("either the resource type ID or name must be specified") + } +} diff --git a/db/types.go b/db/types.go index cdd5cf7..e1e0ad2 100644 --- a/db/types.go +++ b/db/types.go @@ -98,9 +98,9 @@ func NewResourceTypeFromQMS(q *qms.ResourceType) *ResourceType { func (rt ResourceType) ValidateForPlan() error { - // The resource type ID is required. - if rt.ID == "" { - return fmt.Errorf("a resource type ID is required") + // We must have enough information to at least attempt to look up the resource type. + if rt.ID == "" && rt.Name == "" { + return fmt.Errorf("either the resource type name or the resource type ID is required") } return nil @@ -304,6 +304,18 @@ func (p Plan) Validate() error { } } + // Validate the plan rates. + for _, r := range p.Rates { + if err := r.ValidateForPlan(); err != nil { + return err + } + } + + return nil +} + +func (p Plan) ValidateQuotaDefaultUniqueness() error { + // Verify that there's only one quota default per resource type and effective date. uniquePlanQuotaDefaults := make(map[PlanQuotaDefaultKey]bool) for _, qd := range p.QuotaDefaults { @@ -315,12 +327,10 @@ func (p Plan) Validate() error { } } - // Validate the plan rates. - for _, r := range p.Rates { - if err := r.ValidateForPlan(); err != nil { - return err - } - } + return nil +} + +func (p Plan) ValidatePlanRateUniqueness() error { // Verify that there's only one rate per effective date. uniquePlanRates := make(map[int64]bool) @@ -564,6 +574,46 @@ func (a *Addon) ToQMSType() *qms.Addon { } } +func (a *Addon) Validate() error { + + // The name and description are both required. + if a.Name == "" { + return fmt.Errorf("name must be set") + } + if a.Description == "" { + return fmt.Errorf("description must be set") + } + + // The default amount must be positive. + if a.DefaultAmount <= 0.0 { + return fmt.Errorf("default_amount must be greater than 0.0") + } + + // Verify that we have enough information to attempt to look up the resource type. + if err := a.ResourceType.ValidateForPlan(); err != nil { + return err + } + + // Validate the incoming addon rates. + return nil +} + +func (a *Addon) ValidateAddonRateUniqueness() error { + + // Verify that there's only one rate per effective date. + uniqueAddonRates := make(map[int64]bool) + for _, r := range a.AddonRates { + key := r.EffectiveDate.UnixMicro() + if uniqueAddonRates[key] { + return fmt.Errorf("there can only be one plan rate for each effective date") + } else { + uniqueAddonRates[key] = true + } + } + + return nil +} + type AddonRate struct { ID string `db:"id" goqu:"defaultifempty,skipupdate"` AddonID string `db:"addon_id"` @@ -592,6 +642,21 @@ func (r *AddonRate) ToQMSType() *qms.AddonRate { } } +func (r *AddonRate) Validate() error { + + // The rate can't be negative. + if r.Rate < 0 { + return fmt.Errorf("the plan rate must not be less than zero") + } + + // The effective date has to be specified. + if r.EffectiveDate.IsZero() { + return fmt.Errorf("the effective date of the plan rate must be specified") + } + + return nil +} + type UpdateAddon struct { ID string `db:"id" goqu:"skipupdate"` Name string `db:"name"` From 6ccdedc705f93c1a4b87344f8cf28e14a6e9d738 Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Fri, 15 Nov 2024 18:06:59 -0700 Subject: [PATCH 13/21] CORE-2016: updated the handler for the `cyverse.qms.addon.update` --- app/addons.go | 18 +++++++++++-- db/addons.go | 73 ++++++++++++++++++++++++++++++++++++++++++++++++--- db/types.go | 32 ++++++++++++++-------- go.mod | 2 +- go.sum | 4 +-- 5 files changed, 110 insertions(+), 19 deletions(-) diff --git a/app/addons.go b/app/addons.go index 10dfe1f..cb16736 100644 --- a/app/addons.go +++ b/app/addons.go @@ -174,14 +174,28 @@ func (a *App) updateAddon(ctx context.Context, request *qms.UpdateAddonRequest) updateAddon := db.NewUpdateAddonFromQMS(request) - result, err := d.UpdateAddon(ctx, updateAddon) + tx, err := d.Begin() if err != nil { response.Error = serrors.NatsError(ctx, err) return response } + err = tx.Wrap(func() error { + _, err := d.UpdateAddon(ctx, updateAddon, db.WithTX(tx)) + if err != nil { + return err + } - response.Addon = result.ToQMSType() + result, err := d.GetAddonByID(ctx, updateAddon.ID, db.WithTX(tx)) + if err != nil { + return err + } + response.Addon = result.ToQMSType() + return nil + }) + if err != nil { + response.Error = serrors.NatsError(ctx, err) + } return response } diff --git a/db/addons.go b/db/addons.go index 317b63c..f1da9a3 100644 --- a/db/addons.go +++ b/db/addons.go @@ -2,6 +2,7 @@ package db import ( "context" + "fmt" t "github.com/cyverse-de/subscriptions/db/tables" suberrors "github.com/cyverse-de/subscriptions/errors" @@ -75,10 +76,19 @@ func (d *Database) GetAddonByID(ctx context.Context, addonID string, opts ...Que Where(t.Addons.Col("id").Eq(addonID)). Executor() - if addonFound, err = addonInfo.ScanStructContext(ctx, addon); err != nil || !addonFound { + addonFound, err = addonInfo.ScanStructContext(ctx, addon) + if err != nil { return nil, errors.Wrap(err, "unable to get add-on info") + } else if !addonFound { + return nil, fmt.Errorf("addon ID %s not found", addonID) } + addonRates, err := d.ListRatesForAddon(ctx, addonID, opts...) + if err != nil { + return nil, errors.Wrap(err, "unable to get add-on info") + } + addon.AddonRates = addonRates + return addon, nil } @@ -126,7 +136,9 @@ func (d *Database) ListRatesForAddon(ctx context.Context, addonID string, opts . t.AddonRates.Col("addon_id"), t.AddonRates.Col("effective_date"), t.AddonRates.Col("rate"), - ) + ). + Where(goqu.Ex{"addon_id": addonID}). + Order(goqu.I("effective_date").Asc()) d.LogSQL(ds) var addonRates []AddonRate @@ -191,6 +203,45 @@ func (d *Database) ToggleAddonPaid(ctx context.Context, addonID string, opts ... return retval, nil } +func (d *Database) AddAddonRate(ctx context.Context, r AddonRate, opts ...QueryOption) error { + _, db := d.querySettings(opts...) + + ds := db.Insert(t.AddonRates). + Rows( + goqu.Record{ + "addon_id": r.AddonID, + "effective_date": r.EffectiveDate, + "rate": r.Rate, + }, + ). + Executor() + if _, err := ds.ExecContext(ctx); err != nil { + return err + } + + return nil +} + +func (d *Database) UpdateAddonRate(ctx context.Context, r AddonRate, opts ...QueryOption) error { + _, db := d.querySettings(opts...) + + ds := db.Update(t.AddonRates). + Set( + goqu.Record{ + "addon_id": r.AddonID, + "effective_date": r.EffectiveDate, + "rate": r.Rate, + }, + ). + Where(t.AddonRates.Col("id").Eq(r.ID)). + Executor() + if _, err := ds.ExecContext(ctx); err != nil { + return err + } + + return nil +} + func (d *Database) UpdateAddon(ctx context.Context, updatedAddon *UpdateAddon, opts ...QueryOption) (*Addon, error) { _, db := d.querySettings(opts...) @@ -230,11 +281,27 @@ func (d *Database) UpdateAddon(ctx context.Context, updatedAddon *UpdateAddon, o if err != nil { return nil, errors.Wrap(err, "unable to scan results of update") } - if !found { return nil, suberrors.ErrAddonNotFound } + // Update existing addon rates. + if updatedAddon.UpdateAddonRates { + for _, r := range updatedAddon.AddonRates { + if r.ID == "" { + err = d.AddAddonRate(ctx, r, opts...) + if err != nil { + return nil, err + } + } else { + err = d.UpdateAddonRate(ctx, r, opts...) + if err != nil { + return nil, err + } + } + } + } + return retval, nil } diff --git a/db/types.go b/db/types.go index e1e0ad2..5ecb684 100644 --- a/db/types.go +++ b/db/types.go @@ -658,17 +658,19 @@ func (r *AddonRate) Validate() error { } type UpdateAddon struct { - ID string `db:"id" goqu:"skipupdate"` - Name string `db:"name"` - UpdateName bool `db:"-"` - Description string `db:"description"` - UpdateDescription bool `db:"-"` - ResourceTypeID string `db:"resource_type_id"` - UpdateResourceType bool `db:"-"` - DefaultAmount float64 `db:"default_amount"` - UpdateDefaultAmount bool `db:"-"` - DefaultPaid bool `db:"default_paid"` - UpdateDefaultPaid bool `db:"-"` + ID string `db:"id" goqu:"skipupdate"` + Name string `db:"name"` + UpdateName bool `db:"-"` + Description string `db:"description"` + UpdateDescription bool `db:"-"` + ResourceTypeID string `db:"resource_type_id"` + UpdateResourceType bool `db:"-"` + DefaultAmount float64 `db:"default_amount"` + UpdateDefaultAmount bool `db:"-"` + DefaultPaid bool `db:"default_paid"` + UpdateDefaultPaid bool `db:"-"` + AddonRates []AddonRate `db:"-"` + UpdateAddonRates bool `db:"-"` } func NewUpdateAddonFromQMS(u *qms.UpdateAddonRequest) *UpdateAddon { @@ -679,6 +681,7 @@ func NewUpdateAddonFromQMS(u *qms.UpdateAddonRequest) *UpdateAddon { UpdateResourceType: u.UpdateResourceType, UpdateDefaultAmount: u.UpdateDefaultAmount, UpdateDefaultPaid: u.UpdateDefaultPaid, + UpdateAddonRates: u.UpdateAddonRates, } if update.UpdateName { @@ -696,6 +699,13 @@ func NewUpdateAddonFromQMS(u *qms.UpdateAddonRequest) *UpdateAddon { if update.UpdateResourceType { update.ResourceTypeID = u.Addon.ResourceType.Uuid } + if update.UpdateAddonRates { + addonRates := make([]AddonRate, len(u.Addon.AddonRates)) + for i, r := range u.Addon.AddonRates { + addonRates[i] = *NewAddonRateFromQMS(r, u.Addon.Uuid) + } + update.AddonRates = addonRates + } return update } diff --git a/go.mod b/go.mod index 3b2990c..d3a127d 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2 github.com/uptrace/opentelemetry-go-extra/otelsqlx v0.3.2 go.opentelemetry.io/otel v1.31.0 - google.golang.org/protobuf v1.35.1 + google.golang.org/protobuf v1.35.2 ) require ( diff --git a/go.sum b/go.sum index 8e35ccc..e45895e 100644 --- a/go.sum +++ b/go.sum @@ -499,8 +499,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= -google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= +google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 158d8dd3477293e7c168ba03ad7797f39b6b41f5 Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Mon, 18 Nov 2024 12:23:45 -0700 Subject: [PATCH 14/21] CORE-2016: fixed an error that occurred when updating only the rates in an addon --- db/addons.go | 96 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 41 deletions(-) diff --git a/db/addons.go b/db/addons.go index f1da9a3..ed3143e 100644 --- a/db/addons.go +++ b/db/addons.go @@ -242,59 +242,73 @@ func (d *Database) UpdateAddonRate(ctx context.Context, r AddonRate, opts ...Que return nil } -func (d *Database) UpdateAddon(ctx context.Context, updatedAddon *UpdateAddon, opts ...QueryOption) (*Addon, error) { +func (d *Database) UpdateAddon( + ctx context.Context, + addonUpdateRecord *UpdateAddon, + opts ...QueryOption, +) (*Addon, error) { + var retval *Addon _, db := d.querySettings(opts...) rec := goqu.Record{} - if updatedAddon.UpdateName { - rec["name"] = updatedAddon.Name - } - if updatedAddon.UpdateDescription { - rec["description"] = updatedAddon.Description - } - if updatedAddon.UpdateResourceType { - rec["resource_type_id"] = updatedAddon.ResourceTypeID - } - if updatedAddon.UpdateDefaultAmount { - rec["default_amount"] = updatedAddon.DefaultAmount - } - if updatedAddon.UpdateDefaultPaid { - rec["default_paid"] = updatedAddon.DefaultPaid - } - - ds := db.Update(t.Addons). - Set(rec). - Where(t.Addons.Col("id").Eq(updatedAddon.ID)). - Returning( - t.Addons.Col("id"), - t.Addons.Col("name"), - t.Addons.Col("description"), - t.Addons.Col("default_amount"), - t.Addons.Col("default_paid"), - t.Addons.Col("resource_type_id").As(goqu.C("resource_types.id")), - ). - Executor() - - retval := &Addon{} - found, err := ds.ScanStructContext(ctx, retval) - if err != nil { - return nil, errors.Wrap(err, "unable to scan results of update") - } - if !found { - return nil, suberrors.ErrAddonNotFound + updateAddon := false + if addonUpdateRecord.UpdateName { + rec["name"] = addonUpdateRecord.Name + updateAddon = true + } + if addonUpdateRecord.UpdateDescription { + rec["description"] = addonUpdateRecord.Description + updateAddon = true + } + if addonUpdateRecord.UpdateResourceType { + rec["resource_type_id"] = addonUpdateRecord.ResourceTypeID + updateAddon = true + } + if addonUpdateRecord.UpdateDefaultAmount { + rec["default_amount"] = addonUpdateRecord.DefaultAmount + updateAddon = true + } + if addonUpdateRecord.UpdateDefaultPaid { + rec["default_paid"] = addonUpdateRecord.DefaultPaid + updateAddon = true + } + + // Update the top-level addon record if requested. + if updateAddon { + ds := db.Update(t.Addons). + Set(rec). + Where(t.Addons.Col("id").Eq(addonUpdateRecord.ID)). + Returning( + t.Addons.Col("id"), + t.Addons.Col("name"), + t.Addons.Col("description"), + t.Addons.Col("default_amount"), + t.Addons.Col("default_paid"), + t.Addons.Col("resource_type_id").As(goqu.C("resource_types.id")), + ). + Executor() + + retval := &Addon{} + found, err := ds.ScanStructContext(ctx, retval) + if err != nil { + return nil, errors.Wrap(err, "unable to scan results of update") + } + if !found { + return nil, suberrors.ErrAddonNotFound + } } // Update existing addon rates. - if updatedAddon.UpdateAddonRates { - for _, r := range updatedAddon.AddonRates { + if addonUpdateRecord.UpdateAddonRates { + for _, r := range addonUpdateRecord.AddonRates { if r.ID == "" { - err = d.AddAddonRate(ctx, r, opts...) + err := d.AddAddonRate(ctx, r, opts...) if err != nil { return nil, err } } else { - err = d.UpdateAddonRate(ctx, r, opts...) + err := d.UpdateAddonRate(ctx, r, opts...) if err != nil { return nil, err } From 387e7676aa37b3aaf61352c4185695c5514e81c6 Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Mon, 18 Nov 2024 16:37:26 -0700 Subject: [PATCH 15/21] CORE-2016: updated the `cyverse.qms.user.plan.addons.add` handler --- db/addons.go | 6 ++++++ db/types.go | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/db/addons.go b/db/addons.go index ed3143e..f5ae7a1 100644 --- a/db/addons.go +++ b/db/addons.go @@ -424,6 +424,10 @@ func (d *Database) AddSubscriptionAddon(ctx context.Context, subscriptionID, add if err != nil { return nil, err } + addonRate := addon.GetCurrentRate() + if addonRate == nil { + return nil, fmt.Errorf("no active rate found for addon %s", addon.ID) + } ds := db.Insert(t.SubscriptionAddons). Rows(goqu.Record{ @@ -431,6 +435,7 @@ func (d *Database) AddSubscriptionAddon(ctx context.Context, subscriptionID, add "addon_id": addonID, "amount": addon.DefaultAmount, "paid": addon.DefaultPaid, + "addon_rate_id": addonRate.ID, }). Returning(t.SubscriptionAddons.Col("id")). Executor() @@ -457,6 +462,7 @@ func (d *Database) AddSubscriptionAddon(ctx context.Context, subscriptionID, add Subscription: *subscription, Amount: addon.DefaultAmount, Paid: addon.DefaultPaid, + Rate: *addonRate, } return retval, nil diff --git a/db/types.go b/db/types.go index 5ecb684..074143f 100644 --- a/db/types.go +++ b/db/types.go @@ -614,6 +614,19 @@ func (a *Addon) ValidateAddonRateUniqueness() error { return nil } +// GetCurrentRate determines the rate that is currently active. +func (a *Addon) GetCurrentRate() *AddonRate { + var currentRate *AddonRate + now := time.Now() + for _, r := range a.AddonRates { + if r.EffectiveDate.After(now) { + break + } + currentRate = &r + } + return currentRate +} + type AddonRate struct { ID string `db:"id" goqu:"defaultifempty,skipupdate"` AddonID string `db:"addon_id"` @@ -715,6 +728,7 @@ type SubscriptionAddon struct { Subscription Subscription `db:"subscriptions"` Amount float64 `db:"amount"` Paid bool `db:"paid"` + Rate AddonRate `db:"addon_rates"` } func NewSubscriptionAddonFromQMS(sa *qms.SubscriptionAddon) *SubscriptionAddon { @@ -724,6 +738,7 @@ func NewSubscriptionAddonFromQMS(sa *qms.SubscriptionAddon) *SubscriptionAddon { Subscription: *NewSubscriptionFromQMS(sa.Subscription), Amount: float64(sa.Amount), Paid: sa.Paid, + Rate: *NewAddonRateFromQMS(sa.AddonRate, sa.Uuid), } } @@ -734,6 +749,7 @@ func (sa *SubscriptionAddon) ToQMSType() *qms.SubscriptionAddon { Subscription: sa.Subscription.ToQMSSubscription(), Amount: sa.Amount, Paid: sa.Paid, + AddonRate: sa.Rate.ToQMSType(), } } From 242f136d9a0473d4d998639f4c1b9efaf83fbe9c Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Mon, 18 Nov 2024 17:58:24 -0700 Subject: [PATCH 16/21] CORE-2016: updated the `cyverse.qms.user.plan.addons.list` handler to support plan rates and addon rates --- app/addons.go | 18 +++++++++++++----- db/addons.go | 23 ++++++++++++++++++++--- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/app/addons.go b/app/addons.go index cb16736..d241717 100644 --- a/app/addons.go +++ b/app/addons.go @@ -311,16 +311,24 @@ func (a *App) listSubscriptionAddons(ctx context.Context, request *requests.ByUU response := qmsinit.NewSubscriptionAddonListResponse() d := db.New(a.db) - - results, err := d.ListSubscriptionAddons(ctx, request.Uuid) + tx, err := d.Begin() if err != nil { response.Error = serrors.NatsError(ctx, err) return response } - for _, addon := range results { - response.SubscriptionAddons = append(response.SubscriptionAddons, addon.ToQMSType()) - } + err = tx.Wrap(func() error { + results, err := d.ListSubscriptionAddons(ctx, request.Uuid, db.WithTX(tx)) + if err != nil { + return err + } + + for _, addon := range results { + response.SubscriptionAddons = append(response.SubscriptionAddons, addon.ToQMSType()) + } + + return nil + }) return response } diff --git a/db/addons.go b/db/addons.go index f5ae7a1..53d3dd5 100644 --- a/db/addons.go +++ b/db/addons.go @@ -353,6 +353,9 @@ func subAddonDS(db GoquDatabase) *goqu.SelectDataset { t.Subscriptions.Col("last_modified_by").As(goqu.C("subscriptions.last_modified_by")), t.Subscriptions.Col("last_modified_at").As(goqu.C("subscriptions.last_modified_at")), t.Subscriptions.Col("paid").As(goqu.C("subscriptions.paid")), + t.PlanRates.Col("id").As(goqu.C("subscriptions.plan_rates.id")), + t.PlanRates.Col("effective_date").As(goqu.C("subscriptions.plan_rates.effective_date")), + t.PlanRates.Col("rate").As(goqu.C("subscriptions.plan_rates.rate")), t.Users.Col("id").As(goqu.C("subscriptions.users.id")), t.Users.Col("username").As(goqu.C("subscriptions.users.username")), t.Plans.Col("id").As(goqu.C("subscriptions.plans.id")), @@ -361,12 +364,18 @@ func subAddonDS(db GoquDatabase) *goqu.SelectDataset { t.SubscriptionAddons.Col("amount"), t.SubscriptionAddons.Col("paid"), + + t.AddonRates.Col("id").As(goqu.C("addon_rates.id")), + t.AddonRates.Col("effective_date").As(goqu.C("addon_rates.effective_date")), + t.AddonRates.Col("rate").As(goqu.C("addon_rates.rate")), ). Join(t.Subscriptions, goqu.On(t.SubscriptionAddons.Col("subscription_id").Eq(t.Subscriptions.Col("id")))). + Join(t.PlanRates, goqu.On(t.Subscriptions.Col("plan_rate_id").Eq(t.PlanRates.Col("id")))). Join(t.Addons, goqu.On(t.Addons.Col("id").Eq(t.SubscriptionAddons.Col("addon_id")))). Join(t.ResourceTypes, goqu.On(t.Addons.Col("resource_type_id").Eq(t.ResourceTypes.Col("id")))). Join(t.Users, goqu.On(t.Subscriptions.Col("user_id").Eq(t.Users.Col("id")))). - Join(t.Plans, goqu.On(t.Subscriptions.Col("plan_id").Eq(t.Plans.Col("id")))) + Join(t.Plans, goqu.On(t.Subscriptions.Col("plan_id").Eq(t.Plans.Col("id")))). + Join(t.AddonRates, goqu.On(t.SubscriptionAddons.Col("addon_rate_id").Eq(t.AddonRates.Col("id")))) } func (d *Database) GetSubscriptionAddonByID(ctx context.Context, subAddonID string, opts ...QueryOption) (*SubscriptionAddon, error) { @@ -390,7 +399,11 @@ func (d *Database) GetSubscriptionAddonByID(ctx context.Context, subAddonID stri return subAddon, nil } -func (d *Database) ListSubscriptionAddons(ctx context.Context, subscriptionID string, opts ...QueryOption) ([]SubscriptionAddon, error) { +func (d *Database) ListSubscriptionAddons( + ctx context.Context, + subscriptionID string, + opts ...QueryOption, +) ([]SubscriptionAddon, error) { _, db := d.querySettings(opts...) ds := subAddonDS(db). @@ -406,7 +419,11 @@ func (d *Database) ListSubscriptionAddons(ctx context.Context, subscriptionID st return addons, nil } -func (d *Database) AddSubscriptionAddon(ctx context.Context, subscriptionID, addonID string, opts ...QueryOption) (*SubscriptionAddon, error) { +func (d *Database) AddSubscriptionAddon( + ctx context.Context, + subscriptionID, addonID string, + opts ...QueryOption, +) (*SubscriptionAddon, error) { qs, db, err := d.querySettingsWithTX(opts...) if err != nil { return nil, err From ae07fe39bc7336e29a9ce5cadebcbf0e9db48ec1 Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Mon, 2 Dec 2024 20:09:26 -0700 Subject: [PATCH 17/21] CORE-2016: updated the Go version in go.mod --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index d3a127d..8d1b3e2 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/cyverse-de/subscriptions -go 1.23.2 +go 1.23.3 replace github.com/cyverse-de/p/go/qms => /Users/sarahr/src/de/libs/p/go/qms From d17bc6f2b729dd7de704d3b29ac27c297e3e6c5a Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Tue, 3 Dec 2024 15:49:38 -0700 Subject: [PATCH 18/21] CORE-2016: fixed a lint warnings and disabled checks for deprecations in several places --- app/addons.go | 3 +++ main.go | 2 ++ natscl/natscl.go | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/app/addons.go b/app/addons.go index d241717..a701367 100644 --- a/app/addons.go +++ b/app/addons.go @@ -329,6 +329,9 @@ func (a *App) listSubscriptionAddons(ctx context.Context, request *requests.ByUU return nil }) + if err != nil { + response.Error = serrors.NatsError(ctx, err) + } return response } diff --git a/main.go b/main.go index 97a5b48..47f0eda 100644 --- a/main.go +++ b/main.go @@ -71,6 +71,7 @@ func main() { shutdown := otelutils.TracerProviderFromEnv(tracerCtx, serviceName, func(e error) { log.Fatal(e) }) defer shutdown() + //nolint:staticcheck nats.RegisterEncoder("protojson", protobufjson.NewCodec(protobufjson.WithEmitUnpopulated())) config, err = cfg.Init(&cfg.Settings{ @@ -145,6 +146,7 @@ func main() { a := app.New(natsClient, dbconn, userSuffix) + //nolint:staticcheck natsHandlers := map[string]nats.Handler{ qmssubs.GetUserUpdates: a.GetUserUpdatesHandler, qmssubs.AddUserUpdate: a.AddUserUpdateHandler, diff --git a/natscl/natscl.go b/natscl/natscl.go index 84a8110..a1f18de 100644 --- a/natscl/natscl.go +++ b/natscl/natscl.go @@ -82,6 +82,7 @@ func (s *ConnectionSettings) toConnectOptions() []nats.Option { return options } +//nolint:staticcheck func NewConnection(settings *ConnectionSettings) (*nats.EncodedConn, error) { log := log.WithFields(logrus.Fields{"context": "new nats conn"}) @@ -100,12 +101,14 @@ func NewConnection(settings *ConnectionSettings) (*nats.EncodedConn, error) { return encConn, nil } +//nolint:staticcheck type Client struct { conn *nats.EncodedConn subscriptions []*nats.Subscription queueSuffix string } +//nolint:staticcheck func NewClient(conn *nats.EncodedConn, queueSuffix string) *Client { return &Client{ conn: conn, @@ -118,6 +121,7 @@ func (c *Client) queueName(base string) string { return strings.Join([]string{base, c.queueSuffix}, ".") } +//nolint:staticcheck func (c *Client) Subscribe(subject string, handler nats.Handler) error { queue := c.queueName(subject) From b29a7ec38ad0bdcea5219d546e2d0f8e33042981 Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Tue, 3 Dec 2024 17:05:51 -0700 Subject: [PATCH 19/21] CORE-2016: updated the GitHub workflows --- .github/workflows/golangci-lint.yml | 4 ++-- .github/workflows/skaffold-build.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index fed97a5..3c7e1d2 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -8,6 +8,6 @@ on: jobs: call-workflow-passing-data: - uses: cyverse-de/github-workflows/.github/workflows/golangci-lint.yml@v0.0.4 + uses: cyverse-de/github-workflows/.github/workflows/golangci-lint.yml@v0.1.6 with: - go-version: 1.22 + go-version: 1.23 diff --git a/.github/workflows/skaffold-build.yml b/.github/workflows/skaffold-build.yml index db0f5fc..aaf03c8 100644 --- a/.github/workflows/skaffold-build.yml +++ b/.github/workflows/skaffold-build.yml @@ -8,7 +8,7 @@ on: jobs: call-workflow-passing-data: - uses: cyverse-de/github-workflows/.github/workflows/skaffold-build.yml@v0.0.7 + uses: cyverse-de/github-workflows/.github/workflows/skaffold-build.yml@v0.1.6 with: build-prerelease: ${{ contains(github.ref_name, '-rc') }} secrets: From 8aa6f8ec991073178587b546d121b7a6151742b2 Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Tue, 3 Dec 2024 17:17:55 -0700 Subject: [PATCH 20/21] CORE-2016: updated the golangci-lint version to use for lint checks --- .github/workflows/golangci-lint.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 3c7e1d2..aeab93f 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -8,6 +8,7 @@ on: jobs: call-workflow-passing-data: - uses: cyverse-de/github-workflows/.github/workflows/golangci-lint.yml@v0.1.6 + uses: cyverse-de/github-workflows/.github/workflows/golangci-lint.yml@v0.1.8 with: go-version: 1.23 + golangci-lint-version: v1.62.2 From 4f10a52127a8dd0f23fcf45d9c29306b7055655c Mon Sep 17 00:00:00 2001 From: Sarah Roberts Date: Thu, 5 Dec 2024 15:52:44 -0700 Subject: [PATCH 21/21] CORE-2016: updated dependencies --- go.mod | 16 +++++----------- go.sum | 22 ++++++++++++++-------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index 8d1b3e2..3e146ba 100644 --- a/go.mod +++ b/go.mod @@ -2,21 +2,15 @@ module github.com/cyverse-de/subscriptions go 1.23.3 -replace github.com/cyverse-de/p/go/qms => /Users/sarahr/src/de/libs/p/go/qms - -replace github.com/cyverse-de/p/go/requests => /Users/sarahr/src/de/libs/p/go/requests - -replace github.com/cyverse-de/p/go/svcerror => /Users/sarahr/src/de/libs/p/go/svcerror - require ( github.com/cyverse-de/go-mod/cfg v0.0.2 - github.com/cyverse-de/go-mod/gotelnats v0.0.12 + github.com/cyverse-de/go-mod/gotelnats v0.0.15 github.com/cyverse-de/go-mod/logging v0.0.3 - github.com/cyverse-de/go-mod/otelutils v0.0.4 - github.com/cyverse-de/go-mod/pbinit v0.1.12 - github.com/cyverse-de/go-mod/protobufjson v0.0.4 + github.com/cyverse-de/go-mod/otelutils v0.0.5 + github.com/cyverse-de/go-mod/pbinit v0.1.13 + github.com/cyverse-de/go-mod/protobufjson v0.0.7 github.com/cyverse-de/go-mod/subjects v0.1.5 - github.com/cyverse-de/p/go/qms v0.1.13 + github.com/cyverse-de/p/go/qms v0.1.15 github.com/cyverse-de/p/go/requests v0.0.3 github.com/cyverse-de/p/go/svcerror v0.0.8 github.com/doug-martin/goqu/v9 v9.19.0 diff --git a/go.sum b/go.sum index e45895e..d14543e 100644 --- a/go.sum +++ b/go.sum @@ -40,16 +40,16 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cyverse-de/go-mod/cfg v0.0.2 h1:evHNKqLwOPWHhxxzF498/Rtac7LZb1zxnHAjZSuqiEo= github.com/cyverse-de/go-mod/cfg v0.0.2/go.mod h1:jjn1fZJRwqKiYgiS5AcXg9Dzxp2QOiLyrWVWCcq9Dw0= -github.com/cyverse-de/go-mod/gotelnats v0.0.12 h1:oq24rRC2Tsc2z/5d0cso9QqrSRq6ce+e0vfHlk+wtPA= -github.com/cyverse-de/go-mod/gotelnats v0.0.12/go.mod h1:n9+Qw8jV5z+w476xk3RRPBQzJQbA/fehv4UiXtL+Zqk= +github.com/cyverse-de/go-mod/gotelnats v0.0.15 h1:1PzSmKGI0nfUY2JbzgymB51pBaOJtMhiS7oH+ooJ00w= +github.com/cyverse-de/go-mod/gotelnats v0.0.15/go.mod h1:Ksb6NSA9P/O0NklOqqt6ldAFoY1IySQb2nd7Ql6PDvs= github.com/cyverse-de/go-mod/logging v0.0.3 h1:sbehQImEP5cYusWVN1sDvo3lqwEfaZSCZLmrhFaI8xI= github.com/cyverse-de/go-mod/logging v0.0.3/go.mod h1:KRRtiAvsBZlnR9qxXLFYaFdvJAJZKGYAIhRnjuORpIQ= -github.com/cyverse-de/go-mod/otelutils v0.0.4 h1:MHTf9VSeW+463BR1mpbE9lhgEflW9Cb1Tnu8Efj3Nhw= -github.com/cyverse-de/go-mod/otelutils v0.0.4/go.mod h1:ImgwzJFUE3EObZGtbsxCbEXVQCk43IP7Q2qs1H847PU= -github.com/cyverse-de/go-mod/pbinit v0.1.12 h1:HA9q0ffLAzAbcEYJkhQigZXXl06juaAhuft/baIKbOg= -github.com/cyverse-de/go-mod/pbinit v0.1.12/go.mod h1:M5zde8HkoyViaCD1sT/8PNNiYCheCfwhktfaoI6lobA= -github.com/cyverse-de/go-mod/protobufjson v0.0.4 h1:UPZCpdg6zm30tNf/c8JCI+F/SewiqeF42Uwi13X8diU= -github.com/cyverse-de/go-mod/protobufjson v0.0.4/go.mod h1:SJuTgEbjy56L3QtVKiON/kAHM298Xd8F4Uq7kyU8nFo= +github.com/cyverse-de/go-mod/otelutils v0.0.5 h1:PpVRfMO/zlzHMOTU6bzVQYvgUTjtCux8iRCSJhSzL2I= +github.com/cyverse-de/go-mod/otelutils v0.0.5/go.mod h1:ImgwzJFUE3EObZGtbsxCbEXVQCk43IP7Q2qs1H847PU= +github.com/cyverse-de/go-mod/pbinit v0.1.13 h1:WHjuxxKYYzBNINLOVxizIhihdf19S9f9DBiAwQTDPsw= +github.com/cyverse-de/go-mod/pbinit v0.1.13/go.mod h1:qtI+qGruDxvm3YwE6Nm6CAYKP+lAlZ4QhTiYUMGHA3w= +github.com/cyverse-de/go-mod/protobufjson v0.0.7 h1:0R4li2YHyhGms4szDzjT9AC3QALPR/Iwq/99IeMlXDg= +github.com/cyverse-de/go-mod/protobufjson v0.0.7/go.mod h1:G1H075/v5AjaXpBzCXPhdlclwGygE8zPDHXmSJ4EVu8= github.com/cyverse-de/go-mod/subjects v0.1.5 h1:wuThkSyC+XbngIAHVD3+WecSz7ytGRyQBzEBzzr0agU= github.com/cyverse-de/go-mod/subjects v0.1.5/go.mod h1:XjBoa1k2CovbxjNqQFP69eiXEstiV4bqxZWSBLizGjA= github.com/cyverse-de/p v0.0.0-20241022195522-7109f3ff6072 h1:jLG5JQ9UUUV553CEgccOO+opsaAJkZr/ezPMFz3sRRQ= @@ -62,6 +62,12 @@ github.com/cyverse-de/p/go/header v0.0.4 h1:asY/uixi9rCqbDLq2G21CT7WJRaendBfr1z2 github.com/cyverse-de/p/go/header v0.0.4/go.mod h1:1j79PqvJyMRmXXKyW4KbZWGQNontm0B9smsaq5t5Ct8= github.com/cyverse-de/p/go/monitoring v0.0.5 h1:n+GdL9a3R1zM7L+18SIufrtmLxXU8L/cKX6DhOJ7IhY= github.com/cyverse-de/p/go/monitoring v0.0.5/go.mod h1:CB0aMpTRJvCFlGeL/75uX4Snj/OXj9wzKF5KQX4tASg= +github.com/cyverse-de/p/go/qms v0.1.15 h1:xP5D18L1zcgJsUo3OKp85ZokVrHD7IqgymKtyts2XJw= +github.com/cyverse-de/p/go/qms v0.1.15/go.mod h1:VCrtS3TdrM2H85JGT8A+/cdq2AVQXuNBHR6fyNFn0mg= +github.com/cyverse-de/p/go/requests v0.0.3 h1:aFe6XxKPNib0nJSfS8QUPSQc8EnvCMv2dWUqUDEUnBU= +github.com/cyverse-de/p/go/requests v0.0.3/go.mod h1:oS0KhADCAS7trkpQqcperoIl4+Bge9xMPqbOSYzO+bc= +github.com/cyverse-de/p/go/svcerror v0.0.8 h1:UE06rE31kk7OcciTQlZfrJTFlC9AMTfNf6JKll41u0U= +github.com/cyverse-de/p/go/svcerror v0.0.8/go.mod h1:0h/BngUR9cTV86LYqHMkdREFcxJuMyOJV6f3u6Un4LQ= github.com/cyverse-de/p/go/user v0.0.11 h1:VM2WGrdvcmDLwwjUJpCbrhC5te8xFY8f71ALFO2N7LI= github.com/cyverse-de/p/go/user v0.0.11/go.mod h1:g6Gl6+Zv0PlZMoydO2cBmLFTLwQs39gYauboxp769KE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=