From f3f8b7a199ba3c3cd51f878c81f6f7cb05208fe7 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 16:55:23 -0700 Subject: [PATCH 01/37] ignore services bootstrap --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 05fb1ff7..f56c3149 100644 --- a/.gitignore +++ b/.gitignore @@ -39,7 +39,7 @@ react/screenshot.png # deploy faas **/*.zip -**/bootstrap +services/**/bootstrap # Editors and IDEs .idea From 9dd906959c187a3641ee9addc27864b510ce1052 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 16:58:01 -0700 Subject: [PATCH 02/37] module naming --- infrastructure/terraform/aws/environments/init-prod/main.tf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/infrastructure/terraform/aws/environments/init-prod/main.tf b/infrastructure/terraform/aws/environments/init-prod/main.tf index 1d766f5b..afb298b2 100644 --- a/infrastructure/terraform/aws/environments/init-prod/main.tf +++ b/infrastructure/terraform/aws/environments/init-prod/main.tf @@ -16,8 +16,7 @@ provider "aws" { } } -// creates 3 buckets and 1 dynamodb table -module "project_storage_dev" { +module "project_storage_prod" { source = "../../modules/project-storage/v001" force_destroy_tfstate = false env = local.ENV From 9acb20a0d1de23189aba53836a8732c75f964d67 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 16:59:05 -0700 Subject: [PATCH 03/37] add go-migrate ecr storage in terraform --- .../terraform/aws/modules/project-storage/v001/ecr.tf | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 infrastructure/terraform/aws/modules/project-storage/v001/ecr.tf diff --git a/infrastructure/terraform/aws/modules/project-storage/v001/ecr.tf b/infrastructure/terraform/aws/modules/project-storage/v001/ecr.tf new file mode 100644 index 00000000..01cc4617 --- /dev/null +++ b/infrastructure/terraform/aws/modules/project-storage/v001/ecr.tf @@ -0,0 +1,9 @@ +resource "aws_ecr_repository" "go_migrate" { + name = "go-migrate-${local.ID_ENV}" + image_tag_mutability = "MUTABLE" + force_delete = true + + image_scanning_configuration { + scan_on_push = true + } +} From 9de36f08f2eaf92252dffcedc9a00ef42a808ff3 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:02:17 -0700 Subject: [PATCH 04/37] add ecr as artifact source in lambda terraform module --- .../aws/modules/provided-lambda/v001/README.md | 16 ++++++++++++++++ .../aws/modules/provided-lambda/v001/lambda.tf | 18 +++++++++++++----- 2 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 infrastructure/terraform/aws/modules/provided-lambda/v001/README.md diff --git a/infrastructure/terraform/aws/modules/provided-lambda/v001/README.md b/infrastructure/terraform/aws/modules/provided-lambda/v001/README.md new file mode 100644 index 00000000..9a522ea9 --- /dev/null +++ b/infrastructure/terraform/aws/modules/provided-lambda/v001/README.md @@ -0,0 +1,16 @@ +

+ systemaccounting +

+ +#### provided runtime lambda terraform module + +use: +1. assign `var.artifacts_bucket_name` a name to deploy from an s3 bucket +1. assign `var.artifacts_bucket_name` to null and add an `aws_ecr_repository` resource to `infrastructure/terraform/aws/modules/project-storage/v001/ecr.tf` to deploy from a docker image repository +1. assign `var.aws_lwa_port` a unique project application port* to enable the [lambda web adapter](https://github.com/awslabs/aws-lambda-web-adapter) + +examples: +1. `infrastructure/terraform/aws/modules/environment/v001/lambda-services.tf` +1. `infrastructure/terraform/aws/modules/environment/v001/go-migrate.tf` + +\* `project.yaml` env vars with _PORT suffixes are assigned unique port numbers \ No newline at end of file diff --git a/infrastructure/terraform/aws/modules/provided-lambda/v001/lambda.tf b/infrastructure/terraform/aws/modules/provided-lambda/v001/lambda.tf index be225a1e..e28f0f84 100644 --- a/infrastructure/terraform/aws/modules/provided-lambda/v001/lambda.tf +++ b/infrastructure/terraform/aws/modules/provided-lambda/v001/lambda.tf @@ -15,10 +15,16 @@ locals { } data "aws_s3_object" "default" { + count = var.artifacts_bucket_name == null ? 0 : 1 bucket = var.artifacts_bucket_name key = "${var.service_name}-src.zip" } +data "aws_ecr_repository" "default" { + count = var.artifacts_bucket_name == null ? 1 : 0 + name = "${var.service_name}-${local.ID_ENV}" +} + data "aws_region" "current" {} data "aws_caller_identity" "current" {} @@ -26,11 +32,13 @@ data "aws_caller_identity" "current" {} resource "aws_lambda_function" "default" { function_name = "${var.service_name}-${local.ID_ENV}" description = "${var.service_name} lambda service in ${local.SPACED_ID_ENV}" - s3_bucket = data.aws_s3_object.default.bucket - s3_key = data.aws_s3_object.default.key - s3_object_version = data.aws_s3_object.default.version_id - handler = local.BINARY_NAME - runtime = local.LAMBDA_RUNTIME + s3_bucket = var.artifacts_bucket_name == null ? null : data.aws_s3_object.default[0].bucket + s3_key = var.artifacts_bucket_name == null ? null : data.aws_s3_object.default[0].key + s3_object_version = var.artifacts_bucket_name == null ? null : data.aws_s3_object.default[0].version_id + image_uri = var.artifacts_bucket_name == null ? "${data.aws_ecr_repository.default[0].repository_url}:latest" : null + package_type = var.artifacts_bucket_name == null ? "Image" : null + handler = var.artifacts_bucket_name == null ? null : local.BINARY_NAME + runtime = var.artifacts_bucket_name == null ? null : local.LAMBDA_RUNTIME timeout = var.lambda_timeout role = aws_iam_role.default.arn From e7fafb6f286380bcaf168316a0db0b84ab1aad17 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:03:26 -0700 Subject: [PATCH 05/37] switch go-migrate lambda to ecr artifact source --- .../terraform/aws/modules/environment/v001/go-migrate.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infrastructure/terraform/aws/modules/environment/v001/go-migrate.tf b/infrastructure/terraform/aws/modules/environment/v001/go-migrate.tf index a35bf458..3f2d7ebc 100644 --- a/infrastructure/terraform/aws/modules/environment/v001/go-migrate.tf +++ b/infrastructure/terraform/aws/modules/environment/v001/go-migrate.tf @@ -6,9 +6,9 @@ module "go_migrate" { env_id = var.env_id env_vars = merge(local.POSTGRES_VARS, { GO_MIGRATE_PASSPHRASE = random_password.go_migrate.result + SQL_TYPE = local.SQL_TYPE }) - aws_lwa_port = local.GO_MIGRATE_PORT - artifacts_bucket_name = var.artifacts_bucket_name + artifacts_bucket_name = null # defaults to ecr image create_secret = true attached_policy_arns = [] lambda_url_authorization_type = "NONE" From 975730dd3838634221a04537c298e41a8a4a704a Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:04:46 -0700 Subject: [PATCH 06/37] rewrite go-migrate service in bash --- migrations/go-migrate/README.md | 7 +- migrations/go-migrate/bootstrap | 23 ++ migrations/go-migrate/cmd/main.go | 353 ------------------------------ migrations/go-migrate/function.sh | 42 ++++ migrations/go-migrate/makefile | 73 +++++- migrations/go-migrate/migrate.sh | 153 +++++++++++++ 6 files changed, 281 insertions(+), 370 deletions(-) create mode 100644 migrations/go-migrate/bootstrap delete mode 100644 migrations/go-migrate/cmd/main.go create mode 100644 migrations/go-migrate/function.sh create mode 100644 migrations/go-migrate/migrate.sh diff --git a/migrations/go-migrate/README.md b/migrations/go-migrate/README.md index a85a074b..3f908b67 100644 --- a/migrations/go-migrate/README.md +++ b/migrations/go-migrate/README.md @@ -5,15 +5,12 @@ ### go-migrate -deploys pushed migrations in `/mxfactorial/migrations/$DESIRED_MIGRATION_DIRECTORY` to postgres rds through lambda +deploys migrations in `/mxfactorial/migrations/$DESIRED_MIGRATION_DIRECTORY` to local or rds postgres #### build & deploy FAST -* `make deploy ENV=dev` to build and deploy lambda +* `make deploy ENV=dev` to build image and deploy to lambda #### deploy migrations 1. see `/mxfactorial/migrations/README.md` -#### clean -1. `make clean` - terraform: https://github.com/systemaccounting/mxfactorial/blob/develop/infrastructure/terraform/aws/modules/environment/v001/go-migrate.tf \ No newline at end of file diff --git a/migrations/go-migrate/bootstrap b/migrations/go-migrate/bootstrap new file mode 100644 index 00000000..027bdee3 --- /dev/null +++ b/migrations/go-migrate/bootstrap @@ -0,0 +1,23 @@ +#!/bin/sh + +set -euo pipefail + +# Initialization - load function handler +source $LAMBDA_TASK_ROOT/"$(echo $_HANDLER | cut -d. -f1).sh" + +# Processing +while true +do + HEADERS="$(mktemp)" + # Get an event. The HTTP request will block until one is received + EVENT_DATA=$(curl -sS -LD "$HEADERS" "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next") + + # Extract request ID by scraping response headers received above + REQUEST_ID=$(grep -Fi Lambda-Runtime-Aws-Request-Id "$HEADERS" | tr -d '[:space:]' | cut -d: -f2) + + # Run the handler function from the script + RESPONSE=$($(echo "$_HANDLER" | cut -d. -f2) "$EVENT_DATA") + + # Send the response + curl "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/response" -d "$RESPONSE" +done \ No newline at end of file diff --git a/migrations/go-migrate/cmd/main.go b/migrations/go-migrate/cmd/main.go deleted file mode 100644 index dd614ba0..00000000 --- a/migrations/go-migrate/cmd/main.go +++ /dev/null @@ -1,353 +0,0 @@ -package main - -import ( - "context" - "errors" - "fmt" - "log" - "net/http" - "os" - "path" - "strconv" - - "github.com/gin-gonic/gin" - "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing" - "github.com/golang-migrate/migrate/v4" - "github.com/golang-migrate/migrate/v4/database/postgres" - _ "github.com/golang-migrate/migrate/v4/source/file" -) - -const ( - CLONE_DIR = "/tmp/mxfactorial" - MIGRATIONS_DIR = CLONE_DIR + "/" + "migrations" - REPO = "https://github.com/systemaccounting/mxfactorial.git" - TESTSEED = "testseed" -) - -var ( - pgHost = os.Getenv("PGHOST") - pgPort = os.Getenv("PGPORT") - pgUser = os.Getenv("PGUSER") - pgPassword = os.Getenv("PGPASSWORD") - pgDatabase = os.Getenv("PGDATABASE") - connUrl ConnUrl = ConnUrl(fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable", pgUser, pgPassword, pgHost, pgPort, pgDatabase)) - up = []string{"schema", "seed"} - down = reverse(up) - readinessCheckPath = os.Getenv("READINESS_CHECK_PATH") - port = os.Getenv("GO_MIGRATE_PORT") -) - -type ConnUrl string - -func (c ConnUrl) String() string { - return string(c) -} - -func (c ConnUrl) WithMigDir(dir string) string { - return string(c) + "&x-migrations-table=migration_" + dir + "_version" -} - -type params struct { - Branch string `json:"branch"` - Command string `json:"command"` - Count string `json:"count"` - Version string `json:"version"` - Directory string `json:"directory"` - DBType string `json:"db_type"` - Passphrase string `json:"passphrase"` -} - -func GetConnUrl() ConnUrl { - return ConnUrl(connUrl) -} - -func reverse(s []string) []string { - rev := []string{} - for i := len(s) - 1; i >= 0; i-- { - rev = append(rev, s[i]) - } - return rev -} - -func addTestSeedMigration() { - up = append(up, TESTSEED) // append - down = append([]string{TESTSEED}, down...) // prepend -} - -func (p params) Auth() error { - if passphrase, ok := os.LookupEnv("GO_MIGRATE_PASSPHRASE"); ok { - if p.Passphrase != passphrase { - return errors.New("not authd") - } - } - return nil -} - -func (p params) ReferenceName() plumbing.ReferenceName { - return plumbing.NewBranchReferenceName(p.Branch) -} - -func (p params) MigrateVersion() (int, error) { - v, err := strconv.Atoi(p.Version) - if err != nil { - return 0, err - } - return v, nil -} - -func (p params) handleEvent(ctx context.Context) error { - _ = ctx - - err := p.Auth() // auth in lambda - if err != nil { - return err - } - - err = clone(p) - if err != nil { - return err - } - - switch p.Command { - case "up": - return upMigrate(p.Directory) - case "down": - return downMigrate(p.Directory) - case "force": - return forceVersion(p) - case "drop": - return dropDB() - case "reset": - return resetDB(p) - default: - return fmt.Errorf("error: command neither up, down, force, drop, or reset") - } -} - -func resetDB(p params) error { - if p.DBType == "test" { - addTestSeedMigration() - } - for _, subDir := range down { - downMigrate(subDir) - fmt.Println("") // add new line - } - dropDB() // drop db - fmt.Println("") - for _, subDir := range up { - upMigrate(subDir) - fmt.Println("") - } - return nil -} - -func upMigrate(subDir string) error { - - pg := postgres.Postgres{} - - d, err := pg.Open(connUrl.WithMigDir(subDir)) - if err != nil { - return err - } - defer func() error { - if err := d.Close(); err != nil { - return err - } - return nil - }() - - migrationPath := MIGRATIONS_DIR + "/" + subDir - migrationFiles, err := os.ReadDir(migrationPath) - if err != nil { - return err - } - - m, err := migrate.NewWithDatabaseInstance("file://"+migrationPath, "mxfactorial", d) - if err != nil { - return err - } - - fmt.Print("UP migrating from ", migrationPath+":\n") - for _, f := range migrationFiles { - fmt.Println(f.Name()) - } - - err = m.Up() - if err != nil { - return err - } - - return nil -} - -func downMigrate(subDir string) error { - - pg := postgres.Postgres{} - - d, err := pg.Open(connUrl.WithMigDir(subDir)) - if err != nil { - return err - } - defer func() error { - if err := d.Close(); err != nil { - return err - } - return nil - }() - - migrationPath := MIGRATIONS_DIR + "/" + subDir - migrationFiles, err := os.ReadDir(migrationPath) - if err != nil { - return err - } - - m, err := migrate.NewWithDatabaseInstance("file://"+migrationPath, "mxfactorial", d) - if err != nil { - return err - } - - fmt.Print("DOWN migrating from ", migrationPath+":\n") - for _, f := range migrationFiles { - fmt.Println(f.Name()) - } - - // down migrate - err = m.Down() - if err != nil { - return err - } - - return nil -} - -func forceVersion(p params) error { - - pg := postgres.Postgres{} - - d, err := pg.Open(connUrl.WithMigDir(p.Directory)) - if err != nil { - return err - } - defer func() error { - if err := d.Close(); err != nil { - return err - } - return nil - }() - - migrationPath := MIGRATIONS_DIR + "/" + p.Directory - - m, err := migrate.NewWithDatabaseInstance("file://"+migrationPath, "mxfactorial", d) - if err != nil { - return err - } - - v, err := p.MigrateVersion() - if err != nil { - return err - } - - fmt.Print("FORCING to ", v, " migration version in migration_"+p.Directory+"_version table\n") - - err = m.Force(v) - if err != nil { - return err - } - - return nil -} - -func dropDB() error { - - pg := postgres.Postgres{} - - d, err := pg.Open(connUrl.String()) - if err != nil { - return err - } - defer func() error { - if err := d.Close(); err != nil { - return err - } - return nil - }() - - m, err := migrate.NewWithDatabaseInstance("file://", "mxfactorial", d) - if err != nil { - return err - } - - fmt.Print("DROPPING ", "mxfactorial", " database\n") - err = m.Drop() - if err != nil { - return err - } - - return nil -} - -func clone(p params) error { - - // test for existing clone directory - _, err := os.Stat(CLONE_DIR) - if err == nil { - - // list files in clone directory - files, err := os.ReadDir(CLONE_DIR) - if err != nil { - return err - } - - // delete files in clone directory - if len(files) > 0 { - for _, f := range files { - os.RemoveAll(path.Join([]string{CLONE_DIR, f.Name()}...)) - } - } - } - - // clone repo - r, err := git.PlainClone(CLONE_DIR, false, &git.CloneOptions{ - URL: REPO, - ReferenceName: p.ReferenceName(), - SingleBranch: true, - Progress: nil, // os.Stdout, - }) - if err != nil { - return err - } - - ref, err := r.Head() - if err != nil { - return err - } - - fmt.Print("commit sha: ", ref.Hash().String()[0:8], "\n\n") - return nil -} - -func main() { - r := gin.Default() - - // aws-lambda-web-adapter READINESS_CHECK_* - r.GET("/"+readinessCheckPath, func(c *gin.Context) { - c.Status(http.StatusOK) - }) - - r.POST("/", func(c *gin.Context) { - - var p params - c.BindJSON(&p) - - err := p.handleEvent(c.Request.Context()) - if err != nil { - log.Println(err) - c.Status(http.StatusBadRequest) - } - - c.Status(http.StatusOK) - }) - - r.Run(fmt.Sprintf(":%s", port)) -} diff --git a/migrations/go-migrate/function.sh b/migrations/go-migrate/function.sh new file mode 100644 index 00000000..99fe9a94 --- /dev/null +++ b/migrations/go-migrate/function.sh @@ -0,0 +1,42 @@ +function handler () { + EVENT_DATA=$1 + + # avoid using identically named variables in sourced migrate script + + # if EVENT_DATA has branch property, then assign variables from object root + if [[ $(echo $EVENT_DATA | jq -r '.branch') != "null" ]]; then + BRANCH=$(echo $EVENT_DATA | jq -r '.branch') + DATABASE_TYPE=$(echo $EVENT_DATA | jq -r '.db_type') + MIGRATE_CMD=$(echo $EVENT_DATA | jq -r '.cmd') + PASSPHRASE=$(echo $EVENT_DATA | jq -r '.passphrase') + else + # parse escaped variables from body string + BODY=$(echo $EVENT_DATA | jq -r '.body') + BRANCH=$(echo $BODY | jq -r '.branch') + DATABASE_TYPE=$(echo $BODY | jq -r '.db_type') + MIGRATE_CMD=$(echo $BODY | jq -r '.cmd') + PASSPHRASE=$(echo $BODY | jq -r '.passphrase') + fi + + CLONE_DIR="/tmp/mxfactorial" + MIGRATE_DIR="$CLONE_DIR/migrations" + + if [[ "$PASSPHRASE" != "$GO_MIGRATE_PASSPHRASE" ]]; then + # add cloudwatch logs from custom runtime lambda by redirecting stdout to stderr + echo "unmatched passphrase" 1>&2; + exit 1 + fi + + # clean up previous invoke + rm -rf /tmp/mxfactorial + + # clone repo + git clone --branch $BRANCH --depth 1 https://github.com/systemaccounting/mxfactorial "$CLONE_DIR" + + # migrate using files from cloned repo + source ./migrate.sh --dir "$MIGRATE_DIR" --db_type "$DATABASE_TYPE" --cmd "$MIGRATE_CMD" + + RESPONSE="branch: $BRANCH, db_type: $DATABASE_TYPE, cmd: $MIGRATE_CMD" + + echo $RESPONSE +} \ No newline at end of file diff --git a/migrations/go-migrate/makefile b/migrations/go-migrate/makefile index 1b2123aa..0c7246f0 100644 --- a/migrations/go-migrate/makefile +++ b/migrations/go-migrate/makefile @@ -1,16 +1,65 @@ +APP_NAME=$(shell basename $(CURDIR)) RELATIVE_PROJECT_ROOT_PATH=$(shell REL_PATH="."; while [ $$(ls "$$REL_PATH" | grep project.yaml | wc -l | xargs) -eq 0 ]; do REL_PATH="$$REL_PATH./.."; done; printf '%s' "$$REL_PATH") -include $(RELATIVE_PROJECT_ROOT_PATH)/make/shared.mk -include $(RELATIVE_PROJECT_ROOT_PATH)/make/go.mk -BRANCH := develop +PROJECT_CONF_FILE_NAME=project.yaml +PROJECT_CONF=$(RELATIVE_PROJECT_ROOT_PATH)/$(PROJECT_CONF_FILE_NAME) +ENV_ID=$(shell (cd $(RELATIVE_PROJECT_ROOT_PATH); ENV=$(ENV) PROJECT_CONF=$(PROJECT_CONF) . ./scripts/print-env-id.sh)) +TAG_VERSION=latest +IMAGE_NAME=$(IMAGE_PREFIX)-$(ENV_ID)-$(ENV):$(TAG_VERSION) -run: - @$(MAKE) -s test-env-file - @eval $$(cat $(ENV_FILE)) \ - go run $(CMD_DIR) +test-env-arg: +ifndef ENV + $(error trailing ENV assignment missing, e.g. make test ENV=dev) +endif -reset-local: +build-image: @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/migrate.sh \ - --db_type test \ - --branch $(BRANCH) \ - --command reset \ No newline at end of file + docker build -f ./docker/go-migrate.Dockerfile -t $(APP_NAME) ./migrations/go-migrate + +push-image: + @$(MAKE) -s test-env-arg + @cd $(RELATIVE_PROJECT_ROOT_PATH); \ + bash scripts/push-ecr-image.sh --image-prefix $(APP_NAME) --env $(ENV) + +deploy-image: + @$(MAKE) -s test-env-arg + @cd $(RELATIVE_PROJECT_ROOT_PATH); \ + bash scripts/update-function-image.sh --app-name $(APP_NAME) --env $(ENV) + +update-image: + @$(MAKE) -s test-env-arg + @$(MAKE) -s build-image + @$(MAKE) -s push-image + @$(MAKE) -s deploy-image + +clean-artifact: + @for i in $$(docker image ls | grep '$(APP_NAME)' | awk '{print $$3}'); do docker rmi -f "$$i"; done; + +clean: + @$(MAKE) clean-artifact + +build: + @$(MAKE) clean + @$(MAKE) build-image + +###################### globally required ###################### + +initial-deploy: + @$(MAKE) -s test-env-arg + $(MAKE) build + $(MAKE) push-image + +deploy: + @$(MAKE) -s test-env-arg + $(MAKE) build + $(MAKE) push-image + $(MAKE) deploy-image + +deploy-only: + @$(MAKE) -s test-env-arg + $(MAKE) push-image + $(MAKE) deploy-image + +now: + $(MAKE) build + $(MAKE) push-image ENV=dev + $(MAKE) deploy-image ENV=dev \ No newline at end of file diff --git a/migrations/go-migrate/migrate.sh b/migrations/go-migrate/migrate.sh new file mode 100644 index 00000000..7b9d2355 --- /dev/null +++ b/migrations/go-migrate/migrate.sh @@ -0,0 +1,153 @@ +#!/bin/bash + +if [[ "$#" -ne 6 ]]; then + cat <<- 'EOF' + use: + bash migrate.sh --dir /tmp/mxfactorial/migrations --db_type test --cmd up + + possible values: + db_type: test, prod # prod excludes testseed data + cmd: up, down, drop, reset + EOF + exit 1 +fi + +while [[ "$#" -gt 0 ]]; do + case $1 in + --dir) DIR="$2"; shift ;; + --db_type) DB_TYPE="$2"; shift ;; + --cmd) CMD="$2"; shift ;; + *) echo "unknown parameter passed: $1"; exit 1 ;; + esac + shift +done + + +if [[ -z "$DIR" ]]; then + echo "error: DIR not set" + exit 1 +fi + +if [[ -z "$CMD" ]]; then + echo "error: CMD not set" + exit 1 +fi + +case $DB_TYPE in + prod|test) ;; + *) echo "info: unknown db_type: \"$DB_TYPE\". testseed data will be excluded by defaulting to prod"; DB_TYPE='prod' ;; +esac + +if [[ -z "$SQL_TYPE" ]]; then + echo "error: SQL_TYPE not set" + exit 1 +fi + +if [[ -z "$PGUSER" ]]; then + echo "error: PGUSER not set" + exit 1 +fi +if [[ -z "$PGPASSWORD" ]]; then + echo "error: PGPASSWORD not set" + exit 1 +fi + +if [[ -z "$PGHOST" ]]; then + echo "error: PGHOST not set" + exit 1 +fi + +if [[ -z "$PGPORT" ]]; then + echo "error: PGPORT not set" + exit 1 +fi + +if [[ -z "$PGDATABASE" ]]; then + echo "error: PGDATABASE not set" + exit 1 +fi + +PROD_UP=(schema seed) +PROD_DOWN=(seed schema) +# append testseed to PROD_UP to include testseed data +TEST_UP=("${PROD_UP[@]}" testseed) +# prepend testseed to PROD_DOWN to remove testseed data +TEST_DOWN=(testseed "${PROD_DOWN[@]}") + +function create_conn() { + local MIGRATIONS_DIR="$1" + CONN="${SQL_TYPE}://${PGUSER}:${PGPASSWORD}@${PGHOST}:${PGPORT}/${PGDATABASE}?sslmode=disable&x-migrations-table=migration_${MIGRATIONS_DIR}_version" +} + +function up () { + local MIGRATIONS_DIR="$1" + local MIGRATIONS_PATH="${DIR}/${MIGRATIONS_DIR}" + create_conn "$MIGRATIONS_DIR" + migrate -verbose -path "$MIGRATIONS_PATH" -database "$CONN" up +} + +function down () { + local MIGRATIONS_DIR="$1" + local MIGRATIONS_PATH="${DIR}/${MIGRATIONS_DIR}" + create_conn "$MIGRATIONS_DIR" + migrate -verbose -path "$MIGRATIONS_PATH" -database "$CONN" down --all +} + +function drop () { + # go-migrate fails to drop custom types until 09/2021 pull request merged: + # https://github.com/golang-migrate/migrate/pull/627 + # migrate -verbose -path "$DIR" -database "$CONN" drop -f + + # https://www.postgresql.org/docs/current/app-psql.html + DBNAME="host=$PGHOST port=$PGPORT user=$PGUSER password=$PGPASSWORD dbname=$PGDATABASE sslmode=disable" + + if [[ "$PGHOST" == 'localhost' ]]; then + # https://stackoverflow.com/a/13823560 + psql -d "$DBNAME" -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public; GRANT ALL ON SCHEMA public TO postgres;" + else # rds + psql -d "$DBNAME" -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;" + fi +} + +function up_migrate() { + if [[ "$DB_TYPE" == 'prod' ]]; then + for MIG_DIR in "${PROD_UP[@]}"; do + up "$MIG_DIR" + done + elif [[ "$DB_TYPE" == 'test' ]]; then + for MIG_DIR in "${TEST_UP[@]}"; do + up "$MIG_DIR" + done + else + echo "error: unknown db_type: $DB_TYPE" + exit 1 + fi +} + +function down_migrate() { + if [[ "$DB_TYPE" == 'prod' ]]; then + for MIG_DIR in "${PROD_DOWN[@]}"; do + down "$MIG_DIR" + done + elif [[ "$DB_TYPE" == 'test' ]]; then + for MIG_DIR in "${TEST_DOWN[@]}"; do + down "$MIG_DIR" + done + else + echo "error: unknown db_type: $DB_TYPE" + exit 1 + fi +} + +function reset() { + drop + up_migrate +} + +case $CMD in + up) up_migrate ;; + down) down_migrate ;; + drop) drop ;; + reset) reset ;; + *) echo "unknown command: $CMD"; exit 1 ;; +esac \ No newline at end of file From d35a6a4ae9e91a12cf5001560b59597212fbb1bb Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:06:41 -0700 Subject: [PATCH 07/37] ecr convenience scripts --- scripts/auth-ecr-repo.sh | 28 ++++++++++++++++++++++ scripts/print-ecr-repo-name.sh | 30 ++++++++++++++++++++++++ scripts/push-ecr-image.sh | 34 +++++++++++++++++++++++++++ scripts/update-function-image.sh | 40 ++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+) create mode 100644 scripts/auth-ecr-repo.sh create mode 100644 scripts/print-ecr-repo-name.sh create mode 100644 scripts/push-ecr-image.sh create mode 100644 scripts/update-function-image.sh diff --git a/scripts/auth-ecr-repo.sh b/scripts/auth-ecr-repo.sh new file mode 100644 index 00000000..42a3cbd8 --- /dev/null +++ b/scripts/auth-ecr-repo.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +if [[ "$#" -ne 4 ]]; then + cat <<- 'EOF' + use: + bash scripts/auth-ecr-repo.sh --image-prefix go-migrate --env dev + EOF + exit 1 +fi + +while [[ "$#" -gt 0 ]]; do + case $1 in + --image-prefix) IMAGE_PREFIX="$2"; shift ;; + --env) ENV="$2"; shift ;; + *) echo "unknown parameter passed: $1"; exit 1 ;; + esac + shift +done + +PROJECT_CONF=project.yaml + +REGION=$(yq '.infrastructure.terraform.aws.modules.environment.env_var.set.REGION.default' $PROJECT_CONF) + +REPO=$(source scripts/print-ecr-repo-name.sh --image-prefix $IMAGE_PREFIX --env $ENV) + +AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text) + +aws ecr get-login-password --region $REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com \ No newline at end of file diff --git a/scripts/print-ecr-repo-name.sh b/scripts/print-ecr-repo-name.sh new file mode 100644 index 00000000..129cf6f9 --- /dev/null +++ b/scripts/print-ecr-repo-name.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +if [[ "$#" -ne 4 ]]; then + cat <<- 'EOF' + use: + bash scripts/print-ecr-repo-name.sh --image-prefix go-migrate --env dev + EOF + exit 1 +fi + +while [[ "$#" -gt 0 ]]; do + case $1 in + --image-prefix) IMAGE_PREFIX="$2"; shift ;; + --env) ENV="$2"; shift ;; + *) echo "unknown parameter passed: $1"; exit 1 ;; + esac + shift +done + +PROJECT_CONF=project.yaml +ENV_ID=$(source scripts/print-env-id.sh) +ID_ENV="$ENV_ID-$ENV" +IMAGE_NAME=$IMAGE_PREFIX-$ID_ENV +REGION=$(yq '.infrastructure.terraform.aws.modules.environment.env_var.set.REGION.default' $PROJECT_CONF) +AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text) + +aws ecr describe-repositories \ + --query "repositories[?contains(repositoryUri, \`$IMAGE_NAME\`)].repositoryUri" \ + --output text \ + --region $REGION \ No newline at end of file diff --git a/scripts/push-ecr-image.sh b/scripts/push-ecr-image.sh new file mode 100644 index 00000000..36966aad --- /dev/null +++ b/scripts/push-ecr-image.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +if [[ "$#" -ne 4 ]]; then + cat <<- 'EOF' + use: + bash scripts/push-ecr-image.sh --image-prefix go-migrate --env dev + EOF + exit 1 +fi + +while [[ "$#" -gt 0 ]]; do + case $1 in + --image-prefix) IMAGE_PREFIX="$2"; shift ;; + --env) ENV="$2"; shift ;; + *) echo "unknown parameter passed: $1"; exit 1 ;; + esac + shift +done + +source scripts/auth-ecr-repo.sh --image-prefix $IMAGE_PREFIX --env $ENV + +REPO=$(source scripts/print-ecr-repo-name.sh --image-prefix $IMAGE_PREFIX --env $ENV) + +PROJECT_CONF=project.yaml +ENV=dev +ENV_ID=$(source scripts/print-env-id.sh) +ID_ENV="$ENV_ID-$ENV" +TAG_VERSION=latest + +IMAGE_NAME=$REPO:$TAG_VERSION + +docker tag $IMAGE_PREFIX $REPO + +docker push $REPO \ No newline at end of file diff --git a/scripts/update-function-image.sh b/scripts/update-function-image.sh new file mode 100644 index 00000000..d70bbd91 --- /dev/null +++ b/scripts/update-function-image.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +set -e + +if [[ "$#" -ne 4 ]]; then + cat <<- 'EOF' + use: + bash scripts/update-function-image.sh \ + --app-name go-migrate \ + --env dev + EOF + exit 1 +fi + +while [[ "$#" -gt 0 ]]; do + case $1 in + --app-name) APP_NAME="$2"; shift ;; + --env) ENV="$2"; shift ;; + *) echo "unknown parameter passed: $1"; exit 1 ;; + esac + shift +done + +PROJECT_CONF=project.yaml +ENV_ID=$(source scripts/print-env-id.sh) +ID_ENV="$ENV_ID-$ENV" +REPO=$(source scripts/print-ecr-repo-name.sh --image-prefix $APP_NAME --env $ENV) +TAG_VERSION=latest +IMAGE_NAME=$REPO:$TAG_VERSION +LAMBDA_NAME="$APP_NAME-$ID_ENV" +REGION=$(yq '.infrastructure.terraform.aws.modules.environment.env_var.set.REGION.default' $PROJECT_CONF) + +MOD=$(aws lambda update-function-code \ + --function-name="$LAMBDA_NAME" \ + --image-uri=$IMAGE_NAME \ + --region=$REGION \ + --query 'LastModified' \ + --output text) + +echo "*** $LAMBDA_NAME lambda deployed @ $MOD" \ No newline at end of file From 7fdc10af88580a6f8addc8f22ab27185d0a16e65 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:07:17 -0700 Subject: [PATCH 08/37] terraform import convenience script --- scripts/import-tf-init-env.sh | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 scripts/import-tf-init-env.sh diff --git a/scripts/import-tf-init-env.sh b/scripts/import-tf-init-env.sh new file mode 100644 index 00000000..2b2bdfb2 --- /dev/null +++ b/scripts/import-tf-init-env.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +if [[ "$#" -ne 2 ]]; then + cat <<- 'EOF' + use: + bash scripts/import-tf-init-env.sh --env dev + EOF + exit 1 +fi + +while [[ "$#" -gt 0 ]]; do + case $1 in + --env) ENV="$2"; shift ;; + *) echo "unknown parameter passed: $1"; exit 1 ;; + esac + shift +done + +PROJECT_CONF=project.yaml + +ENV_ID=$(source scripts/print-env-id.sh) + +ID_ENV="$ENV_ID-$ENV" + +cd infrastructure/terraform/aws/environments/init-$ENV + +terraform init + +terraform import module.project_storage_$ENV.aws_dynamodb_table.github_workflows github-workflows-$ID_ENV +terraform import module.project_storage_$ENV.aws_s3_bucket.artifacts mxfactorial-artifacts-$ID_ENV +terraform import module.project_storage_$ENV.aws_s3_bucket.client_origin mxfactorial-client-$ID_ENV +terraform import module.project_storage_$ENV.aws_s3_bucket.tfstate mxfactorial-tfstate-$ID_ENV +terraform import module.project_storage_$ENV.aws_s3_bucket_public_access_block.client_origin mxfactorial-client-$ID_ENV +terraform import module.project_storage_$ENV.aws_ecr_repository.go_migrate go-migrate-$ID_ENV \ No newline at end of file From d86416ae353a332b97b887073dcac43cf1e048ab Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:09:54 -0700 Subject: [PATCH 09/37] build go-migrate lambda custom runtime image --- docker/go-migrate.Dockerfile | 43 +++++++++++++++--------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/docker/go-migrate.Dockerfile b/docker/go-migrate.Dockerfile index 7ce001c6..363b4fab 100644 --- a/docker/go-migrate.Dockerfile +++ b/docker/go-migrate.Dockerfile @@ -1,30 +1,23 @@ -# adapted from https://mattdevdba.medium.com/aws-lambda-postgresql-client-69206ff0c439 -FROM golang:1.19-alpine3.16 AS builder1 -ENV GO111MODULE=on -RUN apk add --no-cache git gcc musl-dev make -RUN mkdir -p /go/src/github.com/golang-migrate -WORKDIR /go/src/github.com/golang-migrate -RUN git clone --single-branch --branch master https://github.com/golang-migrate/migrate.git -WORKDIR /go/src/github.com/golang-migrate/migrate -RUN mkdir ./cli/build -RUN VERSION=$(git describe --tags 2>/dev/null | cut -c 2-); \ - cd ./cmd/migrate && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o ../../cli/build/migrate.linux-amd64 -ldflags='-X main.Version=$(VERSION) -extldflags "-static"' -tags 'postgres mysql redshift cassandra spanner cockroachdb yugabytedb clickhouse mongodb sqlserver firebird neo4j pgx file go_bindata github github_ee bitbucket aws_s3 google_cloud_storage godoc_vfs gitlab' . +FROM public.ecr.aws/lambda/provided:al2023 +ARG VERSION=v4.17.0 +ARG ARCH=linux-amd64 + +COPY bootstrap ${LAMBDA_RUNTIME_DIR} +COPY function.sh ${LAMBDA_TASK_ROOT} +COPY migrate.sh ${LAMBDA_TASK_ROOT} -FROM centos:7 AS builder2 WORKDIR /tmp -RUN yum -y install yum-utils rpmdevtools -RUN yum -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-42.0-28.noarch.rpm -RUN yumdownloader -y postgresql11 -RUN yumdownloader -y postgresql11-libs -RUN rpmdev-extract *rpm -RUN mkdir -p /tmp/bin -# todo: set LD_LIBRARY_PATH in lambda to avoid bundling lib/*.so* with bin -RUN cp -r /tmp/postgresql11-libs-11.18-1PGDG.rhel7.x86_64/usr/pgsql-11/lib/*.so* /tmp/bin -RUN cp -r /tmp/postgresql11-11.18-1PGDG.rhel7.x86_64/usr/pgsql-11/bin/* /tmp/bin -COPY --from=builder1 /go/src/github.com/golang-migrate/migrate/cli/build/migrate.linux-amd64 /tmp/bin -RUN zip -r9 /tmp/go-migrate-layer.zip bin +RUN dnf install -y tar gzip git jq postgresql15 && \ + dnf clean all && \ + curl -LO https://github.com/golang-migrate/migrate/releases/download/${VERSION}/migrate.${ARCH}.tar.gz && \ + tar -xvf migrate.${ARCH}.tar.gz -C /usr/local/bin/ && \ + rm -rf /tmp/* && \ + chmod +x ${LAMBDA_RUNTIME_DIR}/bootstrap && \ + chmod +x ${LAMBDA_TASK_ROOT}/function.sh && \ + chmod +x ${LAMBDA_TASK_ROOT}/migrate.sh + +WORKDIR /var/task -FROM centos:7 -COPY --from=builder2 /tmp/go-migrate-layer.zip /tmp \ No newline at end of file +CMD [ "function.handler" ] \ No newline at end of file From 0cf66f6bc8fd51cddbbd507abdc50cd7c98b9ba5 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:10:39 -0700 Subject: [PATCH 10/37] remove go from go-migrate workflow --- .github/workflows/dev-go-migrate.yaml | 5 +---- .github/workflows/prod-go-migrate.yaml | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/dev-go-migrate.yaml b/.github/workflows/dev-go-migrate.yaml index 0b256973..64827526 100644 --- a/.github/workflows/dev-go-migrate.yaml +++ b/.github/workflows/dev-go-migrate.yaml @@ -17,10 +17,7 @@ jobs: AWS_DEFAULT_REGION: us-east-1 CI: true steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: '1.19.x' + - uses: actions/checkout@v4 - name: deploy run: ENV_ID=${{ secrets.DEV_ENV_ID }} make deploy ENV=dev working-directory: migrations/go-migrate \ No newline at end of file diff --git a/.github/workflows/prod-go-migrate.yaml b/.github/workflows/prod-go-migrate.yaml index 65ff614f..e2bc8ba2 100644 --- a/.github/workflows/prod-go-migrate.yaml +++ b/.github/workflows/prod-go-migrate.yaml @@ -17,10 +17,7 @@ jobs: AWS_DEFAULT_REGION: us-east-1 CI: true steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: '1.19.x' + - uses: actions/checkout@v4 - name: deploy run: ENV_ID=${{ secrets.PROD_ENV_ID }} make deploy ENV=prod working-directory: migrations/go-migrate \ No newline at end of file From ba3cacb85bfb1d2d555d41ac806e1e8c788e0c2f Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:12:08 -0700 Subject: [PATCH 11/37] go-migrate postman --- .../go-migrate/postman/go-migrate-reset.postman_collection.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migrations/go-migrate/postman/go-migrate-reset.postman_collection.json b/migrations/go-migrate/postman/go-migrate-reset.postman_collection.json index 8ccd55d7..e5b224d1 100644 --- a/migrations/go-migrate/postman/go-migrate-reset.postman_collection.json +++ b/migrations/go-migrate/postman/go-migrate-reset.postman_collection.json @@ -13,7 +13,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"branch\": \"develop\",\n \"db_type\": \"test\",\n \"command\": \"reset\",\n \"passphrase\": \"{{GO_MIGRATE_PASSPHRASE}}\"\n}", + "raw": "{\n \"branch\": \"develop\",\n \"db_type\": \"test\",\n \"cmd\": \"reset\",\n \"passphrase\": \"{{GO_MIGRATE_PASSPHRASE}}\"\n}", "options": { "raw": { "language": "json" From 442f9e662788d62a9ad4b9388b75dc98265599ff Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:13:58 -0700 Subject: [PATCH 12/37] switch migrations makefile to use migrate bash script --- migrations/makefile | 281 ++++++++++++-------------------------------- 1 file changed, 73 insertions(+), 208 deletions(-) diff --git a/migrations/makefile b/migrations/makefile index 47d7cb57..e29014f8 100644 --- a/migrations/makefile +++ b/migrations/makefile @@ -1,42 +1,25 @@ SHELL=/bin/bash -APP=mxfactorial +APP_NAME=$(shell basename $(CURDIR)) RELATIVE_PROJECT_ROOT_PATH=.. PROJECT_CONF_FILE_NAME=project.yaml PROJECT_CONF=$(RELATIVE_PROJECT_ROOT_PATH)/$(PROJECT_CONF_FILE_NAME) ENV_ID=$(shell (cd $(RELATIVE_PROJECT_ROOT_PATH); ENV=$(ENV) PROJECT_CONF=$(PROJECT_CONF) . ./scripts/print-env-id.sh)) ENV_FILE_NAME=$(shell yq '.env_var.set.ENV_FILE_NAME.default' $(PROJECT_CONF)) ENV_FILE=$(CURDIR)/$(ENV_FILE_NAME) -SSM_VERSION=$(shell yq '.infrastructure.terraform.aws.modules.environment.env_var.set.SSM_VERSION.default' $(PROJECT_CONF)) GO_MIGRATE=github.com/golang-migrate/migrate/v4/cmd/migrate@latest +SQL_TYPE=$(shell yq ".migrations.env_var.set.SQL_TYPE.default" $(PROJECT_CONF)) +MIGRATIONS_DIR=$(CURDIR)/$(DIR) -# migration lambda vars +# go-migrate lambda vars MIGRATION_LAMBDA_NAME=go-migrate-$(ENV_ID)-$(ENV) REGION=$(shell yq '.infrastructure.terraform.aws.modules.environment.env_var.set.REGION.default' $(PROJECT_CONF)) - -RDS_ENV_VARS=DATABASE_TYPE \ -PGUSER \ -PGPASSWORD \ -PGHOST \ -PGPORT \ -PGDATABASE - -PG_CONF_PATH=.infrastructure.terraform.aws.modules.environment.env_var.set -DATABASE_TYPE=postgres -PGHOST=$(shell yq "$(PG_CONF_PATH).PGHOST.default" $(PROJECT_CONF)) -PGPORT=$(shell yq "$(PG_CONF_PATH).PGPORT.default" $(PROJECT_CONF)) -PGDATABASE=$(shell yq "$(PG_CONF_PATH).PGDATABASE.default" $(PROJECT_CONF)) -PGUSER=$(shell yq "$(PG_CONF_PATH).PGUSER.default" $(PROJECT_CONF)) -PGPASSWORD=$(shell yq "$(PG_CONF_PATH).PGPASSWORD.default" $(PROJECT_CONF)) -CONTAINER_PORT=$(PGPORT) - -MIGRATIONS_CONN=$(DATABASE_TYPE)://$(PGUSER):$(PGPASSWORD)@$(PGHOST):$(PGPORT)/$(PGDATABASE)?sslmode=disable&x-migrations-table=migration_$(DIR)_version -MIGRATIONS_DIR=$(CURDIR)/$(DIR) - -# case intended, values matched from make cli args -prod_up = schema seed -prod_down = seed schema -test_up = $(prod_up) testseed -test_down = testseed $(prod_down) +SSM_VERSION=$(shell yq '.infrastructure.terraform.aws.modules.environment.env_var.set.SSM_VERSION.default' $(PROJECT_CONF)) +GO_MIGRATE_PASSPHRASE=$(shell aws ssm get-parameter \ + --name /$(ENV_ID)/$(SSM_VERSION)/$(ENV)/tool/lambda/go_migrate/passphrase \ + --query 'Parameter.Value' \ + --region $(REGION) \ + --with-decryption \ + --output text) run: @$(MAKE) start @@ -83,172 +66,93 @@ clean: prune-builder: docker builder prune -f -# looped go migrate targets for docker postgres -# 2022-07-12: down migrate required until 9 month old pr merged: -# https://github.com/golang-migrate/migrate/pull/627 -resetdocker: - @TABLE_COUNT=$$(psql \ - -At "host=$(PGHOST) port=$(CONTAINER_PORT) user=$(PGUSER) password=$(PGPASSWORD) dbname=$(PGDATABASE)" \ - -tc "select count(*) from information_schema.tables where table_schema = 'public';"); \ - if [ "$$TABLE_COUNT" -gt 3 ]; then \ - echo "***down migrating docker"; \ - $(MAKE) downdocker DB=test; \ - $(MAKE) dropdocker DB=test; \ - fi; \ - echo "***up migrating docker"; \ - $(MAKE) updocker DB=test +###################### migration file management ###################### -testdocker: - $(MAKE) resetdocker - $(MAKE) downdocker DB=test +init: + @$(MAKE) -s test-dir-arg + migrate create -ext sql -dir $(MIGRATIONS_DIR) -seq init_schema -updocker: - @$(MAKE) -s test-db-arg - @$(MAKE) -s test-db-val - $(foreach DIR,$($(DB)_up), migrate -verbose -path ./$(DIR) -database "$(MIGRATIONS_CONN)" up;) +create: + @$(MAKE) -s test-dir-arg + @$(MAKE) -s test-name-arg + migrate -verbose create -ext sql -dir $(MIGRATIONS_DIR) -seq $(NAME) -downdocker: - @$(MAKE) -s test-db-arg - @$(MAKE) -s test-db-val - $(foreach DIR,$($(DB)_down), migrate -verbose -path ./$(DIR) -database "$(MIGRATIONS_CONN)" down --all;) +###################### general migrate command ###################### -dropdocker: +migrate: + @rm -f $(ENV_FILE) + @$(MAKE) -s get-secrets + @$(MAKE) -s test-env-file @$(MAKE) -s test-db-arg @$(MAKE) -s test-db-val - $(foreach DIR,$($(DB)_down), migrate -verbose -path ./$(DIR) -database "$(MIGRATIONS_CONN)" drop -f;) + eval $$(cat $(ENV_FILE)); source ./go-migrate/migrate.sh --dir $(CURDIR) --db_type $(DB) --cmd $(CMD) -insert: - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/insert-transactions.sh +###################### local/docker migrate commands ###################### -# looped go migrate targets for rds postgres -resetrds: - @$(MAKE) -s test-env-arg - @$(MAKE) -s test-db-arg - @$(MAKE) -s test-db-val - $(MAKE) get-secrets - @while read -r i; do export "$$i"; done < $(ENV_FILE); \ - TABLE_COUNT=$$(psql \ - -tc "select count(*) from information_schema.tables where table_schema = 'public';"); \ - if [ "$$TABLE_COUNT" -gt 3 ]; then \ - echo "***down migrating rds"; \ - $(MAKE) downrds DB=test; \ - $(MAKE) droprds DB=test; \ - fi; \ - echo "***up migrating rds"; \ - $(MAKE) uprds DB=test +resetdocker: + $(MAKE) migrate ENV=local DB=test CMD=reset -testrds: - $(MAKE) resetrds - $(MAKE) downrds DB=test +rl: + $(MAKE) resetdocker -uprds: - @$(MAKE) -s test-env-arg - @$(MAKE) -s test-db-arg - @$(MAKE) -s test-db-val - $(MAKE) get-secrets - $(foreach DIR,$($(DB)_up), eval $$(cat $(ENV_FILE)); migrate -verbose -path ./$(DIR) -database "$$DATABASE_TYPE://$$PGUSER:$$PGPASSWORD@$$PGHOST:$$PGPORT/$$PGDATABASE?sslmode=require&x-migrations-table=migration_$(DIR)_version" up;) +downdocker: + $(MAKE) migrate ENV=local DB=test CMD=down -downrds: - @$(MAKE) -s test-env-arg - @$(MAKE) -s test-db-arg - @$(MAKE) -s test-db-val - $(MAKE) get-secrets - $(foreach DIR,$($(DB)_down), eval $$(cat $(ENV_FILE)); migrate -verbose -path ./$(DIR) -database "$$DATABASE_TYPE://$$PGUSER:$$PGPASSWORD@$$PGHOST:$$PGPORT/$$PGDATABASE?sslmode=require&x-migrations-table=migration_$(DIR)_version" down --all;) +testdocker: + $(MAKE) resetdocker + $(MAKE) downdocker -droprds: - @$(MAKE) -s test-env-arg - @$(MAKE) -s test-db-arg - @$(MAKE) -s test-db-val - $(MAKE) get-secrets - $(foreach DIR,$($(DB)_down), eval $$(cat $(ENV_FILE)); migrate -verbose -path ./$(DIR) -database "$$DATABASE_TYPE://$$PGUSER:$$PGPASSWORD@$$PGHOST:$$PGPORT/$$PGDATABASE?sslmode=require&x-migrations-table=migration_$(DIR)_version" drop -f;) +updocker: + $(MAKE) migrate ENV=local DB=test CMD=up -# local go migrate -init: - @$(MAKE) -s test-dir-arg - migrate create -ext sql -dir $(MIGRATIONS_DIR) -seq init_schema +dropdocker: + $(MAKE) migrate ENV=local DB=test CMD=drop -create: - @$(MAKE) -s test-dir-arg - @$(MAKE) -s test-name-arg - migrate -verbose create -ext sql -dir $(MIGRATIONS_DIR) -seq $(NAME) +insert: + @cd $(RELATIVE_PROJECT_ROOT_PATH); \ + bash scripts/insert-transactions.sh -updir: - @$(MAKE) -s test-dir-arg - @$(MAKE) -s test-count-arg - migrate -verbose -path $(MIGRATIONS_DIR) -database "$(MIGRATIONS_CONN)" up $(COUNT) +###################### rds migrate commands ###################### -downdir: - @$(MAKE) -s test-dir-arg - @$(MAKE) -s test-count-arg - migrate -verbose -path $(MIGRATIONS_DIR) -database "$(MIGRATIONS_CONN)" down $(COUNT) +resetrds: + $(MAKE) migrate ENV=dev DB=test CMD=reset -updirall: - @$(MAKE) -s test-dir-arg - migrate -verbose -path $(MIGRATIONS_DIR) -database "$(MIGRATIONS_CONN)" up +downrds: + $(MAKE) migrate ENV=dev DB=test CMD=down -downdirall: - @$(MAKE) -s test-dir-arg - yes | migrate -verbose -path $(MIGRATIONS_DIR) -database "$(MIGRATIONS_CONN)" down +testrds: + @$(MAKE) resetrds + @$(MAKE) downrds -dropdir: - @$(MAKE) -s test-dir-arg - migrate -verbose -path $(MIGRATIONS_DIR) -database "$(MIGRATIONS_CONN)" drop -f +uprds: + $(MAKE) migrate ENV=dev DB=test CMD=up -force: - @$(MAKE) -s test-dir-arg - @$(MAKE) -s test-version-arg - migrate -verbose -path $(MIGRATIONS_DIR) -database "$(MIGRATIONS_CONN)" force $(VERSION) +droprds: + $(MAKE) migrate ENV=dev DB=test CMD=drop -clear: - $(MAKE) drop +###################### invoke migrate lambda ###################### -# lambda -# e.g. make deploy-migrations ENV=dev DIR=migrations BRANCH=199/db-item-transaction CMD=up COUNT=all +# make deploy-migrations ENV=dev BRANCH=develop DB=test CMD=up deploy-migrations: - @$(MAKE) -s test-dir-arg + @$(MAKE) -s test-db-arg + @$(MAKE) -s test-db-val @$(MAKE) -s test-branch-arg @$(MAKE) -s test-cmd-arg - @$(MAKE) -s test-cmd-count-arg - @$(MAKE) -s test-force-version-arg @$(MAKE) -s test-env-arg @aws lambda invoke \ --region $(REGION) \ --invocation-type RequestResponse \ --function-name $(MIGRATION_LAMBDA_NAME) \ - --payload "$$(echo '{"branch":"$(BRANCH)","command":"$(CMD)","count":"$(COUNT)","version":"$(VERSION)","directory":"$(DIR)"}' | base64)" \ + --payload "$$(echo '{"branch":"$(BRANCH)","cmd":"$(CMD)","db_type":"$(DB)","passphrase":"$(GO_MIGRATE_PASSPHRASE)"}' | base64)" \ invoke.log -# make lambda-up-all DB=test ENV=dev BRANCH=199/db-item-transaction -lambda-up-all: - @$(MAKE) -s test-db-arg - @$(MAKE) -s test-db-val - @$(MAKE) -s test-env-arg - @$(MAKE) -s test-branch-arg - $(foreach DIR,$($(DB)_up), $(MAKE) deploy-migrations ENV=$(ENV) DIR=$(DIR) BRANCH=$(BRANCH) CMD=up COUNT=all;) - -# make lambda-down-all DB=test ENV=dev BRANCH=199/db-item-transaction -lambda-down-all: - @$(MAKE) -s test-db-arg - @$(MAKE) -s test-db-val - @$(MAKE) -s test-env-arg - @$(MAKE) -s test-branch-arg - $(foreach DIR,$($(DB)_down), $(MAKE) deploy-migrations ENV=$(ENV) DIR=$(DIR) BRANCH=$(BRANCH) CMD=down COUNT=all;) - -# make lambda-drop-all DB=test ENV=dev BRANCH=199/db-item-transaction -lambda-drop-all: - @$(MAKE) -s test-db-arg - @$(MAKE) -s test-db-val - @$(MAKE) -s test-env-arg - @$(MAKE) -s test-branch-arg - $(foreach DIR,$($(DB)_down), $(MAKE) deploy-migrations ENV=$(ENV) DIR=$(DIR) BRANCH=$(BRANCH) CMD=drop COUNT=all;) - install-ci: - go install -tags '$(DATABASE_TYPE)' $(GO_MIGRATE) + go install -tags '$(SQL_TYPE)' $(GO_MIGRATE) sudo apt update sudo apt install -y postgresql-client -# arg tests +###################### arg tests ###################### + test-db-arg: ifndef DB $(error trailing DB assignment missing, e.g. make up DB=test, or DB=prod) @@ -264,39 +168,14 @@ ifndef DIR $(error trailing DIR assignment missing, e.g. make up DIR=schema) endif -test-env-arg: -ifndef ENV - $(error trailing ENV assignment missing, e.g. make test ENV=dev) -endif - -test-name-arg: -ifndef NAME - $(error trailing NAME assignment missing, e.g. make create NAME=rule) -endif - test-cmd-arg: ifndef CMD $(error trailing CMD assignment missing, e.g. make deploy-migrations CMD=up) endif -test-count-arg: -ifndef COUNT - $(error trailing COUNT assignment missing, e.g. make up COUNT=3, OR make up COUNT=all) -endif - -test-cmd-count-arg: -ifeq ($(CMD),$(filter $(CMD),up down)) - @$(MAKE) -s test-count-arg -endif - -test-version-arg: -ifndef VERSION - $(error trailing VERSION assignment missing, e.g. make force VERSION=7) -endif - -test-force-version-arg: -ifeq ($(CMD),force) - @$(MAKE) -s test-version-arg +test-env-arg: +ifndef ENV + $(error trailing ENV assignment missing, e.g. make test ENV=dev) endif test-branch-arg: @@ -314,26 +193,12 @@ ifeq (,$(wildcard $(ENV_FILE))) $(error no .env file, run 'make get-secrets ENV=dev') endif +env: + @$(MAKE) get-secrets + get-secrets: - @$(MAKE) -s retrieve-each-secret - @if [ ! -s $(ENV_FILE) ]; then \ - rm $(ENV_FILE); \ - echo 'no env vars required'; \ - else \ - echo 'env vars retrieved'; \ - fi - -retrieve-each-secret: test-env-arg clean-env $(RDS_ENV_VARS) -$(RDS_ENV_VARS): - @if [ $@ = DATABASE_TYPE ]; then \ - echo DATABASE_TYPE=$(DATABASE_TYPE) >> $(ENV_FILE); \ - else \ - PARAM_NAME=$(shell yq '... | select(has("$@")).$@.ssm' $(PROJECT_CONF)); \ - ENV_VAR=$$(aws ssm get-parameter \ - --name /$(ENV_ID)/$(SSM_VERSION)/$(ENV)/$$PARAM_NAME \ - --query 'Parameter.Value' \ - --with-decryption \ - --region $(REGION) \ - --output text); \ - echo "$@=$$ENV_VAR" >> $(ENV_FILE); \ - fi + @$(MAKE) -s test-env-arg + @cd $(RELATIVE_PROJECT_ROOT_PATH); \ + bash scripts/create-env-file.sh \ + --app-name $(APP_NAME) \ + --env $(ENV) \ No newline at end of file From 041818df27ef084b4a874b250b068f72fa0597b9 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:15:54 -0700 Subject: [PATCH 13/37] move testdata into tests directory --- {pkg => tests}/testdata/README.md | 2 +- .../testdata/allRuleInstanceIDs.json | 0 {pkg => tests}/testdata/bottledWater.json | 0 .../testdata/clearnotifications.json | 0 {pkg => tests}/testdata/crFirstTrItems.json | 0 {pkg => tests}/testdata/dbFirstTrItems.json | 0 {pkg => tests}/testdata/failFirstTrItems.json | 0 {pkg => tests}/testdata/getnotifications.json | 0 {pkg => tests}/testdata/intRules.json | 0 {pkg => tests}/testdata/nullFirstTrItems.json | 0 .../testdata/nullFirstTrItemsNoAppr.json | 0 {pkg => tests}/testdata/preRuleTrItems.json | 0 {pkg => tests}/testdata/requests.json | 480 +++++++++--------- {pkg => tests}/testdata/trItemWAppr.json | 0 {pkg => tests}/testdata/trItemWZeroAppr.json | 0 {pkg => tests}/testdata/trItemsNoAppr.json | 0 .../testdata/transMultipleRules.json | 0 {pkg => tests}/testdata/transNoAppr.json | 0 {pkg => tests}/testdata/transWAppr.json | 0 {pkg => tests}/testdata/transWTimes.json | 0 20 files changed, 241 insertions(+), 241 deletions(-) rename {pkg => tests}/testdata/README.md (84%) rename {pkg => tests}/testdata/allRuleInstanceIDs.json (100%) rename {pkg => tests}/testdata/bottledWater.json (100%) rename {pkg => tests}/testdata/clearnotifications.json (100%) rename {pkg => tests}/testdata/crFirstTrItems.json (100%) rename {pkg => tests}/testdata/dbFirstTrItems.json (100%) rename {pkg => tests}/testdata/failFirstTrItems.json (100%) rename {pkg => tests}/testdata/getnotifications.json (100%) rename {pkg => tests}/testdata/intRules.json (100%) rename {pkg => tests}/testdata/nullFirstTrItems.json (100%) rename {pkg => tests}/testdata/nullFirstTrItemsNoAppr.json (100%) rename {pkg => tests}/testdata/preRuleTrItems.json (100%) rename {pkg => tests}/testdata/requests.json (98%) rename {pkg => tests}/testdata/trItemWAppr.json (100%) rename {pkg => tests}/testdata/trItemWZeroAppr.json (100%) rename {pkg => tests}/testdata/trItemsNoAppr.json (100%) rename {pkg => tests}/testdata/transMultipleRules.json (100%) rename {pkg => tests}/testdata/transNoAppr.json (100%) rename {pkg => tests}/testdata/transWAppr.json (100%) rename {pkg => tests}/testdata/transWTimes.json (100%) diff --git a/pkg/testdata/README.md b/tests/testdata/README.md similarity index 84% rename from pkg/testdata/README.md rename to tests/testdata/README.md index d49fb916..4c593b60 100644 --- a/pkg/testdata/README.md +++ b/tests/testdata/README.md @@ -6,6 +6,6 @@ shared test data add using https://marketplace.visualstudio.com/items?itemName=nextfaze.json-parse-stringify -makefile use: `TEST_EVENT=$(shell cat ./pkg/testdata/testItems.json)` +makefile use: `TEST_EVENT=$(shell cat ./tests/testdata/testItems.json)` test all dependent services when editing \ No newline at end of file diff --git a/pkg/testdata/allRuleInstanceIDs.json b/tests/testdata/allRuleInstanceIDs.json similarity index 100% rename from pkg/testdata/allRuleInstanceIDs.json rename to tests/testdata/allRuleInstanceIDs.json diff --git a/pkg/testdata/bottledWater.json b/tests/testdata/bottledWater.json similarity index 100% rename from pkg/testdata/bottledWater.json rename to tests/testdata/bottledWater.json diff --git a/pkg/testdata/clearnotifications.json b/tests/testdata/clearnotifications.json similarity index 100% rename from pkg/testdata/clearnotifications.json rename to tests/testdata/clearnotifications.json diff --git a/pkg/testdata/crFirstTrItems.json b/tests/testdata/crFirstTrItems.json similarity index 100% rename from pkg/testdata/crFirstTrItems.json rename to tests/testdata/crFirstTrItems.json diff --git a/pkg/testdata/dbFirstTrItems.json b/tests/testdata/dbFirstTrItems.json similarity index 100% rename from pkg/testdata/dbFirstTrItems.json rename to tests/testdata/dbFirstTrItems.json diff --git a/pkg/testdata/failFirstTrItems.json b/tests/testdata/failFirstTrItems.json similarity index 100% rename from pkg/testdata/failFirstTrItems.json rename to tests/testdata/failFirstTrItems.json diff --git a/pkg/testdata/getnotifications.json b/tests/testdata/getnotifications.json similarity index 100% rename from pkg/testdata/getnotifications.json rename to tests/testdata/getnotifications.json diff --git a/pkg/testdata/intRules.json b/tests/testdata/intRules.json similarity index 100% rename from pkg/testdata/intRules.json rename to tests/testdata/intRules.json diff --git a/pkg/testdata/nullFirstTrItems.json b/tests/testdata/nullFirstTrItems.json similarity index 100% rename from pkg/testdata/nullFirstTrItems.json rename to tests/testdata/nullFirstTrItems.json diff --git a/pkg/testdata/nullFirstTrItemsNoAppr.json b/tests/testdata/nullFirstTrItemsNoAppr.json similarity index 100% rename from pkg/testdata/nullFirstTrItemsNoAppr.json rename to tests/testdata/nullFirstTrItemsNoAppr.json diff --git a/pkg/testdata/preRuleTrItems.json b/tests/testdata/preRuleTrItems.json similarity index 100% rename from pkg/testdata/preRuleTrItems.json rename to tests/testdata/preRuleTrItems.json diff --git a/pkg/testdata/requests.json b/tests/testdata/requests.json similarity index 98% rename from pkg/testdata/requests.json rename to tests/testdata/requests.json index 687adb5b..b668cbe3 100644 --- a/pkg/testdata/requests.json +++ b/tests/testdata/requests.json @@ -17,7 +17,7 @@ "item_id": "9% state sales tax", "price": "0.180", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -93,7 +93,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -169,7 +169,7 @@ "item_id": "9% state sales tax", "price": "0.360", "quantity": "3.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -245,7 +245,7 @@ "item_id": "milk", "price": "2.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -308,7 +308,7 @@ "item_id": "bread", "price": "3.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -371,7 +371,7 @@ "item_id": "eggs", "price": "4.000", "quantity": "3", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -449,7 +449,7 @@ "item_id": "9% state sales tax", "price": "0.180", "quantity": "3.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -525,7 +525,7 @@ "item_id": "9% state sales tax", "price": "0.720", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -601,7 +601,7 @@ "item_id": "9% state sales tax", "price": "0.135", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -677,7 +677,7 @@ "item_id": "candle", "price": "2.000", "quantity": "3", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -740,7 +740,7 @@ "item_id": "olive oil", "price": "8.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -803,7 +803,7 @@ "item_id": "cranberries", "price": "1.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -881,7 +881,7 @@ "item_id": "9% state sales tax", "price": "0.540", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -957,7 +957,7 @@ "item_id": "9% state sales tax", "price": "0.225", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -1033,7 +1033,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -1109,7 +1109,7 @@ "item_id": "shrimp", "price": "6.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -1172,7 +1172,7 @@ "item_id": "lettuce", "price": "2.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -1235,7 +1235,7 @@ "item_id": "bleach", "price": "3.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -1313,7 +1313,7 @@ "item_id": "9% state sales tax", "price": "0.225", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -1389,7 +1389,7 @@ "item_id": "9% state sales tax", "price": "0.540", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -1465,7 +1465,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -1541,7 +1541,7 @@ "item_id": "croissants", "price": "2.500", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -1604,7 +1604,7 @@ "item_id": "sterilizer", "price": "6.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -1667,7 +1667,7 @@ "item_id": "toothpaste", "price": "3.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -1745,7 +1745,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -1821,7 +1821,7 @@ "item_id": "9% state sales tax", "price": "0.090", "quantity": "7.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -1897,7 +1897,7 @@ "item_id": "9% state sales tax", "price": "0.360", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -1973,7 +1973,7 @@ "item_id": "glass cleaner", "price": "3.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -2036,7 +2036,7 @@ "item_id": "grapefruit", "price": "1.000", "quantity": "7", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -2099,7 +2099,7 @@ "item_id": "ground coffee", "price": "4.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -2177,7 +2177,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -2253,7 +2253,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -2329,7 +2329,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -2405,7 +2405,7 @@ "item_id": "butter", "price": "3.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -2468,7 +2468,7 @@ "item_id": "shampoo", "price": "3.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -2531,7 +2531,7 @@ "item_id": "dish soap", "price": "3.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -2609,7 +2609,7 @@ "item_id": "9% state sales tax", "price": "0.090", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -2685,7 +2685,7 @@ "item_id": "9% state sales tax", "price": "0.090", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -2761,7 +2761,7 @@ "item_id": "9% state sales tax", "price": "0.180", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -2837,7 +2837,7 @@ "item_id": "pepper", "price": "1.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -2900,7 +2900,7 @@ "item_id": "salt", "price": "1.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -2963,7 +2963,7 @@ "item_id": "seasoning", "price": "2.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -3041,7 +3041,7 @@ "item_id": "9% state sales tax", "price": "0.450", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -3117,7 +3117,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -3193,7 +3193,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -3269,7 +3269,7 @@ "item_id": "detergent", "price": "5.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -3332,7 +3332,7 @@ "item_id": "softener", "price": "3.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -3395,7 +3395,7 @@ "item_id": "glass cleaner", "price": "3.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -3473,7 +3473,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -3549,7 +3549,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -3625,7 +3625,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -3701,7 +3701,7 @@ "item_id": "peanut butter", "price": "3.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -3764,7 +3764,7 @@ "item_id": "jelly", "price": "3.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -3827,7 +3827,7 @@ "item_id": "bread", "price": "3.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -3905,7 +3905,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -3981,7 +3981,7 @@ "item_id": "9% state sales tax", "price": "0.225", "quantity": "4.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -4057,7 +4057,7 @@ "item_id": "9% state sales tax", "price": "0.450", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -4133,7 +4133,7 @@ "item_id": "paper towels", "price": "3.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -4196,7 +4196,7 @@ "item_id": "pasta", "price": "2.500", "quantity": "4", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -4259,7 +4259,7 @@ "item_id": "ground coffee", "price": "5.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -4337,7 +4337,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -4413,7 +4413,7 @@ "item_id": "9% state sales tax", "price": "0.360", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -4489,7 +4489,7 @@ "item_id": "9% state sales tax", "price": "0.360", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -4565,7 +4565,7 @@ "item_id": "fruit juice", "price": "3.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -4628,7 +4628,7 @@ "item_id": "flour", "price": "4.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -4691,7 +4691,7 @@ "item_id": "coffee creamer", "price": "4.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -4769,7 +4769,7 @@ "item_id": "9% state sales tax", "price": "0.405", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -4845,7 +4845,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -4921,7 +4921,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -4997,7 +4997,7 @@ "item_id": "sliced turkey", "price": "4.500", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -5060,7 +5060,7 @@ "item_id": "mustard", "price": "3.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -5123,7 +5123,7 @@ "item_id": "mayonnaise", "price": "3.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -5201,7 +5201,7 @@ "item_id": "9% state sales tax", "price": "0.090", "quantity": "4.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -5277,7 +5277,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -5353,7 +5353,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -5429,7 +5429,7 @@ "item_id": "raisins", "price": "1.000", "quantity": "4", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -5492,7 +5492,7 @@ "item_id": "cheddar cheese", "price": "3.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -5555,7 +5555,7 @@ "item_id": "vanilla extract", "price": "3.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -5633,7 +5633,7 @@ "item_id": "9% state sales tax", "price": "0.090", "quantity": "4.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -5709,7 +5709,7 @@ "item_id": "9% state sales tax", "price": "0.405", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -5785,7 +5785,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -5861,7 +5861,7 @@ "item_id": "lemon", "price": "1.000", "quantity": "4", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -5924,7 +5924,7 @@ "item_id": "italian sausage", "price": "4.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -5987,7 +5987,7 @@ "item_id": "parmesan cheese", "price": "3.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -6065,7 +6065,7 @@ "item_id": "9% state sales tax", "price": "0.135", "quantity": "3.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -6141,7 +6141,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -6217,7 +6217,7 @@ "item_id": "9% state sales tax", "price": "0.108", "quantity": "6.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -6293,7 +6293,7 @@ "item_id": "celery", "price": "1.500", "quantity": "3", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -6356,7 +6356,7 @@ "item_id": "hand soap", "price": "3.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -6419,7 +6419,7 @@ "item_id": "avocado", "price": "1.200", "quantity": "6", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -6497,7 +6497,7 @@ "item_id": "9% state sales tax", "price": "0.405", "quantity": "4.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -6573,7 +6573,7 @@ "item_id": "9% state sales tax", "price": "0.135", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -6649,7 +6649,7 @@ "item_id": "9% state sales tax", "price": "0.180", "quantity": "3.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -6725,7 +6725,7 @@ "item_id": "roses", "price": "4.500", "quantity": "4", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -6788,7 +6788,7 @@ "item_id": "grapefruit", "price": "1.500", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -6851,7 +6851,7 @@ "item_id": "chocolate", "price": "2.000", "quantity": "3", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -6929,7 +6929,7 @@ "item_id": "9% state sales tax", "price": "0.495", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -7005,7 +7005,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -7081,7 +7081,7 @@ "item_id": "9% state sales tax", "price": "0.405", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -7157,7 +7157,7 @@ "item_id": "shrimp", "price": "5.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -7220,7 +7220,7 @@ "item_id": "tissue", "price": "3.500", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -7283,7 +7283,7 @@ "item_id": "honey", "price": "4.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -7361,7 +7361,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "3.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -7437,7 +7437,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -7513,7 +7513,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -7589,7 +7589,7 @@ "item_id": "crackers", "price": "3.000", "quantity": "3", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -7652,7 +7652,7 @@ "item_id": "lemonade", "price": "3.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -7715,7 +7715,7 @@ "item_id": "granola", "price": "3.500", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -7793,7 +7793,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "3.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -7869,7 +7869,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -7945,7 +7945,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -8021,7 +8021,7 @@ "item_id": "cookies", "price": "3.000", "quantity": "3", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -8084,7 +8084,7 @@ "item_id": "tomato sauce", "price": "3.500", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -8147,7 +8147,7 @@ "item_id": "chicken soup", "price": "3.500", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -8225,7 +8225,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -8301,7 +8301,7 @@ "item_id": "9% state sales tax", "price": "0.090", "quantity": "5.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -8377,7 +8377,7 @@ "item_id": "9% state sales tax", "price": "0.360", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -8453,7 +8453,7 @@ "item_id": "rice", "price": "3.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -8516,7 +8516,7 @@ "item_id": "corn", "price": "1.000", "quantity": "5", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -8579,7 +8579,7 @@ "item_id": "almonds", "price": "4.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -8657,7 +8657,7 @@ "item_id": "9% state sales tax", "price": "0.225", "quantity": "3.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -8733,7 +8733,7 @@ "item_id": "9% state sales tax", "price": "0.360", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -8809,7 +8809,7 @@ "item_id": "9% state sales tax", "price": "0.225", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -8885,7 +8885,7 @@ "item_id": "carrots", "price": "2.500", "quantity": "3", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -8948,7 +8948,7 @@ "item_id": "oats", "price": "4.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -9011,7 +9011,7 @@ "item_id": "ketchup", "price": "2.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -9089,7 +9089,7 @@ "item_id": "9% state sales tax", "price": "0.360", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -9165,7 +9165,7 @@ "item_id": "9% state sales tax", "price": "0.135", "quantity": "3.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -9241,7 +9241,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -9317,7 +9317,7 @@ "item_id": "band aids", "price": "4.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -9380,7 +9380,7 @@ "item_id": "mango", "price": "1.500", "quantity": "3", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -9443,7 +9443,7 @@ "item_id": "ground cinnamon", "price": "3.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -9521,7 +9521,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -9597,7 +9597,7 @@ "item_id": "9% state sales tax", "price": "0.540", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -9673,7 +9673,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -9749,7 +9749,7 @@ "item_id": "frozen vegetables", "price": "3.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -9812,7 +9812,7 @@ "item_id": "ground beef", "price": "6.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -9875,7 +9875,7 @@ "item_id": "strawberry preserve", "price": "3.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -9953,7 +9953,7 @@ "item_id": "9% state sales tax", "price": "0.360", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -10029,7 +10029,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -10105,7 +10105,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -10181,7 +10181,7 @@ "item_id": "corn meal", "price": "4.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -10244,7 +10244,7 @@ "item_id": "pistachios", "price": "3.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -10307,7 +10307,7 @@ "item_id": "orange juice", "price": "3.500", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -10385,7 +10385,7 @@ "item_id": "9% state sales tax", "price": "0.360", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -10461,7 +10461,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -10537,7 +10537,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -10613,7 +10613,7 @@ "item_id": "pineapple", "price": "4.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -10676,7 +10676,7 @@ "item_id": "grapes", "price": "3.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -10739,7 +10739,7 @@ "item_id": "window cleaner", "price": "3.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -10817,7 +10817,7 @@ "item_id": "9% state sales tax", "price": "0.405", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -10893,7 +10893,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -10969,7 +10969,7 @@ "item_id": "9% state sales tax", "price": "0.180", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -11045,7 +11045,7 @@ "item_id": "mozzarella cheese", "price": "4.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -11108,7 +11108,7 @@ "item_id": "pesto sauce", "price": "3.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -11171,7 +11171,7 @@ "item_id": "pine nuts", "price": "2.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -11249,7 +11249,7 @@ "item_id": "9% state sales tax", "price": "0.450", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -11325,7 +11325,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -11401,7 +11401,7 @@ "item_id": "9% state sales tax", "price": "0.360", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -11477,7 +11477,7 @@ "item_id": "pitted dates", "price": "5.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -11540,7 +11540,7 @@ "item_id": "potato salad", "price": "3.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -11603,7 +11603,7 @@ "item_id": "olives", "price": "4.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -11681,7 +11681,7 @@ "item_id": "9% state sales tax", "price": "0.045", "quantity": "6.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -11757,7 +11757,7 @@ "item_id": "9% state sales tax", "price": "0.068", "quantity": "4.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -11833,7 +11833,7 @@ "item_id": "9% state sales tax", "price": "0.360", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -11909,7 +11909,7 @@ "item_id": "jalepeno pepper", "price": "0.500", "quantity": "6", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -11972,7 +11972,7 @@ "item_id": "peach", "price": "0.750", "quantity": "4", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -12035,7 +12035,7 @@ "item_id": "cream cheese", "price": "4.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -12113,7 +12113,7 @@ "item_id": "9% state sales tax", "price": "0.225", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -12189,7 +12189,7 @@ "item_id": "9% state sales tax", "price": "0.135", "quantity": "4.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -12265,7 +12265,7 @@ "item_id": "9% state sales tax", "price": "0.360", "quantity": "3.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -12341,7 +12341,7 @@ "item_id": "baking powder", "price": "2.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -12404,7 +12404,7 @@ "item_id": "serving spoon", "price": "1.500", "quantity": "4", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -12467,7 +12467,7 @@ "item_id": "napkins", "price": "4.000", "quantity": "3", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -12545,7 +12545,7 @@ "item_id": "9% state sales tax", "price": "0.360", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -12621,7 +12621,7 @@ "item_id": "9% state sales tax", "price": "0.225", "quantity": "3.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -12697,7 +12697,7 @@ "item_id": "9% state sales tax", "price": "0.360", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -12773,7 +12773,7 @@ "item_id": "guacamole", "price": "4.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -12836,7 +12836,7 @@ "item_id": "sour cream", "price": "2.500", "quantity": "3", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -12899,7 +12899,7 @@ "item_id": "tortilla chips", "price": "4.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -12977,7 +12977,7 @@ "item_id": "9% state sales tax", "price": "0.450", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -13053,7 +13053,7 @@ "item_id": "9% state sales tax", "price": "0.225", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -13129,7 +13129,7 @@ "item_id": "9% state sales tax", "price": "0.360", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -13205,7 +13205,7 @@ "item_id": "rice noodles", "price": "5.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -13268,7 +13268,7 @@ "item_id": "scallions", "price": "2.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -13331,7 +13331,7 @@ "item_id": "tofu", "price": "4.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -13409,7 +13409,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -13485,7 +13485,7 @@ "item_id": "9% state sales tax", "price": "0.032", "quantity": "5.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -13561,7 +13561,7 @@ "item_id": "9% state sales tax", "price": "0.090", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -13637,7 +13637,7 @@ "item_id": "spinach", "price": "3.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -13700,7 +13700,7 @@ "item_id": "garlic", "price": "0.350", "quantity": "5", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -13763,7 +13763,7 @@ "item_id": "cucumber", "price": "1.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -13841,7 +13841,7 @@ "item_id": "9% state sales tax", "price": "0.900", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -13917,7 +13917,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -13993,7 +13993,7 @@ "item_id": "9% state sales tax", "price": "0.360", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -14069,7 +14069,7 @@ "item_id": "charcoal", "price": "10.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -14132,7 +14132,7 @@ "item_id": "brown sugar", "price": "3.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -14195,7 +14195,7 @@ "item_id": "almond milk", "price": "4.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -14273,7 +14273,7 @@ "item_id": "9% state sales tax", "price": "0.180", "quantity": "4.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -14349,7 +14349,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -14425,7 +14425,7 @@ "item_id": "9% state sales tax", "price": "0.405", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -14501,7 +14501,7 @@ "item_id": "kitchen sponge", "price": "2.000", "quantity": "4", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -14564,7 +14564,7 @@ "item_id": "vinegar", "price": "3.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -14627,7 +14627,7 @@ "item_id": "frozen vegetable mix", "price": "4.500", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -14705,7 +14705,7 @@ "item_id": "9% state sales tax", "price": "0.405", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -14781,7 +14781,7 @@ "item_id": "9% state sales tax", "price": "0.990", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -14857,7 +14857,7 @@ "item_id": "9% state sales tax", "price": "0.180", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -14933,7 +14933,7 @@ "item_id": "blueberries", "price": "4.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -14996,7 +14996,7 @@ "item_id": "strainer", "price": "11.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -15059,7 +15059,7 @@ "item_id": "walnuts", "price": "2.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -15137,7 +15137,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -15213,7 +15213,7 @@ "item_id": "9% state sales tax", "price": "0.450", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -15289,7 +15289,7 @@ "item_id": "9% state sales tax", "price": "0.135", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -15365,7 +15365,7 @@ "item_id": "cottage cheese", "price": "3.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -15428,7 +15428,7 @@ "item_id": "aluminium foil", "price": "5.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -15491,7 +15491,7 @@ "item_id": "sunflower seeds", "price": "1.500", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -15569,7 +15569,7 @@ "item_id": "9% state sales tax", "price": "0.090", "quantity": "3.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -15645,7 +15645,7 @@ "item_id": "9% state sales tax", "price": "0.135", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -15721,7 +15721,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -15797,7 +15797,7 @@ "item_id": "radish", "price": "1.000", "quantity": "3", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -15860,7 +15860,7 @@ "item_id": "string peas", "price": "1.500", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -15923,7 +15923,7 @@ "item_id": "ranch dressing", "price": "3.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -16001,7 +16001,7 @@ "item_id": "9% state sales tax", "price": "0.360", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -16077,7 +16077,7 @@ "item_id": "9% state sales tax", "price": "0.495", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -16153,7 +16153,7 @@ "item_id": "9% state sales tax", "price": "0.315", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -16229,7 +16229,7 @@ "item_id": "fabric softener", "price": "4.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -16292,7 +16292,7 @@ "item_id": "maple syrup", "price": "5.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -16355,7 +16355,7 @@ "item_id": "margarine", "price": "3.500", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -16433,7 +16433,7 @@ "item_id": "9% state sales tax", "price": "0.630", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -16509,7 +16509,7 @@ "item_id": "9% state sales tax", "price": "0.045", "quantity": "5.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -16585,7 +16585,7 @@ "item_id": "9% state sales tax", "price": "0.360", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -16661,7 +16661,7 @@ "item_id": "plastic cups", "price": "7.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -16724,7 +16724,7 @@ "item_id": "lime", "price": "0.500", "quantity": "5", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -16787,7 +16787,7 @@ "item_id": "chilli sauce", "price": "4.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -16865,7 +16865,7 @@ "item_id": "9% state sales tax", "price": "0.630", "quantity": "1.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -16941,7 +16941,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "3.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -17017,7 +17017,7 @@ "item_id": "9% state sales tax", "price": "0.270", "quantity": "2.000", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": "1", "rule_exec_ids": null, "unit_of_measurement": null, @@ -17093,7 +17093,7 @@ "item_id": "salmon", "price": "7.000", "quantity": "1", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -17156,7 +17156,7 @@ "item_id": "artichoke", "price": "3.000", "quantity": "3", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, @@ -17219,7 +17219,7 @@ "item_id": "rice pudding", "price": "3.000", "quantity": "2", - "debitor_first": null, + "debitor_first": false, "rule_instance_id": null, "rule_exec_ids": null, "unit_of_measurement": null, diff --git a/pkg/testdata/trItemWAppr.json b/tests/testdata/trItemWAppr.json similarity index 100% rename from pkg/testdata/trItemWAppr.json rename to tests/testdata/trItemWAppr.json diff --git a/pkg/testdata/trItemWZeroAppr.json b/tests/testdata/trItemWZeroAppr.json similarity index 100% rename from pkg/testdata/trItemWZeroAppr.json rename to tests/testdata/trItemWZeroAppr.json diff --git a/pkg/testdata/trItemsNoAppr.json b/tests/testdata/trItemsNoAppr.json similarity index 100% rename from pkg/testdata/trItemsNoAppr.json rename to tests/testdata/trItemsNoAppr.json diff --git a/pkg/testdata/transMultipleRules.json b/tests/testdata/transMultipleRules.json similarity index 100% rename from pkg/testdata/transMultipleRules.json rename to tests/testdata/transMultipleRules.json diff --git a/pkg/testdata/transNoAppr.json b/tests/testdata/transNoAppr.json similarity index 100% rename from pkg/testdata/transNoAppr.json rename to tests/testdata/transNoAppr.json diff --git a/pkg/testdata/transWAppr.json b/tests/testdata/transWAppr.json similarity index 100% rename from pkg/testdata/transWAppr.json rename to tests/testdata/transWAppr.json diff --git a/pkg/testdata/transWTimes.json b/tests/testdata/transWTimes.json similarity index 100% rename from pkg/testdata/transWTimes.json rename to tests/testdata/transWTimes.json From 53c57f239109af849ea622eaaf1320ceee05fd37 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:19:51 -0700 Subject: [PATCH 14/37] reference current testdata directory --- crates/pg/src/model.rs | 10 +++++----- crates/pg/src/sqls/transaction.rs | 6 +++--- migrations/dumps/README.md | 4 ++-- scripts/insert-transactions.sh | 28 ++++++++++++++++------------ scripts/sum-value.sh | 2 +- services/request-create/makefile | 2 +- services/rule/makefile | 4 ++-- tests/src/helpers.rs | 2 +- tests/src/integration_tests.rs | 18 +++++++++--------- 9 files changed, 40 insertions(+), 36 deletions(-) diff --git a/crates/pg/src/model.rs b/crates/pg/src/model.rs index 11e5458e..e3a8dbc6 100644 --- a/crates/pg/src/model.rs +++ b/crates/pg/src/model.rs @@ -983,7 +983,7 @@ mod integration_tests { let test_conn = _get_conn().await; let api_conn = DatabaseConnection(test_conn); - let file = File::open("../../pkg/testdata/transWTimes.json").unwrap(); + let file = File::open("../../tests/testdata/transWTimes.json").unwrap(); let reader = BufReader::new(file); let test_intra_transaction: IntraTransaction = serde_json::from_reader(reader).unwrap(); let test_transaction_items = test_intra_transaction.transaction.transaction_items; @@ -1318,7 +1318,7 @@ mod integration_tests { let test_conn = _get_conn().await; let mut api_conn = DatabaseConnection(test_conn); - let input_file = File::open("../../pkg/testdata/requests.json").unwrap(); + let input_file = File::open("../../tests/testdata/requests.json").unwrap(); let input_reader = BufReader::new(input_file); let test_transactions: Vec = serde_json::from_reader(input_reader).unwrap(); @@ -1340,7 +1340,7 @@ mod integration_tests { let test_conn = _get_conn().await; let mut api_conn = DatabaseConnection(test_conn); - let input_file = File::open("../../pkg/testdata/requests.json").unwrap(); + let input_file = File::open("../../tests/testdata/requests.json").unwrap(); let input_reader = BufReader::new(input_file); let test_transactions: Vec = serde_json::from_reader(input_reader).unwrap(); @@ -1381,7 +1381,7 @@ mod integration_tests { let test_conn = _get_conn().await; let mut api_conn = DatabaseConnection(test_conn); - let input_file = File::open("../../pkg/testdata/requests.json").unwrap(); + let input_file = File::open("../../tests/testdata/requests.json").unwrap(); let input_reader = BufReader::new(input_file); let test_transactions: Vec = serde_json::from_reader(input_reader).unwrap(); @@ -1412,7 +1412,7 @@ mod integration_tests { let test_conn = _get_conn().await; let mut api_conn = DatabaseConnection(test_conn); - let input_file = File::open("../../pkg/testdata/requests.json").unwrap(); + let input_file = File::open("../../tests/testdata/requests.json").unwrap(); let input_reader = BufReader::new(input_file); let test_transactions: Vec = serde_json::from_reader(input_reader).unwrap(); diff --git a/crates/pg/src/sqls/transaction.rs b/crates/pg/src/sqls/transaction.rs index 125f0661..aada9e80 100644 --- a/crates/pg/src/sqls/transaction.rs +++ b/crates/pg/src/sqls/transaction.rs @@ -267,7 +267,7 @@ mod tests { #[test] fn it_creates_a_with_sql() { - let input_file = File::open("../../pkg/testdata/requests.json").unwrap(); + let input_file = File::open("../../tests/testdata/requests.json").unwrap(); let input_reader = BufReader::new(input_file); let test_transactions: Vec = serde_json::from_reader(input_reader).unwrap(); @@ -290,7 +290,7 @@ mod tests { // test error when approvals in transaction item is None #[test] fn it_returns_error_when_approvals_in_transaction_item_is_none() { - let file = File::open("../../pkg/testdata/transWTimes.json").unwrap(); + let file = File::open("../../tests/testdata/transWTimes.json").unwrap(); let reader = BufReader::new(file); let test_intra_transaction: IntraTransaction = serde_json::from_reader(reader).unwrap(); let mut test_transaction = test_intra_transaction.transaction.clone(); @@ -308,7 +308,7 @@ mod tests { // test error when approvals in transaction item is empty #[test] fn it_returns_error_when_approvals_in_transaction_item_is_empty() { - let file = File::open("../../pkg/testdata/transWTimes.json").unwrap(); + let file = File::open("../../tests/testdata/transWTimes.json").unwrap(); let reader = BufReader::new(file); let test_intra_transaction: IntraTransaction = serde_json::from_reader(reader).unwrap(); let mut test_transaction = test_intra_transaction.transaction; diff --git a/migrations/dumps/README.md b/migrations/dumps/README.md index 8bc34ea1..ba695aa7 100644 --- a/migrations/dumps/README.md +++ b/migrations/dumps/README.md @@ -19,7 +19,7 @@ replaces 2 minute running time to create test db using migrations and service ca `make -C './migrations' insert` - **2 minutes**: 1. drops test db 1. up migrates postgres with `./migrations/schema`, `./migrations/seed` and `./migrations/testseed` directories - 1. inserts mix of approximately 40 requests and transactions from `./pkg/testdata/requests.json` by calling `services/request-create` and `services/request-approve` + 1. inserts mix of approximately 40 requests and transactions from `./tests/testdata/requests.json` by calling `services/request-create` and `services/request-approve` `make -C './migrations/dumps' restore-testseed` - **5 seconds**: 1. down migrates test db to drop functions @@ -31,7 +31,7 @@ replaces 2 minute running time to create test db using migrations and service ca 1. `./migrations/schema` 1. `./migrations/seed` 1. `./migrations/testseed` - 1. `./pkg/testdata/requests.json` + 1. `./tests/testdata/requests.json` 1. rebuild test db with `make -C './migrations' insert` 1. `make -C './migrations/dumps' dump-testseed` to create new `./migrations/dumps/testseed.sql` 1. commit & push `./migrations/dumps/testseed.sql` change diff --git a/scripts/insert-transactions.sh b/scripts/insert-transactions.sh index 1ecb9099..86679e55 100644 --- a/scripts/insert-transactions.sh +++ b/scripts/insert-transactions.sh @@ -3,21 +3,25 @@ set -e PROJECT_CONF=project.yaml -ENV_VAR_PATH='.infrastructure.terraform.aws.modules.environment.env_var.set' -REQUEST_CREATE_URL=$(yq "$ENV_VAR_PATH.REQUEST_CREATE_URL.default" $PROJECT_CONF) -REQUEST_APPROVE_URL=$(yq "$ENV_VAR_PATH.REQUEST_APPROVE_URL.default" $PROJECT_CONF) -TEST_DATA_DIR=./pkg/testdata +LOCAL_ADDRESS=$(yq '.env_var.set.LOCAL_ADDRESS.default' $PROJECT_CONF) +HOST="http://$LOCAL_ADDRESS" +REQUEST_CREATE_PORT=$(yq ".services.request-create.env_var.set.REQUEST_CREATE_PORT.default" $PROJECT_CONF) +REQUEST_CREATE_URL=$HOST:$REQUEST_CREATE_PORT +REQUEST_APPROVE_PORT=$(yq ".services.request-approve.env_var.set.REQUEST_APPROVE_PORT.default" $PROJECT_CONF) +REQUEST_APPROVE_URL=$HOST:$REQUEST_APPROVE_PORT +TEST_DATA_DIR=./tests/testdata TEST_DATA_FILE_NAME=requests.json TEST_DATA_FILE=$TEST_DATA_DIR/$TEST_DATA_FILE_NAME MIGRATIONS_DIR=./migrations TEST_ENV=dev STARTING_TRANS_ID=3 # start from 3 since transaction id 1 & 2 are created by migrations/testseed -export PGDATABASE=$(yq "$ENV_VAR_PATH.PGDATABASE.default" $PROJECT_CONF) -export PGUSER=$(yq "$ENV_VAR_PATH.PGUSER.default" $PROJECT_CONF) -export PGPASSWORD=$(yq "$ENV_VAR_PATH.PGPASSWORD.default" $PROJECT_CONF) -export PGHOST=$(yq "$ENV_VAR_PATH.PGHOST.default" $PROJECT_CONF) -export PGPORT=$(yq "$ENV_VAR_PATH.PGPORT.default" $PROJECT_CONF) +ENV_VAR_PATH='infrastructure.terraform.aws.modules.environment.env_var.set' +export PGDATABASE=$(yq ".${ENV_VAR_PATH}.PGDATABASE.default" $PROJECT_CONF) +export PGUSER=$(yq ".${ENV_VAR_PATH}.PGUSER.default" $PROJECT_CONF) +export PGPASSWORD=$(yq ".${ENV_VAR_PATH}.PGPASSWORD.default" $PROJECT_CONF) +export PGHOST=$(yq ".${ENV_VAR_PATH}.PGHOST.default" $PROJECT_CONF) +export PGPORT=$(yq ".${ENV_VAR_PATH}.PGPORT.default" $PROJECT_CONF) # reset postgres in docker (cd $MIGRATIONS_DIR; make resetdocker DB=test) @@ -30,8 +34,8 @@ TRANSACTION_ID=$STARTING_TRANS_ID yq -I0 -o=json '.[]' $TEST_DATA_FILE | while IFS='\n' read transaction; do - # create requests for each in ./reqsAndTrans.json - curl -s -d "$transaction" $REQUEST_CREATE_URL >/dev/null + # create requests for each in tests/testdata/requests.json + curl -s -H 'Content-Type: application/json' -d "$transaction" $REQUEST_CREATE_URL >/dev/null # approve every other request to create mix of requests and transactions if [[ $(("$TRANSACTION_ID"%2)) -eq 0 ]]; then @@ -43,7 +47,7 @@ yq -I0 -o=json '.[]' $TEST_DATA_FILE | while IFS='\n' read transaction; do APPROVAL="{\"auth_account\":\""$DEBITOR_APPROVER"\",\"id\":\""$TRANSACTION_ID"\",\"account_name\":\""$DEBITOR_APPROVER"\",\"account_role\":\"debitor\"}" # approve transaction request - curl -s -d "$APPROVAL" $REQUEST_APPROVE_URL >/dev/null + curl -s -H 'Content-Type: application/json' -d "$APPROVAL" $REQUEST_APPROVE_URL >/dev/null fi printf '%s' '.' diff --git a/scripts/sum-value.sh b/scripts/sum-value.sh index cdf6822f..c68b17cc 100644 --- a/scripts/sum-value.sh +++ b/scripts/sum-value.sh @@ -6,7 +6,7 @@ set -e if [[ "$#" -ne 2 ]]; then cat <<- 'EOF' use: - bash scripts/sum-value.sh --file-path pkg/testdata/transMultipleRules.json + bash scripts/sum-value.sh --file-path tests/testdata/transMultipleRules.json EOF exit 1 fi diff --git a/services/request-create/makefile b/services/request-create/makefile index 6b371175..77113e3f 100644 --- a/services/request-create/makefile +++ b/services/request-create/makefile @@ -7,7 +7,7 @@ REQUEST_CREATE_URL=$(HOST):$(REQUEST_CREATE_PORT) MIGRATIONS_DIR=$(RELATIVE_PROJECT_ROOT_PATH)/migrations TEST_DATA_FILE=transNoAppr.json -TEST_DATA_DIR=$(RELATIVE_PROJECT_ROOT_PATH)/pkg/testdata +TEST_DATA_DIR=$(RELATIVE_PROJECT_ROOT_PATH)/tests/testdata TEST_EVENT='$(shell cat $(TEST_DATA_DIR)/$(TEST_DATA_FILE))' start: diff --git a/services/rule/makefile b/services/rule/makefile index 0ceccf4f..47d32065 100644 --- a/services/rule/makefile +++ b/services/rule/makefile @@ -7,7 +7,7 @@ RULE_URL=$(HOST):$(RULE_PORT) NOHUP_LOG=$(RELATIVE_PROJECT_ROOT_PATH)/$(shell yq '.env_var.set.NOHUP_LOG.default' $(PROJECT_CONF)) TEST_DATA_FILE=preRuleTrItems.json -TEST_DATA_DIR=$(RELATIVE_PROJECT_ROOT_PATH)/pkg/testdata +TEST_DATA_DIR=$(RELATIVE_PROJECT_ROOT_PATH)/tests/testdata TEST_EVENT='$(shell cat $(TEST_DATA_DIR)/$(TEST_DATA_FILE))' dev: @@ -27,7 +27,7 @@ run: cargo watch --env-file $(ENV_FILE) -w $(SUB_PATH)/src -w crates -x run -p $(SUB_PATH) water: - @REQ=$$(yq -o=json $(RELATIVE_PROJECT_ROOT_PATH)/pkg/testdata/bottledWater.json); \ + @REQ=$$(yq -o=json $(RELATIVE_PROJECT_ROOT_PATH)/tests/testdata/bottledWater.json); \ curl -s -d "$$REQ" -H 'Content-Type: application/json' $(RULE_URL) \ | yq -o=json diff --git a/tests/src/helpers.rs b/tests/src/helpers.rs index bedba114..adde68c9 100644 --- a/tests/src/helpers.rs +++ b/tests/src/helpers.rs @@ -39,7 +39,7 @@ pub fn restore_testseed() { pub async fn create_transaction() -> Transaction { // load test transaction from file - let file = File::open("../pkg/testdata/transNoAppr.json").unwrap(); + let file = File::open("../tests/testdata/transNoAppr.json").unwrap(); let reader = BufReader::new(file); let test_intra_transaction: IntraTransaction = serde_json::from_reader(reader).unwrap(); diff --git a/tests/src/integration_tests.rs b/tests/src/integration_tests.rs index 1ac4373f..4e20d288 100644 --- a/tests/src/integration_tests.rs +++ b/tests/src/integration_tests.rs @@ -33,7 +33,7 @@ mod tests { async fn http_rule_adds_2_objects() { _before_each(); - let file = File::open("../pkg/testdata/nullFirstTrItemsNoAppr.json").unwrap(); + let file = File::open("../tests/testdata/nullFirstTrItemsNoAppr.json").unwrap(); let reader = BufReader::new(file); let test_transaction_items: Vec = serde_json::from_reader(reader).unwrap(); @@ -64,7 +64,7 @@ mod tests { async fn http_request_create_creates_a_request() { _before_each(); - let file = File::open("../pkg/testdata/transNoAppr.json").unwrap(); + let file = File::open("../tests/testdata/transNoAppr.json").unwrap(); let reader = BufReader::new(file); let test_intra_transaction: IntraTransaction = serde_json::from_reader(reader).unwrap(); @@ -105,7 +105,7 @@ mod tests { async fn http_request_approve_approves_a_request() { _before_each(); - let file = File::open("../pkg/testdata/transNoAppr.json").unwrap(); + let file = File::open("../tests/testdata/transNoAppr.json").unwrap(); let reader = BufReader::new(file); let test_intra_transaction: IntraTransaction = serde_json::from_reader(reader).unwrap(); @@ -268,7 +268,7 @@ mod tests { async fn http_request_by_id_returns_a_request_by_id() { _before_each(); - let file = File::open("../pkg/testdata/transNoAppr.json").unwrap(); + let file = File::open("../tests/testdata/transNoAppr.json").unwrap(); let reader = BufReader::new(file); let test_intra_transaction: IntraTransaction = serde_json::from_reader(reader).unwrap(); @@ -313,7 +313,7 @@ mod tests { async fn http_requests_by_account_returns_requests_by_account() { _before_each(); - let file = File::open("../pkg/testdata/transNoAppr.json").unwrap(); + let file = File::open("../tests/testdata/transNoAppr.json").unwrap(); let reader = BufReader::new(file); let mut test_intra_transaction: IntraTransaction = serde_json::from_reader(reader).unwrap(); @@ -366,7 +366,7 @@ mod tests { async fn graphql_creates_a_request() { _before_each(); - let file = File::open("../pkg/testdata/intRules.json").unwrap(); + let file = File::open("../tests/testdata/intRules.json").unwrap(); let reader = BufReader::new(file); let test_transaction_items: TransactionItemsBody = serde_json::from_reader(reader).unwrap(); @@ -390,7 +390,7 @@ mod tests { async fn graphql_approves_a_request() { _before_each(); - let file = File::open("../pkg/testdata/intRules.json").unwrap(); + let file = File::open("../tests/testdata/intRules.json").unwrap(); let reader = BufReader::new(file); let test_transaction_items: TransactionItemsBody = serde_json::from_reader(reader).unwrap(); @@ -540,7 +540,7 @@ mod tests { async fn graphql_returns_requests_by_account() { _before_each(); - let file = File::open("../pkg/testdata/transNoAppr.json").unwrap(); + let file = File::open("../tests/testdata/transNoAppr.json").unwrap(); let reader = BufReader::new(file); let mut test_intra_transaction: IntraTransaction = serde_json::from_reader(reader).unwrap(); @@ -593,7 +593,7 @@ mod tests { async fn graphql_returns_a_request_by_id() { _before_each(); - let file = File::open("../pkg/testdata/transNoAppr.json").unwrap(); + let file = File::open("../tests/testdata/transNoAppr.json").unwrap(); let reader = BufReader::new(file); let test_intra_transaction: IntraTransaction = serde_json::from_reader(reader).unwrap(); From 4416901e79ffd4f004ee28ee6ff479ea4a93a99a Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:21:49 -0700 Subject: [PATCH 15/37] remove go notification and websocket services --- services/notifications-clear/README.md | 16 -- services/notifications-clear/cmd/main.go | 226 --------------------- services/notifications-clear/makefile | 43 ---- services/notifications-get/README.md | 17 -- services/notifications-get/cmd/main.go | 239 ----------------------- services/notifications-get/makefile | 47 ----- services/notifications-send/README.md | 15 -- services/notifications-send/cmd/main.go | 173 ---------------- services/notifications-send/makefile | 15 -- services/wss-connect/README.md | 12 -- services/wss-connect/cmd/main.go | 132 ------------- services/wss-connect/makefile | 6 - 12 files changed, 941 deletions(-) delete mode 100644 services/notifications-clear/README.md delete mode 100644 services/notifications-clear/cmd/main.go delete mode 100644 services/notifications-clear/makefile delete mode 100644 services/notifications-get/README.md delete mode 100644 services/notifications-get/cmd/main.go delete mode 100644 services/notifications-get/makefile delete mode 100644 services/notifications-send/README.md delete mode 100644 services/notifications-send/cmd/main.go delete mode 100644 services/notifications-send/makefile delete mode 100644 services/wss-connect/README.md delete mode 100644 services/wss-connect/cmd/main.go delete mode 100644 services/wss-connect/makefile diff --git a/services/notifications-clear/README.md b/services/notifications-clear/README.md deleted file mode 100644 index 4fe18817..00000000 --- a/services/notifications-clear/README.md +++ /dev/null @@ -1,16 +0,0 @@ -

- systemaccounting -

- -### notifications-clear - -1. invoked by apigateway v2 with `clearnotifications` websocket message from client -1. sets `account_name` in `websocket` table if not set -1. deletes `transaction_notification` records -1. returns `id`s of deleted `transaction_notification` records - -deploy: `make deploy ENV=dev` - -terraform: https://github.com/systemaccounting/mxfactorial/blob/8c92e48e04af73ed700b2471a05f6b0ee76c0912/infrastructure/terraform/aws/modules/environment/v001/lambda-services.tf#L160-L171 - -wscat: local development instructions for api gateway websockets available from services/internal-tools/wss-demo-client/README.md diff --git a/services/notifications-clear/cmd/main.go b/services/notifications-clear/cmd/main.go deleted file mode 100644 index e863a5e3..00000000 --- a/services/notifications-clear/cmd/main.go +++ /dev/null @@ -1,226 +0,0 @@ -package main - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "log" - "os" - - "github.com/aws/aws-lambda-go/events" - "github.com/aws/aws-lambda-go/lambda" - cidp "github.com/systemaccounting/mxfactorial/pkg/aws/cognitoidp" - "github.com/systemaccounting/mxfactorial/pkg/logger" - "github.com/systemaccounting/mxfactorial/pkg/postgres" - "github.com/systemaccounting/mxfactorial/pkg/service" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -var ( - pgConn string = fmt.Sprintf( - "host=%s port=%s user=%s password=%s dbname=%s", - os.Getenv("PGHOST"), - os.Getenv("PGPORT"), - os.Getenv("PGUSER"), - os.Getenv("PGPASSWORD"), - os.Getenv("PGDATABASE")) - awsRegion string = os.Getenv("AWS_REGION") - apiGWConnectionsURI = os.Getenv("APIGW_CONNECTIONS_URI") - cognitoJWKSURI = os.Getenv("COGNITO_JWKS_URI") - jwks *cidp.CognitoJwks -) - -type SQLDB interface { - Close(context.Context) error -} - -type IWebsocketService interface { - SendNotificationOrDeleteStaleWebsocket(connectionID *string, v any) error - AddAccountToCurrentWebsocket(accountName, connectionID string) error -} - -type ITransactionNotificationService interface { - DeleteTransNotificationsByIDs(notifIDs types.IDs) error -} - -type IAuthenticate interface { - GetAuthAccount(token string) (string, error) -} - -type IAuthService interface { - AuthAccount(*cidp.JWToken, *string) (string, error) -} - -type Body struct { - types.WebsocketMessage - NotificationIDs types.IDs `json:"notification_ids"` - cidp.JWToken `json:"token"` -} - -func init() { - jwks = cidp.NewCognitoJwks(cognitoJWKSURI) - err := jwks.Fetch() - if err != nil { - logger.Log(logger.Trace(), err) - panic(err) - } -} - -func lambdaFn( - ctx context.Context, - e events.APIGatewayWebsocketProxyRequest, - jwkeys *cidp.CognitoJwks, - b *Body, - a IAuthService, - dbConnector func(context.Context, string) (SQLDB, error), - websocketServiceConstructor func(db SQLDB) (IWebsocketService, error), - notificationServiceConstructor func(db SQLDB) (ITransactionNotificationService, error), -) (events.APIGatewayProxyResponse, error) { - - // unmarshal body from apigw request - err := json.Unmarshal([]byte(e.Body), &b) - if err != nil { - logger.Log(logger.Trace(), err) - return events.APIGatewayProxyResponse{}, nil - } - - accountName, err := a.AuthAccount(&b.JWToken, b.Account) - if err != nil { - logger.Log(logger.Trace(), err) - return events.APIGatewayProxyResponse{}, err - } - - // connect to db - db, err := dbConnector(context.Background(), pgConn) - if err != nil { - logger.Log(logger.Trace(), err) - return events.APIGatewayProxyResponse{}, err - } - defer db.Close(context.Background()) - - // create websocket service - ws, err := websocketServiceConstructor(db) - if err != nil { - logger.Log(logger.Trace(), err) - return events.APIGatewayProxyResponse{}, err - } - - connectionID := e.RequestContext.ConnectionID - notificationIDsToClear := b.NotificationIDs - - // update websocket with account name - err = ws.AddAccountToCurrentWebsocket(accountName, connectionID) - if err != nil { - log.Printf("websocket update failure: %v", err) - return events.APIGatewayProxyResponse{}, err - } - - // create notification service - ns, err := notificationServiceConstructor(db) - if err != nil { - logger.Log(logger.Trace(), err) - log.Fatal(err) - } - - err = ns.DeleteTransNotificationsByIDs(notificationIDsToClear) - if err != nil { - logger.Log(logger.Trace(), err) - } - - // create response with cleared notifications - notificationsToSend := types.ClearedNotifications{ - Cleared: notificationIDsToClear, - } - - // send notification to websocket connection - // or delete stale websocket from db - err = ws.SendNotificationOrDeleteStaleWebsocket( - &connectionID, - notificationsToSend, - ) - if err != nil { - logger.Log(logger.Trace(), err) - } - - // 200 to api gateway - return events.APIGatewayProxyResponse{StatusCode: 200}, nil -} - -// wraps lambdaFn accepting db interface for testability -func handleEvent( - ctx context.Context, - e events.APIGatewayWebsocketProxyRequest, -) (events.APIGatewayProxyResponse, error) { - websocketMessageBody := new(Body) - authService := service.NewAuthService(jwks) - return lambdaFn( - ctx, - e, - jwks, - websocketMessageBody, - authService, - newIDB, - newWebsocketService, - newNotificationService, - ) -} - -func newWebsocketService(idb SQLDB) (IWebsocketService, error) { - db, ok := idb.(*postgres.DB) - if !ok { - return nil, errors.New("newWebsocketService: failed to assert *postgres.DB") - } - return service.NewWebsocketService(db, &apiGWConnectionsURI, &awsRegion), nil -} - -func newNotificationService(idb SQLDB) (ITransactionNotificationService, error) { - db, ok := idb.(*postgres.DB) - if !ok { - return nil, errors.New("newNotificationService: failed to assert *postgres.DB") - } - return service.NewTransactionNotificationService(db), nil -} - -func newIDB(ctx context.Context, dsn string) (SQLDB, error) { - return postgres.NewDB(ctx, dsn) -} - -// avoids lambda package dependency during local development -func localEnvOnly(event string) { - - // create test event by assigning to proxy request body - testEvent := events.APIGatewayWebsocketProxyRequest{ - Body: event, - RequestContext: events.APIGatewayWebsocketProxyRequestContext{ - // temp hardcoded ConnectionID - // todo: - ConnectionID: "L0SM9cOFvHcCIhw=", - }, - } - - // call event handler with test event - resp, err := handleEvent(context.Background(), testEvent) - if err != nil { - panic(err) - } - - if len(os.Getenv("DEBUG")) > 0 { - log.Print(resp) - } - - _ = resp -} - -func main() { - - // ### LOCAL ENV only: assign event from env var - var osTestEvent string = os.Getenv("TEST_EVENT") - if len(osTestEvent) > 0 { - localEnvOnly(osTestEvent) - return - } - // ### - - lambda.Start(handleEvent) -} diff --git a/services/notifications-clear/makefile b/services/notifications-clear/makefile deleted file mode 100644 index 8fe2f7e8..00000000 --- a/services/notifications-clear/makefile +++ /dev/null @@ -1,43 +0,0 @@ -RELATIVE_PROJECT_ROOT_PATH=$(shell REL_PATH="."; while [ $$(ls "$$REL_PATH" | grep project.yaml | wc -l | xargs) -eq 0 ]; do REL_PATH="$$REL_PATH./.."; done; printf '%s' "$$REL_PATH") -include $(RELATIVE_PROJECT_ROOT_PATH)/make/shared.mk -include $(RELATIVE_PROJECT_ROOT_PATH)/make/go.mk - -test-username-arg: -ifndef ACCT - $(error trailing ACCT assignment missing, e.g. ACCT=SomeAccount) -endif - -test-password-arg: -ifndef PASS - $(error trailing PASS assignment missing, e.g. PASS=SomeSecret) -endif - -test-ids-arg: -ifndef IDS - $(error trailing IDS assignment missing, e.g. IDS=2,7,12) -endif - -run: - @$(DOCKER_ENV_VARS) go run ./cmd/main.go - -save-id-token: - @$(MAKE) -s test-username-arg - @$(MAKE) -s test-password-arg - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/save-id-token.sh \ - --dir-path $(SUB_PATH) \ - --username $(ACCT) \ - --password $(PASS) \ - --region $(REGION) - -get: - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/get-notifications.sh \ - --dir-path $(SUB_PATH) - -clear: - @$(MAKE) -s test-ids-arg - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/clear-notifications.sh \ - --dir-path $(SUB_PATH) \ - --ids '$(IDS)' \ No newline at end of file diff --git a/services/notifications-get/README.md b/services/notifications-get/README.md deleted file mode 100644 index 972841f9..00000000 --- a/services/notifications-get/README.md +++ /dev/null @@ -1,17 +0,0 @@ -

- systemaccounting -

- -### notifications-get - -1. invoked by apigateway v2 with `getnotifications` websocket message received from client -1. sets `account_name` in `websocket` table if not set -1. queries `transaction_notification` by `account_name` -1. returns `transaction_notification` records -1. deletes websocket record in `websocket` table IF websockets proves stale - -deploy: `make deploy ENV=dev` - -terraform: https://github.com/systemaccounting/mxfactorial/blob/8c92e48e04af73ed700b2471a05f6b0ee76c0912/infrastructure/terraform/aws/modules/environment/v001/lambda-services.tf#L145-L157 - -wscat: local development instructions for api gateway websockets available from services/internal-tools/wss-demo-client/README.md \ No newline at end of file diff --git a/services/notifications-get/cmd/main.go b/services/notifications-get/cmd/main.go deleted file mode 100644 index cc76941c..00000000 --- a/services/notifications-get/cmd/main.go +++ /dev/null @@ -1,239 +0,0 @@ -package main - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "log" - "os" - "strconv" - - "github.com/aws/aws-lambda-go/events" - "github.com/aws/aws-lambda-go/lambda" - cidp "github.com/systemaccounting/mxfactorial/pkg/aws/cognitoidp" - "github.com/systemaccounting/mxfactorial/pkg/logger" - "github.com/systemaccounting/mxfactorial/pkg/postgres" - "github.com/systemaccounting/mxfactorial/pkg/service" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -var ( - pgConn string = fmt.Sprintf( - "host=%s port=%s user=%s password=%s dbname=%s", - os.Getenv("PGHOST"), - os.Getenv("PGPORT"), - os.Getenv("PGUSER"), - os.Getenv("PGPASSWORD"), - os.Getenv("PGDATABASE")) - notificationsReturnLimit string = os.Getenv("NOTIFICATIONS_RETURN_LIMIT") - awsRegion string = os.Getenv("AWS_REGION") - apiGWConnectionsURI = os.Getenv("APIGW_CONNECTIONS_URI") - cognitoJWKSURI = os.Getenv("COGNITO_JWKS_URI") - jwks *cidp.CognitoJwks -) - -type SQLDB interface { - Close(context.Context) error -} - -type IWebsocketService interface { - SendNotificationOrDeleteStaleWebsocket(connectionID *string, v any) error - AddAccountToCurrentWebsocket(accountName, connectionID string) error -} - -type ITransactionNotificationService interface { - GetTransNotifsByAccount(accountName string, recordLimit int) (types.TransactionNotifications, error) -} - -type IAuthService interface { - AuthAccount(*cidp.JWToken, *string) (string, error) -} - -type Body struct { - types.WebsocketMessage - cidp.JWToken -} - -func init() { - jwks = cidp.NewCognitoJwks(cognitoJWKSURI) - err := jwks.Fetch() - if err != nil { - logger.Log(logger.Trace(), err) - panic(err) - } -} - -func lambdaFn( - ctx context.Context, - e events.APIGatewayWebsocketProxyRequest, - b *Body, - a IAuthService, - dbConnector func(context.Context, string) (SQLDB, error), - websocketServiceConstructor func(db SQLDB) (IWebsocketService, error), - notificationServiceConstructor func(db SQLDB) (ITransactionNotificationService, error), -) (events.APIGatewayProxyResponse, error) { - - // unmarshal body from apigw request - err := json.Unmarshal([]byte(e.Body), &b) - if err != nil { - logger.Log(logger.Trace(), err) - return events.APIGatewayProxyResponse{}, nil - } - - // assigns account from cognito token when auth enabled, or - // temp account property in websocket message when disabled - accountName, err := a.AuthAccount(&b.JWToken, b.Account) - if err != nil { - logger.Log(logger.Trace(), err) - return events.APIGatewayProxyResponse{}, err - } - - // connect to db - db, err := dbConnector(context.Background(), pgConn) - if err != nil { - logger.Log(logger.Trace(), err) - return events.APIGatewayProxyResponse{}, err - } - defer db.Close(context.Background()) - - // create websocket service - ws, err := websocketServiceConstructor(db) - if err != nil { - logger.Log(logger.Trace(), err) - return events.APIGatewayProxyResponse{}, err - } - - connectionID := e.RequestContext.ConnectionID - - // update websocket with account name - err = ws.AddAccountToCurrentWebsocket(accountName, connectionID) - if err != nil { - logger.Log(logger.Trace(), err) - log.Printf("websocket update failure: %v", err) - return events.APIGatewayProxyResponse{}, err - } - - // create notification service - ns, err := notificationServiceConstructor(db) - if err != nil { - logger.Log(logger.Trace(), err) - log.Fatal(err) - } - - // cadet todo: move into separate function - limit, err := strconv.Atoi(notificationsReturnLimit) - if err != nil { - logger.Log(logger.Trace(), err) - log.Printf("string to int conversion fail %v", err) - return events.APIGatewayProxyResponse{}, nil - } - - transNotifs, err := ns.GetTransNotifsByAccount(accountName, limit) - if err != nil { - logger.Log(logger.Trace(), err) - } - - // 1. create notification payload - // 2. store notifications for delete after delivery - var notificationsToSend types.PendingNotifications - for _, v := range transNotifs { - msg := &types.Message{ - NotificationID: v.ID, - Message: *v.Message, - } - notificationsToSend.Pending = append(notificationsToSend.Pending, msg) - } - - // send notification to websocket connection - // or delete stale websocket from db - err = ws.SendNotificationOrDeleteStaleWebsocket( - &connectionID, - notificationsToSend, - ) - if err != nil { - logger.Log(logger.Trace(), err) - } - - // 200 to api gateway - return events.APIGatewayProxyResponse{StatusCode: 200}, nil -} - -// wraps lambdaFn accepting db interface for testability -func handleEvent( - ctx context.Context, - e events.APIGatewayWebsocketProxyRequest, -) (events.APIGatewayProxyResponse, error) { - websocketMessageBody := new(Body) - authService := service.NewAuthService(jwks) - return lambdaFn( - ctx, - e, - websocketMessageBody, - authService, - newIDB, - newWebsocketService, - newNotificationService, - ) -} - -// enables lambdaFn unit testing -func newWebsocketService(idb SQLDB) (IWebsocketService, error) { - db, ok := idb.(*postgres.DB) - if !ok { - return nil, errors.New("newWebsocketService: failed to assert *DB") - } - return service.NewWebsocketService(db, &apiGWConnectionsURI, &awsRegion), nil -} - -// enables lambdaFn unit testing -func newNotificationService(idb SQLDB) (ITransactionNotificationService, error) { - db, ok := idb.(*postgres.DB) - if !ok { - return nil, errors.New("newNotificationService: failed to assert *DB") - } - return service.NewTransactionNotificationService(db), nil -} - -// enables lambdaFn unit testing -func newIDB(ctx context.Context, dsn string) (SQLDB, error) { - return postgres.NewDB(ctx, dsn) -} - -// avoids lambda package dependency during local development -func localEnvOnly(event string) { - - // create test event by assigning to proxy request body - testEvent := events.APIGatewayWebsocketProxyRequest{ - Body: event, - RequestContext: events.APIGatewayWebsocketProxyRequestContext{ - // temp hardcoded test value during local development - ConnectionID: "L0SM9cOFvHcCIhw=", - }, - } - - // call event handler with test event - resp, err := handleEvent(context.Background(), testEvent) - if err != nil { - panic(err) - } - - if len(os.Getenv("DEBUG")) > 0 { - log.Print(resp) - } - - _ = resp -} - -func main() { - - // ### LOCAL ENV only: assign event from env var - var osTestEvent string = os.Getenv("TEST_EVENT") - if len(osTestEvent) > 0 { - localEnvOnly(osTestEvent) - return - } - // ### - - lambda.Start(handleEvent) -} diff --git a/services/notifications-get/makefile b/services/notifications-get/makefile deleted file mode 100644 index ced3066b..00000000 --- a/services/notifications-get/makefile +++ /dev/null @@ -1,47 +0,0 @@ -RELATIVE_PROJECT_ROOT_PATH=$(shell REL_PATH="."; while [ $$(ls "$$REL_PATH" | grep project.yaml | wc -l | xargs) -eq 0 ]; do REL_PATH="$$REL_PATH./.."; done; printf '%s' "$$REL_PATH") -include $(RELATIVE_PROJECT_ROOT_PATH)/make/shared.mk -include $(RELATIVE_PROJECT_ROOT_PATH)/make/go.mk - -test-username-arg: -ifndef ACCT - $(error trailing ACCT assignment missing, e.g. ACCT=SomeAccount) -endif - -test-password-arg: -ifndef PASS - $(error trailing PASS assignment missing, e.g. PASS=SomeSecret) -endif - -test-ids-arg: -ifndef IDS - $(error trailing IDS assignment missing, e.g. IDS=2,7,12) -endif - -run: - @$(MAKE) -s test-env-file - @$(DOCKER_ENV_VARS) \ - TEST_EVENT=$(TEST_EVENT) \ - eval $$(cat $(ENV_FILE)) \ - go run $(CMD_DIR) - -save-id-token: - @$(MAKE) -s test-username-arg - @$(MAKE) -s test-password-arg - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/save-id-token.sh \ - --dir-path $(SUB_PATH) \ - --username $(ACCT) \ - --password $(PASS) \ - --region $(REGION) - -get: - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/get-notifications.sh \ - --dir-path $(SUB_PATH) - -clear: - @$(MAKE) -s test-ids-arg - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/clear-notifications.sh \ - --dir-path $(SUB_PATH) \ - --ids '$(IDS)' \ No newline at end of file diff --git a/services/notifications-send/README.md b/services/notifications-send/README.md deleted file mode 100644 index 4c390051..00000000 --- a/services/notifications-send/README.md +++ /dev/null @@ -1,15 +0,0 @@ -

- systemaccounting -

- -### notifications-send - -1. invoked by `request-create` or `request-approve` services through sns with `id` of `transaction_notification` records -1. queries `transaction_notification` records by `id` -1. queries open websockets, or `connection_id`, for each recipient account in `websocket` table -1. sends `transaction_notification` records to account recipients with open websockets -1. deletes websocket record in `websocket` table IF websocket proves stale - -deploy: `make deploy ENV=dev` - -terraform: https://github.com/systemaccounting/mxfactorial/blob/8c92e48e04af73ed700b2471a05f6b0ee76c0912/infrastructure/terraform/aws/modules/environment/v001/lambda-services.tf#L126-L136 \ No newline at end of file diff --git a/services/notifications-send/cmd/main.go b/services/notifications-send/cmd/main.go deleted file mode 100644 index 856e23df..00000000 --- a/services/notifications-send/cmd/main.go +++ /dev/null @@ -1,173 +0,0 @@ -package main - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "log" - "os" - - "github.com/aws/aws-lambda-go/events" - "github.com/aws/aws-lambda-go/lambda" - "github.com/jackc/pgconn" - "github.com/jackc/pgx/v4" - "github.com/systemaccounting/mxfactorial/pkg/logger" - "github.com/systemaccounting/mxfactorial/pkg/postgres" - "github.com/systemaccounting/mxfactorial/pkg/service" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -var ( - awsRegion string = os.Getenv("AWS_REGION") - apiGWConnectionsURI = os.Getenv("APIGW_CONNECTIONS_URI") - pgConn = fmt.Sprintf( - "host=%s port=%s user=%s password=%s dbname=%s", - os.Getenv("PGHOST"), - os.Getenv("PGPORT"), - os.Getenv("PGUSER"), - os.Getenv("PGPASSWORD"), - os.Getenv("PGDATABASE")) - snsMsgAttributeName = "SERVICE" -) - -type SQLDB interface { - Query(context.Context, string, ...interface{}) (pgx.Rows, error) - QueryRow(context.Context, string, ...interface{}) pgx.Row - Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) - Begin(context.Context) (pgx.Tx, error) - Close(context.Context) error - IsClosed() bool -} - -type IWebsocketService interface { - SendNotificationOrDeleteStaleWebsocket(connectionID *string, v any) error - BroadcastNotificationsToWebsockets(transNotifs types.TransactionNotifications) ([]string, error) - BroadcastNotificationsOrDeleteStaleWebsockets(transNotifs types.TransactionNotifications) error - AddAccountToCurrentWebsocket(accountName, connectionID string) error -} - -type ITransactionNotificationService interface { - InsertTransactionApprovalNotifications(n types.TransactionNotifications) (types.IDs, error) - DeleteTransactionApprovalNotifications(trID types.ID) error - DeleteTransNotificationsByIDs(notifIDs types.IDs) error - Publish(notifIDs types.IDs, serviceName *string, topicArn *string) error - NotifyTransactionRoleApprovers(approvals types.Approvals, transaction *types.Transaction, topicArn *string) error - GetTransactionNotificationsByIDs(notifIDs types.IDs) (types.TransactionNotifications, error) - GetTransNotifsByAccount(accountName string, recordLimit int) (types.TransactionNotifications, error) - CreateNotificationsPerRoleApprover(approvals types.Approvals, transaction *types.Transaction) (types.TransactionNotifications, error) -} - -func lambdaFn( - ctx context.Context, - e events.SNSEvent, - dbConnector func(context.Context, string) (SQLDB, error), - notificationServiceConstructor func(db SQLDB) (ITransactionNotificationService, error), - websocketServiceConstructor func(db SQLDB) (IWebsocketService, error), -) { - - msg := e.Records[0].SNS.Message // `["23","45","67"]` - attributes := e.Records[0].SNS.MessageAttributes - - var service string - - // discover service sending notifications from sns "SERVICE" message attribute - if s, ok := attributes[snsMsgAttributeName].(map[string]interface{}); ok { - if val, ok := s["Value"].(string); ok { - service = val - } else { - log.Fatal("attribute value not found") - } - } else { - log.Fatal("SERVICE not found") - } - - switch service { - case "TRANSACT": // fall through until transact service code moved to pkg - default: - log.Fatalf("service not supported: %v", service) - } - - // unmarshal transaction_notifcation ids - var notifIDs types.IDs - err := json.Unmarshal([]byte(msg), ¬ifIDs) - if err != nil { - log.Print(err) - } - - // connect to db - db, err := dbConnector(context.Background(), pgConn) - if err != nil { - logger.Log(logger.Trace(), err) - log.Fatal(err) - } - defer db.Close(context.Background()) - - // create transaction service - ns, err := notificationServiceConstructor(db) - if err != nil { - logger.Log(logger.Trace(), err) - log.Fatal(err) - } - - // get transactions - transNotifs, err := ns.GetTransactionNotificationsByIDs(notifIDs) - if err != nil { - logger.Log(logger.Trace(), err) - log.Fatal(err) - } - - // create websocket service - ws, err := websocketServiceConstructor(db) - if err != nil { - logger.Log(logger.Trace(), err) - log.Fatal(err) - } - - // send notifications to recipients - err = ws.BroadcastNotificationsOrDeleteStaleWebsockets(transNotifs) - if err != nil { - logger.Log(logger.Trace(), err) - } -} - -// wraps lambdaFn accepting interfaces for testability -func handleEvent( - ctx context.Context, - e events.SNSEvent, -) { - lambdaFn( - ctx, - e, - newIDB, - newNotificationService, - newWebsocketService, - ) -} - -// enables lambdaFn unit testing -func newNotificationService(idb SQLDB) (ITransactionNotificationService, error) { - db, ok := idb.(*postgres.DB) - if !ok { - return nil, errors.New("newNotificationService: failed to assert *postgres.DB") - } - return service.NewTransactionNotificationService(db), nil -} - -// enables lambdaFn unit testing -func newWebsocketService(idb SQLDB) (IWebsocketService, error) { - db, ok := idb.(*postgres.DB) - if !ok { - return nil, errors.New("newWebsocketService: failed to assert *postgres.DB") - } - return service.NewWebsocketService(db, &apiGWConnectionsURI, &awsRegion), nil -} - -// enables lambdaFn unit testing -func newIDB(ctx context.Context, dsn string) (SQLDB, error) { - return postgres.NewDB(ctx, dsn) -} - -func main() { - lambda.Start(handleEvent) -} diff --git a/services/notifications-send/makefile b/services/notifications-send/makefile deleted file mode 100644 index 5fbea8e5..00000000 --- a/services/notifications-send/makefile +++ /dev/null @@ -1,15 +0,0 @@ -RELATIVE_PROJECT_ROOT_PATH=$(shell REL_PATH="."; while [ $$(ls "$$REL_PATH" | grep project.yaml | wc -l | xargs) -eq 0 ]; do REL_PATH="$$REL_PATH./.."; done; printf '%s' "$$REL_PATH") -include $(RELATIVE_PROJECT_ROOT_PATH)/make/shared.mk -include $(RELATIVE_PROJECT_ROOT_PATH)/make/go.mk - -TEST_DATA_PATH=$(RELATIVE_PROJECT_ROOT_PATH)/pkg/testdata/requestNotification.json - -run: - @$(DOCKER_ENV_VARS) go run ./cmd/main.go - -publish: - $(MAKE) -s test-env-file - eval $$(cat $(ENV_FILE)); aws sns publish \ - --region $(REGION) \ - --topic-arn $$NOTIFY_TOPIC_ARN \ - --message "$$(cat $(TEST_DATA_PATH))" \ No newline at end of file diff --git a/services/wss-connect/README.md b/services/wss-connect/README.md deleted file mode 100644 index 60925fe4..00000000 --- a/services/wss-connect/README.md +++ /dev/null @@ -1,12 +0,0 @@ -

- systemaccounting -

- -### wss-connect - -1. invoked by apigwateway v2 after creating or deleting websocket for client -1. adds or deletes websocket `connection_id` in `websocket` table so other services can notify users through websockets - -deploy: `make deploy ENV=dev` - -terraform: https://github.com/systemaccounting/mxfactorial/blob/develop/infrastructure/terraform/aws/modules/environment/v001/lambda-services.tf#L116-L123 \ No newline at end of file diff --git a/services/wss-connect/cmd/main.go b/services/wss-connect/cmd/main.go deleted file mode 100644 index 5658984a..00000000 --- a/services/wss-connect/cmd/main.go +++ /dev/null @@ -1,132 +0,0 @@ -package main - -import ( - "context" - "errors" - "fmt" - "log" - "os" - - "github.com/aws/aws-lambda-go/events" - "github.com/aws/aws-lambda-go/lambda" - "github.com/systemaccounting/mxfactorial/pkg/logger" - "github.com/systemaccounting/mxfactorial/pkg/postgres" - "github.com/systemaccounting/mxfactorial/pkg/service" -) - -const ( - connectRouteKey = "$connect" - disconnectRouteKey = "$disconnect" -) - -var success = events.APIGatewayProxyResponse{StatusCode: 200} - -var pgConn string = fmt.Sprintf( - "host=%s port=%s user=%s password=%s dbname=%s", - os.Getenv("PGHOST"), - os.Getenv("PGPORT"), - os.Getenv("PGUSER"), - os.Getenv("PGPASSWORD"), - os.Getenv("PGDATABASE")) - -type SQLDB interface { - Close(context.Context) error -} - -type IWebsocketStorageService interface { - AddWebsocketConnection(epochCreatedAt int64, connectionID string) error - DeleteWebsocketConnection(connectionID string) error -} - -func lambdaFn( - ctx context.Context, - e events.APIGatewayWebsocketProxyRequest, - dbConnector func(context.Context, string) (SQLDB, error), - websocketServiceConstructor func(db SQLDB) (IWebsocketStorageService, error), -) (events.APIGatewayProxyResponse, error) { - - // values required to insert and delete on connect and disconnect routes - routeKey := e.RequestContext.RouteKey - connectionID := e.RequestContext.ConnectionID - connectedAt := e.RequestContext.ConnectedAt - - // connect to db - db, err := dbConnector(context.Background(), pgConn) - if err != nil { - logger.Log(logger.Trace(), err) - return events.APIGatewayProxyResponse{}, err - } - defer db.Close(context.Background()) - - // create websocket service - ws, err := websocketServiceConstructor(db) - if err != nil { - logger.Log(logger.Trace(), err) - return events.APIGatewayProxyResponse{}, err - } - - // insert websocket connection in db on connect - if routeKey == connectRouteKey { - - err := ws.AddWebsocketConnection(connectedAt, connectionID) - if err != nil { - logger.Log(logger.Trace(), err) - return events.APIGatewayProxyResponse{}, err - } - - return success, nil - } - - // delete websocket connection in db on disconnect - if routeKey == disconnectRouteKey { - - err := ws.DeleteWebsocketConnection(connectionID) - if err != nil { - logger.Log(logger.Trace(), err) - return events.APIGatewayProxyResponse{}, err - } - - return success, nil - } - - // return route not found to alert misconfigured route integrations - ErrRouteNotFound := fmt.Sprintf("route not found: %v", routeKey) - log.Print(ErrRouteNotFound) - - return events.APIGatewayProxyResponse{ - StatusCode: 404, - Body: ErrRouteNotFound, - }, nil -} - -// wraps lambdaFn accepting interfaces for testability -func handleEvent( - ctx context.Context, - e events.APIGatewayWebsocketProxyRequest, -) (events.APIGatewayProxyResponse, error) { - return lambdaFn( - ctx, - e, - newIDB, - newWebsocketStorageService, - ) -} - -// enables lambdaFn unit testing -func newWebsocketStorageService(idb SQLDB) (IWebsocketStorageService, error) { - db, ok := idb.(*postgres.DB) - if !ok { - return nil, errors.New("newWebsocketService: failed to assert *postgres.DB") - } - - return service.NewWebsocketStorageService(db), nil -} - -// enables lambdaFn unit testing -func newIDB(ctx context.Context, dsn string) (SQLDB, error) { - return postgres.NewDB(ctx, dsn) -} - -func main() { - lambda.Start(handleEvent) -} diff --git a/services/wss-connect/makefile b/services/wss-connect/makefile deleted file mode 100644 index 3036e8f7..00000000 --- a/services/wss-connect/makefile +++ /dev/null @@ -1,6 +0,0 @@ -RELATIVE_PROJECT_ROOT_PATH=$(shell REL_PATH="."; while [ $$(ls "$$REL_PATH" | grep project.yaml | wc -l | xargs) -eq 0 ]; do REL_PATH="$$REL_PATH./.."; done; printf '%s' "$$REL_PATH") -include $(RELATIVE_PROJECT_ROOT_PATH)/make/shared.mk -include $(RELATIVE_PROJECT_ROOT_PATH)/make/go.mk - -run: - @$(DOCKER_ENV_VARS) go run ./cmd/main.go \ No newline at end of file From 42c0c8b9ae4b6680bcb6386ea9a10270c4d41e9b Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:22:56 -0700 Subject: [PATCH 16/37] remove go pkg directory --- pkg/aws/apigwma/apigwma.go | 106 -- pkg/aws/apigwma/apigwma_test.go | 211 --- pkg/aws/apigwma/makefile | 13 - pkg/aws/apigwma/mock_apigwma/apigwma_mock.go | 79 -- pkg/aws/cognitoidp/idp.go | 197 --- pkg/aws/cognitoidp/idp_ext_test.go | 560 -------- pkg/aws/cognitoidp/idp_test.go | 196 --- pkg/aws/cognitoidp/jwt.go | 94 -- pkg/aws/cognitoidp/jwt_ext_test.go | 164 --- pkg/aws/cognitoidp/jwt_test.go | 145 --- pkg/aws/cognitoidp/makefile | 13 - .../mock_cognitoidp/cognitoidp_mock.go | 315 ----- pkg/aws/lambda/lambda.go | 73 -- pkg/aws/lambda/lambda_test.go | 151 --- pkg/aws/lambda/makefile | 13 - pkg/aws/lambda/mock_lambda/lambda_mock.go | 117 -- pkg/aws/session/session.go | 21 - pkg/aws/sns/makefile | 13 - pkg/aws/sns/mock_sns/sns_mock.go | 50 - pkg/aws/sns/sns.go | 95 -- pkg/aws/sns/sns_test.go | 150 --- pkg/httpclient/client.go | 69 - pkg/logger/logger.go | 33 - pkg/postgres/model.go | 1129 ----------------- pkg/postgres/pgx.go | 59 - pkg/print/makefile | 26 - pkg/print/mock_print/print_mock.go | 49 - pkg/print/print.go | 37 - pkg/print/print_test.go | 26 - pkg/service/account.go | 53 - pkg/service/approve.go | 119 -- pkg/service/auth.go | 45 - pkg/service/balance.go | 140 -- pkg/service/create_account.go | 92 -- pkg/service/interfaces.go | 17 - pkg/service/notification.go | 180 --- pkg/service/profile.go | 37 - pkg/service/rule_instance.go | 115 -- pkg/service/rules.go | 49 - pkg/service/transaction.go | 307 ----- pkg/service/websocket.go | 310 ----- pkg/sqls/account.go | 40 - pkg/sqls/account_test.go | 49 - pkg/sqls/approval.go | 75 -- pkg/sqls/approval_test.go | 100 -- pkg/sqls/balance.go | 155 --- pkg/sqls/balance_test.go | 137 -- pkg/sqls/constructor_test.go | 73 -- pkg/sqls/contructor.go | 38 - pkg/sqls/cte.go | 34 - pkg/sqls/cte_test.go | 31 - pkg/sqls/makefile | 13 - pkg/sqls/notification.go | 83 -- pkg/sqls/notification_test.go | 95 -- pkg/sqls/profile.go | 87 -- pkg/sqls/profile_test.go | 105 -- pkg/sqls/rule_instance.go | 69 - pkg/sqls/rule_instance_test.go | 76 -- pkg/sqls/testdata/transaction_query.golden | 1 - pkg/sqls/tr_items.go | 89 -- pkg/sqls/tr_items_test.go | 84 -- pkg/sqls/transaction.go | 248 ---- pkg/sqls/transaction_test.go | 348 ----- pkg/sqls/websocket.go | 89 -- pkg/sqls/websocket_test.go | 107 -- pkg/testdata/fake_profile.go | 96 -- pkg/testdata/unmarshal.go | 37 - pkg/types/account.go | 27 - pkg/types/approval.go | 84 -- pkg/types/balance.go | 48 - pkg/types/enum.go | 84 -- pkg/types/id.go | 61 - pkg/types/interfaces.go | 20 - pkg/types/latlng.go | 36 - pkg/types/makefile | 9 - pkg/types/mock_types/types_mock.go | 152 --- pkg/types/notification.go | 114 -- pkg/types/request_response.go | 147 --- pkg/types/rule.go | 70 - pkg/types/time.go | 66 - pkg/types/transaction.go | 187 --- pkg/types/transaction_item.go | 191 --- pkg/types/websocket.go | 69 - 83 files changed, 9392 deletions(-) delete mode 100644 pkg/aws/apigwma/apigwma.go delete mode 100644 pkg/aws/apigwma/apigwma_test.go delete mode 100644 pkg/aws/apigwma/makefile delete mode 100644 pkg/aws/apigwma/mock_apigwma/apigwma_mock.go delete mode 100644 pkg/aws/cognitoidp/idp.go delete mode 100644 pkg/aws/cognitoidp/idp_ext_test.go delete mode 100644 pkg/aws/cognitoidp/idp_test.go delete mode 100644 pkg/aws/cognitoidp/jwt.go delete mode 100644 pkg/aws/cognitoidp/jwt_ext_test.go delete mode 100644 pkg/aws/cognitoidp/jwt_test.go delete mode 100644 pkg/aws/cognitoidp/makefile delete mode 100644 pkg/aws/cognitoidp/mock_cognitoidp/cognitoidp_mock.go delete mode 100644 pkg/aws/lambda/lambda.go delete mode 100644 pkg/aws/lambda/lambda_test.go delete mode 100644 pkg/aws/lambda/makefile delete mode 100644 pkg/aws/lambda/mock_lambda/lambda_mock.go delete mode 100644 pkg/aws/session/session.go delete mode 100644 pkg/aws/sns/makefile delete mode 100644 pkg/aws/sns/mock_sns/sns_mock.go delete mode 100644 pkg/aws/sns/sns.go delete mode 100644 pkg/aws/sns/sns_test.go delete mode 100644 pkg/httpclient/client.go delete mode 100644 pkg/logger/logger.go delete mode 100644 pkg/postgres/model.go delete mode 100644 pkg/postgres/pgx.go delete mode 100644 pkg/print/makefile delete mode 100644 pkg/print/mock_print/print_mock.go delete mode 100644 pkg/print/print.go delete mode 100644 pkg/print/print_test.go delete mode 100644 pkg/service/account.go delete mode 100644 pkg/service/approve.go delete mode 100644 pkg/service/auth.go delete mode 100644 pkg/service/balance.go delete mode 100644 pkg/service/create_account.go delete mode 100644 pkg/service/interfaces.go delete mode 100644 pkg/service/notification.go delete mode 100644 pkg/service/profile.go delete mode 100644 pkg/service/rule_instance.go delete mode 100644 pkg/service/rules.go delete mode 100644 pkg/service/transaction.go delete mode 100644 pkg/service/websocket.go delete mode 100644 pkg/sqls/account.go delete mode 100644 pkg/sqls/account_test.go delete mode 100644 pkg/sqls/approval.go delete mode 100644 pkg/sqls/approval_test.go delete mode 100644 pkg/sqls/balance.go delete mode 100644 pkg/sqls/balance_test.go delete mode 100644 pkg/sqls/constructor_test.go delete mode 100644 pkg/sqls/contructor.go delete mode 100644 pkg/sqls/cte.go delete mode 100644 pkg/sqls/cte_test.go delete mode 100644 pkg/sqls/makefile delete mode 100644 pkg/sqls/notification.go delete mode 100644 pkg/sqls/notification_test.go delete mode 100644 pkg/sqls/profile.go delete mode 100644 pkg/sqls/profile_test.go delete mode 100644 pkg/sqls/rule_instance.go delete mode 100644 pkg/sqls/rule_instance_test.go delete mode 100644 pkg/sqls/testdata/transaction_query.golden delete mode 100644 pkg/sqls/tr_items.go delete mode 100644 pkg/sqls/tr_items_test.go delete mode 100644 pkg/sqls/transaction.go delete mode 100644 pkg/sqls/transaction_test.go delete mode 100644 pkg/sqls/websocket.go delete mode 100644 pkg/sqls/websocket_test.go delete mode 100644 pkg/testdata/fake_profile.go delete mode 100644 pkg/testdata/unmarshal.go delete mode 100644 pkg/types/account.go delete mode 100644 pkg/types/approval.go delete mode 100644 pkg/types/balance.go delete mode 100644 pkg/types/enum.go delete mode 100644 pkg/types/id.go delete mode 100644 pkg/types/interfaces.go delete mode 100644 pkg/types/latlng.go delete mode 100644 pkg/types/makefile delete mode 100644 pkg/types/mock_types/types_mock.go delete mode 100644 pkg/types/notification.go delete mode 100644 pkg/types/request_response.go delete mode 100644 pkg/types/rule.go delete mode 100644 pkg/types/time.go delete mode 100644 pkg/types/transaction.go delete mode 100644 pkg/types/transaction_item.go delete mode 100644 pkg/types/websocket.go diff --git a/pkg/aws/apigwma/apigwma.go b/pkg/aws/apigwma/apigwma.go deleted file mode 100644 index 8858f7e6..00000000 --- a/pkg/aws/apigwma/apigwma.go +++ /dev/null @@ -1,106 +0,0 @@ -package apigwma - -// api gateway management api used to send -// notifications to client websockets -// 1. https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-how-to-call-websocket-api-connections.html -// 2. https://docs.aws.amazon.com/sdk-for-go/api/service/apigatewaymanagementapi/ - -import ( - "encoding/json" - "errors" - "fmt" - - "github.com/aws/aws-sdk-go/aws/awserr" - apigw "github.com/aws/aws-sdk-go/service/apigatewaymanagementapi" - "github.com/systemaccounting/mxfactorial/pkg/aws/session" - "github.com/systemaccounting/mxfactorial/pkg/logger" -) - -const ErrCodeGoneException = apigw.ErrCodeGoneException - -type IAWSAPIGWMA interface { - CreatePostToConnectionInput(*string, []byte) *apigw.PostToConnectionInput - PostToConnection(*apigw.PostToConnectionInput) (*apigw.PostToConnectionOutput, error) - Marshal(any) ([]byte, error) -} - -type AWSAPIGWMA struct { - MgmtAPI *apigw.ApiGatewayManagementApi -} - -func (a AWSAPIGWMA) Marshal(v any) ([]byte, error) { - return json.Marshal(v) -} - -func (a AWSAPIGWMA) CreatePostToConnectionInput(connectionID *string, payload []byte) *apigw.PostToConnectionInput { - return &apigw.PostToConnectionInput{ - ConnectionId: connectionID, - Data: payload, - } -} - -func (a AWSAPIGWMA) PostToConnection(input *apigw.PostToConnectionInput) (*apigw.PostToConnectionOutput, error) { - return a.MgmtAPI.PostToConnection(input) -} - -type ApiGatewayMgmtAPIService struct { - IAWSAPIGWMA -} - -func (a ApiGatewayMgmtAPIService) PostToConnection(connectionID *string, v any) error { - - payload, err := a.IAWSAPIGWMA.Marshal(v) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - input := a.IAWSAPIGWMA.CreatePostToConnectionInput(connectionID, payload) - - _, err = a.IAWSAPIGWMA.PostToConnection(input) - if err != nil { - - // test for aws error - // https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/handling-errors.html - if aerr, ok := err.(awserr.Error); ok { - - // for isolation, return error code for - // assertion on errors exported by this - // package only, e.g. const ErrCodeGoneException - return errors.New(aerr.Code()) - } - - // log and return other error - logger.Log(logger.Trace(), err) - return err - } - - // message sent to websocket - return nil -} - -func NewApiGatewayMgmtAPIService(apiGWConnectionsURI, awsRegion *string) *ApiGatewayMgmtAPIService { - - if apiGWConnectionsURI == nil { - err := fmt.Errorf("error: apiGWConnectionsURI missing assignment") - logger.Log(logger.Trace(), err) - panic(err) - } - - if awsRegion == nil { - err := fmt.Errorf("error: awsRegion missing assignment") - logger.Log(logger.Trace(), err) - panic(err) - } - - // set region and endpoint in config - c := session.NewAWSConfig(awsRegion).WithEndpoint(*apiGWConnectionsURI) - // create session - sess := session.NewAWSSession(c) - // create api gateway management api service - return &ApiGatewayMgmtAPIService{ - IAWSAPIGWMA: &AWSAPIGWMA{ - MgmtAPI: apigw.New(sess), - }, - } -} diff --git a/pkg/aws/apigwma/apigwma_test.go b/pkg/aws/apigwma/apigwma_test.go deleted file mode 100644 index bd83b4fd..00000000 --- a/pkg/aws/apigwma/apigwma_test.go +++ /dev/null @@ -1,211 +0,0 @@ -package apigwma - -import ( - "errors" - "strconv" - "testing" - - "github.com/aws/aws-sdk-go/aws/awserr" - apigw "github.com/aws/aws-sdk-go/service/apigatewaymanagementapi" - "github.com/golang/mock/gomock" - "github.com/google/go-cmp/cmp" - mapigwma "github.com/systemaccounting/mxfactorial/pkg/aws/apigwma/mock_apigwma" -) - -func TestMarshal(t *testing.T) { - testpayload := "testpayload" - testservice := AWSAPIGWMA{} - want := []byte(strconv.Quote(testpayload)) - got, err := testservice.Marshal(testpayload) - if err != nil { - t.Errorf("Marshal err: %v", err) - } - if !cmp.Equal(got, want) { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestCreatePostToConnectionInput(t *testing.T) { - testpayload := []byte(strconv.Quote("testpayload")) - testconnectionid := "123" - testservice := AWSAPIGWMA{} - want := &apigw.PostToConnectionInput{ - ConnectionId: &testconnectionid, - Data: testpayload, - } - got := testservice.CreatePostToConnectionInput(&testconnectionid, testpayload) - if !cmp.Equal(got, want) { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestPostToConnection(t *testing.T) { - testpayloadtext := "testpayload" - testpayload := []byte(strconv.Quote(testpayloadtext)) - testconnectionid := "123" - testinput := &apigw.PostToConnectionInput{ - ConnectionId: &testconnectionid, - Data: testpayload, - } - - ctrl := gomock.NewController(t) - m := mapigwma.NewMockIAWSAPIGWMA(ctrl) - - testservice := ApiGatewayMgmtAPIService{m} - - m. - EXPECT(). - Marshal(testpayloadtext). - Times(1). - Return(testpayload, nil) - - m. - EXPECT(). - CreatePostToConnectionInput(&testconnectionid, testpayload). - Times(1). - Return(testinput) - - m. - EXPECT(). - PostToConnection(testinput). - Times(1). - Return(nil, nil) - - err := testservice.PostToConnection(&testconnectionid, testpayloadtext) - if err != nil { - t.Errorf("PostToConnection err: %v", err) - } -} - -func TestPostToConnectionMarshalErr(t *testing.T) { - testpayloadtext := "testpayload" - testconnectionid := "123" - want := "test" - testerr := errors.New(want) - - ctrl := gomock.NewController(t) - m := mapigwma.NewMockIAWSAPIGWMA(ctrl) - - testservice := ApiGatewayMgmtAPIService{m} - - m. - EXPECT(). - Marshal(testpayloadtext). - Times(1). - Return(nil, testerr) - - err := testservice.PostToConnection(&testconnectionid, testpayloadtext) - - if err == nil { - t.Errorf("Marshal error failure") - } - - if err != nil { - - got := err.Error() - - if got != want { - t.Errorf("got %v, want %v", got, want) - } - } -} - -func TestPostToConnectionGoneExceptionErr(t *testing.T) { - testpayloadtext := "testpayload" - testpayload := []byte(strconv.Quote(testpayloadtext)) - testconnectionid := "123" - testinput := &apigw.PostToConnectionInput{ - ConnectionId: &testconnectionid, - Data: testpayload, - } - want := apigw.ErrCodeGoneException - testerr := awserr.New(apigw.ErrCodeGoneException, "", errors.New("")) - - ctrl := gomock.NewController(t) - m := mapigwma.NewMockIAWSAPIGWMA(ctrl) - - testservice := ApiGatewayMgmtAPIService{m} - - m. - EXPECT(). - Marshal(testpayloadtext). - Times(1). - Return(testpayload, nil) - - m. - EXPECT(). - CreatePostToConnectionInput(&testconnectionid, testpayload). - Times(1). - Return(testinput) - - m. - EXPECT(). - PostToConnection(testinput). - Times(1). - Return(nil, testerr) - - err := testservice.PostToConnection(&testconnectionid, testpayloadtext) - - if err == nil { - t.Errorf("Marshal error failure") - } - - if err != nil { - - got := err.Error() - - if got != want { - t.Errorf("got %v, want %v", got, want) - } - } -} - -func TestPostToConnectionNonAWSErr(t *testing.T) { - testpayloadtext := "testpayload" - testpayload := []byte(strconv.Quote(testpayloadtext)) - testconnectionid := "123" - testinput := &apigw.PostToConnectionInput{ - ConnectionId: &testconnectionid, - Data: testpayload, - } - want := "test" - testerr := errors.New(want) - - ctrl := gomock.NewController(t) - m := mapigwma.NewMockIAWSAPIGWMA(ctrl) - - testservice := ApiGatewayMgmtAPIService{m} - - m. - EXPECT(). - Marshal(testpayloadtext). - Times(1). - Return(testpayload, nil) - - m. - EXPECT(). - CreatePostToConnectionInput(&testconnectionid, testpayload). - Times(1). - Return(testinput) - - m. - EXPECT(). - PostToConnection(testinput). - Times(1). - Return(nil, testerr) - - err := testservice.PostToConnection(&testconnectionid, testpayloadtext) - - if err == nil { - t.Errorf("Marshal error failure") - } - - if err != nil { - - got := err.Error() - - if got != want { - t.Errorf("got %v, want %v", got, want) - } - } -} diff --git a/pkg/aws/apigwma/makefile b/pkg/aws/apigwma/makefile deleted file mode 100644 index 6e8cb71e..00000000 --- a/pkg/aws/apigwma/makefile +++ /dev/null @@ -1,13 +0,0 @@ -PKG_NAME=apigwma -RELATIVE_PROJECT_ROOT_PATH=../../../.. - -test: - go test -v -race -covermode=atomic -coverprofile=coverage.out - -mock: - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/mock-go-ifaces.sh \ - --app-or-pkg-name $(PKG_NAME) - -install: - go install github.com/golang/mock/mockgen@latest \ No newline at end of file diff --git a/pkg/aws/apigwma/mock_apigwma/apigwma_mock.go b/pkg/aws/apigwma/mock_apigwma/apigwma_mock.go deleted file mode 100644 index eb97a89c..00000000 --- a/pkg/aws/apigwma/mock_apigwma/apigwma_mock.go +++ /dev/null @@ -1,79 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/systemaccounting/mxfactorial/pkg/aws/apigwma (interfaces: IAWSAPIGWMA) - -// Package mock_apigwma is a generated GoMock package. -package mock_apigwma - -import ( - reflect "reflect" - - apigatewaymanagementapi "github.com/aws/aws-sdk-go/service/apigatewaymanagementapi" - gomock "github.com/golang/mock/gomock" -) - -// MockIAWSAPIGWMA is a mock of IAWSAPIGWMA interface. -type MockIAWSAPIGWMA struct { - ctrl *gomock.Controller - recorder *MockIAWSAPIGWMAMockRecorder -} - -// MockIAWSAPIGWMAMockRecorder is the mock recorder for MockIAWSAPIGWMA. -type MockIAWSAPIGWMAMockRecorder struct { - mock *MockIAWSAPIGWMA -} - -// NewMockIAWSAPIGWMA creates a new mock instance. -func NewMockIAWSAPIGWMA(ctrl *gomock.Controller) *MockIAWSAPIGWMA { - mock := &MockIAWSAPIGWMA{ctrl: ctrl} - mock.recorder = &MockIAWSAPIGWMAMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockIAWSAPIGWMA) EXPECT() *MockIAWSAPIGWMAMockRecorder { - return m.recorder -} - -// CreatePostToConnectionInput mocks base method. -func (m *MockIAWSAPIGWMA) CreatePostToConnectionInput(arg0 *string, arg1 []byte) *apigatewaymanagementapi.PostToConnectionInput { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreatePostToConnectionInput", arg0, arg1) - ret0, _ := ret[0].(*apigatewaymanagementapi.PostToConnectionInput) - return ret0 -} - -// CreatePostToConnectionInput indicates an expected call of CreatePostToConnectionInput. -func (mr *MockIAWSAPIGWMAMockRecorder) CreatePostToConnectionInput(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePostToConnectionInput", reflect.TypeOf((*MockIAWSAPIGWMA)(nil).CreatePostToConnectionInput), arg0, arg1) -} - -// Marshal mocks base method. -func (m *MockIAWSAPIGWMA) Marshal(arg0 interface{}) ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Marshal", arg0) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Marshal indicates an expected call of Marshal. -func (mr *MockIAWSAPIGWMAMockRecorder) Marshal(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Marshal", reflect.TypeOf((*MockIAWSAPIGWMA)(nil).Marshal), arg0) -} - -// PostToConnection mocks base method. -func (m *MockIAWSAPIGWMA) PostToConnection(arg0 *apigatewaymanagementapi.PostToConnectionInput) (*apigatewaymanagementapi.PostToConnectionOutput, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PostToConnection", arg0) - ret0, _ := ret[0].(*apigatewaymanagementapi.PostToConnectionOutput) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// PostToConnection indicates an expected call of PostToConnection. -func (mr *MockIAWSAPIGWMAMockRecorder) PostToConnection(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostToConnection", reflect.TypeOf((*MockIAWSAPIGWMA)(nil).PostToConnection), arg0) -} diff --git a/pkg/aws/cognitoidp/idp.go b/pkg/aws/cognitoidp/idp.go deleted file mode 100644 index abb3aeac..00000000 --- a/pkg/aws/cognitoidp/idp.go +++ /dev/null @@ -1,197 +0,0 @@ -package cognitoidp - -import ( - "crypto/rsa" - "encoding/json" - "errors" - "io" - "net/http" - - "github.com/dgrijalva/jwt-go" - "github.com/lestrrat-go/jwx/jwk" - "github.com/systemaccounting/mxfactorial/pkg/logger" -) - -const ErrUnmatchedPubKey = "error: unmatched public key" -const ErrFetchJwks = "error: failed to fetch json web keys" - -type CognitoClaims struct { - *jwt.StandardClaims - EmailVerified *bool `json:"email_verified"` - TokenUse *string `json:"token_use"` - AuthTime *int64 `json:"auth_time"` - CognitoUsername *string `json:"cognito:username"` - GivenName *string `json:"given_name"` - Email *string `json:"email"` -} - -type CognitoJwks struct { - IdpDeps IIdpDeps - Keys []*CognitoJwk `json:"keys"` - Uri string -} - -// https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html#amazon-cognito-user-pools-using-tokens-step-2 -type CognitoJwk struct { - KeyID string `json:"kid"` - Algorithm string `json:"alg"` - KeyType string `json:"kty"` - RSAExponent string `json:"e"` - RSAModulus string `json:"n"` - Use string `json:"use"` -} - -type IGetClaimedKeyID interface { - GetClaimedKeyID() (string, error) -} - -type ICognitoJwks interface { - GetPubKey(token IGetClaimedKeyID) (*rsa.PublicKey, error) - MatchIdentityProviderPublicKey(claimedKeyID string) (*rsa.PublicKey, error) - GetCognitoUser(t IJwToken) (string, error) -} - -type IJwToken interface { - TestToken(*rsa.PublicKey) (*jwt.Token, error) - GetCognitoClaims(*jwt.Token) (CognitoClaims, error) - IGetClaimedKeyID -} - -func (c CognitoJwks) GetCognitoUser(t IJwToken) (string, error) { - - // get matching public rsa from json web key - // after matching with key id from token - pubKey, err := c.GetPubKey(t) - if err != nil { - logger.Log(logger.Trace(), err) - return "", err - } - - // test client token with public key - testedToken, err := t.TestToken(pubKey) - if err != nil { - logger.Log(logger.Trace(), err) - return "", err - } - - // get token claims - claims, err := t.GetCognitoClaims(testedToken) - if err != nil { - logger.Log(logger.Trace(), err) - return "", err - } - - // return account name from cognito token - return *claims.CognitoUsername, nil -} - -func (c CognitoJwks) GetPubKey(token IGetClaimedKeyID) (*rsa.PublicKey, error) { - - // get claimed key id - claimedKeyID, err := token.GetClaimedKeyID() - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // match claimed key id with cognito public key - return c.MatchIdentityProviderPublicKey(claimedKeyID) -} - -func (c *CognitoJwks) Fetch() error { - - resp, err := c.IdpDeps.Get(c.Uri) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - data, err := c.IdpDeps.ReadAll(resp.Body) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - err = c.IdpDeps.Unmarshal(data, &c) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - if len(c.Keys) == 0 { - return errors.New(ErrFetchJwks) - } - - return nil -} - -func (c CognitoJwks) MatchIdentityProviderPublicKey(claimedKeyID string) (*rsa.PublicKey, error) { - - cjwk, err := c.matchIdentityProviderJWK(claimedKeyID) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - b, err := c.IdpDeps.Marshal(cjwk) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return c.IdpDeps.ParseRawKey(b) -} - -func (c CognitoJwks) matchIdentityProviderJWK(claimedKeyID string) (*CognitoJwk, error) { - - for _, v := range c.Keys { - if v.KeyID == claimedKeyID { - return v, nil - } - } - - return nil, errors.New(ErrUnmatchedPubKey) -} - -type IIdpDeps interface { - Get(uri string) (*http.Response, error) - ReadAll(r io.Reader) ([]byte, error) - Unmarshal(d []byte, i interface{}) error - Marshal(v interface{}) ([]byte, error) - ParseRawKey(rawKey []byte) (*rsa.PublicKey, error) -} - -type IdpDeps struct{} - -func (IdpDeps) Get(uri string) (*http.Response, error) { - return http.Get(uri) -} - -func (IdpDeps) ReadAll(r io.Reader) ([]byte, error) { - return io.ReadAll(r) -} - -func (IdpDeps) Unmarshal(d []byte, i interface{}) error { - return json.Unmarshal(d, i) -} - -func (IdpDeps) Marshal(v interface{}) ([]byte, error) { - return json.Marshal(v) -} - -func (IdpDeps) ParseRawKey(rawKey []byte) (*rsa.PublicKey, error) { - pubKey := new(rsa.PublicKey) - err := jwk.ParseRawKey(rawKey, pubKey) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - return pubKey, nil -} - -func NewCognitoJwks(uri string) *CognitoJwks { - return &CognitoJwks{ - IdpDeps: new(IdpDeps), - Uri: uri, - } -} diff --git a/pkg/aws/cognitoidp/idp_ext_test.go b/pkg/aws/cognitoidp/idp_ext_test.go deleted file mode 100644 index 1779c388..00000000 --- a/pkg/aws/cognitoidp/idp_ext_test.go +++ /dev/null @@ -1,560 +0,0 @@ -package cognitoidp_test // avoids cycle import error from mocks - -import ( - "bytes" - "crypto/rsa" - "fmt" - "io" - "net/http" - "testing" - - "github.com/dgrijalva/jwt-go" - "github.com/golang/mock/gomock" - cidp "github.com/systemaccounting/mxfactorial/pkg/aws/cognitoidp" - mcidp "github.com/systemaccounting/mxfactorial/pkg/aws/cognitoidp/mock_cognitoidp" -) - -func TestGetCognitoUser(t *testing.T) { - c := gomock.NewController(t) - midp := mcidp.NewMockIIdpDeps(c) - mjwt := mcidp.NewMockIJwToken(c) - - testkid := "test" - testjwk := &cidp.CognitoJwk{KeyID: testkid} - testjwks := cidp.CognitoJwks{ - Keys: []*cidp.CognitoJwk{testjwk}, - IdpDeps: midp, - } - testdata := []byte("") - testpubkey := &rsa.PublicKey{} - testjwt := &jwt.Token{} - testuser := "test" - testclaims := cidp.CognitoClaims{CognitoUsername: &testuser} - - mjwt. - EXPECT(). - GetClaimedKeyID(). - Times(1). - Return(testkid, nil) - - midp. - EXPECT(). - Marshal(testjwk). - Times(1). - Return(testdata, nil) - - midp. - EXPECT(). - ParseRawKey(testdata). - Times(1). - Return(testpubkey, nil) - - mjwt. - EXPECT(). - TestToken(testpubkey). - Times(1). - Return(testjwt, nil) - - mjwt. - EXPECT(). - GetCognitoClaims(testjwt). - Times(1). - Return(testclaims, nil) - - testjwks.GetCognitoUser(mjwt) -} - -func TestGetCognitoUserErr1(t *testing.T) { - c := gomock.NewController(t) - midp := mcidp.NewMockIIdpDeps(c) - mjwt := mcidp.NewMockIJwToken(c) - - testkid := "test" - testjwk := &cidp.CognitoJwk{KeyID: testkid} - testjwks := cidp.CognitoJwks{ - Keys: []*cidp.CognitoJwk{testjwk}, - IdpDeps: midp, - } - testdata := []byte("") - testpubkey := &rsa.PublicKey{} - - want := "test" - testerr := fmt.Errorf(want) - - mjwt. - EXPECT(). - GetClaimedKeyID(). - Times(1). - Return(testkid, nil) - - midp. - EXPECT(). - Marshal(testjwk). - Times(1). - Return(testdata, nil) - - midp. - EXPECT(). - ParseRawKey(testdata). - Times(1). - Return(testpubkey, nil) - - mjwt. - EXPECT(). - TestToken(testpubkey). - Times(1). - Return(nil, testerr) - - _, got := testjwks.GetCognitoUser(mjwt) - if got == nil { - t.Errorf("got nil, want %v", want) - } - if got.Error() != want { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestGetCognitoUserErr2(t *testing.T) { - c := gomock.NewController(t) - midp := mcidp.NewMockIIdpDeps(c) - mjwt := mcidp.NewMockIJwToken(c) - - testkid := "test" - testjwk := &cidp.CognitoJwk{KeyID: testkid} - testjwks := cidp.CognitoJwks{ - Keys: []*cidp.CognitoJwk{testjwk}, - IdpDeps: midp, - } - testdata := []byte("") - - want := "test" - testerr := fmt.Errorf(want) - - mjwt. - EXPECT(). - GetClaimedKeyID(). - Times(1). - Return(testkid, nil) - - midp. - EXPECT(). - Marshal(testjwk). - Times(1). - Return(testdata, nil) - - midp. - EXPECT(). - ParseRawKey(testdata). - Times(1). - Return(nil, testerr) - - _, got := testjwks.GetCognitoUser(mjwt) - if got == nil { - t.Errorf("got nil, want %v", want) - } - if got.Error() != want { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestGetCognitoUserErr3(t *testing.T) { - c := gomock.NewController(t) - midp := mcidp.NewMockIIdpDeps(c) - mjwt := mcidp.NewMockIJwToken(c) - - testkid := "test" - testjwk := &cidp.CognitoJwk{KeyID: testkid} - testjwks := cidp.CognitoJwks{ - Keys: []*cidp.CognitoJwk{testjwk}, - IdpDeps: midp, - } - testdata := []byte("") - testpubkey := &rsa.PublicKey{} - testjwt := &jwt.Token{} - - want := "test" - testerr := fmt.Errorf(want) - - mjwt. - EXPECT(). - GetClaimedKeyID(). - Times(1). - Return(testkid, nil) - - midp. - EXPECT(). - Marshal(testjwk). - Times(1). - Return(testdata, nil) - - midp. - EXPECT(). - ParseRawKey(testdata). - Times(1). - Return(testpubkey, nil) - - mjwt. - EXPECT(). - TestToken(testpubkey). - Times(1). - Return(testjwt, nil) - - mjwt. - EXPECT(). - GetCognitoClaims(testjwt). - Times(1). - Return(cidp.CognitoClaims{}, testerr) - - _, got := testjwks.GetCognitoUser(mjwt) - if got == nil { - t.Errorf("got nil, want %v", want) - } - if got.Error() != want { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestGetPubKey(t *testing.T) { - c := gomock.NewController(t) - midp := mcidp.NewMockIIdpDeps(c) - mkeyid := mcidp.NewMockIGetClaimedKeyID(c) - testkid := "test" - testjwk := &cidp.CognitoJwk{KeyID: testkid} - testjwks := cidp.CognitoJwks{ - Keys: []*cidp.CognitoJwk{testjwk}, - IdpDeps: midp, - } - testdata := []byte("") - testpubkey := &rsa.PublicKey{} - - mkeyid. - EXPECT(). - GetClaimedKeyID(). - Times(1). - Return(testkid, nil) - - midp. - EXPECT(). - Marshal(testjwk). - Times(1). - Return(testdata, nil) - - midp. - EXPECT(). - ParseRawKey(testdata). - Times(1). - Return(testpubkey, nil) - - testjwks.GetPubKey(mkeyid) -} - -func TestGetPubKeyErr(t *testing.T) { - c := gomock.NewController(t) - midp := mcidp.NewMockIIdpDeps(c) - mkeyid := mcidp.NewMockIGetClaimedKeyID(c) - testjwks := cidp.CognitoJwks{ - Keys: []*cidp.CognitoJwk{{}}, - IdpDeps: midp, - } - want := "test" - testerr := fmt.Errorf(want) - - mkeyid. - EXPECT(). - GetClaimedKeyID(). - Times(1). - Return("", testerr) - - _, got := testjwks.GetPubKey(mkeyid) - if got == nil { - t.Errorf("got nil, want %v", want) - } - if got.Error() != want { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestFetch(t *testing.T) { - c := gomock.NewController(t) - m := mcidp.NewMockIIdpDeps(c) - - testuri := "testuri" - testdata := []byte("") - testresponse := new(http.Response) - testbody := io.NopCloser(bytes.NewReader(testdata)) - testresponse.Body = testbody - testjwks := &cidp.CognitoJwks{ - Uri: testuri, - Keys: []*cidp.CognitoJwk{{}, {}}, - IdpDeps: m, - } - - m. - EXPECT(). - Get(testuri). - Times(1). - Return(testresponse, nil) - - m. - EXPECT(). - ReadAll(testbody). - Times(1). - Return(testdata, nil) - - m. - EXPECT(). - Unmarshal(testdata, &testjwks). - Times(1) - - if err := testjwks.Fetch(); err != nil { - t.Errorf("Fetch error %v", err) - } -} - -func TestFetchErr1(t *testing.T) { - c := gomock.NewController(t) - m := mcidp.NewMockIIdpDeps(c) - - want := "test" - testerr := fmt.Errorf(want) - testuri := "testuri" - testdata := []byte("") - testresponse := new(http.Response) - testbody := io.NopCloser(bytes.NewReader(testdata)) - testresponse.Body = testbody - testjwks := &cidp.CognitoJwks{ - Uri: testuri, - Keys: []*cidp.CognitoJwk{{}, {}}, - IdpDeps: m, - } - - m. - EXPECT(). - Get(testuri). - Times(1). - Return(nil, testerr) - - got := testjwks.Fetch() - if got == nil { - t.Errorf("got nil, want %v", want) - } - if got.Error() != want { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestFetchErr2(t *testing.T) { - c := gomock.NewController(t) - m := mcidp.NewMockIIdpDeps(c) - - want := "test" - testerr := fmt.Errorf(want) - testuri := "testuri" - testdata := []byte("") - testresponse := new(http.Response) - testbody := io.NopCloser(bytes.NewReader(testdata)) - testresponse.Body = testbody - testjwks := &cidp.CognitoJwks{ - Uri: testuri, - Keys: []*cidp.CognitoJwk{{}, {}}, - IdpDeps: m, - } - - m. - EXPECT(). - Get(testuri). - Times(1). - Return(testresponse, nil) - - m. - EXPECT(). - ReadAll(testbody). - Times(1). - Return(nil, testerr) - - got := testjwks.Fetch() - if got == nil { - t.Errorf("got nil, want %v", want) - } - if got.Error() != want { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestFetchErr3(t *testing.T) { - c := gomock.NewController(t) - m := mcidp.NewMockIIdpDeps(c) - - want := "test" - testerr := fmt.Errorf(want) - testuri := "testuri" - testdata := []byte("") - testresponse := new(http.Response) - testbody := io.NopCloser(bytes.NewReader(testdata)) - testresponse.Body = testbody - testjwks := &cidp.CognitoJwks{ - Uri: testuri, - Keys: []*cidp.CognitoJwk{{}, {}}, - IdpDeps: m, - } - m. - EXPECT(). - Get(testuri). - Times(1). - Return(testresponse, nil) - - m. - EXPECT(). - ReadAll(testbody). - Times(1). - Return(testdata, nil) - - m. - EXPECT(). - Unmarshal(testdata, &testjwks). - Times(1). - Return(testerr) - - got := testjwks.Fetch() - if got == nil { - t.Errorf("got nil, want %v", want) - } - if got.Error() != want { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestFetchErr4(t *testing.T) { - c := gomock.NewController(t) - m := mcidp.NewMockIIdpDeps(c) - - testuri := "testuri" - testdata := []byte("") - testresponse := new(http.Response) - testbody := io.NopCloser(bytes.NewReader(testdata)) - testresponse.Body = testbody - testjwks := &cidp.CognitoJwks{ - Uri: testuri, - Keys: nil, // keys missing - IdpDeps: m, - } - m. - EXPECT(). - Get(testuri). - Times(1). - Return(testresponse, nil) - - m. - EXPECT(). - ReadAll(testbody). - Times(1). - Return(testdata, nil) - - m. - EXPECT(). - Unmarshal(testdata, &testjwks). - Times(1) - - want := "error: failed to fetch json web keys" - got := testjwks.Fetch() - if got == nil { - t.Errorf("got nil, want %v", want) - } - if got.Error() != want { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestMatchIdentityProviderPublicKey(t *testing.T) { - c := gomock.NewController(t) - m := mcidp.NewMockIIdpDeps(c) - - testkid1 := "test1" - testkid2 := "test2" - testrawkey := []byte("") - testjwk := &cidp.CognitoJwk{KeyID: testkid1} - testjwks := cidp.CognitoJwks{ - Keys: []*cidp.CognitoJwk{ - testjwk, - { - KeyID: testkid2, - }, - }, - IdpDeps: m, - } - - m. - EXPECT(). - Marshal(testjwk). - Times(1). - Return(testrawkey, nil) - - m. - EXPECT(). - ParseRawKey(testrawkey). - Times(1) - - testjwks.MatchIdentityProviderPublicKey(testkid1) -} - -func TestMatchIdentityProviderPublicKeyErr1(t *testing.T) { - c := gomock.NewController(t) - m := mcidp.NewMockIIdpDeps(c) - - testkid1 := "test1" - testkid2 := "test2" - testjwk := &cidp.CognitoJwk{KeyID: testkid1} - testjwks := cidp.CognitoJwks{ - Keys: []*cidp.CognitoJwk{ - testjwk, - { - KeyID: testkid2, - }, - }, - IdpDeps: m, - } - - want := "error: unmatched public key" - - _, got := testjwks.MatchIdentityProviderPublicKey("doest exist") - if got == nil { - t.Errorf("got nil, want %v", want) - } - if got.Error() != want { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestMatchIdentityProviderPublicKeyErr2(t *testing.T) { - c := gomock.NewController(t) - m := mcidp.NewMockIIdpDeps(c) - - testkid1 := "test1" - testkid2 := "test2" - want := "test" - testerr := fmt.Errorf(want) - testjwk := &cidp.CognitoJwk{KeyID: testkid1} - testjwks := cidp.CognitoJwks{ - Keys: []*cidp.CognitoJwk{ - testjwk, - { - KeyID: testkid2, - }, - }, - IdpDeps: m, - } - - m. - EXPECT(). - Marshal(testjwk). - Times(1). - Return(nil, testerr) - - _, got := testjwks.MatchIdentityProviderPublicKey(testkid1) - if got == nil { - t.Errorf("got nil, want %v", want) - } - if got.Error() != want { - t.Errorf("got %v, want %v", got, want) - } -} diff --git a/pkg/aws/cognitoidp/idp_test.go b/pkg/aws/cognitoidp/idp_test.go deleted file mode 100644 index b42ecdba..00000000 --- a/pkg/aws/cognitoidp/idp_test.go +++ /dev/null @@ -1,196 +0,0 @@ -package cognitoidp - -import ( - "bytes" - "crypto/rsa" - "fmt" - "io/ioutil" - "math/big" - "net/http" - "strings" - "testing" - - "github.com/google/go-cmp/cmp" -) - -func TestMatchIdentityProviderJWK(t *testing.T) { - testkid1 := "test1" - testkid2 := "test2" - want := &CognitoJwk{KeyID: testkid1} - testjwks := CognitoJwks{ - Keys: []*CognitoJwk{ - want, - { - KeyID: testkid2, - }, - }, - } - - got, err := testjwks.matchIdentityProviderJWK(testkid1) - if err != nil { - t.Errorf("TestMatchIdentityProviderJWK error: %v", err) - } - if !cmp.Equal(got, want) { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestMatchIdentityProviderJWKErr(t *testing.T) { - testkid1 := "test1" - testkid2 := "test2" - testjwks := CognitoJwks{ - Keys: []*CognitoJwk{ - { - KeyID: testkid1, - }, - { - KeyID: testkid2, - }, - }, - } - - want := "error: unmatched public key" - - _, got := testjwks.matchIdentityProviderJWK("doesnt exist") - if got == nil { - t.Errorf("got nil, want %v", want) - } - if got.Error() != want { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestGet(t *testing.T) { - - // run a webserver during test - port := 8090 - localhost := fmt.Sprintf("http://localhost:%d/", port) - go func() { - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, "test") - }) - if err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil); err != nil { - t.Errorf("test webserver error: %v", err) - } - }() - - testidpdeps := IdpDeps{} - res, err := testidpdeps.Get(localhost) - if err != nil { - t.Errorf("TestGet Get error: %v", err) - } - - body, err := ioutil.ReadAll(res.Body) - if err != nil { - t.Errorf("TestGet ReadAll error: %v", err) - } - - got := string(body) - want := "test" - - if got != want { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestReadAll(t *testing.T) { - - test := "test" - testreader := strings.NewReader(test) - - testidpdeps := IdpDeps{} - - got, err := testidpdeps.ReadAll(testreader) - if err != nil { - t.Errorf("TestReadAll error: %v", err) - } - - want := []byte(test) - if !bytes.Equal(got, want) { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestUnmarshalFromIdpDeps(t *testing.T) { - - testkid1 := "test1" - testkid2 := "test2" - testjson := []byte( - fmt.Sprintf("{\"keys\":[{\"kid\":\"%s\"},{\"kid\":\"%s\"}]}", testkid1, testkid2), - ) - - want := CognitoJwks{ - Keys: []*CognitoJwk{ - { - KeyID: testkid1, - }, - { - KeyID: testkid2, - }, - }, - } - got := CognitoJwks{} - - testidpdeps := IdpDeps{} - err := testidpdeps.Unmarshal(testjson, &got) - if err != nil { - t.Errorf("TestUnmarshalFromIdpDeps err: %v", err) - } - if !cmp.Equal(got, want) { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestMarshal(t *testing.T) { - testkid := "test" - want := []byte( - fmt.Sprintf("{\"kid\":\"%s\",\"alg\":\"\",\"kty\":\"\",\"e\":\"\",\"n\":\"\",\"use\":\"\"}", testkid), - ) - testjwk := CognitoJwk{ - KeyID: testkid, - } - testidpdeps := IdpDeps{} - got, err := testidpdeps.Marshal(testjwk) - if err != nil { - t.Errorf("TestUnmarshalFromIdpDeps err: %v", err) - } - if !bytes.Equal(got, want) { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestParseRawKey(t *testing.T) { - // copied from https://github.com/lestrrat-go/jwx/blob/3fa12c9bedcebd03db23f61cfb65ae0b040bf211/jwk/jwk_test.go#L433-L437 - testjwk := `{ - "e":"AQAB", - "kty":"RSA", - "n":"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw" - }` - testidpdeps := IdpDeps{} - got, err := testidpdeps.ParseRawKey([]byte(testjwk)) - if err != nil { - t.Errorf("TestParseRawKey err: %v", err) - } - testmodulus := new(big.Int) - testmodulus.SetString("26634547600177008912365441464036882611104634136430581696102639463075266436216946316053845642300166320042915031924501272705275043130211783228252369194856949397782880847235143381529207382262647906987655738647387007320361149854766523417293323739185308113373529512728932838100141612048712597178695720651344295450174895369923383396704334331627261565907266749863744707920606364678231639106403854977302183719246256958550651555767664134467706614553219592981545363271425781391262006405169505726523023628770285432062044391310047445749287563161668548354322560223509946990827691654627968182167826397015368836435965354956581554819", 10) - want := &rsa.PublicKey{N: testmodulus, E: 65537} - if !cmp.Equal(got, want) { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestParseRawKeyErr(t *testing.T) { - testjwk := `{ - "e":"AQAB", - "kty":"RSA" - }` - testidpdeps := IdpDeps{} - _, got := testidpdeps.ParseRawKey([]byte(testjwk)) - if got == nil { - t.Errorf("got nil err") - } - want := "failed to parse key: failed to unmarshal JSON into key (*jwk.rsaPublicKey): required field n is missing" - if got.Error() != want { - t.Errorf("got %v, want %v", got.Error(), want) - } -} diff --git a/pkg/aws/cognitoidp/jwt.go b/pkg/aws/cognitoidp/jwt.go deleted file mode 100644 index eac43a2c..00000000 --- a/pkg/aws/cognitoidp/jwt.go +++ /dev/null @@ -1,94 +0,0 @@ -package cognitoidp - -import ( - "crypto/rsa" - "encoding/json" - "errors" - "fmt" - "strings" - - "github.com/dgrijalva/jwt-go" -) - -const ErrTokenValueNotSet = "error: token value not set" -const ErrCognitoClaims = "error: CognitoClaims convert failure" - -type JWToken struct { - Value *string `json:"token"` - Header *struct { - KeyID *string `json:"kid"` - Alg *string `json:"alg"` - } - Deps IJwtDeps -} - -func (j JWToken) TestToken(verifyKey *rsa.PublicKey) (*jwt.Token, error) { - if j.Value == nil { - return nil, fmt.Errorf(ErrTokenValueNotSet) - } - return j.Deps.TestToken(*j.Value, verifyKey) -} - -func (j JWToken) GetCognitoClaims(testedToken *jwt.Token) (CognitoClaims, error) { - return j.Deps.GetCognitoClaims(testedToken) -} - -func (j *JWToken) GetClaimedKeyID() (string, error) { - - header := j.Deps.ParseHeader(*j.Value) - - b, err := j.Deps.DecodeSegment(header) - if err != nil { - return "", err - } - - err = j.Deps.Unmarshal(b, &j.Header) - if err != nil { - return "", err - } - - return *j.Header.KeyID, nil -} - -type IJwtDeps interface { - ParseHeader(s string) string - DecodeSegment(header string) ([]byte, error) - Unmarshal(data []byte, v interface{}) error - TestToken(token string, verifyKey *rsa.PublicKey) (*jwt.Token, error) - GetCognitoClaims(testedToken *jwt.Token) (CognitoClaims, error) -} - -type JwtDeps struct{} - -func (j JwtDeps) TestToken(token string, verifyKey *rsa.PublicKey) (*jwt.Token, error) { - return jwt.ParseWithClaims(token, &CognitoClaims{}, func(token *jwt.Token) (interface{}, error) { - return verifyKey, nil - }) -} - -func (JwtDeps) ParseHeader(s string) string { - return strings.Split(s, ".")[0] -} - -func (JwtDeps) DecodeSegment(header string) ([]byte, error) { - return jwt.DecodeSegment(header) -} - -func (JwtDeps) Unmarshal(data []byte, v interface{}) error { - return json.Unmarshal(data, v) -} - -func (JwtDeps) GetCognitoClaims(testedToken *jwt.Token) (CognitoClaims, error) { - claims, ok := testedToken.Claims.(*CognitoClaims) - if !ok { - return CognitoClaims{}, errors.New(ErrCognitoClaims) - } - return *claims, nil -} - -func NewJWToken(token string) *JWToken { - return &JWToken{ - Value: &token, - Deps: new(JwtDeps), - } -} diff --git a/pkg/aws/cognitoidp/jwt_ext_test.go b/pkg/aws/cognitoidp/jwt_ext_test.go deleted file mode 100644 index 58ea05a4..00000000 --- a/pkg/aws/cognitoidp/jwt_ext_test.go +++ /dev/null @@ -1,164 +0,0 @@ -package cognitoidp_test // avoids cycle import error from mocks - -import ( - "crypto/rsa" - "fmt" - "testing" - - "github.com/dgrijalva/jwt-go" - "github.com/golang/mock/gomock" - cidp "github.com/systemaccounting/mxfactorial/pkg/aws/cognitoidp" - mcidp "github.com/systemaccounting/mxfactorial/pkg/aws/cognitoidp/mock_cognitoidp" -) - -func TestTestToken(t *testing.T) { - c := gomock.NewController(t) - m := mcidp.NewMockIJwtDeps(c) - - testkey := &rsa.PublicKey{} - - testtokenvalue := "test" - testjwtoken := cidp.JWToken{Value: &testtokenvalue, Deps: m} - - m. - EXPECT(). - TestToken(testtokenvalue, testkey). - Times(1) - - testjwtoken.TestToken(testkey) -} - -func TestGetCognitoClaims(t *testing.T) { - c := gomock.NewController(t) - m := mcidp.NewMockIJwtDeps(c) - - testjwt := &jwt.Token{} - - testjwtoken := cidp.JWToken{Deps: m} - - m. - EXPECT(). - GetCognitoClaims(testjwt). - Times(1) - - testjwtoken.GetCognitoClaims(testjwt) -} - -func TestGetClaimedKeyID(t *testing.T) { - c := gomock.NewController(t) - m := mcidp.NewMockIJwtDeps(c) - - testheader := "test" - testkeyid := "test" - testtokenvalue := fmt.Sprintf("%s.token", testheader) - testurlbytes := []byte("test") - testjwtoken := cidp.JWToken{Value: &testtokenvalue, Deps: m} - - m. - EXPECT(). - ParseHeader(testtokenvalue). - Times(1). - Return(testheader) - - m. - EXPECT(). - DecodeSegment(testheader). - Times(1). - Return(testurlbytes, nil) - - m. - EXPECT(). - Unmarshal(testurlbytes, &testjwtoken.Header). - Times(1). - DoAndReturn(func(b []byte, d interface{}) error { - testjwtoken.Header = &struct { - KeyID *string "json:\"kid\"" - Alg *string "json:\"alg\"" - }{ - KeyID: &testkeyid, - } - return nil - }) - - testjwtoken.GetClaimedKeyID() -} - -func TestGetClaimedKeyIDDecodeSegmentErr(t *testing.T) { - c := gomock.NewController(t) - m := mcidp.NewMockIJwtDeps(c) - - testheader := "test" - testtokenvalue := fmt.Sprintf("%s.token", testheader) - testjwtoken := cidp.JWToken{Value: &testtokenvalue, Deps: m} - - want := "testerr" - - m. - EXPECT(). - ParseHeader(testtokenvalue). - Times(1). - Return(testheader) - - m. - EXPECT(). - DecodeSegment(testheader). - Times(1). - Return(nil, fmt.Errorf(want)) - - _, got := testjwtoken.GetClaimedKeyID() - if got == nil { - t.Errorf("got nil, want %v", want) - } - - if got.Error() != want { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestGetClaimedKeyIDUnmarshalErr(t *testing.T) { - c := gomock.NewController(t) - m := mcidp.NewMockIJwtDeps(c) - - testheader := "test" - testkeyid := "test" - testtokenvalue := fmt.Sprintf("%s.token", testheader) - testurlbytes := []byte("test") - testjwtoken := cidp.JWToken{Value: &testtokenvalue, Deps: m} - - want := "testerr" - - m. - EXPECT(). - ParseHeader(testtokenvalue). - Times(1). - Return(testheader) - - m. - EXPECT(). - DecodeSegment(testheader). - Times(1). - Return(testurlbytes, nil) - - m. - EXPECT(). - Unmarshal(testurlbytes, &testjwtoken.Header). - Times(1). - DoAndReturn(func(b []byte, d interface{}) error { - testjwtoken.Header = &struct { - KeyID *string "json:\"kid\"" - Alg *string "json:\"alg\"" - }{ - KeyID: &testkeyid, - } - return fmt.Errorf(want) - }) - - _, got := testjwtoken.GetClaimedKeyID() - if got == nil { - t.Errorf("got nil, want %v", want) - } - - if got.Error() != want { - t.Errorf("got %v, want %v", got, want) - } -} diff --git a/pkg/aws/cognitoidp/jwt_test.go b/pkg/aws/cognitoidp/jwt_test.go deleted file mode 100644 index 946e8cf7..00000000 --- a/pkg/aws/cognitoidp/jwt_test.go +++ /dev/null @@ -1,145 +0,0 @@ -package cognitoidp - -import ( - "bytes" - "crypto/rsa" - "crypto/x509" - "encoding/base64" - "encoding/pem" - "fmt" - "testing" - - "github.com/dgrijalva/jwt-go" - "github.com/google/go-cmp/cmp" -) - -func TestTestTokenErr(t *testing.T) { - want := "error: token value not set" - testkey := rsa.PublicKey{} - testjwtoken := JWToken{} - _, got := testjwtoken.TestToken(&testkey) - if got == nil { - t.Errorf("got nil, want %v", want) - } - if got.Error() != want { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestParseHeader(t *testing.T) { - want := "test" - testtoken := fmt.Sprintf("%s.token", want) - - testJwtDeps := JwtDeps{} - - got := testJwtDeps.ParseHeader(testtoken) - if got != want { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestDecodeSegment(t *testing.T) { - want := []byte("https://YOUR_DOMAIN/.well-known/jwks.json") - testb64url := base64.URLEncoding.EncodeToString(want) - testJwtDeps := JwtDeps{} - got, err := testJwtDeps.DecodeSegment(testb64url) - if err != nil { - t.Errorf("TestDecodeSegment err: %v", err) - } - if !bytes.Equal(got, want) { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestUnmarshal(t *testing.T) { - testtokenvalue := "test" - testjson := []byte( - fmt.Sprintf("{\"token\":\"%s\"}", testtokenvalue), - ) - - want := JWToken{Value: &testtokenvalue} - got := JWToken{} - testJwtDeps := JwtDeps{} - err := testJwtDeps.Unmarshal(testjson, &got) - if err != nil { - t.Errorf("TestUnmarshal err: %v", err) - } - if !cmp.Equal(got, want) { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestGetCognitoClaimsFromJwtDeps(t *testing.T) { - testclaim := "test" - want := CognitoClaims{TokenUse: &testclaim} - testtoken := jwt.Token{Claims: &want} - - testJwtDeps := JwtDeps{} - got, err := testJwtDeps.GetCognitoClaims(&testtoken) - if err != nil { - t.Errorf("TestGetCognitoClaims err: %v", err) - } - if !cmp.Equal(got, want) { - t.Errorf("got %v, want %v", got, want) - } -} - -type unwantedClaims struct{} - -func (unwantedClaims) Valid() error { - return fmt.Errorf("") -} - -func TestGetCognitoClaimsErr(t *testing.T) { - want := "error: CognitoClaims convert failure" - testtoken := jwt.Token{Claims: &unwantedClaims{}} - - testJwtDeps := JwtDeps{} - _, got := testJwtDeps.GetCognitoClaims(&testtoken) - if got == nil { - t.Errorf("got nil err, want: %v", want) - } - if got.Error() != want { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestTestTokenFromJwtDeps(t *testing.T) { - - testtoken := "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.fQEGF80Q26SfgXEBTOLNM3sMo5psp8zMrLBVQGaF1WnfBeqo0H7ZxKnOhkwHrP0_a8ruJW3LX5j3O84iV1CdCr9D-p29hWg6LVs4Q54xrbetqJNqiCgaURPSbZrqKOXg-xJIFtIHlj_J8UZ9R5-X5Hlca9KtLJ9r2vVrM_5aS49gT7nt3prZsT48vQMAcyUIZvQbfu51f4yFGeD45sDW7UBaKFGktebfRPouePM02xoKUAL4ef3yMXbedpJJi146ih21KC5u8pYljBUhqCZuDVlksJ6fnS0XBVrvgQW6uOPBTG81W9Vr2NiGzytODBIom1Zwg29N03hp1WMwHbTXyubpyLjoFSRNM1yomx1-Zm4AdPcLd0tziYTkskoDZPbZ6V3rL4-lf7P6y3gPn7LwJ3z2y6tV0fC9MvPFshJXSKb41-UiVxfJSKaiSgxWLGJIFA58t-NxbByOpEECm0oCCuKTPjTY5Od8RCdysoysQH2PpiDUF17xEhAET8HZuXlu" - - testpubkey := ` ------BEGIN PUBLIC KEY----- -MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA7w16Zn9nX56OjrTRSyPX -2oIIYWFjXgDhkZclr6hwcV4rYxCW/assMhy35+CiTTPiwqSEOvZCCippJGaYP1QH -O/no6pudKFFD1oWoKPKF7Q6/ff0m0pBBAMHuzG0tp1ZY9mNKpQodKpZlsZN/fiV1 -6nZnJT/HG621VA6DA85W3/uqU0pATQu2ed9dsbGmN7IfXYpy1jDevSbEPWT0KMYj -W9bR++dt9ej/PnDP0SfR6PjHwbjPLLafeMu323B7BA7SbH43Ar5939fFuUke56WH -z/2530LnhwtLCBYFw1Y6+WbYN8KoH1Os6lkl29cOuQH8niOTVbFEYXm0N7l6N/WY -vU1qc1FD1xEQiWk+NguGO+vKdgV2p3YKLVheIWmV6LZYmuDBQJwiIcHyS5//wrIE -9rwzUDYPJ9OqAEg6FnBw6OPSO585EHFGKXWVnixSrHWeMCkDHvL8+pfD4lJae6su -bM6lJ/FvqBYk40psSh1TKizUMVEFcyL8O0x3kIOZMBgFAgMBAAE= ------END PUBLIC KEY-----` - - pubpem, _ := pem.Decode([]byte(testpubkey)) - - parsed, err := x509.ParsePKIXPublicKey(pubpem.Bytes) - if err != nil { - t.Errorf("failed to parse pem key") - } - - testrsapubkey, ok := parsed.(*rsa.PublicKey) - if !ok { - t.Errorf("failed to parse pub key") - } - - testJwtDeps := JwtDeps{} - got, err := testJwtDeps.TestToken(testtoken, testrsapubkey) - if err != nil { - t.Errorf("TestTestTokenFromJwtDeps err: %v", err) - } - - if !got.Valid { - t.Errorf("testtoken fail") - } -} diff --git a/pkg/aws/cognitoidp/makefile b/pkg/aws/cognitoidp/makefile deleted file mode 100644 index 5c8e163e..00000000 --- a/pkg/aws/cognitoidp/makefile +++ /dev/null @@ -1,13 +0,0 @@ -PKG_NAME=cognitoidp -RELATIVE_PROJECT_ROOT_PATH=../../../.. - -test: - go test -v -race -covermode=atomic -coverprofile=coverage.out - -mock: - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/mock-go-ifaces.sh \ - --app-or-pkg-name $(PKG_NAME) - -install: - go install github.com/golang/mock/mockgen@latest \ No newline at end of file diff --git a/pkg/aws/cognitoidp/mock_cognitoidp/cognitoidp_mock.go b/pkg/aws/cognitoidp/mock_cognitoidp/cognitoidp_mock.go deleted file mode 100644 index c3edc3f7..00000000 --- a/pkg/aws/cognitoidp/mock_cognitoidp/cognitoidp_mock.go +++ /dev/null @@ -1,315 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/systemaccounting/mxfactorial/pkg/aws/cognitoidp (interfaces: IJwtDeps,IGetClaimedKeyID,IIdpDeps,IJwToken) - -// Package mock_cognitoidp is a generated GoMock package. -package mock_cognitoidp - -import ( - rsa "crypto/rsa" - io "io" - http "net/http" - reflect "reflect" - - jwt "github.com/dgrijalva/jwt-go" - gomock "github.com/golang/mock/gomock" - cognitoidp "github.com/systemaccounting/mxfactorial/pkg/aws/cognitoidp" -) - -// MockIJwtDeps is a mock of IJwtDeps interface. -type MockIJwtDeps struct { - ctrl *gomock.Controller - recorder *MockIJwtDepsMockRecorder -} - -// MockIJwtDepsMockRecorder is the mock recorder for MockIJwtDeps. -type MockIJwtDepsMockRecorder struct { - mock *MockIJwtDeps -} - -// NewMockIJwtDeps creates a new mock instance. -func NewMockIJwtDeps(ctrl *gomock.Controller) *MockIJwtDeps { - mock := &MockIJwtDeps{ctrl: ctrl} - mock.recorder = &MockIJwtDepsMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockIJwtDeps) EXPECT() *MockIJwtDepsMockRecorder { - return m.recorder -} - -// DecodeSegment mocks base method. -func (m *MockIJwtDeps) DecodeSegment(arg0 string) ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DecodeSegment", arg0) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DecodeSegment indicates an expected call of DecodeSegment. -func (mr *MockIJwtDepsMockRecorder) DecodeSegment(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DecodeSegment", reflect.TypeOf((*MockIJwtDeps)(nil).DecodeSegment), arg0) -} - -// GetCognitoClaims mocks base method. -func (m *MockIJwtDeps) GetCognitoClaims(arg0 *jwt.Token) (cognitoidp.CognitoClaims, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetCognitoClaims", arg0) - ret0, _ := ret[0].(cognitoidp.CognitoClaims) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetCognitoClaims indicates an expected call of GetCognitoClaims. -func (mr *MockIJwtDepsMockRecorder) GetCognitoClaims(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCognitoClaims", reflect.TypeOf((*MockIJwtDeps)(nil).GetCognitoClaims), arg0) -} - -// ParseHeader mocks base method. -func (m *MockIJwtDeps) ParseHeader(arg0 string) string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParseHeader", arg0) - ret0, _ := ret[0].(string) - return ret0 -} - -// ParseHeader indicates an expected call of ParseHeader. -func (mr *MockIJwtDepsMockRecorder) ParseHeader(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParseHeader", reflect.TypeOf((*MockIJwtDeps)(nil).ParseHeader), arg0) -} - -// TestToken mocks base method. -func (m *MockIJwtDeps) TestToken(arg0 string, arg1 *rsa.PublicKey) (*jwt.Token, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TestToken", arg0, arg1) - ret0, _ := ret[0].(*jwt.Token) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// TestToken indicates an expected call of TestToken. -func (mr *MockIJwtDepsMockRecorder) TestToken(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TestToken", reflect.TypeOf((*MockIJwtDeps)(nil).TestToken), arg0, arg1) -} - -// Unmarshal mocks base method. -func (m *MockIJwtDeps) Unmarshal(arg0 []byte, arg1 interface{}) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Unmarshal", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// Unmarshal indicates an expected call of Unmarshal. -func (mr *MockIJwtDepsMockRecorder) Unmarshal(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unmarshal", reflect.TypeOf((*MockIJwtDeps)(nil).Unmarshal), arg0, arg1) -} - -// MockIGetClaimedKeyID is a mock of IGetClaimedKeyID interface. -type MockIGetClaimedKeyID struct { - ctrl *gomock.Controller - recorder *MockIGetClaimedKeyIDMockRecorder -} - -// MockIGetClaimedKeyIDMockRecorder is the mock recorder for MockIGetClaimedKeyID. -type MockIGetClaimedKeyIDMockRecorder struct { - mock *MockIGetClaimedKeyID -} - -// NewMockIGetClaimedKeyID creates a new mock instance. -func NewMockIGetClaimedKeyID(ctrl *gomock.Controller) *MockIGetClaimedKeyID { - mock := &MockIGetClaimedKeyID{ctrl: ctrl} - mock.recorder = &MockIGetClaimedKeyIDMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockIGetClaimedKeyID) EXPECT() *MockIGetClaimedKeyIDMockRecorder { - return m.recorder -} - -// GetClaimedKeyID mocks base method. -func (m *MockIGetClaimedKeyID) GetClaimedKeyID() (string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetClaimedKeyID") - ret0, _ := ret[0].(string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetClaimedKeyID indicates an expected call of GetClaimedKeyID. -func (mr *MockIGetClaimedKeyIDMockRecorder) GetClaimedKeyID() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetClaimedKeyID", reflect.TypeOf((*MockIGetClaimedKeyID)(nil).GetClaimedKeyID)) -} - -// MockIIdpDeps is a mock of IIdpDeps interface. -type MockIIdpDeps struct { - ctrl *gomock.Controller - recorder *MockIIdpDepsMockRecorder -} - -// MockIIdpDepsMockRecorder is the mock recorder for MockIIdpDeps. -type MockIIdpDepsMockRecorder struct { - mock *MockIIdpDeps -} - -// NewMockIIdpDeps creates a new mock instance. -func NewMockIIdpDeps(ctrl *gomock.Controller) *MockIIdpDeps { - mock := &MockIIdpDeps{ctrl: ctrl} - mock.recorder = &MockIIdpDepsMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockIIdpDeps) EXPECT() *MockIIdpDepsMockRecorder { - return m.recorder -} - -// Get mocks base method. -func (m *MockIIdpDeps) Get(arg0 string) (*http.Response, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Get", arg0) - ret0, _ := ret[0].(*http.Response) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Get indicates an expected call of Get. -func (mr *MockIIdpDepsMockRecorder) Get(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockIIdpDeps)(nil).Get), arg0) -} - -// Marshal mocks base method. -func (m *MockIIdpDeps) Marshal(arg0 interface{}) ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Marshal", arg0) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Marshal indicates an expected call of Marshal. -func (mr *MockIIdpDepsMockRecorder) Marshal(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Marshal", reflect.TypeOf((*MockIIdpDeps)(nil).Marshal), arg0) -} - -// ParseRawKey mocks base method. -func (m *MockIIdpDeps) ParseRawKey(arg0 []byte) (*rsa.PublicKey, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ParseRawKey", arg0) - ret0, _ := ret[0].(*rsa.PublicKey) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ParseRawKey indicates an expected call of ParseRawKey. -func (mr *MockIIdpDepsMockRecorder) ParseRawKey(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParseRawKey", reflect.TypeOf((*MockIIdpDeps)(nil).ParseRawKey), arg0) -} - -// ReadAll mocks base method. -func (m *MockIIdpDeps) ReadAll(arg0 io.Reader) ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ReadAll", arg0) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ReadAll indicates an expected call of ReadAll. -func (mr *MockIIdpDepsMockRecorder) ReadAll(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadAll", reflect.TypeOf((*MockIIdpDeps)(nil).ReadAll), arg0) -} - -// Unmarshal mocks base method. -func (m *MockIIdpDeps) Unmarshal(arg0 []byte, arg1 interface{}) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Unmarshal", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// Unmarshal indicates an expected call of Unmarshal. -func (mr *MockIIdpDepsMockRecorder) Unmarshal(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unmarshal", reflect.TypeOf((*MockIIdpDeps)(nil).Unmarshal), arg0, arg1) -} - -// MockIJwToken is a mock of IJwToken interface. -type MockIJwToken struct { - ctrl *gomock.Controller - recorder *MockIJwTokenMockRecorder -} - -// MockIJwTokenMockRecorder is the mock recorder for MockIJwToken. -type MockIJwTokenMockRecorder struct { - mock *MockIJwToken -} - -// NewMockIJwToken creates a new mock instance. -func NewMockIJwToken(ctrl *gomock.Controller) *MockIJwToken { - mock := &MockIJwToken{ctrl: ctrl} - mock.recorder = &MockIJwTokenMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockIJwToken) EXPECT() *MockIJwTokenMockRecorder { - return m.recorder -} - -// GetClaimedKeyID mocks base method. -func (m *MockIJwToken) GetClaimedKeyID() (string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetClaimedKeyID") - ret0, _ := ret[0].(string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetClaimedKeyID indicates an expected call of GetClaimedKeyID. -func (mr *MockIJwTokenMockRecorder) GetClaimedKeyID() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetClaimedKeyID", reflect.TypeOf((*MockIJwToken)(nil).GetClaimedKeyID)) -} - -// GetCognitoClaims mocks base method. -func (m *MockIJwToken) GetCognitoClaims(arg0 *jwt.Token) (cognitoidp.CognitoClaims, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetCognitoClaims", arg0) - ret0, _ := ret[0].(cognitoidp.CognitoClaims) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetCognitoClaims indicates an expected call of GetCognitoClaims. -func (mr *MockIJwTokenMockRecorder) GetCognitoClaims(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCognitoClaims", reflect.TypeOf((*MockIJwToken)(nil).GetCognitoClaims), arg0) -} - -// TestToken mocks base method. -func (m *MockIJwToken) TestToken(arg0 *rsa.PublicKey) (*jwt.Token, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TestToken", arg0) - ret0, _ := ret[0].(*jwt.Token) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// TestToken indicates an expected call of TestToken. -func (mr *MockIJwTokenMockRecorder) TestToken(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TestToken", reflect.TypeOf((*MockIJwToken)(nil).TestToken), arg0) -} diff --git a/pkg/aws/lambda/lambda.go b/pkg/aws/lambda/lambda.go deleted file mode 100644 index 3300ecbb..00000000 --- a/pkg/aws/lambda/lambda.go +++ /dev/null @@ -1,73 +0,0 @@ -package lambda - -import ( - "encoding/json" - - "github.com/aws/aws-sdk-go/service/lambda" - "github.com/systemaccounting/mxfactorial/pkg/aws/session" - "github.com/systemaccounting/mxfactorial/pkg/logger" -) - -type IAWSLambda interface { - CreateInvokeInput([]byte) *lambda.InvokeInput - Invoke(*lambda.InvokeInput) (*lambda.InvokeOutput, error) - Marshal(any) ([]byte, error) -} - -type AWSLambda struct { - *lambda.Lambda - FunctionName *string -} - -func (a AWSLambda) CreateInvokeInput(body []byte) *lambda.InvokeInput { - return &lambda.InvokeInput{ - FunctionName: a.FunctionName, - Payload: body, - } -} - -func (a AWSLambda) Invoke(input *lambda.InvokeInput) (*lambda.InvokeOutput, error) { - return a.Lambda.Invoke(input) -} - -func (a AWSLambda) Marshal(v any) ([]byte, error) { - return json.Marshal(v) -} - -type ILambdaService interface { - Invoke(any) ([]byte, error) -} - -type LambdaService struct { - IAWSLambda -} - -func (l LambdaService) Invoke(v any) ([]byte, error) { - - body, err := l.IAWSLambda.Marshal(v) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - input := l.CreateInvokeInput(body) - - out, err := l.IAWSLambda.Invoke(input) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return out.Payload, nil -} - -func NewLambdaService(lambdaFnName, awsRegion *string) *LambdaService { - c := session.NewAWSConfig(awsRegion) - sess := session.NewAWSSession(c) - return &LambdaService{ - IAWSLambda: AWSLambda{ - Lambda: lambda.New(sess), - FunctionName: lambdaFnName, - }, - } -} diff --git a/pkg/aws/lambda/lambda_test.go b/pkg/aws/lambda/lambda_test.go deleted file mode 100644 index b977e364..00000000 --- a/pkg/aws/lambda/lambda_test.go +++ /dev/null @@ -1,151 +0,0 @@ -package lambda - -import ( - "fmt" - "testing" - - "github.com/aws/aws-sdk-go/service/lambda" - "github.com/golang/mock/gomock" - "github.com/google/go-cmp/cmp" - mlambda "github.com/systemaccounting/mxfactorial/pkg/aws/lambda/mock_lambda" -) - -func TestCreateInvokeInput(t *testing.T) { - - testlambdafnname := "testlambdafnname" - - testlambdaservice := LambdaService{ - IAWSLambda: AWSLambda{FunctionName: &testlambdafnname}, - } - - testbody := []byte("body") - - want := &lambda.InvokeInput{ - FunctionName: &testlambdafnname, - Payload: testbody, - } - - got := testlambdaservice.IAWSLambda.CreateInvokeInput(testbody) - - if !cmp.Equal(got, want) { - t.Errorf("\ngot: %v\nwant: %v", got, want) - } -} - -func TestInvoke(t *testing.T) { - - ctrl := gomock.NewController(t) - - m := mlambda.NewMockIAWSLambda(ctrl) - - testlambdafnname := "testlambdafnname" - testbodytxt := "body" - testbody := []byte(testbodytxt) - testinput := &lambda.InvokeInput{ - FunctionName: &testlambdafnname, - Payload: testbody, - } - testoutput := &lambda.InvokeOutput{} - testreturn := []byte("testreturn") - testoutput.Payload = testreturn - - m. - EXPECT(). - Marshal(testbody). - Times(1). - Return(testbody, nil) - - m. - EXPECT(). - CreateInvokeInput(testbody). - Times(1). - Return(testinput) - - m. - EXPECT(). - Invoke(testinput). - Times(1). - Return(testoutput, nil) - - testlambdaserv := LambdaService{IAWSLambda: m} - - want := testreturn - got, err := testlambdaserv.Invoke(testbody) - if err != nil { - t.Errorf("Invoke err: %v", err) - } - - if !cmp.Equal(got, want) { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestInvokeMarshalErr(t *testing.T) { - - ctrl := gomock.NewController(t) - - m := mlambda.NewMockIAWSLambda(ctrl) - - testbodytxt := "body" - testbody := []byte(testbodytxt) - testerr := fmt.Errorf("testerr") - - m. - EXPECT(). - Marshal(testbody). - Times(1). - Return(nil, testerr) - - testlambdaserv := LambdaService{IAWSLambda: m} - - want := testerr - _, got := testlambdaserv.Invoke(testbody) - - if got.Error() != want.Error() { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestInvokeErr(t *testing.T) { - - ctrl := gomock.NewController(t) - - m := mlambda.NewMockIAWSLambda(ctrl) - - testlambdafnname := "testlambdafnname" - testbodytxt := "body" - testbody := []byte(testbodytxt) - testinput := &lambda.InvokeInput{ - FunctionName: &testlambdafnname, - Payload: testbody, - } - testerr := fmt.Errorf("testerr") - - m. - EXPECT(). - Marshal(testbody). - Times(1). - Return(testbody, nil) - - m. - EXPECT(). - CreateInvokeInput(testbody). - Times(1). - Return(testinput) - - m. - EXPECT(). - Invoke(testinput). - Times(1). - Return(nil, testerr) - - testlambdaserv := LambdaService{IAWSLambda: m} - - want := testerr.Error() - _, err := testlambdaserv.Invoke(testbody) - got := err.Error() - - if got != want { - t.Errorf("got %v, want %v", got, want) - } -} diff --git a/pkg/aws/lambda/makefile b/pkg/aws/lambda/makefile deleted file mode 100644 index 5647f103..00000000 --- a/pkg/aws/lambda/makefile +++ /dev/null @@ -1,13 +0,0 @@ -PKG_NAME=lambda -RELATIVE_PROJECT_ROOT_PATH=../../../.. - -test: - go test -v -race -covermode=atomic -coverprofile=coverage.out - -mock: - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/mock-go-ifaces.sh \ - --app-or-pkg-name $(PKG_NAME) - -install: - go install github.com/golang/mock/mockgen@latest \ No newline at end of file diff --git a/pkg/aws/lambda/mock_lambda/lambda_mock.go b/pkg/aws/lambda/mock_lambda/lambda_mock.go deleted file mode 100644 index 105455f4..00000000 --- a/pkg/aws/lambda/mock_lambda/lambda_mock.go +++ /dev/null @@ -1,117 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/systemaccounting/mxfactorial/pkg/aws/lambda (interfaces: IAWSLambda,ILambdaService) - -// Package mock_lambda is a generated GoMock package. -package mock_lambda - -import ( - reflect "reflect" - - lambda "github.com/aws/aws-sdk-go/service/lambda" - gomock "github.com/golang/mock/gomock" -) - -// MockIAWSLambda is a mock of IAWSLambda interface. -type MockIAWSLambda struct { - ctrl *gomock.Controller - recorder *MockIAWSLambdaMockRecorder -} - -// MockIAWSLambdaMockRecorder is the mock recorder for MockIAWSLambda. -type MockIAWSLambdaMockRecorder struct { - mock *MockIAWSLambda -} - -// NewMockIAWSLambda creates a new mock instance. -func NewMockIAWSLambda(ctrl *gomock.Controller) *MockIAWSLambda { - mock := &MockIAWSLambda{ctrl: ctrl} - mock.recorder = &MockIAWSLambdaMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockIAWSLambda) EXPECT() *MockIAWSLambdaMockRecorder { - return m.recorder -} - -// CreateInvokeInput mocks base method. -func (m *MockIAWSLambda) CreateInvokeInput(arg0 []byte) *lambda.InvokeInput { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateInvokeInput", arg0) - ret0, _ := ret[0].(*lambda.InvokeInput) - return ret0 -} - -// CreateInvokeInput indicates an expected call of CreateInvokeInput. -func (mr *MockIAWSLambdaMockRecorder) CreateInvokeInput(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateInvokeInput", reflect.TypeOf((*MockIAWSLambda)(nil).CreateInvokeInput), arg0) -} - -// Invoke mocks base method. -func (m *MockIAWSLambda) Invoke(arg0 *lambda.InvokeInput) (*lambda.InvokeOutput, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Invoke", arg0) - ret0, _ := ret[0].(*lambda.InvokeOutput) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Invoke indicates an expected call of Invoke. -func (mr *MockIAWSLambdaMockRecorder) Invoke(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Invoke", reflect.TypeOf((*MockIAWSLambda)(nil).Invoke), arg0) -} - -// Marshal mocks base method. -func (m *MockIAWSLambda) Marshal(arg0 interface{}) ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Marshal", arg0) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Marshal indicates an expected call of Marshal. -func (mr *MockIAWSLambdaMockRecorder) Marshal(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Marshal", reflect.TypeOf((*MockIAWSLambda)(nil).Marshal), arg0) -} - -// MockILambdaService is a mock of ILambdaService interface. -type MockILambdaService struct { - ctrl *gomock.Controller - recorder *MockILambdaServiceMockRecorder -} - -// MockILambdaServiceMockRecorder is the mock recorder for MockILambdaService. -type MockILambdaServiceMockRecorder struct { - mock *MockILambdaService -} - -// NewMockILambdaService creates a new mock instance. -func NewMockILambdaService(ctrl *gomock.Controller) *MockILambdaService { - mock := &MockILambdaService{ctrl: ctrl} - mock.recorder = &MockILambdaServiceMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockILambdaService) EXPECT() *MockILambdaServiceMockRecorder { - return m.recorder -} - -// Invoke mocks base method. -func (m *MockILambdaService) Invoke(arg0 interface{}) ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Invoke", arg0) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Invoke indicates an expected call of Invoke. -func (mr *MockILambdaServiceMockRecorder) Invoke(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Invoke", reflect.TypeOf((*MockILambdaService)(nil).Invoke), arg0) -} diff --git a/pkg/aws/session/session.go b/pkg/aws/session/session.go deleted file mode 100644 index b38a1cbb..00000000 --- a/pkg/aws/session/session.go +++ /dev/null @@ -1,21 +0,0 @@ -package session - -import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" -) - -type AWSSession struct { - *session.Session -} - -func NewAWSConfig(awsRegion *string) *aws.Config { - return &aws.Config{ - Region: awsRegion, - } -} - -func NewAWSSession(config *aws.Config) *AWSSession { - s := session.Must(session.NewSession(config)) - return &AWSSession{Session: s} -} diff --git a/pkg/aws/sns/makefile b/pkg/aws/sns/makefile deleted file mode 100644 index f883a74c..00000000 --- a/pkg/aws/sns/makefile +++ /dev/null @@ -1,13 +0,0 @@ -PKG_NAME=sns -RELATIVE_PROJECT_ROOT_PATH=../../../.. - -test: - go test -race -covermode=atomic -coverprofile=coverage.out - -mock: - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/mock-go-ifaces.sh \ - --app-or-pkg-name $(PKG_NAME) - -install: - go install github.com/golang/mock/mockgen@latest \ No newline at end of file diff --git a/pkg/aws/sns/mock_sns/sns_mock.go b/pkg/aws/sns/mock_sns/sns_mock.go deleted file mode 100644 index 36ba93bf..00000000 --- a/pkg/aws/sns/mock_sns/sns_mock.go +++ /dev/null @@ -1,50 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/systemaccounting/mxfactorial/pkg/aws/sns (interfaces: ISNS) - -// Package mock_sns is a generated GoMock package. -package mock_sns - -import ( - reflect "reflect" - - sns "github.com/aws/aws-sdk-go/service/sns" - gomock "github.com/golang/mock/gomock" -) - -// MockISNS is a mock of ISNS interface. -type MockISNS struct { - ctrl *gomock.Controller - recorder *MockISNSMockRecorder -} - -// MockISNSMockRecorder is the mock recorder for MockISNS. -type MockISNSMockRecorder struct { - mock *MockISNS -} - -// NewMockISNS creates a new mock instance. -func NewMockISNS(ctrl *gomock.Controller) *MockISNS { - mock := &MockISNS{ctrl: ctrl} - mock.recorder = &MockISNSMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockISNS) EXPECT() *MockISNSMockRecorder { - return m.recorder -} - -// PublishMessage mocks base method. -func (m *MockISNS) PublishMessage(arg0 *sns.PublishInput) (*sns.PublishOutput, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PublishMessage", arg0) - ret0, _ := ret[0].(*sns.PublishOutput) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// PublishMessage indicates an expected call of PublishMessage. -func (mr *MockISNSMockRecorder) PublishMessage(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublishMessage", reflect.TypeOf((*MockISNS)(nil).PublishMessage), arg0) -} diff --git a/pkg/aws/sns/sns.go b/pkg/aws/sns/sns.go deleted file mode 100644 index 9ed9f082..00000000 --- a/pkg/aws/sns/sns.go +++ /dev/null @@ -1,95 +0,0 @@ -package sns - -import ( - "encoding/json" - - "github.com/aws/aws-sdk-go/service/sns" - "github.com/systemaccounting/mxfactorial/pkg/aws/session" - "github.com/systemaccounting/mxfactorial/pkg/logger" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -type ISNS interface { - PublishMessage(*sns.PublishInput) (*sns.PublishOutput, error) -} - -type AWSSNS struct { - *sns.SNS -} - -type snsMsgAttributes map[string]*sns.MessageAttributeValue - -func (s *AWSSNS) PublishMessage(i *sns.PublishInput) (*sns.PublishOutput, error) { - return s.SNS.Publish(i) -} - -type SNS struct { - ISNS -} - -var ( - snsMsgAttributeName = "SERVICE" - snsMsgAttributeValueDataType = "String" - TRANSACT_SERVICE_NAME = "TRANSACT" -) - -func (s *SNS) Publish(notifIDs types.IDs, serviceName *string, topicArn *string) error { - - input, err := createPublishInput(notifIDs, serviceName, topicArn) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - _, err = s.PublishMessage(input) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func createSNSAttributes(serviceName *string) snsMsgAttributes { - return snsMsgAttributes{ - snsMsgAttributeName: &sns.MessageAttributeValue{ - DataType: &snsMsgAttributeValueDataType, - StringValue: serviceName, - }, - } -} - -func createPublishInput( - notifIDs types.IDs, - serviceName *string, - topicArn *string, -) (*sns.PublishInput, error) { - - snsMsgBytes, err := json.Marshal(¬ifIDs) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - snsMsg := string(snsMsgBytes) - - msgAttr := createSNSAttributes(serviceName) - - return &sns.PublishInput{ - Message: &snsMsg, - TopicArn: topicArn, - MessageAttributes: msgAttr, - }, nil -} - -func NewSNS() *SNS { - - sess := session.NewAWSSession(nil) - awssns := new(AWSSNS) - awssns.SNS = sns.New(sess.Session) - - snsService := new(SNS) - snsService.ISNS = awssns - - return snsService -} diff --git a/pkg/aws/sns/sns_test.go b/pkg/aws/sns/sns_test.go deleted file mode 100644 index fd07533e..00000000 --- a/pkg/aws/sns/sns_test.go +++ /dev/null @@ -1,150 +0,0 @@ -package sns - -import ( - "fmt" - "testing" - - "github.com/aws/aws-sdk-go/service/sns" - "github.com/golang/mock/gomock" - "github.com/google/go-cmp/cmp" - msns "github.com/systemaccounting/mxfactorial/pkg/aws/sns/mock_sns" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -func TestCreateSNSAttributes(t *testing.T) { - - testservicename := "testservicename" - - want := snsMsgAttributes{ - snsMsgAttributeName: &sns.MessageAttributeValue{ - DataType: &snsMsgAttributeValueDataType, - StringValue: &testservicename, - }, - } - - got := createSNSAttributes(&testservicename) - - if !cmp.Equal(got, want) { - t.Errorf("\ngot: %v\nwant: %v", got, want) - } -} - -func TestCreatePublishInput(t *testing.T) { - - testid1 := types.ID("1") - testid2 := types.ID("2") - testservicename := "testservicename" - testtopicarn := "testtopicarn" - testmarshaledids := `["1","2"]` - testnotifids := types.IDs{ - &testid1, - &testid2, - } - - want := &sns.PublishInput{ - Message: &testmarshaledids, - TopicArn: &testtopicarn, - MessageAttributes: createSNSAttributes(&testservicename), - } - - got, err := createPublishInput( - testnotifids, - &testservicename, - &testtopicarn, - ) - if err != nil { - t.Errorf("createPublishInput error: %v", err) - } - - if !cmp.Equal(got, want) { - t.Errorf("\ngot: %v\nwant: %v", got, want) - } - -} - -func TestPublish(t *testing.T) { - - ctrl := gomock.NewController(t) - m := msns.NewMockISNS(ctrl) - - testid1 := types.ID("1") - testid2 := types.ID("2") - testservicename := "testservicename" - testtopicarn := "testtopicarn" - testmarshaledids := `["1","2"]` - - testnotifids := types.IDs{ - &testid1, - &testid2, - } - - want := &sns.PublishInput{ - Message: &testmarshaledids, - TopicArn: &testtopicarn, - MessageAttributes: createSNSAttributes(&testservicename), - } - - testsns := SNS{ISNS: m} - - m. - EXPECT(). - PublishMessage(want). - Times(1). - Return(nil, nil) - - err := testsns.Publish( - testnotifids, - &testservicename, - &testtopicarn, - ) - - if err != nil { - t.Errorf("Publish error: %v", err) - } -} - -func TestPublishErr(t *testing.T) { - - ctrl := gomock.NewController(t) - m := msns.NewMockISNS(ctrl) - - testid1 := types.ID("1") - testid2 := types.ID("2") - testservicename := "testservicename" - testtopicarn := "testtopicarn" - testmarshaledids := `["1","2"]` - - want := "testerr" - testerr := fmt.Errorf(want) - - testnotifids := types.IDs{ - &testid1, - &testid2, - } - - testinput := &sns.PublishInput{ - Message: &testmarshaledids, - TopicArn: &testtopicarn, - MessageAttributes: createSNSAttributes(&testservicename), - } - - testsns := SNS{ISNS: m} - - m. - EXPECT(). - PublishMessage(testinput). - Times(1). - Return(nil, testerr) - - err := testsns.Publish( - testnotifids, - &testservicename, - &testtopicarn, - ) - - got := err.Error() - - if got != want { - t.Errorf("got %v, want %v", got, want) - } -} diff --git a/pkg/httpclient/client.go b/pkg/httpclient/client.go deleted file mode 100644 index cbe4a3fc..00000000 --- a/pkg/httpclient/client.go +++ /dev/null @@ -1,69 +0,0 @@ -package httpclient - -import ( - "bytes" - "io/ioutil" - "net/http" - "os" - "time" - - "github.com/aws/aws-sdk-go/aws/credentials" - v4 "github.com/aws/aws-sdk-go/aws/signer/v4" - "github.com/systemaccounting/mxfactorial/pkg/logger" -) - -type HttpClient struct { - *http.Client - Url string -} - -func (h *HttpClient) Post(b []byte) ([]byte, error) { - - br := bytes.NewReader(b) - - req, err := http.NewRequest(http.MethodPost, h.Url, br) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - req.Header.Add("Content-Type", "application/json") - - // https://docs.amazonaws.cn/en_us/opensearch-service/latest/developerguide/request-signing.html - - if os.Getenv("AWS_LAMBDA_FUNCTION_NAME") != "" { - - creds := credentials.NewEnvCredentials() - signer := v4.NewSigner(creds) - - _, err = signer.Sign(req, br, "lambda", os.Getenv("AWS_REGION"), time.Now()) - - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - } - - resp, err := h.Client.Do(req) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - resp.Body.Close() - - return body, nil -} - -func NewHttpClient(url string) *HttpClient { - return &HttpClient{ - Client: new(http.Client), - Url: url, - } -} diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go deleted file mode 100644 index 99f7d4cd..00000000 --- a/pkg/logger/logger.go +++ /dev/null @@ -1,33 +0,0 @@ -package logger - -import ( - "fmt" - "path" - "runtime" - "time" -) - -func Trace() string { - pc := make([]uintptr, 15) - n := runtime.Callers(2, pc) - frames := runtime.CallersFrames(pc[:n]) - frame, _ := frames.Next() - return fmt.Sprintf("TRACE: %s:%d:%s", path.Base(frame.File), frame.Line, path.Base(frame.Function)) -} - -func Err(trace string, err error) error { - return fmt.Errorf("%v: %s: %v", Now(), trace, err) -} - -func ErrFmt(err error) error { - return fmt.Errorf("%s: ERROR: %v", Now(), err) -} - -func Now() string { - return time.Now().UTC().Format("2006-01-02T15:04:05.000Z") -} - -// logger.Log(logger.Trace(), err) -func Log(trace string, err error) { - fmt.Println(Err(trace, err)) -} diff --git a/pkg/postgres/model.go b/pkg/postgres/model.go deleted file mode 100644 index 67bc0379..00000000 --- a/pkg/postgres/model.go +++ /dev/null @@ -1,1129 +0,0 @@ -package postgres - -import ( - "context" - "fmt" - "log" - "time" - - "github.com/jackc/pgconn" - "github.com/jackc/pgtype" - "github.com/jackc/pgx/v4" - "github.com/shopspring/decimal" - "github.com/systemaccounting/mxfactorial/pkg/logger" - "github.com/systemaccounting/mxfactorial/pkg/sqls" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -type SQLDB interface { - Query(context.Context, string, ...interface{}) (pgx.Rows, error) - QueryRow(context.Context, string, ...interface{}) pgx.Row - Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) - Begin(context.Context) (pgx.Tx, error) - Close(context.Context) error - IsClosed() bool -} - -type IAccountSQL interface { - InsertAccountSQL(string) (string, []interface{}) - DeleteOwnerAccountSQL(string) (string, []interface{}) - DeleteAccountSQL(string) (string, []interface{}) -} - -type AccountModel struct { - db SQLDB - s IAccountSQL -} - -func (a *AccountModel) InsertAccount(accountName string) error { - - // create sql - sql, args := a.s.InsertAccountSQL(accountName) - - // query - _, err := a.db.Exec(context.Background(), sql, args...) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func (a *AccountModel) DeleteOwnerAccount(accountName string) error { - - // create sql - sql, args := a.s.DeleteOwnerAccountSQL(accountName) - - // query - _, err := a.db.Exec(context.Background(), sql, args...) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func (a *AccountModel) DeleteAccount(accountName string) error { - - // create sql - sql, args := a.s.DeleteAccountSQL(accountName) - - // query - _, err := a.db.Exec(context.Background(), sql, args...) - if err != nil { - return err - } - - return nil -} - -func NewAccountModel(db SQLDB) *AccountModel { - return &AccountModel{ - db: db, - s: sqls.NewAccountSQLs(), - } -} - -type IAccountBalanceSQLs interface { - SelectAccountBalancesSQL([]string) (string, []interface{}) - SelectCurrentAccountBalanceByAccountNameSQL(string) (string, []interface{}) - InsertAccountBalanceSQL(string, decimal.Decimal, types.ID) (string, []interface{}) - UpdateAccountBalancesSQL(types.TransactionItems) (string, []interface{}) -} - -type AccountBalanceModel struct { - db SQLDB - s IAccountBalanceSQLs - types.AccountBalance -} - -func (ab *AccountBalanceModel) GetAccountBalance(accountName string) (*types.AccountBalance, error) { - - // create sql - sql, args := ab.s.SelectCurrentAccountBalanceByAccountNameSQL(accountName) - - // query - row := ab.db.QueryRow(context.Background(), sql, args...) - - // scan row into struct field - err := ab.AccountBalance.ScanRow(row) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return &ab.AccountBalance, nil -} - -func NewAccountBalanceModel(db SQLDB) *AccountBalanceModel { - return &AccountBalanceModel{ - db: db, - s: sqls.NewAccountBalanceSQLs(), - } -} - -type AccountBalancesModel struct { - db SQLDB - s IAccountBalanceSQLs - types.AccountBalances -} - -func (abs *AccountBalancesModel) GetAccountBalances(accounts []string) (types.AccountBalances, error) { - - // create sql - sql, args := abs.s.SelectAccountBalancesSQL(accounts) - - // query - rows, err := abs.db.Query(context.Background(), sql, args...) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // scan rows into struct field - err = abs.AccountBalances.ScanRows(rows) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return abs.AccountBalances, nil -} - -func (abs *AccountBalancesModel) ChangeAccountBalances(trItems types.TransactionItems) error { - - // create sql - sql, args := abs.s.UpdateAccountBalancesSQL(trItems) - - // query - _, err := abs.db.Exec( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -// todo: move to AccountBalanceModel -func (abs *AccountBalancesModel) InsertAccountBalance( - accountName string, - accountBalance decimal.Decimal, - account types.ID, -) error { - - // create sql - sql, args := abs.s.InsertAccountBalanceSQL( - accountName, - accountBalance, - account, - ) - - // query - _, err := abs.db.Exec( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func NewAccountBalancesModel(db SQLDB) *AccountBalancesModel { - return &AccountBalancesModel{ - db: db, - s: sqls.NewAccountBalanceSQLs(), - } -} - -type IApprovalSQLs interface { - InsertApprovalsSQL(types.Approvals, sqls.Builder, sqls.Builder) sqls.Builder - SelectApprovalsByTrIDSQL(types.ID) (string, []interface{}) - SelectApprovalsByTrIDsSQL(types.IDs) (string, []interface{}) -} - -type ApprovalsModel struct { - db SQLDB - s IApprovalSQLs - types.Approvals -} - -func (a *ApprovalsModel) GetApprovalsByTransactionID(id types.ID) (types.Approvals, error) { - - // create sql - sql, args := a.s.SelectApprovalsByTrIDSQL(id) - - // query - rows, err := a.db.Query( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // scan rows - err = a.ScanRows(rows) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return a.Approvals, nil -} - -func (a *ApprovalsModel) GetApprovalsByTransactionIDs(IDs types.IDs) (types.Approvals, error) { - - // create sql - sql, args := a.s.SelectApprovalsByTrIDsSQL(IDs) - - // query - rows, err := a.db.Query( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // scan rows - err = a.ScanRows(rows) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return a.Approvals, nil -} - -func (a *ApprovalsModel) UpdateApprovalsByAccountAndRole( - trID types.ID, - accountName string, - accountRole types.Role, -) (pgtype.Timestamptz, error) { - - // begin tx - dbtx, err := a.db.Begin(context.Background()) - if err != nil { - logger.Log(logger.Trace(), err) - return pgtype.Timestamptz{}, err - } - - defer dbtx.Rollback(context.Background()) - - // create sql - sql := `SELECT approve_all_role_account($1, $2, $3) AS equilibrium_time` - args := []interface{}{trID, accountName, accountRole} - - // query - row := dbtx.QueryRow( - context.Background(), - sql, - args..., - ) - - var equilibriumTime pgtype.Timestamptz - - // scan row - err = row.Scan(&equilibriumTime) - if err != nil { - logger.Log(logger.Trace(), err) - return pgtype.Timestamptz{}, err - } - - // commit tx - err = dbtx.Commit(context.Background()) - if err != nil { - logger.Log(logger.Trace(), err) - return pgtype.Timestamptz{}, err - } - - return equilibriumTime, nil -} - -func NewApprovalsModel(db SQLDB) *ApprovalsModel { - return &ApprovalsModel{ - db: db, - s: sqls.NewApprovalSQLs(), - } -} - -type IAccountProfileSQLS interface { - SelectProfileIDsByAccountNames([]string) (string, []interface{}) - InsertAccountProfileSQL(*types.AccountProfile) (string, []interface{}) -} - -type AccountProfileModel struct { - db SQLDB - s IAccountProfileSQLS - types.AccountProfile -} - -func (ap *AccountProfileModel) GetProfileIDsByAccountNames( - accountNames []string, -) (types.AccountProfileIDs, error) { - - // create sql - sql, args := ap.s.SelectProfileIDsByAccountNames(accountNames) - - // query - rows, err := ap.db.Query( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // assign account profile ids from db - var profileIDs types.AccountProfileIDs - err = profileIDs.ScanRows(rows) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return profileIDs, nil -} - -func (ap *AccountProfileModel) InsertAccountProfile( - accountProfile *types.AccountProfile, -) error { - - // create sql - sql, args := ap.s.InsertAccountProfileSQL(accountProfile) - - // query - _, err := ap.db.Exec( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func NewAccountProfileModel(db SQLDB) *AccountProfileModel { - return &AccountProfileModel{ - db: db, - s: sqls.NewAccountProfileSQLs(), - } -} - -type ITransactionItemSQLs interface { - InsertTrItemSQL(*types.TransactionItem, sqls.Builder) sqls.Builder - SelectTrItemsByTrIDSQL(types.ID) (string, []interface{}) - SelectTrItemsByTrIDsSQL(types.IDs) (string, []interface{}) -} - -type TransactionItemsModel struct { - db SQLDB - s ITransactionItemSQLs - types.TransactionItems -} - -func (t *TransactionItemsModel) GetTrItemsByTransactionID(ID types.ID) (types.TransactionItems, error) { - - // create sql - sql, args := t.s.SelectTrItemsByTrIDSQL(ID) - - // query - rows, err := t.db.Query(context.Background(), sql, args...) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // scan rows - err = t.ScanRows(rows) - if err != nil { - log.Print(err) - logger.Log(logger.Trace(), err) - return nil, err - } - - return t.TransactionItems, nil -} - -func (t *TransactionItemsModel) GetTrItemsByTrIDs(IDs types.IDs) (types.TransactionItems, error) { - - // create sql - sql, args := t.s.SelectTrItemsByTrIDsSQL(IDs) - - // query - rows, err := t.db.Query(context.Background(), sql, args...) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // scan rows - err = t.ScanRows(rows) - if err != nil { - log.Print(err) - logger.Log(logger.Trace(), err) - return nil, err - } - - return t.TransactionItems, nil -} - -func NewTransactionItemsModel(db SQLDB) *TransactionItemsModel { - return &TransactionItemsModel{ - db: db, - s: sqls.NewTransactionItemSQLs(), - } -} - -type ITransactionSQLs interface { - InsertTransactionSQL(*types.ID, *string, *string, *string, types.Role, *string, *decimal.NullDecimal) sqls.Builder - SelectTransactionByIDSQL(types.ID) (string, []interface{}) - SelectTransactionsByIDsSQL(types.IDs) (string, []interface{}) - UpdateTransactionByIDSQL(*types.ID, string) (string, []interface{}) - CreateTransactionRequestSQL(*types.Transaction) (string, []interface{}, error) - SelectLastNReqsOrTransByAccount(string, bool, string) (string, []interface{}) -} - -type TransactionModel struct { - db SQLDB - s ITransactionSQLs - types.Transaction -} - -func (t *TransactionModel) GetTransactionByID(trID types.ID) (*types.Transaction, error) { - - // create sql - sql, args := t.s.SelectTransactionByIDSQL(trID) - - // query - row := t.db.QueryRow( - context.Background(), - sql, - args..., - ) - - // scan row - err := t.ScanRow(row) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return &t.Transaction, nil -} - -func (t *TransactionModel) InsertTransactionTx( - ruleTestedTransaction *types.Transaction, -) (*types.ID, error) { - - // begin tx - dbtx, err := t.db.Begin(context.Background()) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - defer dbtx.Rollback(context.Background()) - - // create sql - sql, args, err := t.s.CreateTransactionRequestSQL(ruleTestedTransaction) - if err != nil { - return nil, fmt.Errorf("%v: %s\n%v", time.Now(), logger.Trace(), err) - } - - // query - row := dbtx.QueryRow( - context.Background(), - sql, - args..., - ) - - // scan id - err = t.ScanID(row) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // commit tx - err = dbtx.Commit(context.Background()) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return t.ID, nil -} - -func NewTransactionModel(db SQLDB) *TransactionModel { - return &TransactionModel{ - db: db, - s: sqls.NewTransactionSQLs(), - } -} - -type TransactionsModel struct { - db SQLDB - s ITransactionSQLs - types.Transactions -} - -func (t *TransactionsModel) GetLastNTransactions( - accountName string, - recordLimit string, -) (types.Transactions, error) { - - // create sql - sql, args := t.s.SelectLastNReqsOrTransByAccount( - accountName, - true, // get transactions - recordLimit, - ) - - // query - rows, err := t.db.Query( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // scan rows - err = t.ScanRows(rows) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return t.Transactions, nil -} - -func (t *TransactionsModel) GetLastNRequests( - accountName string, - recordLimit string, -) (types.Transactions, error) { - - // create sql - sql, args := t.s.SelectLastNReqsOrTransByAccount( - accountName, - false, // get requests - recordLimit, - ) - - // query - rows, err := t.db.Query( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // scan rows - err = t.ScanRows(rows) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return t.Transactions, nil -} - -func (t *TransactionsModel) GetTransactionsByIDs(trIDs types.IDs) (types.Transactions, error) { - - // create sql - sql, args := t.s.SelectTransactionsByIDsSQL(trIDs) - - // query - rows, err := t.db.Query( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // scan rows - err = t.ScanRows(rows) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return t.Transactions, nil -} - -func NewTransactionsModel(db SQLDB) *TransactionsModel { - return &TransactionsModel{ - db: db, - s: sqls.NewTransactionSQLs(), - } -} - -type IRuleInstanceSQLs interface { - SelectRuleInstanceSQL(string, string, string, string, string, string) (string, []interface{}) - InsertRuleInstanceSQL(string, string, string, string, string, string) (string, []interface{}) -} - -type RuleInstanceModel struct { - db SQLDB - s IRuleInstanceSQLs - types.RuleInstance -} - -func (ri *RuleInstanceModel) SelectRuleInstance( - ruleType, - ruleName, - ruleInstanceName, - accountRole, - accountName, - variableValuesArray string, -) error { - - // create sql - sql, args := ri.s.SelectRuleInstanceSQL( - ruleType, - ruleName, - ruleInstanceName, - accountRole, - accountName, - variableValuesArray, - ) - - // query - row := ri.db.QueryRow( - context.Background(), - sql, - args..., - ) - - // scan row - err := ri.ScanRow(row) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func (ri *RuleInstanceModel) InsertRuleInstance( - ruleType, - ruleName, - ruleInstanceName, - accountRole, - accountName, - variableValuesArray string, -) error { - - // create sql - sql, args := ri.s.InsertRuleInstanceSQL( - ruleType, - ruleName, - ruleInstanceName, - accountRole, - accountName, - variableValuesArray, - ) - - // query - _, err := ri.db.Exec( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func (ri *RuleInstanceModel) SelectApproveAllCreditRuleInstance( - accountName string, -) (*types.RuleInstance, error) { - - // create sql - sql, args := ri.s.SelectRuleInstanceSQL( - "approval", - "approveAnyCreditItem", - "ApprovalAllCreditRequests", - "creditor", - accountName, - fmt.Sprintf( - "{\"%s\", \"creditor\", \"%s\"}", - accountName, - accountName, - ), - ) - - // query - row := ri.db.QueryRow( - context.Background(), - sql, - args..., - ) - - // scan row - err := ri.ScanRow(row) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return &ri.RuleInstance, nil -} - -func (ri *RuleInstanceModel) InsertApproveAllCreditRuleInstance( - accountName string, -) error { - - // create sql - sql, args := ri.s.InsertRuleInstanceSQL( - "approval", - "approveAnyCreditItem", - "ApprovalAllCreditRequests", - "creditor", - accountName, - fmt.Sprintf( - "{\"%s\", \"creditor\", \"%s\"}", - accountName, - accountName, - ), - ) - - // query - _, err := ri.db.Exec( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func (ri *RuleInstanceModel) InsertApproveAllCreditRuleInstanceIfDoesNotExist( - accountName string, -) error { - - // test availability of approve all credit rule instance for account - // create sql - sql, args := ri.s.SelectRuleInstanceSQL( - "approval", - "approveAnyCreditItem", - "ApprovalAllCreditRequests", - "creditor", - accountName, - fmt.Sprintf( - "{\"%s\", \"creditor\", \"%s\"}", - accountName, - accountName, - ), - ) - - // query - row := ri.db.QueryRow( - context.Background(), - sql, - args..., - ) - - var testRuleInstance types.RuleInstance - err := row.Scan( - &testRuleInstance.RuleType, - &testRuleInstance.RuleName, - &testRuleInstance.RuleInstanceName, - &testRuleInstance.AccountRole, - &testRuleInstance.AccountName, - &testRuleInstance.VariableValues, - ) - - if err != nil && err != pgx.ErrNoRows { - logger.Log(logger.Trace(), err) - return err - } - // insert approve all credit rule instance if not in table - if err == pgx.ErrNoRows { - - insErr := ri.InsertApproveAllCreditRuleInstance(accountName) - if insErr != nil { - logger.Log(logger.Trace(), err) - return insErr - } - } - - return nil -} - -func NewRuleInstanceModel(db SQLDB) *RuleInstanceModel { - return &RuleInstanceModel{ - db: db, - s: sqls.NewRuleInstanceSQLs(), - } -} - -type INotificationSQLs interface { - InsertTransactionNotificationsSQL(types.TransactionNotifications) (string, []interface{}) - SelectTransNotifsByIDsSQL(types.IDs) (string, []interface{}) - DeleteTransNotificationsByIDsSQL(types.IDs) (string, []interface{}) - SelectTransNotifsByAccountSQL(string, int) (string, []interface{}) - DeleteTransNotificationsByTransIDSQL(types.ID) (string, []interface{}) -} - -type TransactionNotificationModel struct { - db SQLDB - s INotificationSQLs - types.TransactionNotifications -} - -func (t *TransactionNotificationModel) InsertTransactionApprovalNotifications( - n types.TransactionNotifications, -) (types.IDs, error) { - - // create sql - sql, args := t.s.InsertTransactionNotificationsSQL(n) - - // query - rows, err := t.db.Query( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // scan rows - err = t.ScanIDs(rows) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return t.TransactionNotifications.ListIDs(), nil -} - -func (t *TransactionNotificationModel) SelectTransNotifsByIDs(notifIDs types.IDs) (types.TransactionNotifications, error) { - - // create sql - sql, args := t.s.SelectTransNotifsByIDsSQL(notifIDs) - - // query - rows, err := t.db.Query( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // scan rows - err = t.ScanRows(rows) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return t.TransactionNotifications, nil -} - -func (t *TransactionNotificationModel) SelectTransNotifsByAccount(accountName string, recordLimit int) (types.TransactionNotifications, error) { - - // create sql - sql, args := t.s.SelectTransNotifsByAccountSQL(accountName, recordLimit) - - // query - rows, err := t.db.Query( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // scan rows - err = t.ScanRows(rows) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return t.TransactionNotifications, nil -} - -// a single transaction ID can delete multiple notifications -func (t *TransactionNotificationModel) DeleteTransactionApprovalNotifications( - trID types.ID, -) error { - - // create sql - sql, args := t.s.DeleteTransNotificationsByTransIDSQL(trID) - - // query - _, err := t.db.Exec( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func (t *TransactionNotificationModel) DeleteTransNotificationsByIDs( - notifIDs types.IDs, -) error { - - // create sql - sql, args := t.s.DeleteTransNotificationsByIDsSQL(notifIDs) - - // query - _, err := t.db.Exec( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func NewTransactionNotificationModel(db SQLDB) *TransactionNotificationModel { - return &TransactionNotificationModel{ - db: db, - s: sqls.NewNotificationSQLs(), - } -} - -type IWebsocketSQLs interface { - InsertWebsocketConnectionSQL(string, int64) (string, []interface{}) - DeleteWebsocketConnectionByConnectionIDSQL(string) (string, []interface{}) - DeleteWebsocketsByConnectionIDsSQL([]string) (string, []interface{}) - SelectWebsocketsByAccountsSQL([]string) (string, []interface{}) - SelectWebsocketByConnectionIDSQL(string) (string, []interface{}) - UpdateWebsocketByConnIDSQL(string, string) (string, []interface{}) -} - -type WebsocketsModel struct { - db SQLDB - s IWebsocketSQLs - types.Websockets -} - -func (w *WebsocketsModel) UpdateWebsocketByConnID( - accountName, - connectionID string, -) error { - - // create sql - sql, args := w.s.UpdateWebsocketByConnIDSQL(accountName, connectionID) - - // query - _, err := w.db.Exec( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func (w *WebsocketsModel) InsertWebsocketConnection( - epochCreatedAt int64, - connectionID string, -) error { - - // create sql - sql, args := w.s.InsertWebsocketConnectionSQL(connectionID, epochCreatedAt) - - // query - _, err := w.db.Exec( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func (w *WebsocketsModel) DeleteWebsocketConnection(connectionID string) error { - - // create sql - sql, args := w.s.DeleteWebsocketConnectionByConnectionIDSQL(connectionID) - - // query - _, err := w.db.Exec( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func (w *WebsocketsModel) DeleteWebsocketsByConnectionIDs(connectionIDs []string) error { - - // create sql - sql, args := w.s.DeleteWebsocketsByConnectionIDsSQL(connectionIDs) - - // query - _, err := w.db.Exec( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func (w *WebsocketsModel) SelectWebsocketsByAccounts(accounts []string) (types.Websockets, error) { - - // create sql - sql, args := w.s.SelectWebsocketsByAccountsSQL(accounts) - - // query - rows, err := w.db.Query( - context.Background(), - sql, - args..., - ) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // scan rows - err = w.ScanRows(rows) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return w.Websockets, nil -} - -func NewWebsocketsModel(db SQLDB) *WebsocketsModel { - return &WebsocketsModel{ - db: db, - s: sqls.NewWebsocketSQLs(), - } -} diff --git a/pkg/postgres/pgx.go b/pkg/postgres/pgx.go deleted file mode 100644 index dcf43821..00000000 --- a/pkg/postgres/pgx.go +++ /dev/null @@ -1,59 +0,0 @@ -package postgres - -import ( - "context" - - "github.com/jackc/pgconn" - "github.com/jackc/pgx/v4" -) - -type DB struct { - pg *pgx.Conn -} - -func (db *DB) Begin(ctx context.Context) (pgx.Tx, error) { - return db.pg.Begin(ctx) -} - -func (db *DB) Close(ctx context.Context) error { - if db.pg != nil { - return db.pg.Close(ctx) - } - return nil -} - -func (db *DB) IsClosed() bool { - return db.pg.IsClosed() -} - -func (db *DB) QueryRow( - ctx context.Context, - sql string, - args ...interface{}, -) pgx.Row { - return db.pg.QueryRow(ctx, sql, args...) -} - -func (db *DB) Query( - ctx context.Context, - sql string, - args ...interface{}, -) (pgx.Rows, error) { - return db.pg.Query(ctx, sql, args...) -} - -func (db *DB) Exec( - ctx context.Context, - sql string, - args ...interface{}, -) (pgconn.CommandTag, error) { - return db.pg.Exec(ctx, sql, args...) -} - -func NewDB(ctx context.Context, dsn string) (*DB, error) { - db, err := pgx.Connect(ctx, dsn) - if err != nil { - return nil, err - } - return &DB{db}, nil -} diff --git a/pkg/print/makefile b/pkg/print/makefile deleted file mode 100644 index 1362afc5..00000000 --- a/pkg/print/makefile +++ /dev/null @@ -1,26 +0,0 @@ -PKG_NAME=print -RELATIVE_PROJECT_ROOT_PATH=../../.. - -mock: - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/mock-go-ifaces.sh \ - --app-or-pkg-name $(PKG_NAME) - -test: - go test -race -covermode=atomic -coverprofile=coverage.out - -install: - go install github.com/golang/mock/mockgen@latest - -test-dependents: - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/test-dependents.sh \ - --app-or-pkg-name $(PKG_NAME) - -set-pending-tests: - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/set-pending-tests.sh \ - --app-or-pkg-name $(PKG_NAME) \ - --sha $$GITHUB_SHA \ - --region $$AWS_REGION \ - --env $$ENVIRONMENT \ No newline at end of file diff --git a/pkg/print/mock_print/print_mock.go b/pkg/print/mock_print/print_mock.go deleted file mode 100644 index fb1e7f21..00000000 --- a/pkg/print/mock_print/print_mock.go +++ /dev/null @@ -1,49 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/systemaccounting/mxfactorial/pkg/print (interfaces: Marshaler) - -// Package mock_print is a generated GoMock package. -package mock_print - -import ( - reflect "reflect" - - gomock "github.com/golang/mock/gomock" -) - -// MockMarshaler is a mock of Marshaler interface. -type MockMarshaler struct { - ctrl *gomock.Controller - recorder *MockMarshalerMockRecorder -} - -// MockMarshalerMockRecorder is the mock recorder for MockMarshaler. -type MockMarshalerMockRecorder struct { - mock *MockMarshaler -} - -// NewMockMarshaler creates a new mock instance. -func NewMockMarshaler(ctrl *gomock.Controller) *MockMarshaler { - mock := &MockMarshaler{ctrl: ctrl} - mock.recorder = &MockMarshalerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockMarshaler) EXPECT() *MockMarshalerMockRecorder { - return m.recorder -} - -// MarshalIndent mocks base method. -func (m *MockMarshaler) MarshalIndent() ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "MarshalIndent") - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// MarshalIndent indicates an expected call of MarshalIndent. -func (mr *MockMarshalerMockRecorder) MarshalIndent() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MarshalIndent", reflect.TypeOf((*MockMarshaler)(nil).MarshalIndent)) -} diff --git a/pkg/print/print.go b/pkg/print/print.go deleted file mode 100644 index feb34c07..00000000 --- a/pkg/print/print.go +++ /dev/null @@ -1,37 +0,0 @@ -package print - -//go:generate mockgen -destination=./mock/print.go -package=mock github.com/systemaccounting/mxfactorial/pkg/print Marshaler - -import ( - "encoding/json" - "fmt" - - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -// not adding receivers to pkg/types yet -// so wrapping transactions -type Printable struct { - types.Transaction -} - -type Marshaler interface { - MarshalIndent() ([]byte, error) -} - -func NewPrintable(t *types.Transaction) Marshaler { - p := Printable{*t} - return p -} - -func (p Printable) MarshalIndent() ([]byte, error) { - return json.MarshalIndent(p, "", " ") -} - -func PrintTransaction(j Marshaler) { - b, err := j.MarshalIndent() - if err != nil { - panic(err) - } - fmt.Println(string(b)) -} diff --git a/pkg/print/print_test.go b/pkg/print/print_test.go deleted file mode 100644 index 3b479d8a..00000000 --- a/pkg/print/print_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package print - -import ( - "testing" - - "github.com/golang/mock/gomock" - "github.com/google/go-cmp/cmp" - mprint "github.com/systemaccounting/mxfactorial/pkg/print/mock_print" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -func TestNewPrintable(t *testing.T) { - tr := new(types.Transaction) - got := NewPrintable(tr) - want := Printable{} - if !cmp.Equal(got, want) { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestPrintTransaction(t *testing.T) { - ctrl := gomock.NewController(t) - m := mprint.NewMockMarshaler(ctrl) - m.EXPECT().MarshalIndent().Times(1) - PrintTransaction(m) -} diff --git a/pkg/service/account.go b/pkg/service/account.go deleted file mode 100644 index c8435664..00000000 --- a/pkg/service/account.go +++ /dev/null @@ -1,53 +0,0 @@ -package service - -import ( - "github.com/systemaccounting/mxfactorial/pkg/logger" - "github.com/systemaccounting/mxfactorial/pkg/postgres" -) - -type IAccountModel interface { - InsertAccount(string) error - DeleteOwnerAccount(string) error - DeleteAccount(string) error -} - -type AccountService struct { - m IAccountModel -} - -func (a AccountService) CreateAccount(accountName string) error { - - err := a.m.InsertAccount(accountName) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} -func (a AccountService) DeleteOwnerAccount(accountName string) error { - - err := a.m.DeleteOwnerAccount(accountName) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} -func (a AccountService) DeleteAccount(accountName string) error { - - err := a.m.DeleteAccount(accountName) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func NewAccountService(db SQLDB) *AccountService { - return &AccountService{ - m: postgres.NewAccountModel(db), - } -} diff --git a/pkg/service/approve.go b/pkg/service/approve.go deleted file mode 100644 index 1fd70cbe..00000000 --- a/pkg/service/approve.go +++ /dev/null @@ -1,119 +0,0 @@ -package service - -import ( - "context" - "log" - "os" - - "github.com/jackc/pgtype" - "github.com/systemaccounting/mxfactorial/pkg/logger" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -type ApproveService struct { - *TransactionService - *BalanceService - *TransactionNotificationService -} - -func (a ApproveService) Approve( - ctx context.Context, - authAccount string, // requester may be different from preApprovalTransaction.Author - approverRole types.Role, - preApprovalTransaction *types.Transaction, - notifyTopicArn string, -) (string, error) { - - err := a.BalanceService.TestDebitorCapacity(preApprovalTransaction.TransactionItems) - if err != nil { - logger.Log(logger.Trace(), err) - return "", err - } - - // fail approval when self payment - // detected in any transaction item - err = preApprovalTransaction.IsEachContraAccountUnique() - if err != nil { - logger.Log(logger.Trace(), err) - return "", err - } - - beginningApprovals, err := preApprovalTransaction.GetApprovals() - if err != nil { - logger.Log(logger.Trace(), err) - return "", err - } - - var equilibriumTime pgtype.Timestamptz - - // test for pending approvals to reduce db writes - err = beginningApprovals.TestPendingRoleApproval(authAccount, approverRole) - if err == nil { - - // add requester timestamps to approvals - equilibriumTime, err = a.TransactionService.AddApprovalTimesByAccountAndRole( - *preApprovalTransaction.ID, - authAccount, - approverRole, - ) - - if err != nil { - logger.Log(logger.Trace(), err) - return "", err - } - - } else { - - // avoid repeating approval when added by rule - log.Println(err) - } - - postApprovalTransaction, err := a.TransactionService.GetTransactionWithTrItemsAndApprovalsByID( - *preApprovalTransaction.ID, - ) - if err != nil { - logger.Log(logger.Trace(), err) - return "", err - } - - endingApprovals, err := postApprovalTransaction.GetApprovals() - if err != nil { - logger.Log(logger.Trace(), err) - return "", err - } - - // test for equilibrium - if !equilibriumTime.Time.IsZero() { - - // change account balances from transaction items - a.BalanceService.ChangeAccountBalances(preApprovalTransaction.TransactionItems) - - } - - if os.Getenv("ENABLE_NOTIFICATIONS") == "true" { - // notify role approvers - err = a.TransactionNotificationService.NotifyTransactionRoleApprovers( - endingApprovals, - postApprovalTransaction, - ¬ifyTopicArn, - ) - if err != nil { - logger.Log(logger.Trace(), err) - return "", err - } - } - - // create transaction for response to client - intraTr := postApprovalTransaction.CreateIntraTransaction(authAccount) - - // send string or error response to client - return intraTr.MarshalIntraTransaction() -} - -func NewApproveService(db SQLDB) *ApproveService { - return &ApproveService{ - TransactionService: NewTransactionService(db), - BalanceService: NewAccountBalanceService(db), - TransactionNotificationService: NewTransactionNotificationService(db), - } -} diff --git a/pkg/service/auth.go b/pkg/service/auth.go deleted file mode 100644 index 5e68a2b2..00000000 --- a/pkg/service/auth.go +++ /dev/null @@ -1,45 +0,0 @@ -package service - -import ( - "fmt" - "os" - - cidp "github.com/systemaccounting/mxfactorial/pkg/aws/cognitoidp" - "github.com/systemaccounting/mxfactorial/pkg/logger" -) - -type AuthService struct { - j cidp.ICognitoJwks -} - -func (a AuthService) AuthAccount( - t *cidp.JWToken, - tempAccount *string, -) (string, error) { - - if os.Getenv("ENABLE_API_AUTH") == "true" { // auth with cognito - - if t.Value == nil { - err := fmt.Errorf("error: token missing") - logger.Log(logger.Trace(), err) - return "", err - } - - return a.j.GetCognitoUser(t) - - } else { // or override with temp account - - if tempAccount == nil { - err := fmt.Errorf("error: temp account missing") - logger.Log(logger.Trace(), err) - return "", err - } - - return *tempAccount, nil - } - -} - -func NewAuthService(j *cidp.CognitoJwks) *AuthService { - return &AuthService{j} -} diff --git a/pkg/service/balance.go b/pkg/service/balance.go deleted file mode 100644 index 2676296c..00000000 --- a/pkg/service/balance.go +++ /dev/null @@ -1,140 +0,0 @@ -package service - -import ( - "fmt" - - "github.com/shopspring/decimal" - "github.com/systemaccounting/mxfactorial/pkg/logger" - "github.com/systemaccounting/mxfactorial/pkg/postgres" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -type IAccountBalanceModel interface { - GetAccountBalance(string) (*types.AccountBalance, error) -} - -type IAccountBalancesModel interface { - GetAccountBalances([]string) (types.AccountBalances, error) - ChangeAccountBalances(types.TransactionItems) error - // todo: move to AccountBalanceModel - InsertAccountBalance(string, decimal.Decimal, types.ID) error -} - -type BalanceService struct { - m IAccountBalanceModel - ms IAccountBalancesModel -} - -func (b BalanceService) GetAccountBalance(accountName string) (*types.AccountBalance, error) { - - ab, err := b.m.GetAccountBalance(accountName) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return ab, nil -} - -func (b BalanceService) GetAccountBalances(accountNames []string) (types.AccountBalances, error) { - - abs, err := b.ms.GetAccountBalances(accountNames) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return abs, nil -} - -func (b BalanceService) GetDebitorAccountBalances(trItems types.TransactionItems) (types.AccountBalances, error) { - - debitors := trItems.ListUniqueDebitorAccountsFromTrItems() - - debitorBalances, err := b.ms.GetAccountBalances(debitors) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return debitorBalances, nil -} - -func (b BalanceService) CreateAccountBalance( - accountName string, - accountBalance decimal.Decimal, - account types.ID, -) error { - - err := b.ms.InsertAccountBalance(accountName, accountBalance, account) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func (b BalanceService) ChangeAccountBalances(trItems types.TransactionItems) error { - - err := b.ms.ChangeAccountBalances(trItems) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func (b BalanceService) TestDebitorCapacity(trItems types.TransactionItems) error { - - debitorBalances, err := b.GetDebitorAccountBalances(trItems) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - // map required debitor funds from transaction items - requiredFunds := trItems.MapDebitorsToRequiredFunds() - - // loop through map of required debitor funds - for acct, reqd := range requiredFunds { - - // loop through account balances returned from db - for _, v := range debitorBalances { - - // match account balance belonging to debitor - if *v.AccountName == acct { - - // test debitor capacity - err := TestDebitorBalanceGreaterThanRequiredFunds(acct, reqd, v.CurrentBalance) - if err != nil { - return fmt.Errorf("BalanceSerice TestDebitorCapacity: %v", err) - } - } - } - } - - return nil -} - -func NewAccountBalanceService(db SQLDB) *BalanceService { - return &BalanceService{ - m: postgres.NewAccountBalanceModel(db), - ms: postgres.NewAccountBalancesModel(db), - } -} - -func TestDebitorBalanceGreaterThanRequiredFunds( - accountName string, - required decimal.Decimal, - currentDebitorBalance decimal.Decimal, -) error { - lessThanRequired := currentDebitorBalance.LessThan(required) - if lessThanRequired { - return fmt.Errorf( - "error: insufficient funds in debitor %v account", accountName, - ) - } - return nil -} diff --git a/pkg/service/create_account.go b/pkg/service/create_account.go deleted file mode 100644 index 7109b653..00000000 --- a/pkg/service/create_account.go +++ /dev/null @@ -1,92 +0,0 @@ -package service - -import ( - "github.com/shopspring/decimal" - "github.com/systemaccounting/mxfactorial/pkg/logger" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -type IAccountService interface { - CreateAccount(accountName string) error - DeleteOwnerAccount(accountName string) error - DeleteAccount(accountName string) error -} - -type IProfileService interface { - GetProfileIDsByAccountNames(accountNames []string) (types.AccountProfileIDs, error) - CreateAccountProfile(accountProfile *types.AccountProfile) error -} - -type IBalanceService interface { - GetAccountBalance(accountName string) (*types.AccountBalance, error) - GetAccountBalances(accountNames []string) (types.AccountBalances, error) - GetDebitorAccountBalances(trItems types.TransactionItems) (types.AccountBalances, error) - CreateAccountBalance(accountName string, accountBalance decimal.Decimal, account types.ID) error - ChangeAccountBalances(trItems types.TransactionItems) error - TestDebitorCapacity(trItems types.TransactionItems) error -} - -type IRuleInstanceService interface { - InsertApproveAllCreditRuleInstance(accountName string) error - SelectApproveAllCreditRuleInstance(accountName string) (*types.RuleInstance, error) - InsertApproveAllCreditRuleInstanceIfDoesNotExist(accountName string) error - AddRuleInstance(ruleType, ruleName, ruleInstanceName, accountRole, accountName, variableValuesArray string) error - GetRuleInstanceByCurrentlyUsedValues(ruleType, ruleName, ruleInstanceName, accountRole, accountName, variableValuesArray string) error -} - -type CreateAccountService struct { - a IAccountService - p IProfileService - b IBalanceService - ri IRuleInstanceService -} - -func (c CreateAccountService) CreateAccountFromCognitoTrigger( - accountProfile *types.AccountProfile, - beginningBalance decimal.Decimal, - currentTransactionItemID types.ID, -) error { - - // create account - err := c.a.CreateAccount(*accountProfile.AccountName) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - // create profile - err = c.p.CreateAccountProfile(accountProfile) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - // create initial account balance - err = c.b.CreateAccountBalance( - *accountProfile.AccountName, - beginningBalance, - currentTransactionItemID, - ) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - // insert approve all credit rule for account if does not exist - err = c.ri.InsertApproveAllCreditRuleInstanceIfDoesNotExist(*accountProfile.AccountName) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func NewCreateAccountService(db SQLDB) *CreateAccountService { - return &CreateAccountService{ - a: NewAccountService(db), - p: NewProfileService(db), - b: NewAccountBalanceService(db), - ri: NewRuleInstanceService(db), - } -} diff --git a/pkg/service/interfaces.go b/pkg/service/interfaces.go deleted file mode 100644 index bda27f68..00000000 --- a/pkg/service/interfaces.go +++ /dev/null @@ -1,17 +0,0 @@ -package service - -import ( - "context" - - "github.com/jackc/pgconn" - "github.com/jackc/pgx/v4" -) - -type SQLDB interface { - Query(context.Context, string, ...interface{}) (pgx.Rows, error) - QueryRow(context.Context, string, ...interface{}) pgx.Row - Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) - Begin(context.Context) (pgx.Tx, error) - Close(context.Context) error - IsClosed() bool -} diff --git a/pkg/service/notification.go b/pkg/service/notification.go deleted file mode 100644 index 907719e0..00000000 --- a/pkg/service/notification.go +++ /dev/null @@ -1,180 +0,0 @@ -package service - -import ( - "encoding/json" - "fmt" - - awssns "github.com/aws/aws-sdk-go/service/sns" - "github.com/jackc/pgtype" - "github.com/systemaccounting/mxfactorial/pkg/aws/sns" - "github.com/systemaccounting/mxfactorial/pkg/logger" - "github.com/systemaccounting/mxfactorial/pkg/postgres" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -type ITransactionNotificationModel interface { - InsertTransactionApprovalNotifications(types.TransactionNotifications) (types.IDs, error) - SelectTransNotifsByIDs(types.IDs) (types.TransactionNotifications, error) - SelectTransNotifsByAccount(string, int) (types.TransactionNotifications, error) - DeleteTransactionApprovalNotifications(types.ID) error - DeleteTransNotificationsByIDs(types.IDs) error -} - -type ISNS interface { - PublishMessage(*awssns.PublishInput) (*awssns.PublishOutput, error) -} - -type TransactionNotificationService struct { - m ITransactionNotificationModel - ISNS *sns.SNS -} - -func (tn TransactionNotificationService) InsertTransactionApprovalNotifications(n types.TransactionNotifications) (types.IDs, error) { - - notifIDs, err := tn.m.InsertTransactionApprovalNotifications(n) - if err != nil { - return nil, err - } - - return notifIDs, nil -} - -func (tn TransactionNotificationService) DeleteTransactionApprovalNotifications(trID types.ID) error { - - err := tn.m.DeleteTransactionApprovalNotifications(trID) - if err != nil { - return err - } - - return nil -} - -func (tn TransactionNotificationService) DeleteTransNotificationsByIDs(notifIDs types.IDs) error { - - err := tn.m.DeleteTransNotificationsByIDs(notifIDs) - if err != nil { - return err - } - - return nil -} - -func (tn TransactionNotificationService) Publish(notifIDs types.IDs, serviceName *string, topicArn *string) error { - - err := tn.ISNS.Publish(notifIDs, serviceName, topicArn) - if err != nil { - return err - } - - return nil -} - -func (tn TransactionNotificationService) NotifyTransactionRoleApprovers( - approvals types.Approvals, - transaction *types.Transaction, - topicArn *string, -) error { - - err := tn.m.DeleteTransactionApprovalNotifications(*transaction.ID) - if err != nil { - return err - } - - notifs, err := tn.CreateNotificationsPerRoleApprover(approvals, transaction) - if err != nil { - return err - } - - notifIDs, err := tn.InsertTransactionApprovalNotifications(notifs) - if err != nil { - return err - } - - err = tn.Publish( - notifIDs, - &sns.TRANSACT_SERVICE_NAME, - topicArn, - ) - if err != nil { - return err - } - - return nil -} - -func (tn TransactionNotificationService) GetTransactionNotificationsByIDs(notifIDs types.IDs) (types.TransactionNotifications, error) { - - notifs, err := tn.m.SelectTransNotifsByIDs(notifIDs) - if err != nil { - return nil, err - } - - return notifs, nil -} - -func (tn TransactionNotificationService) GetTransNotifsByAccount(accountName string, recordLimit int) (types.TransactionNotifications, error) { - - notifs, err := tn.m.SelectTransNotifsByAccount(accountName, recordLimit) - if err != nil { - return nil, err - } - - return notifs, nil -} - -func (tn *TransactionNotificationService) CreateNotificationsPerRoleApprover( - approvals types.Approvals, - transaction *types.Transaction, -) (types.TransactionNotifications, error) { - - // dedupe role approvers to send only 1 notification - // per approver role: someone shopping at their own store - // receives 1 debitor and 1 creditor approval - var uniqueRoleApprovers types.Approvals - for _, v := range approvals { - if isRoleApproverUnique(*v, uniqueRoleApprovers) { - uniqueRoleApprovers = append(uniqueRoleApprovers, v) - } - } - - // add transaction as notification message - pgMsg, err := json.Marshal(transaction) - if err != nil { - return nil, fmt.Errorf("%s: %v", logger.Trace(), err) - } - - jsonb := new(pgtype.JSONB) - jsonb.Set(pgMsg) - - // create transaction_notification per role approver - var notifs types.TransactionNotifications - for _, v := range uniqueRoleApprovers { - - n := &types.TransactionNotification{ - TransactionID: v.TransactionID, - AccountName: v.AccountName, - AccountRole: v.AccountRole, - Message: jsonb, - } - - notifs = append(notifs, n) - } - - return notifs, nil -} - -func isRoleApproverUnique(a types.Approval, l types.Approvals) bool { - for _, v := range l { - if *v.AccountName == *a.AccountName && *v.AccountRole == *a.AccountRole { - return false - } - } - return true -} - -func NewTransactionNotificationService(db SQLDB) *TransactionNotificationService { - return &TransactionNotificationService{ - m: postgres.NewTransactionNotificationModel(db), - ISNS: sns.NewSNS(), - } -} diff --git a/pkg/service/profile.go b/pkg/service/profile.go deleted file mode 100644 index f692f857..00000000 --- a/pkg/service/profile.go +++ /dev/null @@ -1,37 +0,0 @@ -package service - -import ( - "github.com/systemaccounting/mxfactorial/pkg/logger" - "github.com/systemaccounting/mxfactorial/pkg/postgres" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -type IAccountProfileModel interface { - GetProfileIDsByAccountNames([]string) (types.AccountProfileIDs, error) - InsertAccountProfile(*types.AccountProfile) error -} - -type ProfileService struct { - m IAccountProfileModel -} - -func (p ProfileService) GetProfileIDsByAccountNames(accountNames []string) (types.AccountProfileIDs, error) { - return p.m.GetProfileIDsByAccountNames(accountNames) -} - -func (p ProfileService) CreateAccountProfile(accountProfile *types.AccountProfile) error { - - err := p.m.InsertAccountProfile(accountProfile) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func NewProfileService(db SQLDB) *ProfileService { - return &ProfileService{ - m: postgres.NewAccountProfileModel(db), - } -} diff --git a/pkg/service/rule_instance.go b/pkg/service/rule_instance.go deleted file mode 100644 index 9d463a5b..00000000 --- a/pkg/service/rule_instance.go +++ /dev/null @@ -1,115 +0,0 @@ -package service - -import ( - "github.com/systemaccounting/mxfactorial/pkg/logger" - "github.com/systemaccounting/mxfactorial/pkg/postgres" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -type IRuleInstanceModel interface { - SelectRuleInstance(string, string, string, string, string, string) error - InsertRuleInstance(string, string, string, string, string, string) error - SelectApproveAllCreditRuleInstance(string) (*types.RuleInstance, error) - InsertApproveAllCreditRuleInstance(string) error - InsertApproveAllCreditRuleInstanceIfDoesNotExist(string) error -} - -type RuleInstanceService struct { - m IRuleInstanceModel -} - -func (ri RuleInstanceService) InsertApproveAllCreditRuleInstance( - accountName string, -) error { - - err := ri.m.InsertApproveAllCreditRuleInstance(accountName) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func (ri RuleInstanceService) SelectApproveAllCreditRuleInstance( - accountName string, -) (*types.RuleInstance, error) { - - ruleIn, err := ri.m.SelectApproveAllCreditRuleInstance(accountName) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return ruleIn, nil -} - -func (ri RuleInstanceService) InsertApproveAllCreditRuleInstanceIfDoesNotExist( - accountName string, -) error { - - err := ri.m.InsertApproveAllCreditRuleInstanceIfDoesNotExist(accountName) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func (ri RuleInstanceService) AddRuleInstance( - ruleType, - ruleName, - ruleInstanceName, - accountRole, - accountName, - variableValuesArray string, -) error { - - err := ri.m.InsertRuleInstance( - ruleType, - ruleName, - ruleInstanceName, - accountRole, - accountName, - variableValuesArray, - ) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -// complicated name intended -func (ri RuleInstanceService) GetRuleInstanceByCurrentlyUsedValues( - ruleType, - ruleName, - ruleInstanceName, - accountRole, - accountName, - variableValuesArray string, -) error { - - err := ri.m.SelectRuleInstance( - ruleType, - ruleName, - ruleInstanceName, - accountRole, - accountName, - variableValuesArray, - ) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func NewRuleInstanceService(db SQLDB) *RuleInstanceService { - return &RuleInstanceService{ - m: postgres.NewRuleInstanceModel(db), - } -} diff --git a/pkg/service/rules.go b/pkg/service/rules.go deleted file mode 100644 index 99f73fc4..00000000 --- a/pkg/service/rules.go +++ /dev/null @@ -1,49 +0,0 @@ -package service - -import ( - "encoding/json" - - "github.com/systemaccounting/mxfactorial/pkg/httpclient" - "github.com/systemaccounting/mxfactorial/pkg/logger" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -type IHttpClient interface { - Post([]byte) ([]byte, error) -} - -type RulesService struct { - Client IHttpClient -} - -func (r RulesService) GetRuleAppliedIntraTransactionFromTrItems(trItems types.TransactionItems) (*types.IntraTransaction, error) { - - b, err := json.Marshal(trItems) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - response, err := r.Client.Post(b) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - var ruleTested types.IntraTransaction - - err = ruleTested.Unmarshal(response) - - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return &ruleTested, nil -} - -func NewRulesService(url string) *RulesService { - return &RulesService{ - Client: httpclient.NewHttpClient(url), - } -} diff --git a/pkg/service/transaction.go b/pkg/service/transaction.go deleted file mode 100644 index 9055b84f..00000000 --- a/pkg/service/transaction.go +++ /dev/null @@ -1,307 +0,0 @@ -package service - -import ( - "github.com/jackc/pgtype" - "github.com/systemaccounting/mxfactorial/pkg/logger" - "github.com/systemaccounting/mxfactorial/pkg/postgres" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -type ITransactionModel interface { - GetTransactionByID(types.ID) (*types.Transaction, error) - InsertTransactionTx(*types.Transaction) (*types.ID, error) -} - -type ITransactionsModel interface { - GetLastNTransactions(string, string) (types.Transactions, error) - GetLastNRequests(string, string) (types.Transactions, error) - GetTransactionsByIDs(types.IDs) (types.Transactions, error) -} - -type ITransactionItemsModel interface { - GetTrItemsByTransactionID(types.ID) (types.TransactionItems, error) - GetTrItemsByTrIDs(types.IDs) (types.TransactionItems, error) -} - -type IApprovalsModel interface { - GetApprovalsByTransactionID(types.ID) (types.Approvals, error) - GetApprovalsByTransactionIDs(types.IDs) (types.Approvals, error) - UpdateApprovalsByAccountAndRole(types.ID, string, types.Role) (pgtype.Timestamptz, error) -} - -type TransactionService struct { - tm ITransactionModel - tsm ITransactionsModel - tim ITransactionItemsModel - am IApprovalsModel -} - -func (t TransactionService) GetTransactionByID(ID types.ID) (*types.Transaction, error) { - - tr, err := t.tm.GetTransactionByID(ID) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return tr, nil -} - -func (t TransactionService) InsertTransactionTx( - ruleTestedTransaction *types.Transaction, -) (*types.ID, error) { - - trID, err := t.tm.InsertTransactionTx(ruleTestedTransaction) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return trID, nil -} - -// todo: convert to postgres function to avoid 3 db queries -func (t TransactionService) GetTransactionWithTrItemsAndApprovalsByID(trID types.ID) (*types.Transaction, error) { - - // get the transaction - tr, err := t.tm.GetTransactionByID(trID) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // get the transaction items - trItems, err := t.tim.GetTrItemsByTransactionID(trID) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // get the approvals - approvals, err := t.am.GetApprovalsByTransactionID(trID) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // return the transaction with the - // transaction items and approvals attached - return BuildTransaction(tr, trItems, approvals), nil -} - -// todo: convert to postgres function to avoid 3 db queries -func (t TransactionService) GetTransactionsWithTrItemsAndApprovalsByID(trIDs types.IDs) (types.Transactions, error) { - - // get the transactions - trs, err := t.tsm.GetTransactionsByIDs(trIDs) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // get the transaction items - trItems, err := t.tim.GetTrItemsByTrIDs(trIDs) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // get the approvals - approvals, err := t.am.GetApprovalsByTransactionIDs(trIDs) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - // return the transaction with the transaction items and approvals attached - return BuildTransactions(trs, trItems, approvals), nil -} - -func (t TransactionService) GetLastNTransactions( - accountName string, - recordLimit string, -) (types.Transactions, error) { - - trs, err := t.tsm.GetLastNTransactions(accountName, recordLimit) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - trIDs := trs.ListIDs() - - if len(trIDs) == 0 { - return BuildTransactions(types.Transactions{}, types.TransactionItems{}, types.Approvals{}), nil - } - - trItems, approvals, err := t.GetTrItemsAndApprovalsByTransactionIDs(trIDs) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return BuildTransactions(trs, trItems, approvals), nil -} - -func (t TransactionService) GetLastNRequests( - accountName string, - recordLimit string, -) (types.Transactions, error) { - - requests, err := t.tsm.GetLastNRequests(accountName, recordLimit) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - trIDs := requests.ListIDs() - - trItems, approvals, err := t.GetTrItemsAndApprovalsByTransactionIDs(trIDs) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return BuildTransactions(requests, trItems, approvals), nil -} - -func (t TransactionService) GetTrItemsAndApprovalsByTransactionIDs(trIDs types.IDs) (types.TransactionItems, types.Approvals, error) { - - trItems, err := t.tim.GetTrItemsByTrIDs(trIDs) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, nil, err - } - - approvals, err := t.GetApprovalsByTransactionIDs(trIDs) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, nil, err - } - - return trItems, approvals, nil -} - -func (t TransactionService) GetTrItemsByTransactionID(ID types.ID) (types.TransactionItems, error) { - - trItems, err := t.tim.GetTrItemsByTransactionID(ID) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return trItems, nil -} - -func (t TransactionService) GetTrItemsByTrIDs(IDs types.IDs) (types.TransactionItems, error) { - - trItems, err := t.tim.GetTrItemsByTrIDs(IDs) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return trItems, nil -} - -func (t TransactionService) GetApprovalsByTransactionID(ID types.ID) (types.Approvals, error) { - - approvals, err := t.am.GetApprovalsByTransactionID(ID) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return approvals, nil -} - -func (t TransactionService) GetApprovalsByTransactionIDs(IDs types.IDs) (types.Approvals, error) { - - approvals, err := t.am.GetApprovalsByTransactionIDs(IDs) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return approvals, nil -} - -func (t TransactionService) AddApprovalTimesByAccountAndRole( - trID types.ID, - accountName string, - accountRole types.Role, -) (pgtype.Timestamptz, error) { - - equilibriumTime, err := t.am.UpdateApprovalsByAccountAndRole(trID, accountName, accountRole) - if err != nil { - logger.Log(logger.Trace(), err) - return pgtype.Timestamptz{}, err - } - - return equilibriumTime, nil -} - -func NewTransactionService(db SQLDB) *TransactionService { - return &TransactionService{ - tm: postgres.NewTransactionModel(db), - tsm: postgres.NewTransactionsModel(db), - tim: postgres.NewTransactionItemsModel(db), - am: postgres.NewApprovalsModel(db), - } -} - -func BuildTransactions( - trs types.Transactions, - trItems types.TransactionItems, - apprvs types.Approvals, -) types.Transactions { - - for _, v := range trs { - BuildTransaction(v, trItems, apprvs) - } - - return trs - -} - -func BuildTransaction( - tr *types.Transaction, - trItems types.TransactionItems, - apprvs types.Approvals, -) *types.Transaction { - - // attach transaction items to transaction - AttachTransactionItemsToTransaction(trItems, tr) - - // attach approvals to transaction items - AttachApprovalsToTransactionItems(apprvs, trItems) - - return tr -} - -func AttachApprovalsToTransactionItems( - apprvs types.Approvals, - trItems types.TransactionItems, -) { - - for _, ti := range trItems { - for _, ap := range apprvs { - if *ap.TransactionItemID == *ti.ID { - ti.Approvals = append(ti.Approvals, ap) - } - } - } -} - -// used when filtering transaction items belonging to multiple transactions -func AttachTransactionItemsToTransaction( - trItems types.TransactionItems, - tr *types.Transaction, -) { - - for _, ti := range trItems { - if *ti.TransactionID == *tr.ID { - tr.TransactionItems = append(tr.TransactionItems, ti) - } - } -} diff --git a/pkg/service/websocket.go b/pkg/service/websocket.go deleted file mode 100644 index a16dff56..00000000 --- a/pkg/service/websocket.go +++ /dev/null @@ -1,310 +0,0 @@ -package service - -import ( - "fmt" - "log" - - "github.com/systemaccounting/mxfactorial/pkg/aws/apigwma" - "github.com/systemaccounting/mxfactorial/pkg/logger" - "github.com/systemaccounting/mxfactorial/pkg/postgres" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -type IWebsocketsModel interface { - UpdateWebsocketByConnID(accountName, connectionID string) error - InsertWebsocketConnection(epochCreatedAt int64, connectionID string) error - DeleteWebsocketConnection(connectionID string) error - DeleteWebsocketsByConnectionIDs(connectionIDs []string) error - SelectWebsocketsByAccounts(accounts []string) (types.Websockets, error) -} - -type IApiGatewayMgmtAPIService interface { - PostToConnection(*string, any) error -} - -type WebsocketService struct { - WebsocketStorageService - WebsocketNotificationService -} - -type IWebsocketStorageService interface { - AddAccountToCurrentWebsocket(accountName, connectionID string) error - AddWebsocketConnection(epochCreatedAt int64, connectionID string) error - DeleteWebsocketConnection(connectionID string) error - GetWebsocketsByAccounts(accounts []string) (types.Websockets, error) - DeleteWebsocketsByConnectionIDs(connectionIDs []string) error -} - -type WebsocketStorageService struct { - m IWebsocketsModel -} - -type IWebsocketNotificationService interface { - SendNotificationToWebsocket(connectionID *string, v any) error -} - -type WebsocketNotificationService struct { - a IApiGatewayMgmtAPIService -} - -// account names not added to websocket connection records on connect -// workaround: each lambda updates current websocket record with account value - -// adding account values to all connection id records supports notification -// broadcast (send notifications to all connection ids owned by current account) - -func (w WebsocketStorageService) AddAccountToCurrentWebsocket(accountName, connectionID string) error { - - err := w.m.UpdateWebsocketByConnID(accountName, connectionID) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func (w WebsocketStorageService) AddWebsocketConnection(epochCreatedAt int64, connectionID string) error { - - err := w.m.InsertWebsocketConnection(epochCreatedAt, connectionID) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func (w WebsocketStorageService) DeleteWebsocketConnection(connectionID string) error { - - err := w.m.DeleteWebsocketConnection(connectionID) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func (w WebsocketStorageService) GetWebsocketsByAccounts(accounts []string) (types.Websockets, error) { - - ws, err := w.m.SelectWebsocketsByAccounts(accounts) - if err != nil { - logger.Log(logger.Trace(), err) - return nil, err - } - - return ws, nil -} - -func (w WebsocketStorageService) DeleteWebsocketsByConnectionIDs(connectionIDs []string) error { - - err := w.m.DeleteWebsocketsByConnectionIDs(connectionIDs) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func (w WebsocketNotificationService) SendNotificationToWebsocket(connectionID *string, v any) error { - - err := w.a.PostToConnection(connectionID, v) - if err != nil { - - if err.Error() == apigwma.ErrCodeGoneException { - - // return error without logging on GoneException - return err - - } else { - - // log and return other error - logger.Log(logger.Trace(), err) - return err - } - } - - return nil -} - -func (w WebsocketService) SendNotificationOrDeleteStaleWebsocket(connectionID *string, v any) error { - - err := w.SendNotificationToWebsocket(connectionID, v) - if err != nil { - if err.Error() == apigwma.ErrCodeGoneException { - - // delete websocket connection id on GoneException - err := w.m.DeleteWebsocketConnection(*connectionID) - if err != nil { - - // log failure to delete websocket connection id - logger.Log(logger.Trace(), fmt.Errorf("DeleteWebsocketConnection: %v", err)) - return err - } - - // log deleted stale websocket - log.Printf("deleted stale websococket %v", connectionID) - - return nil - - } else { - - // log and return other error - logger.Log(logger.Trace(), err) - return err - } - - } - - return nil -} - -func (w WebsocketService) BroadcastNotificationsToWebsockets( - transNotifs types.TransactionNotifications, -) ([]string, error) { - - // list accounts receiving notifications - wssAccounts := getAccountsFromNotifications(transNotifs) - - // list websockets for accounts - websockets, err := w.GetWebsocketsByAccounts(wssAccounts) - if err != nil { - logger.Log(logger.Trace(), err) - } - - // attach websockets for accounts receiving notifications - recipientsWithWebsockets := attachWebsocketsPerRecipient( - transNotifs, - websockets, - ) - - // list stale websockets to delete later in single query - var staleWebsocketsToDelete []string - - for _, r := range recipientsWithWebsockets { - for _, ws := range r.Websockets { - - // create notification payload - payload := &types.PendingNotifications{ - Pending: []*types.Message{ - { - NotificationID: r.Notification.ID, - Message: *r.Notification.Message, - }, - }, - } - - // send notification to websocket - err = w.SendNotificationToWebsocket(ws.ConnectionID, payload) - if err != nil { - - // test for GoneException - if err.Error() == apigwma.ErrCodeGoneException { - - // list unique stale websocket to delete - if isStringUnique(*ws.ConnectionID, staleWebsocketsToDelete) { - staleWebsocketsToDelete = append(staleWebsocketsToDelete, *ws.ConnectionID) - } - - } else { - - // just log while continuing to - // send notifications, dont exit - logger.Log(logger.Trace(), err) - } - - } - } - } - - return staleWebsocketsToDelete, nil -} - -func (w WebsocketService) BroadcastNotificationsOrDeleteStaleWebsockets( - transNotifs types.TransactionNotifications, -) error { - - staleWebsocketsToDelete, err := w.BroadcastNotificationsToWebsockets(transNotifs) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - // delete stale websockets - if len(staleWebsocketsToDelete) > 0 { - err = w.m.DeleteWebsocketsByConnectionIDs(staleWebsocketsToDelete) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - } - - return nil - -} - -func isStringUnique(s string, l []string) bool { - for _, v := range l { - if v == s { - return false - } - } - return true -} - -func getAccountsFromNotifications(transNotifs types.TransactionNotifications) []string { - var wssAccounts []string - for _, v := range transNotifs { - wssAccounts = append(wssAccounts, *v.AccountName) - } - return wssAccounts -} - -func attachWebsocketsPerRecipient( - transNotifs types.TransactionNotifications, - websockets types.Websockets, -) []*types.NotificationAndWebsockets { - - var recipientsWithWebsockets []*types.NotificationAndWebsockets - for _, y := range transNotifs { - - wss := &types.NotificationAndWebsockets{ - Notification: y, - } - - for _, z := range websockets { - if *z.AccountName == *y.AccountName { - wss.Websockets = append(wss.Websockets, z) - } - } - - recipientsWithWebsockets = append(recipientsWithWebsockets, wss) - } - - return recipientsWithWebsockets -} - -func NewWebsocketStorageService(db SQLDB) *WebsocketStorageService { - return &WebsocketStorageService{ - m: postgres.NewWebsocketsModel(db), - } -} - -func NewWebsocketNotificationService(apiGWConnectionsURI, awsRegion *string) *WebsocketNotificationService { - return &WebsocketNotificationService{ - a: apigwma.NewApiGatewayMgmtAPIService(apiGWConnectionsURI, awsRegion), - } -} - -func NewWebsocketService(db SQLDB, apiGWConnectionsURI, awsRegion *string) *WebsocketService { - return &WebsocketService{ - WebsocketStorageService{ - m: postgres.NewWebsocketsModel(db), - }, - WebsocketNotificationService{ - a: apigwma.NewApiGatewayMgmtAPIService(apiGWConnectionsURI, awsRegion), - }, - } -} diff --git a/pkg/sqls/account.go b/pkg/sqls/account.go deleted file mode 100644 index a622a0dc..00000000 --- a/pkg/sqls/account.go +++ /dev/null @@ -1,40 +0,0 @@ -package sqls - -import "github.com/huandu/go-sqlbuilder" - -type AccountSQLs struct { - SQLBuilder -} - -func (a *AccountSQLs) InsertAccountSQL(account string) (string, []interface{}) { - a.Init() - a.ib.InsertInto("account") - a.ib.Cols("name") - a.ib.Values(account) - // format with ib arg only to avoid: - // can't scan into dest[0]: unable to assign to *int32 - ret := sqlbuilder.Buildf("%v ON CONFLICT (name) DO NOTHING", a.ib) - return sqlbuilder.WithFlavor(ret, sqlbuilder.PostgreSQL).Build() -} - -func (a *AccountSQLs) DeleteOwnerAccountSQL(account string) (string, []interface{}) { - a.Init() - a.db.DeleteFrom("account_owner") - a.db.Where( - a.db.Equal("owner_account", account), - ) - return a.db.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func (a *AccountSQLs) DeleteAccountSQL(account string) (string, []interface{}) { - a.Init() - a.db.DeleteFrom("account") - a.db.Where( - a.db.Equal("name", account), - ) - return a.db.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func NewAccountSQLs() *AccountSQLs { - return new(AccountSQLs) -} diff --git a/pkg/sqls/account_test.go b/pkg/sqls/account_test.go deleted file mode 100644 index c00b6312..00000000 --- a/pkg/sqls/account_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package sqls - -import ( - "testing" - - "github.com/google/go-cmp/cmp" -) - -func TestInsertAccountSQL(t *testing.T) { - testsqlb := AccountSQLs{} - testaccount := "test" - got1, got2 := testsqlb.InsertAccountSQL(testaccount) - want1 := "INSERT INTO account (name) VALUES ($1) ON CONFLICT (name) DO NOTHING" - want2 := []interface{}{testaccount} - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestDeleteOwnerAccountSQL(t *testing.T) { - testsqlb := AccountSQLs{} - testaccount := "test" - got1, got2 := testsqlb.DeleteOwnerAccountSQL(testaccount) - want1 := "DELETE FROM account_owner WHERE owner_account = $1" - want2 := []interface{}{testaccount} - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestDeleteAccountSQL(t *testing.T) { - testsqlb := AccountSQLs{} - testaccount := "test" - got1, got2 := testsqlb.DeleteAccountSQL(testaccount) - want1 := "DELETE FROM account WHERE name = $1" - want2 := []interface{}{testaccount} - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} diff --git a/pkg/sqls/approval.go b/pkg/sqls/approval.go deleted file mode 100644 index b4df4795..00000000 --- a/pkg/sqls/approval.go +++ /dev/null @@ -1,75 +0,0 @@ -package sqls - -import ( - "github.com/huandu/go-sqlbuilder" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -type ApprovalSQLs struct { - SQLBuilder -} - -func (a *ApprovalSQLs) InsertApprovalsSQL( - approvals types.Approvals, - transactionAuxStmt, - trItemAuxStatement sqlbuilder.Builder, -) sqlbuilder.Builder { - a.Init() - a.ib.InsertInto("approval") - a.ib.Cols( - "rule_instance_id", - "transaction_id", - "transaction_item_id", - "account_name", - "account_role", - "device_id", - "device_latlng", - "approval_time", - "expiration_time", - ) - - for _, ap := range approvals { - a.ib.Values( - ap.RuleInstanceID, - sqlbuilder.Buildf("(%v)", transactionAuxStmt), - sqlbuilder.Buildf("(%v)", trItemAuxStatement), - ap.AccountName, - ap.AccountRole, - ap.DeviceID, - ap.DeviceLatlng, - ap.ApprovalTime, - ap.ExpirationTime, - ) - } - - return sqlbuilder.WithFlavor(a.ib, sqlbuilder.PostgreSQL) -} - -func (a *ApprovalSQLs) SelectApprovalsByTrIDSQL(trID types.ID) (string, []interface{}) { - a.Init() - a.sb.Select("*") - a.sb.From("approval"). - Where( - a.sb.Equal("transaction_id", trID), - ) - return a.sb.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func (a *ApprovalSQLs) SelectApprovalsByTrIDsSQL(trIDs types.IDs) (string, []interface{}) { - a.Init() - - // sqlbuilder wants interface slice - iIDs := IDtoInterfaceSlice(trIDs) - - a.sb.Select("*") - a.sb.From("approval"). - Where( - a.sb.In("transaction_id", iIDs...), - ) - - return a.sb.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func NewApprovalSQLs() *ApprovalSQLs { - return new(ApprovalSQLs) -} diff --git a/pkg/sqls/approval_test.go b/pkg/sqls/approval_test.go deleted file mode 100644 index 3da4eb18..00000000 --- a/pkg/sqls/approval_test.go +++ /dev/null @@ -1,100 +0,0 @@ -package sqls - -import ( - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/systemaccounting/mxfactorial/pkg/testdata" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -func TestInsertApprovalsSQL(t *testing.T) { - - testtransaction := testdata.GetTestTransaction("../testdata/transWTimes.json") - testapprovals := testtransaction.TransactionItems[0].Approvals - - testwithsql := WithSQLs{} - testtrauxstmtbuilder := testwithsql.SelectIDFromInsertTransactionCTEAuxStmt() - - testtranssql := TransactionSQLs{} - trItemAliasName := testtranssql.buildAuxStmtName(trItemAliasPrefix, 1) - - trItemAliasBuilder := testwithsql.SelectIDFromTrItemAliasCTEAuxStmt(trItemAliasName) - - testbuilder := ApprovalSQLs{} - got1, testparams := testbuilder.InsertApprovalsSQL( - testapprovals, - testtrauxstmtbuilder, - trItemAliasBuilder, - ).Build() - - want1 := "INSERT INTO approval (rule_instance_id, transaction_id, transaction_item_id, account_name, account_role, device_id, device_latlng, approval_time, expiration_time) VALUES ($1, (SELECT id FROM insert_transaction), (SELECT id FROM i_1), $2, $3, $4, $5, $6, $7), ($8, (SELECT id FROM insert_transaction), (SELECT id FROM i_1), $9, $10, $11, $12, $13, $14), ($15, (SELECT id FROM insert_transaction), (SELECT id FROM i_1), $16, $17, $18, $19, $20, $21)" - - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - - // count approvals - testapprovalcount := len(testapprovals) - - if len(testparams)%testapprovalcount != 0 { - t.Errorf("error: testparams not evenly divided by testapprovals") - } - - // divide testparams per testapprovals entry since its - // a flattened list of values from multiple approvals - testparamscount := len(testparams) / testapprovalcount - - // assert per testapproval - for i, v := range testapprovals { - - want := []interface{}{ - v.RuleInstanceID, - v.AccountName, - v.AccountRole, - v.DeviceID, - v.DeviceLatlng, - v.ApprovalTime, - v.ExpirationTime, - } - - start := i * testparamscount - end := i*testparamscount + testparamscount - - got := testparams[start:end] - - if !cmp.Equal(got, want) { - t.Errorf("got %v, want %v", got, want) - } - } -} - -func TestSelectApprovalsByTrIDSQL(t *testing.T) { - testid := types.ID("1") - testbuilder := ApprovalSQLs{} - want1 := "SELECT * FROM approval WHERE transaction_id = $1" - want2 := []interface{}{testid} - got1, got2 := testbuilder.SelectApprovalsByTrIDSQL(testid) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestSelectApprovalsByTrIDsSQL(t *testing.T) { - testid1 := types.ID("1") - testid2 := types.ID("2") - testids := types.IDs{&testid1, &testid2} - testbuilder := ApprovalSQLs{} - want1 := "SELECT * FROM approval WHERE transaction_id IN ($1, $2)" - want2 := []interface{}{&testid1, &testid2} - got1, got2 := testbuilder.SelectApprovalsByTrIDsSQL(testids) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} diff --git a/pkg/sqls/balance.go b/pkg/sqls/balance.go deleted file mode 100644 index 9d78b06b..00000000 --- a/pkg/sqls/balance.go +++ /dev/null @@ -1,155 +0,0 @@ -package sqls - -import ( - "fmt" - "strings" - - "github.com/huandu/go-sqlbuilder" - "github.com/shopspring/decimal" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -type AccountBalanceSQLs struct { - SQLBuilder -} - -func (ab *AccountBalanceSQLs) SelectAccountBalancesSQL( - accountNames []string, -) (string, []interface{}) { - ab.Init() - - // sqlbuilder wants interface slice - accts := stringToInterfaceSlice(accountNames) - - ab.sb.Select( - "account_name", - "current_balance", - ) - - ab.sb.From("account_balance"). - Where( - ab.sb.In("account_name", accts...), - ) - - return ab.sb.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func (ab *AccountBalanceSQLs) SelectCurrentAccountBalanceByAccountNameSQL( - accountName string, -) (string, []interface{}) { - ab.Init() - - ab.sb.Select("current_balance") - ab.sb.From("account_balance"). - Where( - ab.sb.Equal("account_name", accountName), - ) - - return ab.sb.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func (ab *AccountBalanceSQLs) InsertAccountBalanceSQL( - accountName string, - accountBalance decimal.Decimal, - account types.ID, -) (string, []interface{}) { - ab.Init() - ab.ib.InsertInto("account_balance") - ab.ib.Cols( - "account_name", - "current_balance", - "current_transaction_item_id", - ) - ab.ib.Values(accountName, accountBalance, account) - return ab.ib.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func (ab *AccountBalanceSQLs) UpdateDebitorAccountBalanceSQL(trItem *types.TransactionItem) (string, []interface{}) { - ab.Init() - ab.ub.Update("account_balance"). - Set( - ab.ub.Assign("current_balance", trItem.Price.Mul(trItem.Quantity).Neg()), - ab.ub.Assign("current_transaction_item_id", trItem.ID), - ). - Where( - ab.ub.Equal("account_name", *trItem.Debitor), - ) - return ab.ub.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func (ab *AccountBalanceSQLs) UpdateCreditorAccountBalanceSQL(trItem *types.TransactionItem) (string, []interface{}) { - ab.Init() - ab.ub.Update("account_balance"). - Set( - ab.ub.Assign("current_balance", trItem.Price.Mul(trItem.Quantity)), - ab.ub.Assign("current_transaction_item_id", trItem.ID), - ). - Where( - ab.ub.Equal("account_name", *trItem.Creditor), - ) - return ab.ub.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -// creates sql for plpgsql function accepting -// variadic "balance_change" composite type parameter -// in migrations/schema/000008_account_balance.up.sql -// e.g. SELECT change_account_balances('(PaulClayton, -10, 8)', '(CharlesPike, -10, 8)', '(JoseGarcia, 20, 8)'); -// *exclude single quotes in go -> postgres -func (AccountBalanceSQLs) UpdateAccountBalancesSQL(trItems types.TransactionItems) (string, []interface{}) { - - updSQL := `SELECT change_account_balances(` - args := []interface{}{} - paramCount := 1 - - for _, v := range trItems { - // begin creditor composite literal - updSQL += `(` - // add creditor account name to sql args - args = append(args, *v.Creditor) - // add positional parameter for creditor account name to sql - updSQL += fmt.Sprintf("$%d", paramCount) - // increment param counter - paramCount++ - // comma delimeter in composite literal - updSQL += `, ` - // add revenue earned by creditor to sql args - args = append(args, v.Price.Mul(v.Quantity)) - // add positional parameter for revenue earned by creditor - updSQL += fmt.Sprintf("$%d", paramCount) - // increment param counter - paramCount++ - // comma delim in composite literal - updSQL += `, ` - // add transaction_item.id to sql args - args = append(args, string(*v.ID)) - // add positional param for transaction_item.id - updSQL += fmt.Sprintf("$%d", paramCount) - // increment param counter - paramCount++ - // end creditor composite literal - updSQL += `), ` - // begin debitor composite literal - updSQL += `(` - args = append(args, *v.Debitor) - updSQL += fmt.Sprintf("$%d", paramCount) - paramCount++ - updSQL += `, ` - args = append(args, v.Price.Mul(v.Quantity).Neg()) - updSQL += fmt.Sprintf("$%d", paramCount) - paramCount++ - updSQL += `, ` - args = append(args, string(*v.ID)) - updSQL += fmt.Sprintf("$%d", paramCount) - paramCount++ - updSQL += `), ` - } - - updSQL = strings.TrimSuffix(updSQL, `, `) - updSQL += `)` - - return updSQL, args -} - -func NewAccountBalanceSQLs() *AccountBalanceSQLs { - return new(AccountBalanceSQLs) -} diff --git a/pkg/sqls/balance_test.go b/pkg/sqls/balance_test.go deleted file mode 100644 index 72848c27..00000000 --- a/pkg/sqls/balance_test.go +++ /dev/null @@ -1,137 +0,0 @@ -package sqls - -import ( - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/shopspring/decimal" - "github.com/systemaccounting/mxfactorial/pkg/testdata" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -func TestSelectAccountBalancesSQL(t *testing.T) { - testacct1 := "testacct1" - testacct2 := "testacct2" - testaccts := []string{testacct1, testacct2} - testbuilder := AccountBalanceSQLs{} - want1 := "SELECT account_name, current_balance FROM account_balance WHERE account_name IN ($1, $2)" - want2 := []interface{}{testacct1, testacct2} - got1, got2 := testbuilder.SelectAccountBalancesSQL(testaccts) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestSelectCurrentAccountBalanceByAccountNameSQL(t *testing.T) { - testacct := "testacct" - testbuilder := AccountBalanceSQLs{} - want1 := "SELECT current_balance FROM account_balance WHERE account_name = $1" - want2 := []interface{}{testacct} - got1, got2 := testbuilder.SelectCurrentAccountBalanceByAccountNameSQL(testacct) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestInsertAccountBalanceSQL(t *testing.T) { - testacct := "testacct" - testbalance := decimal.Decimal{} - testacctid := types.ID("1") - testbuilder := AccountBalanceSQLs{} - want1 := "INSERT INTO account_balance (account_name, current_balance, current_transaction_item_id) VALUES ($1, $2, $3)" - want2 := []interface{}{testacct, testbalance, testacctid} - got1, got2 := testbuilder.InsertAccountBalanceSQL(testacct, testbalance, testacctid) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestUpdateDebitorAccountBalanceSQL(t *testing.T) { - - testtransaction := testdata.GetTestTransaction("../testdata/transWTimes.json") - testtritem := testtransaction.TransactionItems[0] - - want1 := "UPDATE account_balance SET current_balance = $1, current_transaction_item_id = $2 WHERE account_name = $3" - - want2Price := testtritem.Price.Mul(testtritem.Quantity).Neg() - want2TrItID := testtritem.ID - want2Debitor := *testtritem.Debitor - want2 := []interface{}{want2Price, want2TrItID, want2Debitor} - - testbuilder := AccountBalanceSQLs{} - - got1, got2 := testbuilder.UpdateDebitorAccountBalanceSQL(testtritem) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestUpdateCreditorAccountBalanceSQL(t *testing.T) { - - testtransaction := testdata.GetTestTransaction("../testdata/transWTimes.json") - testtritem := testtransaction.TransactionItems[0] - - want1 := "UPDATE account_balance SET current_balance = $1, current_transaction_item_id = $2 WHERE account_name = $3" - - want2Price := testtritem.Price.Mul(testtritem.Quantity) - want2TrItID := testtritem.ID - want2Creditor := *testtritem.Creditor - want2 := []interface{}{want2Price, want2TrItID, want2Creditor} - - testbuilder := AccountBalanceSQLs{} - - got1, got2 := testbuilder.UpdateCreditorAccountBalanceSQL(testtritem) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestUpdateAccountBalancesSQL(t *testing.T) { - - testtransaction := testdata.GetTestTransaction("../testdata/transWTimes.json") - testtritems := testtransaction.TransactionItems - - want1 := "SELECT change_account_balances(($1, $2, $3), ($4, $5, $6), ($7, $8, $9), ($10, $11, $12), ($13, $14, $15), ($16, $17, $18), ($19, $20, $21), ($22, $23, $24), ($25, $26, $27), ($28, $29, $30), ($31, $32, $33), ($34, $35, $36))" - - testbuilder := AccountBalanceSQLs{} - got1, got2 := testbuilder.UpdateAccountBalancesSQL(testtritems) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - - // build flattened list of sql params in - // want2 before asserting flattened got2 - want2 := []interface{}{} - - for _, v := range testtritems { - - want2 = append(want2, - *v.Creditor, - v.Price.Mul(v.Quantity), - string(*v.ID), - *v.Debitor, - v.Price.Mul(v.Quantity).Neg(), - string(*v.ID)) - } - - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} diff --git a/pkg/sqls/constructor_test.go b/pkg/sqls/constructor_test.go deleted file mode 100644 index 5478f9fc..00000000 --- a/pkg/sqls/constructor_test.go +++ /dev/null @@ -1,73 +0,0 @@ -package sqls - -import ( - "fmt" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -func TestInit(t *testing.T) { - testbuilder := SQLBuilder{} - testbuilder.Init() - - // test select builder field - if testbuilder.sb == nil { - t.Errorf("got nil, want value") - } - got1 := fmt.Sprintf("%T", testbuilder.sb) - want1 := "*sqlbuilder.SelectBuilder" - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - - // test insert builder field - if testbuilder.ib == nil { - t.Errorf("got nil, want value") - } - got2 := fmt.Sprintf("%T", testbuilder.ib) - want2 := "*sqlbuilder.InsertBuilder" - if got2 != want2 { - t.Errorf("got %v, want %v", got2, want2) - } - - // test update builder field - if testbuilder.ub == nil { - t.Errorf("got nil, want value") - } - got3 := fmt.Sprintf("%T", testbuilder.ub) - want3 := "*sqlbuilder.UpdateBuilder" - if got3 != want3 { - t.Errorf("got %v, want %v", got3, want3) - } - - // test delete builder field - if testbuilder.db == nil { - t.Errorf("got nil, want value") - } - got4 := fmt.Sprintf("%T", testbuilder.db) - want4 := "*sqlbuilder.DeleteBuilder" - if got4 != want4 { - t.Errorf("got %v, want %v", got4, want4) - } -} - -func TestStringToInterfaceSlice(t *testing.T) { - teststringslice := []string{"test"} - want := []interface{}{"test"} - got := stringToInterfaceSlice(teststringslice) - if !cmp.Equal(got, want) { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestIDtoInterfaceSlice(t *testing.T) { - testid := types.ID("1") - testids := types.IDs{&testid} - want := []interface{}{&testid} - got := IDtoInterfaceSlice(testids) - if !cmp.Equal(got, want) { - t.Errorf("got %v, want %v", got, want) - } -} diff --git a/pkg/sqls/contructor.go b/pkg/sqls/contructor.go deleted file mode 100644 index 53f36494..00000000 --- a/pkg/sqls/contructor.go +++ /dev/null @@ -1,38 +0,0 @@ -package sqls - -import ( - "github.com/huandu/go-sqlbuilder" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -type Builder = sqlbuilder.Builder - -type SQLBuilder struct { - sb *sqlbuilder.SelectBuilder - ib *sqlbuilder.InsertBuilder - ub *sqlbuilder.UpdateBuilder - db *sqlbuilder.DeleteBuilder -} - -func (s *SQLBuilder) Init() { - s.sb = sqlbuilder.NewSelectBuilder() - s.ib = sqlbuilder.NewInsertBuilder() - s.ub = sqlbuilder.NewUpdateBuilder() - s.db = sqlbuilder.NewDeleteBuilder() -} - -func stringToInterfaceSlice(s []string) []interface{} { - i := []interface{}{} - for _, v := range s { - i = append(i, v) - } - return i -} - -func IDtoInterfaceSlice(IDs types.IDs) []interface{} { - i := []interface{}{} - for _, v := range IDs { - i = append(i, v) - } - return i -} diff --git a/pkg/sqls/cte.go b/pkg/sqls/cte.go deleted file mode 100644 index d9f58426..00000000 --- a/pkg/sqls/cte.go +++ /dev/null @@ -1,34 +0,0 @@ -package sqls - -import "github.com/huandu/go-sqlbuilder" - -type IWithSQLs interface { - SelectIDFromInsertTransactionCTEAuxStmt() sqlbuilder.Builder - SelectIDFromTrItemAliasCTEAuxStmt(string) sqlbuilder.Builder -} - -type WithSQLs struct { - SQLBuilder -} - -// passed as arg to InsertApprovalsSQL to -// reference approval relationship with a transaction -func (w *WithSQLs) SelectIDFromInsertTransactionCTEAuxStmt() sqlbuilder.Builder { - w.Init() - w.sb.Select("id") - w.sb.From("insert_transaction") - return sqlbuilder.WithFlavor(w.sb, sqlbuilder.PostgreSQL) -} - -// passed as arg to InsertApprovalsSQL to -// reference approval relationship with a transaction_item -func (w *WithSQLs) SelectIDFromTrItemAliasCTEAuxStmt(alias string) sqlbuilder.Builder { - w.Init() - w.sb.Select("id") - w.sb.From(alias) - return sqlbuilder.WithFlavor(w.sb, sqlbuilder.PostgreSQL) -} - -func NewWithSQLs() *WithSQLs { - return new(WithSQLs) -} diff --git a/pkg/sqls/cte_test.go b/pkg/sqls/cte_test.go deleted file mode 100644 index 2d714ff4..00000000 --- a/pkg/sqls/cte_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package sqls - -import ( - "fmt" - "testing" -) - -func TestSelectIDFromInsertTransactionCTEAuxStmt(t *testing.T) { - testsqlb := WithSQLs{} - got1, got2 := testsqlb.SelectIDFromInsertTransactionCTEAuxStmt().Build() - want1 := "SELECT id FROM insert_transaction" - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if len(got2) != 0 { - t.Errorf("got %v, want 0 len slice", got2) - } -} - -func TestSelectIDFromTrItemAliasCTEAuxStmt(t *testing.T) { - testsqlb := WithSQLs{} - testalias := "t_01" - got1, got2 := testsqlb.SelectIDFromTrItemAliasCTEAuxStmt(testalias).Build() - want1 := fmt.Sprintf("SELECT id FROM %s", testalias) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if len(got2) != 0 { - t.Errorf("got %v, want 0 len slice", got2) - } -} diff --git a/pkg/sqls/makefile b/pkg/sqls/makefile deleted file mode 100644 index ac7f0aef..00000000 --- a/pkg/sqls/makefile +++ /dev/null @@ -1,13 +0,0 @@ -PKG_NAME=sqls -RELATIVE_PROJECT_ROOT_PATH=../../.. - -test: - go test -v -race -covermode=atomic -coverprofile=coverage.out - -mock: - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/mock-go-ifaces.sh \ - --app-or-pkg-name $(PKG_NAME) - -install: - go install github.com/golang/mock/mockgen@latest \ No newline at end of file diff --git a/pkg/sqls/notification.go b/pkg/sqls/notification.go deleted file mode 100644 index d8cb30e6..00000000 --- a/pkg/sqls/notification.go +++ /dev/null @@ -1,83 +0,0 @@ -package sqls - -import ( - "github.com/huandu/go-sqlbuilder" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -type NotificationSQLs struct { - SQLBuilder -} - -func (n *NotificationSQLs) InsertTransactionNotificationsSQL(tns types.TransactionNotifications) (string, []interface{}) { - n.Init() - n.ib.InsertInto("transaction_notification") - n.ib.Cols( - "transaction_id", - "account_name", - "account_role", - "message", - ) - for _, v := range tns { - n.ib.Values( - *v.TransactionID, - *v.AccountName, - *v.AccountRole, - *v.Message, - ) - } - retID := sqlbuilder.Buildf("%v returning id", n.ib) - return sqlbuilder.WithFlavor(retID, sqlbuilder.PostgreSQL).Build() -} - -func (n *NotificationSQLs) SelectTransNotifsByIDsSQL(notifIDs types.IDs) (string, []interface{}) { - n.Init() - - iNotifIDs := IDtoInterfaceSlice(notifIDs) - - n.sb.Select("*") - n.sb.From("transaction_notification"). - Where( - n.sb.In("id", iNotifIDs...), - ) - - return n.sb.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func (n *NotificationSQLs) DeleteTransNotificationsByIDsSQL(notifIDs types.IDs) (string, []interface{}) { - n.Init() - - iNotifIDs := IDtoInterfaceSlice(notifIDs) - - n.db.DeleteFrom("transaction_notification") - n.db.Where( - n.db.In("id", iNotifIDs...), - ) - - return n.db.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func (n *NotificationSQLs) SelectTransNotifsByAccountSQL(accountName string, limit int) (string, []interface{}) { - n.Init() - n.sb.Select("*") - n.sb.From("transaction_notification"). - Where( - n.sb.Equal("account_name", accountName), - ) - n.sb.OrderBy("id").Desc() - n.sb.Limit(limit) - return n.sb.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func (n *NotificationSQLs) DeleteTransNotificationsByTransIDSQL(trID types.ID) (string, []interface{}) { - n.Init() - n.db.DeleteFrom("transaction_notification") - n.db.Where( - n.db.Equal("transaction_id", trID), - ) - return n.db.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func NewNotificationSQLs() *NotificationSQLs { - return new(NotificationSQLs) -} diff --git a/pkg/sqls/notification_test.go b/pkg/sqls/notification_test.go deleted file mode 100644 index 42d42501..00000000 --- a/pkg/sqls/notification_test.go +++ /dev/null @@ -1,95 +0,0 @@ -package sqls - -import ( - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/jackc/pgtype" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -func TestInsertTransactionNotificationsSQL(t *testing.T) { - testbuilder := NotificationSQLs{} - testid1 := types.ID("testid1") - testacct1 := "testacct1" - testrole1 := types.Role(0) - testmsg1 := pgtype.JSONB{} - - testnotifications := types.TransactionNotifications{ - &types.TransactionNotification{ - TransactionID: &testid1, - AccountName: &testacct1, - AccountRole: &testrole1, - Message: &testmsg1, - }, - } - - got1, got2 := testbuilder.InsertTransactionNotificationsSQL(testnotifications) - want1 := "INSERT INTO transaction_notification (transaction_id, account_name, account_role, message) VALUES ($1, $2, $3, $4) returning id" - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - want2 := []interface{}{testid1, testacct1, testrole1, testmsg1} - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestSelectTransNotifsByIDsSQL(t *testing.T) { - testid1 := types.ID("testid1") - testids := types.IDs{&testid1} - testbuilder := NotificationSQLs{} - want1 := "SELECT * FROM transaction_notification WHERE id IN ($1)" - want2 := []interface{}{&testid1} - got1, got2 := testbuilder.SelectTransNotifsByIDsSQL(testids) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestDeleteTransNotificationsByIDsSQL(t *testing.T) { - testid1 := types.ID("testid1") - testids := types.IDs{&testid1} - testbuilder := NotificationSQLs{} - want1 := "DELETE FROM transaction_notification WHERE id IN ($1)" - want2 := []interface{}{&testid1} - got1, got2 := testbuilder.DeleteTransNotificationsByIDsSQL(testids) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestSelectTransNotifsByAccountSQL(t *testing.T) { - testacct := "testacct" - testlimit := 1 - testbuilder := NotificationSQLs{} - want1 := "SELECT * FROM transaction_notification WHERE account_name = $1 ORDER BY id DESC LIMIT 1" - want2 := []interface{}{testacct} - got1, got2 := testbuilder.SelectTransNotifsByAccountSQL(testacct, testlimit) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestDeleteTransNotificationsByTransIDSQL(t *testing.T) { - testid1 := types.ID("testid1") - testbuilder := NotificationSQLs{} - want1 := "DELETE FROM transaction_notification WHERE transaction_id = $1" - want2 := []interface{}{testid1} - got1, got2 := testbuilder.DeleteTransNotificationsByTransIDSQL(testid1) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} diff --git a/pkg/sqls/profile.go b/pkg/sqls/profile.go deleted file mode 100644 index 4af1668a..00000000 --- a/pkg/sqls/profile.go +++ /dev/null @@ -1,87 +0,0 @@ -package sqls - -import ( - "github.com/huandu/go-sqlbuilder" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -type AccountProfileSQLs struct { - SQLBuilder -} - -func (ap *AccountProfileSQLs) SelectProfileIDsByAccountNames(accountNames []string) (string, []interface{}) { - ap.Init() - - // sqlbuilder wants interface slice - iAccts := stringToInterfaceSlice(accountNames) - - ap.sb.Select( - "id", - "account_name", - ) - ap.sb.From("account_profile"). - Where( - ap.sb.In("account_name", iAccts...), - ap.sb.IsNull("removal_time"), - ) - - return ap.sb.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func (ap *AccountProfileSQLs) InsertAccountProfileSQL(p *types.AccountProfile) (string, []interface{}) { - ap.Init() - ap.ib.InsertInto("account_profile") - ap.ib.Cols( - "account_name", - "description", - "first_name", - "middle_name", - "last_name", - "country_name", - "street_number", - "street_name", - "floor_number", - "unit_number", - "city_name", - "county_name", - "region_name", - "state_name", - "postal_code", - "latlng", - "email_address", - "telephone_country_code", - "telephone_area_code", - "telephone_number", - "occupation_id", - "industry_id", - ) - ap.ib.Values( - p.AccountName, - p.Description, - p.FirstName, - p.MiddleName, - p.LastName, - p.CountryName, - p.StreetNumber, - p.StreetName, - p.FloorNumber, - p.UnitNumber, - p.CityName, - p.CountyName, - p.RegionName, - p.StateName, - p.PostalCode, - p.Latlng, - p.EmailAddress, - p.TelephoneCountryCode, - p.TelephoneAreaCode, - p.TelephoneNumber, - p.OccupationID, - p.IndustryID, - ) - return ap.ib.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func NewAccountProfileSQLs() *AccountProfileSQLs { - return new(AccountProfileSQLs) -} diff --git a/pkg/sqls/profile_test.go b/pkg/sqls/profile_test.go deleted file mode 100644 index ae361995..00000000 --- a/pkg/sqls/profile_test.go +++ /dev/null @@ -1,105 +0,0 @@ -package sqls - -import ( - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -func TestSelectProfileIDsByAccountNames(t *testing.T) { - testacct := "testacct" - testaccounts := []string{testacct} - testbuilder := AccountProfileSQLs{} - want1 := "SELECT id, account_name FROM account_profile WHERE account_name IN ($1) AND removal_time IS NULL" - want2 := []interface{}{testacct} - got1, got2 := testbuilder.SelectProfileIDsByAccountNames(testaccounts) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestInsertAccountProfileSQL(t *testing.T) { - testacct := "testacct" - testdesc := "testdesc" - testfirstname := "testfirstname" - testmiddlename := "testmiddlename" - testlastname := "testlastname" - testcountryname := "testcountryname" - teststreetnumber := "teststreetnumber" - teststreetname := "teststreetname" - testfloornumber := "testfloornumber" - testunitnumber := "testunitnumber" - testcityname := "testcityname" - testcountyname := "testcountyname" - testregionname := "testregionname" - teststatename := "teststatename" - testpostalcode := "testpostalcode" - testlatlng := types.LatLng("(1,2)") - testemailaddress := "testemailaddress" - testtelephonecountrycode := int32(111) - testtelephoneareacode := int32(222) - testtelephonenumber := int32(333) - testoccupationid := int32(1) - testindustryid := int32(2) - testprofile := &types.AccountProfile{ - AccountName: &testacct, - Description: &testdesc, - FirstName: &testfirstname, - MiddleName: &testmiddlename, - LastName: &testlastname, - CountryName: &testcountryname, - StreetNumber: &teststreetnumber, - StreetName: &teststreetname, - FloorNumber: &testfloornumber, - UnitNumber: &testunitnumber, - CityName: &testcityname, - CountyName: &testcountyname, - RegionName: &testregionname, - StateName: &teststatename, - PostalCode: &testpostalcode, - Latlng: &testlatlng, - EmailAddress: &testemailaddress, - TelephoneCountryCode: &testtelephonecountrycode, - TelephoneAreaCode: &testtelephoneareacode, - TelephoneNumber: &testtelephonenumber, - OccupationID: &testoccupationid, - IndustryID: &testindustryid, - } - testbuilder := AccountProfileSQLs{} - want1 := "INSERT INTO account_profile (account_name, description, first_name, middle_name, last_name, country_name, street_number, street_name, floor_number, unit_number, city_name, county_name, region_name, state_name, postal_code, latlng, email_address, telephone_country_code, telephone_area_code, telephone_number, occupation_id, industry_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22)" - want2 := []interface{}{ - &testacct, - &testdesc, - &testfirstname, - &testmiddlename, - &testlastname, - &testcountryname, - &teststreetnumber, - &teststreetname, - &testfloornumber, - &testunitnumber, - &testcityname, - &testcountyname, - &testregionname, - &teststatename, - &testpostalcode, - &testlatlng, - &testemailaddress, - &testtelephonecountrycode, - &testtelephoneareacode, - &testtelephonenumber, - &testoccupationid, - &testindustryid, - } - got1, got2 := testbuilder.InsertAccountProfileSQL(testprofile) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} diff --git a/pkg/sqls/rule_instance.go b/pkg/sqls/rule_instance.go deleted file mode 100644 index f7e34300..00000000 --- a/pkg/sqls/rule_instance.go +++ /dev/null @@ -1,69 +0,0 @@ -package sqls - -import "github.com/huandu/go-sqlbuilder" - -type RuleInstanceSQLs struct { - SQLBuilder -} - -func (r *RuleInstanceSQLs) SelectRuleInstanceSQL( - ruleType, - ruleName, - ruleInstanceName, - accountRole, - accountName, - variableValuesArray string, -) (string, []interface{}) { - r.Init() - r.sb.Select( - "rule_type", - "rule_name", - "rule_instance_name", - "account_role", - "account_name", - "variable_values", - ) - r.sb.From("rule_instance"). - Where( - r.sb.Equal("rule_type", ruleType), - r.sb.Equal("rule_name", ruleName), - r.sb.Equal("rule_instance_name", ruleInstanceName), - r.sb.Equal("account_role", accountRole), - r.sb.Equal("account_name", accountName), - r.sb.Equal("variable_values", variableValuesArray), - ) - return r.sb.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func (r *RuleInstanceSQLs) InsertRuleInstanceSQL( - ruleType, - ruleName, - ruleInstanceName, - accountRole, - accountName, - variableValues string, -) (string, []interface{}) { - r.Init() - r.ib.InsertInto("rule_instance") - r.ib.Cols( - "rule_type", - "rule_name", - "rule_instance_name", - "account_role", - "account_name", - "variable_values", - ) - r.ib.Values( - ruleType, - ruleName, - ruleInstanceName, - accountRole, - accountName, - variableValues, - ) - return r.ib.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func NewRuleInstanceSQLs() *RuleInstanceSQLs { - return new(RuleInstanceSQLs) -} diff --git a/pkg/sqls/rule_instance_test.go b/pkg/sqls/rule_instance_test.go deleted file mode 100644 index 806c292d..00000000 --- a/pkg/sqls/rule_instance_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package sqls - -import ( - "testing" - - "github.com/google/go-cmp/cmp" -) - -func TestSelectRuleInstanceSQL(t *testing.T) { - testruletype := "testruletype" - testrulename := "testrulename" - testruleinstancename := "testruleinstancename" - testacctrole := "creditor" - testacctname := "testruletype" - testvariables := "{'testvalue'}" - - want1 := "SELECT rule_type, rule_name, rule_instance_name, account_role, account_name, variable_values FROM rule_instance WHERE rule_type = $1 AND rule_name = $2 AND rule_instance_name = $3 AND account_role = $4 AND account_name = $5 AND variable_values = $6" - want2 := []interface{}{ - testruletype, - testrulename, - testruleinstancename, - testacctrole, - testacctname, - testvariables, - } - - testbuilder := RuleInstanceSQLs{} - got1, got2 := testbuilder.SelectRuleInstanceSQL( - testruletype, - testrulename, - testruleinstancename, - testacctrole, - testacctname, - testvariables, - ) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} -func TestInsertRuleInstanceSQL(t *testing.T) { - - testruletype := "testruletype" - testrulename := "testrulename" - testruleinstancename := "testruleinstancename" - testacctrole := "creditor" - testacctname := "testruletype" - testvariables := "{'testvalue'}" - - testbuilder := RuleInstanceSQLs{} - want1 := "INSERT INTO rule_instance (rule_type, rule_name, rule_instance_name, account_role, account_name, variable_values) VALUES ($1, $2, $3, $4, $5, $6)" - want2 := []interface{}{ - testruletype, - testrulename, - testruleinstancename, - testacctrole, - testacctname, - testvariables, - } - got1, got2 := testbuilder.InsertRuleInstanceSQL( - testruletype, - testrulename, - testruleinstancename, - testacctrole, - testacctname, - testvariables, - ) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} diff --git a/pkg/sqls/testdata/transaction_query.golden b/pkg/sqls/testdata/transaction_query.golden deleted file mode 100644 index 8d96cfb7..00000000 --- a/pkg/sqls/testdata/transaction_query.golden +++ /dev/null @@ -1 +0,0 @@ -WITH insert_transaction AS (INSERT INTO transaction (rule_instance_id, author, author_device_id, author_device_latlng, author_role, equilibrium_time, sum_value) VALUES ($1, $2, $3, $4, $5, $6, $7) returning *), i_0 AS (INSERT INTO transaction_item (transaction_id, item_id, price, quantity, debitor_first, rule_instance_id, rule_exec_ids, unit_of_measurement, units_measured, debitor, creditor, debitor_profile_id, creditor_profile_id, debitor_approval_time, creditor_approval_time, debitor_expiration_time, creditor_expiration_time) VALUES ((SELECT id FROM insert_transaction), $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23) returning id), a_0 AS (INSERT INTO approval (rule_instance_id, transaction_id, transaction_item_id, account_name, account_role, device_id, device_latlng, approval_time, expiration_time) VALUES ($24, (SELECT id FROM insert_transaction), (SELECT id FROM i_0), $25, $26, $27, $28, $29, $30), ($31, (SELECT id FROM insert_transaction), (SELECT id FROM i_0), $32, $33, $34, $35, $36, $37), ($38, (SELECT id FROM insert_transaction), (SELECT id FROM i_0), $39, $40, $41, $42, $43, $44), ($45, (SELECT id FROM insert_transaction), (SELECT id FROM i_0), $46, $47, $48, $49, $50, $51)), i_1 AS (INSERT INTO transaction_item (transaction_id, item_id, price, quantity, debitor_first, rule_instance_id, rule_exec_ids, unit_of_measurement, units_measured, debitor, creditor, debitor_profile_id, creditor_profile_id, debitor_approval_time, creditor_approval_time, debitor_expiration_time, creditor_expiration_time) VALUES ((SELECT id FROM insert_transaction), $52, $53, $54, $55, $56, $57, $58, $59, $60, $61, $62, $63, $64, $65, $66, $67) returning id), a_1 AS (INSERT INTO approval (rule_instance_id, transaction_id, transaction_item_id, account_name, account_role, device_id, device_latlng, approval_time, expiration_time) VALUES ($68, (SELECT id FROM insert_transaction), (SELECT id FROM i_1), $69, $70, $71, $72, $73, $74), ($75, (SELECT id FROM insert_transaction), (SELECT id FROM i_1), $76, $77, $78, $79, $80, $81), ($82, (SELECT id FROM insert_transaction), (SELECT id FROM i_1), $83, $84, $85, $86, $87, $88), ($89, (SELECT id FROM insert_transaction), (SELECT id FROM i_1), $90, $91, $92, $93, $94, $95)), i_2 AS (INSERT INTO transaction_item (transaction_id, item_id, price, quantity, debitor_first, rule_instance_id, rule_exec_ids, unit_of_measurement, units_measured, debitor, creditor, debitor_profile_id, creditor_profile_id, debitor_approval_time, creditor_approval_time, debitor_expiration_time, creditor_expiration_time) VALUES ((SELECT id FROM insert_transaction), $96, $97, $98, $99, $100, $101, $102, $103, $104, $105, $106, $107, $108, $109, $110, $111) returning id), a_2 AS (INSERT INTO approval (rule_instance_id, transaction_id, transaction_item_id, account_name, account_role, device_id, device_latlng, approval_time, expiration_time) VALUES ($112, (SELECT id FROM insert_transaction), (SELECT id FROM i_2), $113, $114, $115, $116, $117, $118), ($119, (SELECT id FROM insert_transaction), (SELECT id FROM i_2), $120, $121, $122, $123, $124, $125), ($126, (SELECT id FROM insert_transaction), (SELECT id FROM i_2), $127, $128, $129, $130, $131, $132), ($133, (SELECT id FROM insert_transaction), (SELECT id FROM i_2), $134, $135, $136, $137, $138, $139)), i_3 AS (INSERT INTO transaction_item (transaction_id, item_id, price, quantity, debitor_first, rule_instance_id, rule_exec_ids, unit_of_measurement, units_measured, debitor, creditor, debitor_profile_id, creditor_profile_id, debitor_approval_time, creditor_approval_time, debitor_expiration_time, creditor_expiration_time) VALUES ((SELECT id FROM insert_transaction), $140, $141, $142, $143, $144, $145, $146, $147, $148, $149, $150, $151, $152, $153, $154, $155) returning id), a_3 AS (INSERT INTO approval (rule_instance_id, transaction_id, transaction_item_id, account_name, account_role, device_id, device_latlng, approval_time, expiration_time) VALUES ($156, (SELECT id FROM insert_transaction), (SELECT id FROM i_3), $157, $158, $159, $160, $161, $162), ($163, (SELECT id FROM insert_transaction), (SELECT id FROM i_3), $164, $165, $166, $167, $168, $169), ($170, (SELECT id FROM insert_transaction), (SELECT id FROM i_3), $171, $172, $173, $174, $175, $176)), i_4 AS (INSERT INTO transaction_item (transaction_id, item_id, price, quantity, debitor_first, rule_instance_id, rule_exec_ids, unit_of_measurement, units_measured, debitor, creditor, debitor_profile_id, creditor_profile_id, debitor_approval_time, creditor_approval_time, debitor_expiration_time, creditor_expiration_time) VALUES ((SELECT id FROM insert_transaction), $177, $178, $179, $180, $181, $182, $183, $184, $185, $186, $187, $188, $189, $190, $191, $192) returning id), a_4 AS (INSERT INTO approval (rule_instance_id, transaction_id, transaction_item_id, account_name, account_role, device_id, device_latlng, approval_time, expiration_time) VALUES ($193, (SELECT id FROM insert_transaction), (SELECT id FROM i_4), $194, $195, $196, $197, $198, $199), ($200, (SELECT id FROM insert_transaction), (SELECT id FROM i_4), $201, $202, $203, $204, $205, $206), ($207, (SELECT id FROM insert_transaction), (SELECT id FROM i_4), $208, $209, $210, $211, $212, $213)), i_5 AS (INSERT INTO transaction_item (transaction_id, item_id, price, quantity, debitor_first, rule_instance_id, rule_exec_ids, unit_of_measurement, units_measured, debitor, creditor, debitor_profile_id, creditor_profile_id, debitor_approval_time, creditor_approval_time, debitor_expiration_time, creditor_expiration_time) VALUES ((SELECT id FROM insert_transaction), $214, $215, $216, $217, $218, $219, $220, $221, $222, $223, $224, $225, $226, $227, $228, $229) returning id), a_5 AS (INSERT INTO approval (rule_instance_id, transaction_id, transaction_item_id, account_name, account_role, device_id, device_latlng, approval_time, expiration_time) VALUES ($230, (SELECT id FROM insert_transaction), (SELECT id FROM i_5), $231, $232, $233, $234, $235, $236), ($237, (SELECT id FROM insert_transaction), (SELECT id FROM i_5), $238, $239, $240, $241, $242, $243), ($244, (SELECT id FROM insert_transaction), (SELECT id FROM i_5), $245, $246, $247, $248, $249, $250)) SELECT id FROM insert_transaction \ No newline at end of file diff --git a/pkg/sqls/tr_items.go b/pkg/sqls/tr_items.go deleted file mode 100644 index 8dd1fe49..00000000 --- a/pkg/sqls/tr_items.go +++ /dev/null @@ -1,89 +0,0 @@ -package sqls - -import ( - "github.com/huandu/go-sqlbuilder" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -type TransactionItemSQLs struct { - SQLBuilder -} - -func (t *TransactionItemSQLs) InsertTrItemSQL( - trItem *types.TransactionItem, - transactionAuxStmt sqlbuilder.Builder, -) sqlbuilder.Builder { - t.Init() - t.ib.InsertInto("transaction_item") - t.ib.Cols( - "transaction_id", - "item_id", - "price", - "quantity", - "debitor_first", - "rule_instance_id", - "rule_exec_ids", - "unit_of_measurement", - "units_measured", - "debitor", - "creditor", - "debitor_profile_id", - "creditor_profile_id", - "debitor_approval_time", - "creditor_approval_time", - "debitor_expiration_time", - "creditor_expiration_time", - ) - - t.ib.Values( - sqlbuilder.Buildf("(%v)", transactionAuxStmt), - trItem.ItemID, - trItem.Price, - trItem.Quantity, - trItem.DebitorFirst, - trItem.RuleInstanceID, - trItem.RuleExecIDs, - trItem.UnitOfMeasurement, - trItem.UnitsMeasured, - trItem.Debitor, - trItem.Creditor, - trItem.DebitorProfileID, - trItem.CreditorProfileID, - trItem.DebitorApprovalTime, - trItem.CreditorApprovalTime, - trItem.DebitorExpirationTime, - trItem.CreditorExpirationTime, - ) - - retID := sqlbuilder.Buildf("%v returning id", t.ib) - return sqlbuilder.WithFlavor(retID, sqlbuilder.PostgreSQL) -} - -func (t *TransactionItemSQLs) SelectTrItemsByTrIDSQL(trID types.ID) (string, []interface{}) { - t.Init() - t.sb.Select("*") - t.sb.From("transaction_item"). - Where( - t.sb.Equal("transaction_id", trID), - ) - return t.sb.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func (t *TransactionItemSQLs) SelectTrItemsByTrIDsSQL(trIDs types.IDs) (string, []interface{}) { - t.Init() - - // sql builder wants interface slice - iIDs := IDtoInterfaceSlice(trIDs) - - t.sb.Select("*") - t.sb.From("transaction_item"). - Where( - t.sb.In("transaction_id", iIDs...), - ) - - return t.sb.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func NewTransactionItemSQLs() *TransactionItemSQLs { - return new(TransactionItemSQLs) -} diff --git a/pkg/sqls/tr_items_test.go b/pkg/sqls/tr_items_test.go deleted file mode 100644 index 8cce5654..00000000 --- a/pkg/sqls/tr_items_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package sqls - -import ( - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/systemaccounting/mxfactorial/pkg/testdata" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -func TestInsertTrItemSQL(t *testing.T) { - - testtransaction := testdata.GetTestTransaction("../testdata/transWTimes.json") - testtritem := testtransaction.TransactionItems[0] - - testwithsql := WithSQLs{} - testtrauxstmtbuilder := testwithsql.SelectIDFromInsertTransactionCTEAuxStmt() - - testbuilder := TransactionItemSQLs{} - testinstritembuilder := testbuilder.InsertTrItemSQL( - testtritem, - testtrauxstmtbuilder, - ) - - got1, got2 := testinstritembuilder.Build() - - want1 := "INSERT INTO transaction_item (transaction_id, item_id, price, quantity, debitor_first, rule_instance_id, rule_exec_ids, unit_of_measurement, units_measured, debitor, creditor, debitor_profile_id, creditor_profile_id, debitor_approval_time, creditor_approval_time, debitor_expiration_time, creditor_expiration_time) VALUES ((SELECT id FROM insert_transaction), $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) returning id" - want2 := []interface{}{ - testtritem.ItemID, - testtritem.Price, - testtritem.Quantity, - testtritem.DebitorFirst, - testtritem.RuleInstanceID, - testtritem.RuleExecIDs, - testtritem.UnitOfMeasurement, - testtritem.UnitsMeasured, - testtritem.Debitor, - testtritem.Creditor, - testtritem.DebitorProfileID, - testtritem.CreditorProfileID, - testtritem.DebitorApprovalTime, - testtritem.CreditorApprovalTime, - testtritem.DebitorExpirationTime, - testtritem.CreditorExpirationTime, - } - - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestSelectTrItemsByTrIDSQL(t *testing.T) { - testid := types.ID("1") - testbuilder := TransactionItemSQLs{} - want1 := "SELECT * FROM transaction_item WHERE transaction_id = $1" - want2 := []interface{}{testid} - got1, got2 := testbuilder.SelectTrItemsByTrIDSQL(testid) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestSelectTrItemsByTrIDsSQL(t *testing.T) { - testid1 := types.ID("1") - testid2 := types.ID("2") - testids := types.IDs{&testid1, &testid2} - testbuilder := TransactionItemSQLs{} - want1 := "SELECT * FROM transaction_item WHERE transaction_id IN ($1, $2)" - want2 := []interface{}{&testid1, &testid2} - got1, got2 := testbuilder.SelectTrItemsByTrIDsSQL(testids) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} diff --git a/pkg/sqls/transaction.go b/pkg/sqls/transaction.go deleted file mode 100644 index a0245c55..00000000 --- a/pkg/sqls/transaction.go +++ /dev/null @@ -1,248 +0,0 @@ -package sqls - -import ( - "errors" - "fmt" - "strings" - - "github.com/huandu/go-sqlbuilder" - "github.com/shopspring/decimal" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -const ( - sqlParam = "$?" - trItemAliasPrefix = "i" - approvalAliasPrefix = "a" - trAlias = "insert_transaction" -) - -type TransactionSQLs struct { - SQLBuilder -} - -func (t *TransactionSQLs) InsertTransactionSQL( - trRuleInstanceID *types.ID, - trAuthor *string, - trDeviceID *string, - trAuthorDeviceLatlng *string, - trAuthorRole types.Role, - trEquilibriumTime *string, - trSumValue *decimal.NullDecimal, -) sqlbuilder.Builder { - t.Init() - t.ib.InsertInto("transaction") - t.ib.Cols( - "rule_instance_id", - "author", - "author_device_id", - "author_device_latlng", - "author_role", - "equilibrium_time", - "sum_value", - ) - - t.ib.Values( - trRuleInstanceID, - trAuthor, - trDeviceID, - trAuthorDeviceLatlng, - trAuthorRole, - trEquilibriumTime, - trSumValue, - ) - - ret := sqlbuilder.Buildf("%v returning *", t.ib) - return sqlbuilder.WithFlavor(ret, sqlbuilder.PostgreSQL) -} - -func (t *TransactionSQLs) SelectTransactionByIDSQL(trID types.ID) (string, []interface{}) { - t.Init() - t.sb.Select("*") - t.sb.From("transaction"). - Where( - t.sb.Equal("id", trID), - ) - return t.sb.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func (t *TransactionSQLs) SelectTransactionsByIDsSQL(trIDs types.IDs) (string, []interface{}) { - t.Init() - - // sql builder wants interface slice - iIDs := IDtoInterfaceSlice(trIDs) - - t.sb.Select("*") - t.sb.From("transaction"). - Where( - t.sb.In("id", iIDs...), - ) - - return t.sb.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func (t *TransactionSQLs) UpdateTransactionByIDSQL(trID *types.ID, equilTime string) (string, []interface{}) { - t.Init() - t.ub.Update("transaction"). - Set( - t.ub.Assign("equilibrium_time", equilTime), - ). - Where( - t.ub.Equal("id", *trID), - ) - // format with ub arg only to avoid - // can't scan into dest[0]: unable to assign to *int32 - retID := sqlbuilder.Buildf("%v returning *", t.ub) - return sqlbuilder.WithFlavor(retID, sqlbuilder.PostgreSQL).Build() -} - -// => i_0, transaction_item insert index 0 -func (TransactionSQLs) buildAuxStmtName(prefix string, idx int) string { - return fmt.Sprintf("%v_%v", prefix, idx) -} - -func (TransactionSQLs) buildAuxStmt(stmtName string) string { - return fmt.Sprintf("%v AS (%v), ", stmtName, sqlParam) -} - -func (t TransactionSQLs) buildWithSQL(trItems types.TransactionItems) (string, error) { - t.Init() - - cte := fmt.Sprintf("WITH %v AS (%v), ", trAlias, sqlParam) - - for i, u := range trItems { - - trItemName := t.buildAuxStmtName(trItemAliasPrefix, i) // i_0 - cte += t.buildAuxStmt(trItemName) // i_0 AS ($?), - - if len(u.Approvals) == 0 { - return "", errors.New("buildWithSQL: 0 approvals") - } - - apprName := t.buildAuxStmtName(approvalAliasPrefix, i) // a_0 - cte += t.buildAuxStmt(apprName) // a_0 AS ($?), - } - - // end with clause by removing last comma - cte = strings.TrimSuffix(cte, ", ") - - // return inserted transaction.id as final query - cte += fmt.Sprintf(" SELECT id FROM %v", trAlias) - - return cte, nil -} - -func (t TransactionSQLs) CreateTransactionRequestSQL(tr *types.Transaction) (string, []interface{}, error) { - - // create transaction sql builder - insTr := TransactionSQLs{} - - // create insert transaction sql - insTrBuilder := insTr.InsertTransactionSQL( - nil, - tr.Author, - nil, - nil, - *tr.AuthorRole, - nil, - tr.SumValue, - ) - - // build with sql - with, err := insTr.buildWithSQL(tr.TransactionItems) - if err != nil { - return "", nil, err - } - - // init 'WITH' sql builder list - builders := make([]interface{}, 0) - - // add transaction sql builder as first builder - builders = append(builders, insTrBuilder) - - // create a "select id from insert_transaction" auxiliary statement sql builder - trAuxStmt := WithSQLs{} - trAuxStmtBuilder := trAuxStmt.SelectIDFromInsertTransactionCTEAuxStmt() - - // add to 'WITH' sql builders list by looping - // through transaction items and adding - // transaction item sql builders - for i, v := range tr.TransactionItems { - - // create sql builder from constructor - insTrItem := TransactionItemSQLs{} - - // create transaction_item sql builder - trItemBuilder := insTrItem.InsertTrItemSQL(v, trAuxStmtBuilder) - - // add transction_item sql builder to list - builders = append(builders, trItemBuilder) - - // approvals need to reference the preceding transaction_item id - // in the cte as theyre inserted, e.g. t_01 AS ... - trItemAliasName := t.buildAuxStmtName(trItemAliasPrefix, i) - - // create transaction item auxiliary statement for reference by approval inserts - // e.g. (select id from t_01) - trItemAlias := WithSQLs{} - trItemAliasBuilder := trItemAlias.SelectIDFromTrItemAliasCTEAuxStmt(trItemAliasName) - - // create an approval insert sql builder - ibAppr := ApprovalSQLs{} - - // create approval sql builder - apprBuilder := ibAppr.InsertApprovalsSQL(v.Approvals, trAuxStmtBuilder, trItemAliasBuilder) - - // add approval sql builder to list - builders = append(builders, apprBuilder) - } - - // build 'WITH' sql that includes rows for: - // 1. transaction - // 2. transaction_item - // 3. approval - insSQL, insArgs := sqlbuilder.Build(with, builders...).BuildWithFlavor(sqlbuilder.PostgreSQL) - - return insSQL, insArgs, nil -} - -func (TransactionSQLs) SelectLastNReqsOrTransByAccount( - accountName string, - isAllApproved bool, - recordLimit string, -) (string, []interface{}) { - - // postgres boolean as $2 argument placeholder throws - // ERROR: syntax error at or near "$2" (SQLSTATE 42601) - // temp workaround: - isTransaction := "TRUE" - if !isAllApproved { - isTransaction = "FALSE" - } - - return fmt.Sprintf(`WITH transactions AS ( - SELECT transaction_id, every(approval_time IS NOT NULL) AS all_approved - FROM approval - WHERE transaction_id IN ( - SELECT DISTINCT(transaction_id) - FROM approval - WHERE account_name = $1 - ORDER BY transaction_id - DESC - ) - GROUP BY transaction_id - ORDER BY transaction_id - DESC - ) - SELECT * FROM transaction - WHERE id IN ( - SELECT transaction_id - FROM transactions - WHERE all_approved IS %s - LIMIT $2 - );`, isTransaction), []interface{}{accountName, recordLimit} -} - -func NewTransactionSQLs() *TransactionSQLs { - return new(TransactionSQLs) -} diff --git a/pkg/sqls/transaction_test.go b/pkg/sqls/transaction_test.go deleted file mode 100644 index 9b59064c..00000000 --- a/pkg/sqls/transaction_test.go +++ /dev/null @@ -1,348 +0,0 @@ -package sqls - -import ( - "os" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/shopspring/decimal" - "github.com/systemaccounting/mxfactorial/pkg/testdata" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -func TestInsertTransactionSQL(t *testing.T) { - - testacctid := types.ID("1") - testauthor := "testauthor" - testdeviceid := "testdeviceid" - testauthdevicelatlng := "(1,2)" - testauthrole := types.Role(1) - testequilibriumtime := "2022-06-24T03:09:32.772Z" - testsumvalue := &decimal.NullDecimal{} - - want1 := "INSERT INTO transaction (rule_instance_id, author, author_device_id, author_device_latlng, author_role, equilibrium_time, sum_value) VALUES ($1, $2, $3, $4, $5, $6, $7) returning *" - want2 := []interface{}{ - &testacctid, - &testauthor, - &testdeviceid, - &testauthdevicelatlng, - testauthrole, - &testequilibriumtime, - testsumvalue, - } - - testbuilder := TransactionSQLs{} - got1, got2 := testbuilder.InsertTransactionSQL( - &testacctid, - &testauthor, - &testdeviceid, - &testauthdevicelatlng, - testauthrole, - &testequilibriumtime, - testsumvalue, - ).Build() - - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestSelectTransactionByIDSQL(t *testing.T) { - - testtrid := types.ID("1") - - want1 := "SELECT * FROM transaction WHERE id = $1" - want2 := []interface{}{testtrid} - - testbuilder := TransactionSQLs{} - got1, got2 := testbuilder.SelectTransactionByIDSQL(testtrid) - - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestSelectTransactionsByIDsSQL(t *testing.T) { - - testtrid1 := types.ID("1") - testtrid2 := types.ID("2") - testtrids := types.IDs{&testtrid1, &testtrid2} - - want1 := "SELECT * FROM transaction WHERE id IN ($1, $2)" - want2 := []interface{}{&testtrid1, &testtrid2} - - testbuilder := TransactionSQLs{} - got1, got2 := testbuilder.SelectTransactionsByIDsSQL(testtrids) - - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestUpdateTransactionByIDSQL(t *testing.T) { - - testtrid := types.ID("1") - testequiltime := "testequiltime" - - want1 := "UPDATE transaction SET equilibrium_time = $1 WHERE id = $2 returning *" - want2 := []interface{}{testequiltime, testtrid} - - testbuilder := TransactionSQLs{} - got1, got2 := testbuilder.UpdateTransactionByIDSQL(&testtrid, testequiltime) - - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestBuildAuxStmtName(t *testing.T) { - want := "i_1" - testbuilder := TransactionSQLs{} - got := testbuilder.buildAuxStmtName(trItemAliasPrefix, 1) - if got != want { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestBuildAuxStmt(t *testing.T) { - testbuilder := TransactionSQLs{} - teststmtname := testbuilder.buildAuxStmtName(trItemAliasPrefix, 1) - - want := "i_1 AS ($?), " - got := testbuilder.buildAuxStmt(teststmtname) - - if got != want { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestBuildWithSQL(t *testing.T) { - - testtransaction := testdata.GetTestTransaction("../testdata/transWTimes.json") - testtritems := testtransaction.TransactionItems - - testbuilder := TransactionSQLs{} - got, err := testbuilder.buildWithSQL(testtritems) - - if err != nil { - t.Errorf("TestBuildWithSQL error: %v", err) - } - - want := "WITH insert_transaction AS ($?), i_0 AS ($?), a_0 AS ($?), i_1 AS ($?), a_1 AS ($?), i_2 AS ($?), a_2 AS ($?), i_3 AS ($?), a_3 AS ($?), i_4 AS ($?), a_4 AS ($?), i_5 AS ($?), a_5 AS ($?) SELECT id FROM insert_transaction" - if got != want { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestBuildWithSQLErr(t *testing.T) { - - testtransaction := testdata.GetTestTransaction("../testdata/transWTimes.json") - testtritems := testtransaction.TransactionItems - - // hit error by setting empty approvals - testtritems[0].Approvals = types.Approvals{} - - testbuilder := TransactionSQLs{} - _, got := testbuilder.buildWithSQL(testtritems) - - if got == nil { - t.Errorf("got nil, want %v", got) - } - - want := "buildWithSQL: 0 approvals" - - if got.Error() != want { - t.Errorf("got %v, want %v", got, want) - } -} - -func TestCreateTransactionRequestSQL(t *testing.T) { - testdata := testdata.GetTestTransactions("../testdata/requests.json") - testtransaction := testdata[0].Transaction - - testbuilder := TransactionSQLs{} - got1, got2, err := testbuilder.CreateTransactionRequestSQL(testtransaction) - if err != nil { - t.Errorf("CreateTransactionRequestSQL error: %v", err) - } - - golden1, err := os.ReadFile("./testdata/transaction_query.golden") - if err != nil { - t.Errorf("Readfile error: %v", err) - } - want1 := string(golden1) - - if got1 != want1 { - t.Errorf("got1 %v, want1 %v", got1, want1) - } - - var testauthordevicelatlng *string - var testequiltime *string - - want2 := []interface{}{} - - // 1. add transaction values - want2 = append(want2, - testtransaction.RuleInstanceID, - testtransaction.Author, - testtransaction.AuthorDeviceID, - // cadet todo: switch InsertTransactionSQL trAuthorDeviceLatlng param to LatLng type - testauthordevicelatlng, - *testtransaction.AuthorRole, - // cadet todo: switch InsertTransactionSQL trEquilibriumTime param to TZTime type - testequiltime, - testtransaction.SumValue) - - // 2. add transaction item values - for _, v := range testtransaction.TransactionItems { - want2 = append(want2, - v.ItemID, - v.Price, - v.Quantity, - v.DebitorFirst, - v.RuleInstanceID, - v.RuleExecIDs, - v.UnitOfMeasurement, - v.UnitsMeasured, - v.Debitor, - v.Creditor, - v.DebitorProfileID, - v.CreditorProfileID, - v.DebitorApprovalTime, - v.CreditorApprovalTime, - v.DebitorExpirationTime, - v.CreditorExpirationTime, - ) - - // 3. add approval values - for _, w := range v.Approvals { - want2 = append(want2, - w.RuleInstanceID, - w.AccountName, - w.AccountRole, - w.DeviceID, - w.DeviceLatlng, - w.ApprovalTime, - w.ExpirationTime, - ) - } - } - - if !cmp.Equal(got2, want2) { - t.Errorf("got2 %+v, want2 %+v", got2, want2) - } -} - -func TestCreateTransactionRequestSQLErr1(t *testing.T) { - testdata := testdata.GetTestTransactions("../testdata/requests.json") - testtransaction := testdata[0].Transaction - - // hit error by setting empty approvals - testtransaction.TransactionItems[0].Approvals = types.Approvals{} - - want := "buildWithSQL: 0 approvals" - - testbuilder := TransactionSQLs{} - _, _, got := testbuilder.CreateTransactionRequestSQL(testtransaction) - if got == nil { - t.Errorf("got nil, want %v", want) - } - - if got.Error() != want { - t.Errorf("got nil, want %v", want) - } -} - -func TestSelectLastNReqsOrTransByAccountTrue(t *testing.T) { - testacct := "testacct" - testisallapproved := true - testrecordlimit := "1" - testbuilder := TransactionSQLs{} - got1, got2 := testbuilder.SelectLastNReqsOrTransByAccount(testacct, testisallapproved, testrecordlimit) - - want1 := `WITH transactions AS ( - SELECT transaction_id, every(approval_time IS NOT NULL) AS all_approved - FROM approval - WHERE transaction_id IN ( - SELECT DISTINCT(transaction_id) - FROM approval - WHERE account_name = $1 - ORDER BY transaction_id - DESC - ) - GROUP BY transaction_id - ORDER BY transaction_id - DESC - ) - SELECT * FROM transaction - WHERE id IN ( - SELECT transaction_id - FROM transactions - WHERE all_approved IS TRUE - LIMIT $2 - );` - want2 := []interface{}{testacct, testrecordlimit} - - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestSelectLastNReqsOrTransByAccountFalse(t *testing.T) { - testacct := "testacct" - testisallapproved := false - testrecordlimit := "1" - testbuilder := TransactionSQLs{} - got1, got2 := testbuilder.SelectLastNReqsOrTransByAccount(testacct, testisallapproved, testrecordlimit) - - want1 := `WITH transactions AS ( - SELECT transaction_id, every(approval_time IS NOT NULL) AS all_approved - FROM approval - WHERE transaction_id IN ( - SELECT DISTINCT(transaction_id) - FROM approval - WHERE account_name = $1 - ORDER BY transaction_id - DESC - ) - GROUP BY transaction_id - ORDER BY transaction_id - DESC - ) - SELECT * FROM transaction - WHERE id IN ( - SELECT transaction_id - FROM transactions - WHERE all_approved IS FALSE - LIMIT $2 - );` - want2 := []interface{}{testacct, testrecordlimit} - - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} diff --git a/pkg/sqls/websocket.go b/pkg/sqls/websocket.go deleted file mode 100644 index 74bd9c91..00000000 --- a/pkg/sqls/websocket.go +++ /dev/null @@ -1,89 +0,0 @@ -package sqls - -import ( - "github.com/huandu/go-sqlbuilder" -) - -type WebsocketSQLs struct { - SQLBuilder -} - -func (w *WebsocketSQLs) InsertWebsocketConnectionSQL( - connectionID string, - epochCreatedAt int64, -) (string, []interface{}) { - w.Init() - w.ib.InsertInto("websocket") - w.ib.Cols( - "connection_id", - "epoch_created_at", - ) - w.ib.Values( - connectionID, - epochCreatedAt, - ) - return w.ib.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func (w *WebsocketSQLs) DeleteWebsocketConnectionByConnectionIDSQL(connectionID string) (string, []interface{}) { - w.Init() - w.db.DeleteFrom("websocket") - w.db.Where( - w.db.Equal("connection_id", connectionID), - ) - return w.db.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func (w *WebsocketSQLs) DeleteWebsocketsByConnectionIDsSQL(connectionIDs []string) (string, []interface{}) { - - // sqlbuilder wants interface slice - iConnectionIDs := stringToInterfaceSlice(connectionIDs) - - w.Init() - w.db.DeleteFrom("websocket") - w.db.Where( - w.db.In("connection_id", iConnectionIDs...), - ) - - return w.db.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func (w *WebsocketSQLs) SelectWebsocketsByAccountsSQL(accounts []string) (string, []interface{}) { - - // sqlbuilder wants interface slice - iaccounts := stringToInterfaceSlice(accounts) - - w.Init() - w.sb.Select("*") - w.sb.From("websocket"). - Where( - w.sb.In("account_name", iaccounts...), - ) - return w.sb.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func (w *WebsocketSQLs) SelectWebsocketByConnectionIDSQL(connID string) (string, []interface{}) { - w.Init() - w.sb.Select("*") - w.sb.From("websocket"). - Where( - w.sb.Equal("connection_id", connID), - ) - return w.sb.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func (w *WebsocketSQLs) UpdateWebsocketByConnIDSQL(accountName, connectionID string) (string, []interface{}) { - w.Init() - w.ub.Update("websocket"). - Set( - w.ub.Assign("account_name", accountName), - ). - Where( - w.ub.Equal("connection_id", connectionID), - ) - return w.ub.BuildWithFlavor(sqlbuilder.PostgreSQL) -} - -func NewWebsocketSQLs() *WebsocketSQLs { - return new(WebsocketSQLs) -} diff --git a/pkg/sqls/websocket_test.go b/pkg/sqls/websocket_test.go deleted file mode 100644 index bd8c9d9e..00000000 --- a/pkg/sqls/websocket_test.go +++ /dev/null @@ -1,107 +0,0 @@ -package sqls - -import ( - "testing" - - "github.com/google/go-cmp/cmp" -) - -func TestInsertWebsocketConnectionSQL(t *testing.T) { - testconnectionid := "L0SM9cOFvHcCIhw=" - testepochcreatedat := int64(1547557733712) - testbuilder := WebsocketSQLs{} - want1 := "INSERT INTO websocket (connection_id, epoch_created_at) VALUES ($1, $2)" - want2 := []interface{}{ - testconnectionid, - testepochcreatedat, - } - got1, got2 := testbuilder.InsertWebsocketConnectionSQL( - testconnectionid, - testepochcreatedat, - ) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestDeleteWebsocketConnectionByConnectionIDSQL(t *testing.T) { - testconnectionid := "L0SM9cOFvHcCIhw=" - testbuilder := WebsocketSQLs{} - want1 := "DELETE FROM websocket WHERE connection_id = $1" - want2 := []interface{}{ - testconnectionid, - } - got1, got2 := testbuilder.DeleteWebsocketConnectionByConnectionIDSQL( - testconnectionid, - ) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestDeleteWebsocketsByConnectionIDsSQL(t *testing.T) { - testconnectionid1 := "L0SM9cOFvHcCIhw=" - testconnectionid2 := "L0SM9cOFvHcCIhx=" - testconnectionids := []string{testconnectionid1, testconnectionid2} - testbuilder := WebsocketSQLs{} - want1 := "DELETE FROM websocket WHERE connection_id IN ($1, $2)" - want2 := []interface{}{testconnectionid1, testconnectionid2} - got1, got2 := testbuilder.DeleteWebsocketsByConnectionIDsSQL(testconnectionids) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestSelectWebsocketsByAccountsSQL(t *testing.T) { - testacctname1 := "testacctname1" - testacctname2 := "testacctname2" - testacctnames := []string{testacctname1, testacctname2} - testbuilder := WebsocketSQLs{} - want1 := "SELECT * FROM websocket WHERE account_name IN ($1, $2)" - want2 := []interface{}{testacctname1, testacctname2} - got1, got2 := testbuilder.SelectWebsocketsByAccountsSQL(testacctnames) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestSelectWebsocketByConnectionIDSQL(t *testing.T) { - testconnectionid := "L0SM9cOFvHcCIhw=" - testbuilder := WebsocketSQLs{} - want1 := "SELECT * FROM websocket WHERE connection_id = $1" - want2 := []interface{}{testconnectionid} - got1, got2 := testbuilder.SelectWebsocketByConnectionIDSQL(testconnectionid) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} - -func TestUpdateWebsocketByConnIDSQL(t *testing.T) { - testacctname := "testacctname" - testconnectionid := "L0SM9cOFvHcCIhw=" - testbuilder := WebsocketSQLs{} - want1 := "UPDATE websocket SET account_name = $1 WHERE connection_id = $2" - want2 := []interface{}{testacctname, testconnectionid} - got1, got2 := testbuilder.UpdateWebsocketByConnIDSQL(testacctname, testconnectionid) - if got1 != want1 { - t.Errorf("got %v, want %v", got1, want1) - } - if !cmp.Equal(got2, want2) { - t.Errorf("got %v, want %v", got2, want2) - } -} diff --git a/pkg/testdata/fake_profile.go b/pkg/testdata/fake_profile.go deleted file mode 100644 index dc2a7e53..00000000 --- a/pkg/testdata/fake_profile.go +++ /dev/null @@ -1,96 +0,0 @@ -package testdata - -import ( - "fmt" - "log" - "math/rand" - "strconv" - "unicode" - - rd "github.com/Pallinder/go-randomdata" - "github.com/bxcodec/faker/v3" - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -type FakerValues struct { - Description string `faker:"sentence"` - MiddleName string `faker:"last_name"` - Email string `faker:"email"` - Latitude float32 `faker:"lat"` - Longitude float32 `faker:"long"` -} - -func randomNumber(min, max int) int { - return rand.Intn(max-min) + min -} - -func GuessFirstAndLastNames(account string) (firstName, lastName string) { - rem := account[1:] - nextCapitalLetterIndex := 0 - for i, v := range rem { - if unicode.IsUpper(v) { - nextCapitalLetterIndex = i + 1 - } - } - if nextCapitalLetterIndex == 0 { - nextCapitalLetterIndex = len(account) / 2 - } - firstName = account[0:nextCapitalLetterIndex] - lastName = account[nextCapitalLetterIndex:] - return firstName, lastName -} - -func CreateFakeProfile(accountName, firstName, lastName string) types.AccountProfile { - f := FakerValues{} - err := faker.FakeData(&f) - if err != nil { - log.Print(err) - } - testAccount := accountName - description := f.Description[0 : len(f.Description)-1] - middleName := f.MiddleName - countryName := "United States of America" - streetNumber := strconv.Itoa(randomNumber(1, 1000)) - streetName := rd.StreetForCountry("US") - floorNumber := strconv.Itoa(randomNumber(1, 20)) - unitNumber := strconv.Itoa(randomNumber(1, 100)) - cityName := rd.City() - countyName := fmt.Sprintf("%s County", cityName) - region := "" - stateName := "California" // triggers California state tax rule - postalCode := rd.PostalCode("US") - latLng := types.LatLng(fmt.Sprintf("(%v,%v)", f.Latitude, f.Longitude)) - emailAddress := f.Email - teleCountryCode := int32(1) - teleAreaCode := int32(randomNumber(100, 999)) - teleNumber := int32(randomNumber(1000000, 9999999)) - occID := int32(randomNumber(1, 12)) - indID := int32(randomNumber(1, 11)) - - profile := types.AccountProfile{ - AccountName: &testAccount, - Description: &description, - FirstName: &firstName, - MiddleName: &middleName, - LastName: &lastName, - CountryName: &countryName, - StreetNumber: &streetNumber, - StreetName: &streetName, - FloorNumber: &floorNumber, - UnitNumber: &unitNumber, - CityName: &cityName, - CountyName: &countyName, - RegionName: ®ion, - StateName: &stateName, - PostalCode: &postalCode, - Latlng: &latLng, - EmailAddress: &emailAddress, - TelephoneCountryCode: &teleCountryCode, - TelephoneAreaCode: &teleAreaCode, - TelephoneNumber: &teleNumber, - OccupationID: &occID, - IndustryID: &indID, - } - - return profile -} diff --git a/pkg/testdata/unmarshal.go b/pkg/testdata/unmarshal.go deleted file mode 100644 index 7a7182c3..00000000 --- a/pkg/testdata/unmarshal.go +++ /dev/null @@ -1,37 +0,0 @@ -package testdata - -import ( - "encoding/json" - "fmt" - "os" - - "github.com/systemaccounting/mxfactorial/pkg/types" -) - -func GetTestTransaction(path string) types.Transaction { - f, err := os.ReadFile(path) - if err != nil { - msgErr := fmt.Errorf("read fail %s: %v", path, err) - panic(msgErr) - } - var i types.IntraTransaction - if err := json.Unmarshal(f, &i); err != nil { - msgErr := fmt.Errorf("unmarshal fail: %v", err) - panic(msgErr) - } - return *i.Transaction -} - -func GetTestTransactions(path string) []*types.IntraTransaction { - f, err := os.ReadFile(path) - if err != nil { - msgErr := fmt.Errorf("read fail %s: %v", path, err) - panic(msgErr) - } - var i []*types.IntraTransaction - if err := json.Unmarshal(f, &i); err != nil { - msgErr := fmt.Errorf("unmarshal fail: %v", err) - panic(msgErr) - } - return i -} diff --git a/pkg/types/account.go b/pkg/types/account.go deleted file mode 100644 index 34488d22..00000000 --- a/pkg/types/account.go +++ /dev/null @@ -1,27 +0,0 @@ -package types - -type AccountProfile struct { - ID *ID `json:"id"` - AccountName *string `json:"account_name"` - Description *string `json:"description"` - FirstName *string `json:"first_name"` - MiddleName *string `json:"middle_name"` - LastName *string `json:"last_name"` - CountryName *string `json:"country_name"` - StreetNumber *string `json:"street_number"` - StreetName *string `json:"street_name"` - FloorNumber *string `json:"floor_number"` - UnitNumber *string `json:"unit_number"` - CityName *string `json:"city_name"` - CountyName *string `json:"county_name"` - RegionName *string `json:"region_name"` - StateName *string `json:"state_name"` - PostalCode *string `json:"postal_code"` - Latlng *LatLng `json:"latlng"` - EmailAddress *string `json:"email_address"` - TelephoneCountryCode *int32 `json:"telephone_country_code"` - TelephoneAreaCode *int32 `json:"telephone_area_code"` - TelephoneNumber *int32 `json:"telephone_number"` - OccupationID *int32 `json:"occupation_id"` - IndustryID *int32 `json:"industry_id"` -} diff --git a/pkg/types/approval.go b/pkg/types/approval.go deleted file mode 100644 index 7541d3ab..00000000 --- a/pkg/types/approval.go +++ /dev/null @@ -1,84 +0,0 @@ -package types - -import ( - "errors" - "fmt" - - "github.com/jackc/pgx/v4" -) - -// Approval approves a transaction item -type Approval struct { - ID *ID `json:"id"` - RuleInstanceID *ID `json:"rule_instance_id"` - TransactionID *ID `json:"transaction_id"` - TransactionItemID *ID `json:"transaction_item_id"` - AccountName *string `json:"account_name"` - AccountRole *Role `json:"account_role"` - DeviceID *string `json:"device_id"` - DeviceLatlng *LatLng `json:"device_latlng"` - ApprovalTime *TZTime `json:"approval_time"` - RejectionTime *TZTime `json:"rejection_time"` - ExpirationTime *TZTime `json:"expiration_time"` -} - -type Approvals []*Approval - -func (apprvs *Approvals) ScanRows(rows pgx.Rows) error { - - defer rows.Close() - for rows.Next() { - - a := new(Approval) - - err := rows.Scan( - &a.ID, - &a.RuleInstanceID, - &a.TransactionID, - &a.TransactionItemID, - &a.AccountName, - &a.AccountRole, - &a.DeviceID, - &a.DeviceLatlng, - &a.ApprovalTime, - &a.RejectionTime, - &a.ExpirationTime, - ) - if err != nil { - return fmt.Errorf("Approvals scan: %v", err) - } - - *apprvs = append(*apprvs, a) - } - - err := rows.Err() - if err != nil { - return fmt.Errorf("Approvals rows: %v", err) - } - - return nil -} - -// TestPendingRoleApproval errors when 0 pending -// approvals found for current debitor or creditor account -func (apprvs Approvals) TestPendingRoleApproval( - accountName string, - accountRole Role, -) error { - - approvalTimeStampsPending := 0 - - for _, v := range apprvs { - if *v.AccountName == accountName && - *v.AccountRole == accountRole && - v.ApprovalTime == nil { - approvalTimeStampsPending++ - } - } - - if approvalTimeStampsPending == 0 { - return errors.New("0 timestamps pending for approver. skipping approval") - } - - return nil -} diff --git a/pkg/types/balance.go b/pkg/types/balance.go deleted file mode 100644 index c95aff07..00000000 --- a/pkg/types/balance.go +++ /dev/null @@ -1,48 +0,0 @@ -package types - -import ( - "fmt" - - "github.com/jackc/pgx/v4" - "github.com/shopspring/decimal" -) - -type AccountBalance struct { - AccountName *string `json:"account_name"` - CurrentBalance decimal.Decimal `json:"current_balance"` -} - -func (ab *AccountBalance) ScanRow(row pgx.Row) error { - - err := row.Scan( - &ab.CurrentBalance, - ) - if err != nil { - return fmt.Errorf("AccountBlance Scan row: %v", err) - } - - return nil -} - -type AccountBalances []*AccountBalance - -func (abs *AccountBalances) ScanRows(rows pgx.Rows) error { - - defer rows.Close() - for rows.Next() { - - a := new(AccountBalance) - - err := rows.Scan( - &a.AccountName, - &a.CurrentBalance, - ) - if err != nil { - return fmt.Errorf("AccountBalances scan rows: %v", err) - } - - *abs = append(*abs, a) - } - - return nil -} diff --git a/pkg/types/enum.go b/pkg/types/enum.go deleted file mode 100644 index 56726e00..00000000 --- a/pkg/types/enum.go +++ /dev/null @@ -1,84 +0,0 @@ -package types - -import ( - "database/sql/driver" - "fmt" - "strconv" -) - -type Role int - -const ( - DEBITOR Role = iota - CREDITOR -) - -var ( - DB string = "debitor" - CR = "creditor" -) - -func (r Role) String() string { - return [...]string{DB, CR}[r] -} - -func isQuoted(s string) bool { - if len(s) <= 1 { - return false - } - firstChar := s[0] - lastChar := s[len(s)-1] - if firstChar == 34 && lastChar == 34 { // double quote char = 34 - return true - } - return false -} - -func (r Role) MatchString(s string) (Role, error) { - unquoted := s - if isQuoted(s) { - unq, err := strconv.Unquote(s) - if err != nil { - return 0, fmt.Errorf("failed to unquote %q", s) - - } - unquoted = unq - } - if unquoted == DB { - return DEBITOR, nil - } - if unquoted == CR { - return CREDITOR, nil - } - return 0, fmt.Errorf("%q neither debitor or creditor", s) -} - -func (r *Role) Set(val string) error { - var err error - *r, err = r.MatchString(val) - if err != nil { - return err - } - return nil -} - -func (r *Role) UnmarshalJSON(data []byte) error { - return r.Set(string(data)) -} - -func (r Role) MarshalJSON() ([]byte, error) { - quoted := strconv.Quote(r.String()) - return []byte(quoted), nil -} - -func (r *Role) Scan(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("failed to scan role with value: %v", str) - } - return r.Set(str) -} - -func (r *Role) Value() (driver.Value, error) { - return r.String(), nil -} diff --git a/pkg/types/id.go b/pkg/types/id.go deleted file mode 100644 index 99393c10..00000000 --- a/pkg/types/id.go +++ /dev/null @@ -1,61 +0,0 @@ -package types - -import ( - "database/sql/driver" - "fmt" - "strconv" - - "github.com/jackc/pgx/v4" -) - -type ID string - -func (id *ID) Value() (driver.Value, error) { - if id == nil { - return nil, nil - } - if *id == "" { - return nil, nil - } - s := string(*id) - i, err := strconv.Atoi(s) - if err != nil { - return nil, err - } - i32 := int32(i) - return &i32, nil -} - -func (id *ID) Scan(v interface{}) error { - val, ok := v.(int64) - if !ok { - return fmt.Errorf("failed to scan ID var with value: %v", val) - } - s := ID(strconv.FormatInt(val, 10)) - *id = s - return nil -} - -type IDs []*ID - -func (ids IDs) ScanRows(rows pgx.Rows) error { - defer rows.Close() - - for rows.Next() { - - ID := new(ID) - err := rows.Scan(&ID) - if err != nil { - return fmt.Errorf("IDs scan: %v", err) - } - - ids = append(ids, ID) - } - - err := rows.Err() - if err != nil { - return fmt.Errorf("IDs rows: %v ", err) - } - - return nil -} diff --git a/pkg/types/interfaces.go b/pkg/types/interfaces.go deleted file mode 100644 index 641a3528..00000000 --- a/pkg/types/interfaces.go +++ /dev/null @@ -1,20 +0,0 @@ -package types - -import ( - "github.com/jackc/pgx/v4" - "github.com/shopspring/decimal" -) - -type IScanRow interface { - ScanRow(pgx.Row) error -} - -type IScanRows interface { - ScanRows(pgx.Rows) error -} - -type TrItemListHelper interface { - MapDebitorsToRequiredFunds() map[string]decimal.Decimal - ListUniqueDebitorAccountsFromTrItems() []string - ListUniqueAccountsFromTrItems() []interface{} -} diff --git a/pkg/types/latlng.go b/pkg/types/latlng.go deleted file mode 100644 index 13dd0ecf..00000000 --- a/pkg/types/latlng.go +++ /dev/null @@ -1,36 +0,0 @@ -package types - -import ( - "database/sql/driver" - "errors" - - "github.com/jackc/pgtype" -) - -type LatLng string // fmt.Sprintf("(%v,%v)", latitude, longitude) - -func (l LatLng) Value() (driver.Value, error) { - if l == "" { - return nil, nil - } - var latlng pgtype.Point - err := latlng.Set(string(l)) - if err != nil { - return nil, err - } - return latlng, nil -} - -func (l *LatLng) Scan(v interface{}) error { - var p pgtype.Point - err := p.Scan(v) - if err != nil { - return errors.New("failed to scan LatLng type") - } - j, err := p.MarshalJSON() - if err != nil { - return errors.New("failed to marshal pgtype.Point") - } - *l = LatLng(string(j)) - return nil -} diff --git a/pkg/types/makefile b/pkg/types/makefile deleted file mode 100644 index 2ef3b453..00000000 --- a/pkg/types/makefile +++ /dev/null @@ -1,9 +0,0 @@ -RELATIVE_PROJECT_ROOT_PATH=../../.. -PKG_NAME=types - -mock: - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/mock-go-ifaces.sh \ - --app-or-pkg-name $(PKG_NAME) - -.PHONY: mock \ No newline at end of file diff --git a/pkg/types/mock_types/types_mock.go b/pkg/types/mock_types/types_mock.go deleted file mode 100644 index b7f0a833..00000000 --- a/pkg/types/mock_types/types_mock.go +++ /dev/null @@ -1,152 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/systemaccounting/mxfactorial/pkg/types (interfaces: TrItemListHelper,IScanRow,IScanRows) - -// Package mock_types is a generated GoMock package. -package mock_types - -import ( - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - pgx "github.com/jackc/pgx/v4" - decimal "github.com/shopspring/decimal" -) - -// MockTrItemListHelper is a mock of TrItemListHelper interface. -type MockTrItemListHelper struct { - ctrl *gomock.Controller - recorder *MockTrItemListHelperMockRecorder -} - -// MockTrItemListHelperMockRecorder is the mock recorder for MockTrItemListHelper. -type MockTrItemListHelperMockRecorder struct { - mock *MockTrItemListHelper -} - -// NewMockTrItemListHelper creates a new mock instance. -func NewMockTrItemListHelper(ctrl *gomock.Controller) *MockTrItemListHelper { - mock := &MockTrItemListHelper{ctrl: ctrl} - mock.recorder = &MockTrItemListHelperMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockTrItemListHelper) EXPECT() *MockTrItemListHelperMockRecorder { - return m.recorder -} - -// ListUniqueAccountsFromTrItems mocks base method. -func (m *MockTrItemListHelper) ListUniqueAccountsFromTrItems() []interface{} { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListUniqueAccountsFromTrItems") - ret0, _ := ret[0].([]interface{}) - return ret0 -} - -// ListUniqueAccountsFromTrItems indicates an expected call of ListUniqueAccountsFromTrItems. -func (mr *MockTrItemListHelperMockRecorder) ListUniqueAccountsFromTrItems() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListUniqueAccountsFromTrItems", reflect.TypeOf((*MockTrItemListHelper)(nil).ListUniqueAccountsFromTrItems)) -} - -// ListUniqueDebitorAccountsFromTrItems mocks base method. -func (m *MockTrItemListHelper) ListUniqueDebitorAccountsFromTrItems() []string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListUniqueDebitorAccountsFromTrItems") - ret0, _ := ret[0].([]string) - return ret0 -} - -// ListUniqueDebitorAccountsFromTrItems indicates an expected call of ListUniqueDebitorAccountsFromTrItems. -func (mr *MockTrItemListHelperMockRecorder) ListUniqueDebitorAccountsFromTrItems() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListUniqueDebitorAccountsFromTrItems", reflect.TypeOf((*MockTrItemListHelper)(nil).ListUniqueDebitorAccountsFromTrItems)) -} - -// MapDebitorsToRequiredFunds mocks base method. -func (m *MockTrItemListHelper) MapDebitorsToRequiredFunds() map[string]decimal.Decimal { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "MapDebitorsToRequiredFunds") - ret0, _ := ret[0].(map[string]decimal.Decimal) - return ret0 -} - -// MapDebitorsToRequiredFunds indicates an expected call of MapDebitorsToRequiredFunds. -func (mr *MockTrItemListHelperMockRecorder) MapDebitorsToRequiredFunds() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MapDebitorsToRequiredFunds", reflect.TypeOf((*MockTrItemListHelper)(nil).MapDebitorsToRequiredFunds)) -} - -// MockIScanRow is a mock of IScanRow interface. -type MockIScanRow struct { - ctrl *gomock.Controller - recorder *MockIScanRowMockRecorder -} - -// MockIScanRowMockRecorder is the mock recorder for MockIScanRow. -type MockIScanRowMockRecorder struct { - mock *MockIScanRow -} - -// NewMockIScanRow creates a new mock instance. -func NewMockIScanRow(ctrl *gomock.Controller) *MockIScanRow { - mock := &MockIScanRow{ctrl: ctrl} - mock.recorder = &MockIScanRowMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockIScanRow) EXPECT() *MockIScanRowMockRecorder { - return m.recorder -} - -// ScanRow mocks base method. -func (m *MockIScanRow) ScanRow(arg0 pgx.Row) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ScanRow", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// ScanRow indicates an expected call of ScanRow. -func (mr *MockIScanRowMockRecorder) ScanRow(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScanRow", reflect.TypeOf((*MockIScanRow)(nil).ScanRow), arg0) -} - -// MockIScanRows is a mock of IScanRows interface. -type MockIScanRows struct { - ctrl *gomock.Controller - recorder *MockIScanRowsMockRecorder -} - -// MockIScanRowsMockRecorder is the mock recorder for MockIScanRows. -type MockIScanRowsMockRecorder struct { - mock *MockIScanRows -} - -// NewMockIScanRows creates a new mock instance. -func NewMockIScanRows(ctrl *gomock.Controller) *MockIScanRows { - mock := &MockIScanRows{ctrl: ctrl} - mock.recorder = &MockIScanRowsMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockIScanRows) EXPECT() *MockIScanRowsMockRecorder { - return m.recorder -} - -// ScanRows mocks base method. -func (m *MockIScanRows) ScanRows(arg0 pgx.Rows) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ScanRows", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// ScanRows indicates an expected call of ScanRows. -func (mr *MockIScanRowsMockRecorder) ScanRows(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ScanRows", reflect.TypeOf((*MockIScanRows)(nil).ScanRows), arg0) -} diff --git a/pkg/types/notification.go b/pkg/types/notification.go deleted file mode 100644 index 45bbf735..00000000 --- a/pkg/types/notification.go +++ /dev/null @@ -1,114 +0,0 @@ -package types - -import ( - "fmt" - "time" - - "github.com/jackc/pgtype" - "github.com/jackc/pgx/v4" -) - -type TransactionNotification struct { - ID *ID `json:"id"` - TransactionID *ID `json:"transaction_id"` - AccountName *string `json:"account_name"` - AccountRole *Role `json:"account_role"` - Message *pgtype.JSONB `json:"message"` - CreatedAt *time.Time `json:"created_at"` -} - -type TransactionNotifications []*TransactionNotification - -func (t *TransactionNotifications) ScanRows(rows pgx.Rows) error { - defer rows.Close() - - for rows.Next() { - - n := new(TransactionNotification) - - err := rows.Scan( - &n.ID, - &n.TransactionID, - &n.AccountName, - &n.AccountRole, - &n.Message, - &n.CreatedAt, - ) - - if err != nil { - return fmt.Errorf("TransactionNotifications scan: %v", err) - } - - *t = append(*t, n) - } - - err := rows.Err() - if err != nil { - return fmt.Errorf("TransactionNotifications rows: %v", err) - } - - return nil -} - -func (t *TransactionNotifications) ScanIDs(rows pgx.Rows) error { - defer rows.Close() - - for rows.Next() { - - n := new(TransactionNotification) - - err := rows.Scan( - &n.ID, - ) - - if err != nil { - return fmt.Errorf("TransactionNotifications scan: %v", err) - } - - *t = append(*t, n) - } - - err := rows.Err() - if err != nil { - return fmt.Errorf("TransactionNotifications rows: %v", err) - } - - return nil -} - -func (trs TransactionNotifications) ListIDs() IDs { - var trIDs IDs - - for _, v := range trs { - trIDs = append(trIDs, v.ID) - } - - return trIDs -} - -type NotificationEvent struct { - Service *string -} - -type TransactionNotificationEvent struct { - NotificationEvent - TransactionNotification -} - -type Message struct { - NotificationID *ID `json:"notification_id"` - Message pgtype.JSONB `json:"message"` -} - -type PendingNotifications struct { - Pending []*Message `json:"pending"` -} - -type ClearedNotifications struct { - Cleared []*ID `json:"cleared"` -} - -type NotificationAndWebsockets struct { - Notification *TransactionNotification - Websockets []*Websocket -} diff --git a/pkg/types/request_response.go b/pkg/types/request_response.go deleted file mode 100644 index 6ed2a036..00000000 --- a/pkg/types/request_response.go +++ /dev/null @@ -1,147 +0,0 @@ -package types - -import ( - "encoding/json" - "fmt" - "log" - - "github.com/jackc/pgx/v4" - "github.com/systemaccounting/mxfactorial/pkg/logger" -) - -// IntraEvent is embedded for -// post-auth internal service requests -type IntraEvent struct { - AuthAccount string `json:"auth_account"` -} - -type IntraTransaction struct { - IntraEvent - Transaction *Transaction `json:"transaction"` -} - -func (it *IntraTransaction) Unmarshal(data []byte) error { - err := json.Unmarshal(data, &it) - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -// Marshal returns a IntraTransaction as json string -func (it *IntraTransaction) MarshalIntraTransaction() (string, error) { - j, err := json.Marshal(it) - if err != nil { - return "", err - } - - js := string(j) - - // ## debugging only - transInd, err := json.MarshalIndent(it, "", " ") - if err != nil { - log.Print(err) - return "", err - } - indented := string(transInd) - _ = indented - // log.Print(indented) - // ### - - return js, nil -} - -func EmptyMarshaledIntraTransaction(authAccount string) (string, error) { - emptyTr := &Transaction{} - emptyIntraTr := emptyTr.CreateIntraTransaction(authAccount) - return emptyIntraTr.MarshalIntraTransaction() -} - -type IntraTransactions struct { - IntraEvent - Transaction Transactions `json:"transactions"` -} - -// Marshal returns a IntraTransaction as json string -func (its *IntraTransactions) MarshalIntraTransactions() (string, error) { - j, err := json.Marshal(its) - if err != nil { - return "", err - } - - js := string(j) - - // ## debugging only - transInd, err := json.MarshalIndent(its, "", " ") - if err != nil { - log.Print(err) - return "", err - } - indented := string(transInd) - _ = indented - // log.Print(indented) - // ### - - return js, nil -} - -type RequestApprove struct { - IntraEvent - ID *ID `json:"id"` - AccountName *string `json:"account_name"` - AccountRole *Role `json:"account_role"` -} - -type AccountProfileID struct { - ID *ID `json:"id"` - AccountName *string `json:"account_name"` -} - -type AccountProfileIDs []*AccountProfileID - -func (IDs *AccountProfileIDs) ScanRows(rows pgx.Rows) error { - defer rows.Close() - for rows.Next() { - - ap := new(AccountProfileID) - - err := rows.Scan( - &ap.ID, - &ap.AccountName, - ) - - if err != nil { - return fmt.Errorf("AccountProfileIDs scan %v", err) - } - - *IDs = append(*IDs, ap) - } - - err := rows.Err() - if err != nil { - return fmt.Errorf("AccountProfileIDs rows %v", err) - } - - return nil -} - -func (IDs AccountProfileIDs) MapProfileIDsToAccounts() map[string]ID { - profileIDs := make(map[string]ID) - for _, v := range IDs { - profileIDs[*v.AccountName] = *v.ID - } - return profileIDs -} - -type QueryByAccount struct { - IntraEvent - AccountName *string `json:"account_name"` -} - -type QueryByID struct { - IntraEvent - AccountName *string `json:"account_name"` - ID *ID `json:"id"` -} diff --git a/pkg/types/rule.go b/pkg/types/rule.go deleted file mode 100644 index 7f5739b5..00000000 --- a/pkg/types/rule.go +++ /dev/null @@ -1,70 +0,0 @@ -package types - -import ( - "fmt" - - "github.com/jackc/pgx/v4" - "github.com/shopspring/decimal" -) - -type Rule struct { - Name *string - VariableNames []*string - CreatedAt *TZTime -} - -type RuleInstance struct { - ID *ID - RuleType *string - RuleName *string - RuleInstanceName *string - VariableValues []*string - AccountRole Role - ItemID *ID - Price decimal.NullDecimal - Quantity decimal.NullDecimal - UnitOfMeasurement *string - UnitsMeasured decimal.NullDecimal - AccountName *string - FirstName *string - MiddleName *string - LastName *string - CountryName *string - StreetNumber *string - StreetName *string - FloorNumber *string - UnitNumber *string - CityName *string - CountyName *string - RegionName *string - StateName *string - PostalCode *string - Latlng *LatLng - EmailAddress *string - TelephoneCountryCode *int32 - TelephoneAreaCode *int32 - TelephoneNumber *int32 - OccupationID *int32 - IndustryID *int32 - DisabledTime *TZTime - RemovedTime *TZTime - CreatedAt *TZTime -} - -func (ri *RuleInstance) ScanRow(row pgx.Row) error { - - // only scanning currently used columns, see rule_instance.go in sqls package - err := row.Scan( - &ri.RuleType, - &ri.RuleName, - &ri.RuleInstanceName, - &ri.VariableValues, - &ri.AccountRole, - &ri.AccountName, - ) - if err != nil { - return fmt.Errorf("RuleInstance Scan row: %v", err) - } - - return nil -} diff --git a/pkg/types/time.go b/pkg/types/time.go deleted file mode 100644 index b7fb7bd5..00000000 --- a/pkg/types/time.go +++ /dev/null @@ -1,66 +0,0 @@ -package types - -import ( - "database/sql/driver" - "encoding/json" - "fmt" - "strconv" - "time" - - "github.com/jackc/pgtype" -) - -const MILLI_TZ_FORMAT = "2006-01-02T15:04:05.000Z" - -type TZTime struct { - time.Time -} - -func (tz TZTime) Value() (driver.Value, error) { - if tz.IsZero() { - return nil, nil - } - var t pgtype.Timestamptz - t.Set(tz.Time) - return t.Value() -} - -func (tz *TZTime) Scan(v interface{}) error { - var t pgtype.Timestamptz - err := t.Scan(v) - if err != nil { - return fmt.Errorf("TZTime failed to scan pgtype.Timestamptz %v", err) - } - tz.Time = t.Time - return nil -} - -func (tz *TZTime) UnmarshalJSON(b []byte) error { - - s, err := strconv.Unquote(string(b)) - if err != nil { - return fmt.Errorf("TZTime UnmarshalJSON unquote error: %v", err) - } - - t, err := time.Parse(MILLI_TZ_FORMAT, s) - if err != nil { - return fmt.Errorf("TZTime UnmarshalJSON parse error: %v", err) - } - - tz.Time = t - - return nil -} - -func (tz TZTime) MarshalJSON() ([]byte, error) { - if tz.IsZero() { - j, err := json.Marshal(nil) - if err != nil { - return nil, fmt.Errorf("TZTime MarshalJSON nil: %v", err) - } - return j, nil - } - unQuotedTime := tz.Time.Format(MILLI_TZ_FORMAT) - t := strconv.Quote(unQuotedTime) - return []byte(t), nil -} diff --git a/pkg/types/transaction.go b/pkg/types/transaction.go deleted file mode 100644 index 3d5fca39..00000000 --- a/pkg/types/transaction.go +++ /dev/null @@ -1,187 +0,0 @@ -package types - -import ( - "errors" - "fmt" - "time" - - "github.com/jackc/pgx/v4" - "github.com/shopspring/decimal" - "github.com/systemaccounting/mxfactorial/pkg/logger" -) - -// Transaction is an envelope for TransactionItems -type Transaction struct { - ID *ID `json:"id"` - RuleInstanceID *ID `json:"rule_instance_id"` - Author *string `json:"author"` - AuthorDeviceID *string `json:"author_device_id"` - AuthorDeviceLatlng *LatLng `json:"author_device_latlng"` // pg point type - AuthorRole *Role `json:"author_role"` - EquilibriumTime *TZTime `json:"equilibrium_time"` - SumValue *decimal.NullDecimal `json:"sum_value"` - TransactionItems TransactionItems `json:"transaction_items"` -} - -func (t *Transaction) ScanID(row pgx.Row) error { - - err := row.Scan(&t.ID) - - if err != nil { - return fmt.Errorf("Transaction id scan: %v", err) - } - - return nil -} - -func (t *Transaction) ScanRow(row pgx.Row) error { - - // not using "createdAt" but returning extra column - // for easy "select *" building in sqls pkg - var createdAt time.Time - - err := row.Scan( - &t.ID, - &t.RuleInstanceID, - &t.Author, - &t.AuthorDeviceID, - &t.AuthorDeviceLatlng, - &t.AuthorRole, - &t.EquilibriumTime, - &t.SumValue, - &createdAt, - ) - - if err != nil { - logger.Log(logger.Trace(), err) - return err - } - - return nil -} - -func (t Transaction) IsEachContraAccountUnique() error { - for _, v := range t.TransactionItems { - if *v.Creditor == *v.Debitor { - return fmt.Errorf("same debitor and creditor in transaction_item. exiting %v", v.Creditor) - } - } - return nil -} - -func (t Transaction) GetApprovals() (Approvals, error) { - - if len(t.TransactionItems) == 0 { - return nil, fmt.Errorf("%s: 0 transaction items found", logger.Trace()) - } - - var approvals Approvals - - for _, v := range t.TransactionItems { - - if len(v.Approvals) == 0 { - return nil, fmt.Errorf("%s: 0 approvals found", logger.Trace()) - } - - for _, u := range v.Approvals { - approvals = append(approvals, u) - } - } - - return approvals, nil -} - -func (t *Transaction) CreateIntraTransaction(authAccount string) IntraTransaction { - return IntraTransaction{ - IntraEvent: IntraEvent{ - AuthAccount: authAccount, - }, - Transaction: t, - } -} - -// GetAuthorRole gets author role from a transaction -func (t Transaction) GetAuthorRole(author string) (Role, error) { - - // test for rule added transaction author - if t.RuleInstanceID != nil && *t.RuleInstanceID != "" { - return *t.AuthorRole, nil - } - - // if transaction is NOT rule generated - for _, v := range t.TransactionItems { - - if v.RuleInstanceID == nil || *v.RuleInstanceID == "" { - - if *v.Debitor == author { - return DEBITOR, nil - } - - if *v.Creditor == author { - return CREDITOR, nil - } - - } - } - - return 0, errors.New("author not in items") -} - -type Transactions []*Transaction - -func (trs *Transactions) ScanRows(rows pgx.Rows) error { - defer rows.Close() - for rows.Next() { - - t := new(Transaction) - - // not using "createdAt" but returning extra column - // for easy "select *" building in sqls pkg - var createdAt time.Time - - err := rows.Scan( - &t.ID, - &t.RuleInstanceID, - &t.Author, - &t.AuthorDeviceID, - &t.AuthorDeviceLatlng, - &t.AuthorRole, - &t.EquilibriumTime, - &t.SumValue, - &createdAt, - ) - - if err != nil { - return fmt.Errorf("Transactions scan: %v", err) - } - - *trs = append(*trs, t) - } - - err := rows.Err() - if err != nil { - return fmt.Errorf("Transactions rows: %v", err) - } - - return nil -} - -func (trs Transactions) ListIDs() IDs { - var trIDs IDs - - for _, v := range trs { - trIDs = append(trIDs, v.ID) - } - - return trIDs -} - -func (trs Transactions) CreateIntraTransactions(authAccount string) IntraTransactions { - return IntraTransactions{ - IntraEvent: IntraEvent{ - AuthAccount: authAccount, - }, - // todo: change field name to "transactions" - Transaction: trs, - } -} diff --git a/pkg/types/transaction_item.go b/pkg/types/transaction_item.go deleted file mode 100644 index 51c0e0d9..00000000 --- a/pkg/types/transaction_item.go +++ /dev/null @@ -1,191 +0,0 @@ -package types - -import ( - "fmt" - - "github.com/jackc/pgx/v4" - "github.com/shopspring/decimal" -) - -// TransactionItem transacts goods and services -type TransactionItem struct { - ID *ID `json:"id"` - TransactionID *ID `json:"transaction_id"` - ItemID *string `json:"item_id"` - Price decimal.Decimal `json:"price"` - Quantity decimal.Decimal `json:"quantity"` - DebitorFirst *bool `json:"debitor_first"` - RuleInstanceID *ID `json:"rule_instance_id"` - RuleExecIDs []*string `json:"rule_exec_ids"` - UnitOfMeasurement *string `json:"unit_of_measurement"` - UnitsMeasured decimal.NullDecimal `json:"units_measured"` - Debitor *string `json:"debitor"` - Creditor *string `json:"creditor"` - DebitorProfileID *ID `json:"debitor_profile_id"` - CreditorProfileID *ID `json:"creditor_profile_id"` - DebitorApprovalTime *TZTime `json:"debitor_approval_time"` - CreditorApprovalTime *TZTime `json:"creditor_approval_time"` - DebitorRejectionTime *TZTime `json:"debitor_rejection_time"` - CreditorRejectionTime *TZTime `json:"creditor_rejection_time"` - DebitorExpirationTime *TZTime `json:"debitor_expiration_time"` - CreditorExpirationTime *TZTime `json:"creditor_expiration_time"` - Approvals Approvals `json:"approvals"` -} - -type TransactionItems []*TransactionItem - -func (t *TransactionItems) ScanRows(rows pgx.Rows) error { - defer rows.Close() - for rows.Next() { - - i := new(TransactionItem) - - err := rows.Scan( - &i.ID, - &i.TransactionID, - &i.ItemID, - &i.Price, - &i.Quantity, - &i.DebitorFirst, - &i.RuleInstanceID, - &i.RuleExecIDs, - &i.UnitOfMeasurement, - &i.UnitsMeasured, - &i.Debitor, - &i.Creditor, - &i.DebitorProfileID, - &i.CreditorProfileID, - &i.DebitorApprovalTime, - &i.CreditorApprovalTime, - &i.DebitorRejectionTime, - &i.CreditorRejectionTime, - &i.DebitorExpirationTime, - &i.CreditorExpirationTime, - ) - - if err != nil { - return fmt.Errorf("TransactionItems scan %v", err) - } - - *t = append(*t, i) - } - - err := rows.Err() - if err != nil { - return fmt.Errorf("TransactionItems rows %v", err) - } - - return nil -} - -func (trItems TransactionItems) MapDebitorsToRequiredFunds() map[string]decimal.Decimal { - - // map stores debitor funds required for transaction - // e.g. JacobWebb needs 10.000, SarahBell needs 1.000 - reqd := make(map[string]decimal.Decimal) - - // loop through transaction items - for _, v := range trItems { - - // test map for debitor - if _, ok := reqd[*v.Debitor]; !ok { - - // init decimal value for account - // when account not found in map - reqd[*v.Debitor] = decimal.New(0, 1) - } - - // test for pending approval timestamp - if v.DebitorApprovalTime == nil { - - // increase required debitor funds by price * quantity - reqd[*v.Debitor] = reqd[*v.Debitor].Add(v.Price.Mul(v.Quantity)) - } - } - - return reqd -} - -func (trItems TransactionItems) ListUniqueDebitorAccountsFromTrItems() []string { - var uniqueDebitors []string - for _, v := range trItems { - if isStringUnique(*v.Debitor, uniqueDebitors) { - uniqueDebitors = append(uniqueDebitors, *v.Debitor) - } - } - return uniqueDebitors -} - -func isStringUnique(s string, l []string) bool { - for _, v := range l { - if v == s { - return false - } - } - return true -} - -// used for sql builder -func (trItems TransactionItems) ListUniqueAccountsFromTrItems() []string { - var uniqueAccounts []string - for _, v := range trItems { - if isStringUnique(*v.Debitor, uniqueAccounts) { - uniqueAccounts = append(uniqueAccounts, *v.Debitor) - } - if isStringUnique(*v.Creditor, uniqueAccounts) { - uniqueAccounts = append(uniqueAccounts, *v.Creditor) - } - } - return uniqueAccounts -} - -func (trItems TransactionItems) RemoveUnauthorizedValues() TransactionItems { - var authorized TransactionItems - - for _, v := range trItems { - - debitorFirst := falseIfNilPtr(v.DebitorFirst) - - authorized = append(authorized, &TransactionItem{ - ID: nil, - TransactionID: nil, - ItemID: v.ItemID, - Price: v.Price, - Quantity: v.Quantity, - DebitorFirst: &debitorFirst, - RuleInstanceID: v.RuleInstanceID, - RuleExecIDs: []*string{}, - UnitOfMeasurement: nil, - UnitsMeasured: v.UnitsMeasured, - Debitor: v.Debitor, - Creditor: v.Creditor, - DebitorProfileID: nil, - CreditorProfileID: nil, - DebitorApprovalTime: nil, - CreditorApprovalTime: nil, - DebitorRejectionTime: nil, - CreditorRejectionTime: nil, - DebitorExpirationTime: nil, - CreditorExpirationTime: nil, - Approvals: Approvals{}, - }) - } - - return authorized -} - -func falseIfNilPtr(v *bool) bool { - if v == nil { - return false - } - return *v -} - -func (trItems TransactionItems) AddProfileIDsToTrItems(accountProfileIDs map[string]ID) { - for _, v := range trItems { - v.DebitorProfileID = new(ID) - *v.DebitorProfileID = accountProfileIDs[*v.Debitor] - v.CreditorProfileID = new(ID) - *v.CreditorProfileID = accountProfileIDs[*v.Creditor] - } -} diff --git a/pkg/types/websocket.go b/pkg/types/websocket.go deleted file mode 100644 index e071a846..00000000 --- a/pkg/types/websocket.go +++ /dev/null @@ -1,69 +0,0 @@ -package types - -import ( - "fmt" - "time" - - "github.com/jackc/pgx/v4" -) - -type Websocket struct { - ID *ID `json:"id"` - ConnectionID *string `json:"connection_id"` // e.g. "L0SM9cOFvHcCIhw=" - AccountName *string `json:"account_name"` - EpochCreatedAt *int64 `json:"epoch_created_at"` - CreatedAt *time.Time `json:"created_at"` -} - -func (ws *Websocket) Scan(row pgx.Row) error { - - err := row.Scan( - &ws.ID, - &ws.ConnectionID, - &ws.AccountName, - &ws.EpochCreatedAt, - &ws.CreatedAt, - ) - - if err != nil { - return fmt.Errorf("Websocket scan: %v", err) - } - - return nil -} - -type Websockets []*Websocket - -func (ws *Websockets) ScanRows(rows pgx.Rows) error { - defer rows.Close() - for rows.Next() { - - w := new(Websocket) - - err := rows.Scan( - &w.ID, - &w.ConnectionID, - &w.AccountName, - &w.EpochCreatedAt, - &w.CreatedAt, - ) - if err != nil { - return fmt.Errorf("Websockets scan: %v", err) - } - - *ws = append(*ws, w) - } - - err := rows.Err() - if err != nil { - return fmt.Errorf("Websockets rows %v", err) - } - - return nil -} - -// used in services/notifications-get and services/notifications-clear -type WebsocketMessage struct { - Action *string `json:"action"` - Account *string `json:"account"` // substitutes token when auth disabled during development -} From 0aec6eb828b65ba8df51eb5faff0a33b1e47736f Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:24:05 -0700 Subject: [PATCH 17/37] remove go base dockerfile --- docker/prod/go-base.Dockerfile | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 docker/prod/go-base.Dockerfile diff --git a/docker/prod/go-base.Dockerfile b/docker/prod/go-base.Dockerfile deleted file mode 100644 index fb0a4a50..00000000 --- a/docker/prod/go-base.Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM golang:alpine - -WORKDIR /app - -COPY go.* ./ - -RUN go mod download \ No newline at end of file From e182b1204f4fe435e855ae7a01b305e846020fbb Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:24:16 -0700 Subject: [PATCH 18/37] remove shared go makefile --- make/go.mk | 30 ------------------------------ 1 file changed, 30 deletions(-) delete mode 100644 make/go.mk diff --git a/make/go.mk b/make/go.mk deleted file mode 100644 index 7da70fbd..00000000 --- a/make/go.mk +++ /dev/null @@ -1,30 +0,0 @@ -# requires include shared.mk -APP_CONF_PATH=$(shell cd $(RELATIVE_PROJECT_ROOT_PATH); . ./scripts/list-conf-paths.sh --type app | grep --color=never -E "$(APP_NAME)$$|$(APP_NAME)\"]$$") -CMD_DIR=$(CURDIR)/$(shell yq '$(APP_CONF_PATH).build_src_path' $(PROJECT_CONF)) -WATCH=$(CMD_DIR) -RUN=$(CMD_DIR) - -start: - @$(MAKE) -s get-secrets ENV=local - nohup cargo watch -w $(WATCH) -w pkg --env-file $(ENV_FILE) -s 'go run $(RUN)' >> $(NOHUP_LOG) & - -install: - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/download-go-mod.sh - -clean-build: - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/clean-binary.sh \ - --app-name $(APP_NAME) \ - --binary-name $(EXECUTABLE_NAME) - -compile: - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/compile-go-linux.sh \ - --app-name $(APP_NAME) -zip: - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/zip-executable.sh \ - --app-name $(APP_NAME) \ - --artifact-name $(ARTIFACT_NAME) \ - --executable-name $(EXECUTABLE_NAME) \ No newline at end of file From b767beba06159c8eba848105235a3c8f417277b8 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:25:28 -0700 Subject: [PATCH 19/37] remove go module config and lockfile --- go.mod | 96 ------------ go.sum | 461 --------------------------------------------------------- 2 files changed, 557 deletions(-) delete mode 100644 go.mod delete mode 100644 go.sum diff --git a/go.mod b/go.mod deleted file mode 100644 index 95250685..00000000 --- a/go.mod +++ /dev/null @@ -1,96 +0,0 @@ -module github.com/systemaccounting/mxfactorial - -go 1.19 - -require ( - github.com/99designs/gqlgen v0.17.24 - github.com/Pallinder/go-randomdata v1.2.0 - github.com/aws/aws-lambda-go v1.41.0 - github.com/aws/aws-sdk-go v1.44.171 - github.com/bxcodec/faker/v3 v3.8.0 - github.com/dgrijalva/jwt-go v3.2.0+incompatible - github.com/gin-gonic/gin v1.8.1 - github.com/golang/mock v1.6.0 - github.com/google/go-cmp v0.5.9 - github.com/huandu/go-sqlbuilder v1.15.0 - github.com/jackc/pgconn v1.14.0 - github.com/jackc/pgtype v1.14.0 - github.com/jackc/pgx/v4 v4.18.1 - github.com/lestrrat-go/jwx v1.2.20 - github.com/rs/cors/wrapper/gin v0.0.0-20221003140808-fcebdb403f4d - github.com/shopspring/decimal v1.3.1 - github.com/vektah/gqlparser/v2 v2.5.1 -) - -require ( - dario.cat/mergo v1.0.0 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect - github.com/acomagu/bufpipe v1.0.4 // indirect - github.com/cloudflare/circl v1.3.3 // indirect - github.com/cyphar/filepath-securejoin v0.2.4 // indirect - github.com/emirpasic/gods v1.18.1 // indirect - github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect - github.com/go-git/go-billy/v5 v5.5.0 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect - github.com/kevinburke/ssh_config v1.2.0 // indirect - github.com/lib/pq v1.10.2 // indirect - github.com/pjbgf/sha1cd v0.3.0 // indirect - github.com/sergi/go-diff v1.1.0 // indirect - github.com/skeema/knownhosts v1.2.0 // indirect - github.com/xanzy/ssh-agent v0.3.3 // indirect - go.uber.org/atomic v1.7.0 // indirect - gopkg.in/warnings.v0 v0.1.2 // indirect -) - -require ( - github.com/agnivade/levenshtein v1.1.1 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect - github.com/gin-contrib/sse v0.1.0 // indirect - github.com/go-git/go-git/v5 v5.9.0 - github.com/go-playground/locales v0.14.0 // indirect - github.com/go-playground/universal-translator v0.18.0 // indirect - github.com/go-playground/validator/v10 v10.10.0 // indirect - github.com/goccy/go-json v0.9.11 // indirect - github.com/golang-migrate/migrate/v4 v4.16.2 - github.com/gorilla/websocket v1.5.0 // indirect - github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/huandu/xstrings v1.3.2 // indirect - github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgio v1.0.0 // indirect - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.2 // indirect - github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/leodido/go-urn v1.2.1 // indirect - github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect - github.com/lestrrat-go/blackmagic v1.0.0 // indirect - github.com/lestrrat-go/httpcc v1.0.0 // indirect - github.com/lestrrat-go/iter v1.0.2 // indirect - github.com/lestrrat-go/option v1.0.0 // indirect - github.com/mattn/go-isatty v0.0.16 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.0.1 // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/rs/cors v1.8.1 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/ugorji/go/codec v1.2.7 // indirect - github.com/urfave/cli/v2 v2.8.1 // indirect - github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - golang.org/x/crypto v0.13.0 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.15.0 // indirect - golang.org/x/sys v0.12.0 // indirect - golang.org/x/text v0.13.0 // indirect - golang.org/x/tools v0.13.0 // indirect - google.golang.org/protobuf v1.28.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/go.sum b/go.sum deleted file mode 100644 index fe13641b..00000000 --- a/go.sum +++ /dev/null @@ -1,461 +0,0 @@ -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= -github.com/99designs/gqlgen v0.17.24 h1:pcd/HFIoSdRvyADYQG2dHvQN2KZqX/nXzlVm6TMMq7E= -github.com/99designs/gqlgen v0.17.24/go.mod h1:BMhYIhe4bp7OlCo5I2PnowSK/Wimpv/YlxfNkqZGwLo= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/Pallinder/go-randomdata v1.2.0 h1:DZ41wBchNRb/0GfsePLiSwb0PHZmT67XY00lCDlaYPg= -github.com/Pallinder/go-randomdata v1.2.0/go.mod h1:yHmJgulpD2Nfrm0cR9tI/+oAgRqCQQixsA8HyRZfV9Y= -github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= -github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= -github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= -github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= -github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= -github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= -github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= -github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= -github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= -github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= -github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/aws/aws-lambda-go v1.28.0 h1:fZiik1PZqW2IyAN4rj+Y0UBaO1IDFlsNo9Zz/XnArK4= -github.com/aws/aws-lambda-go v1.28.0/go.mod h1:jJmlefzPfGnckuHdXX7/80O3BvUUi12XOkbv4w9SGLU= -github.com/aws/aws-lambda-go v1.41.0 h1:l/5fyVb6Ud9uYd411xdHZzSf2n86TakxzpvIoz7l+3Y= -github.com/aws/aws-lambda-go v1.41.0/go.mod h1:jwFe2KmMsHmffA1X2R09hH6lFzJQxzI8qK17ewzbQMM= -github.com/aws/aws-sdk-go v1.44.171 h1:maREiPAmibvuONMOEZIkCH2OTosLRnDelceTtH3SYfo= -github.com/aws/aws-sdk-go v1.44.171/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= -github.com/bxcodec/faker/v3 v3.8.0 h1:F59Qqnsh0BOtZRC+c4cXoB/VNYDMS3R5mlSpxIap1oU= -github.com/bxcodec/faker/v3 v3.8.0/go.mod h1:gF31YgnMSMKgkvl+fyEo1xuSMbEuieyqfeslGYFjneM= -github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= -github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= -github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= -github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= -github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= -github.com/dhui/dktest v0.3.16 h1:i6gq2YQEtcrjKbeJpBkWjE8MmLZPYllcjOFbTZuPDnw= -github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= -github.com/docker/docker v20.10.24+incompatible h1:Ugvxm7a8+Gz6vqQYQQ2W7GYq5EUPaAiuPgIfVyI3dYE= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= -github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= -github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= -github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= -github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= -github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= -github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= -github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= -github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= -github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8= -github.com/go-git/go-git/v5 v5.9.0 h1:cD9SFA7sHVRdJ7AYck1ZaAa/yeuBvGPxwXDL8cxrObY= -github.com/go-git/go-git/v5 v5.9.0/go.mod h1:RKIqga24sWdMGZF+1Ekv9kylsDz6LzdTSI2s/OsZWE0= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= -github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= -github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= -github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= -github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0= -github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/goccy/go-json v0.9.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= -github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/golang-migrate/migrate/v4 v4.16.2 h1:8coYbMKUyInrFk1lfGfRovTLAW7PhWp8qQDT2iKfuoA= -github.com/golang-migrate/migrate/v4 v4.16.2/go.mod h1:pfcJX4nPHaVdc5nmdCikFBWtm+UBpiZjRNNsyBbp0/o= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= -github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= -github.com/huandu/go-sqlbuilder v1.15.0 h1:sIc0elfNoGQRyrnfUjgNtqW2NepNagsgNX0G0n9hKrI= -github.com/huandu/go-sqlbuilder v1.15.0/go.mod h1:nUVmMitjOmn/zacMLXT0d3Yd3RHoO2K+vy906JzqxMI= -github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= -github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= -github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= -github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= -github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= -github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= -github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.14.0 h1:vrbA9Ud87g6JdFWkHTJXppVce58qPIdP7N8y0Ml/A7Q= -github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= -github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= -github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= -github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= -github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= -github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= -github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= -github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0= -github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= -github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= -github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= -github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= -github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= -github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0= -github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE= -github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= -github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= -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/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= -github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= -github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A= -github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= -github.com/lestrrat-go/blackmagic v1.0.0 h1:XzdxDbuQTz0RZZEmdU7cnQxUtFUzgCSPq8RCz4BxIi4= -github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ= -github.com/lestrrat-go/httpcc v1.0.0 h1:FszVC6cKfDvBKcJv646+lkh4GydQg2Z29scgUfkOpYc= -github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++0Gf8MBnAvE= -github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc= -github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= -github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= -github.com/lestrrat-go/jwx v1.2.20 h1:ckMNlG0MqCcVp7LnD5FN2+459ndm7SW3vryE79Dz9nk= -github.com/lestrrat-go/jwx v1.2.20/go.mod h1:tLE1XszaFgd7zaS5wHe4NxA+XVhu7xgdRvDpNyi3kNM= -github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4= -github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/logrusorgru/aurora/v3 v3.0.0/go.mod h1:vsR12bk5grlLvLXAYrBsb5Oc/N+LxAlxggSjiwMnCUc= -github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= -github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= -github.com/matryer/moq v0.2.7/go.mod h1:kITsx543GOENm48TUAQyJ9+SAvFSr7iGQXPoth/VUBk= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= -github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= -github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= -github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= -github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= -github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= -github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rs/cors v1.8.1 h1:OrP+y5H+5Md29ACTA9imbALaKHwOSUZkcizaG0LT5ow= -github.com/rs/cors v1.8.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/rs/cors/wrapper/gin v0.0.0-20221003140808-fcebdb403f4d h1:xKonGHdG2Wh3vUkHP0dQC6ZruT9epZCyKrXTxo+xWpk= -github.com/rs/cors/wrapper/gin v0.0.0-20221003140808-fcebdb403f4d/go.mod h1:IqFyM9uAsle0Bd4h2u+28E+Ma2884FPhOsrREy4dj80= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= -github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= -github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= -github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM= -github.com/skeema/knownhosts v1.2.0/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo= -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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -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.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= -github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= -github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= -github.com/urfave/cli/v2 v2.8.1 h1:CGuYNZF9IKZY/rfBe3lJpccSoIY1ytfvmgQT90cNOl4= -github.com/urfave/cli/v2 v2.8.1/go.mod h1:Z41J9TPoffeoqP0Iza0YbAhGvymRdZAd2uPmZ5JxRdY= -github.com/vektah/gqlparser/v2 v2.5.1 h1:ZGu+bquAY23jsxDRcYpWjttRZrUz07LbiY77gUOHcr4= -github.com/vektah/gqlparser/v2 v2.5.1/go.mod h1:mPgqFBu/woKTVYWyNk8cO3kh4S/f4aRFZrvOnp3hmCs= -github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= -github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -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.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -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-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -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.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= From 5e6c4674658b5faab727a6ac787ebfe1e6ee786b Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:25:46 -0700 Subject: [PATCH 20/37] remove internal tools --- .../delete-faker-accounts/README.md | 10 - .../delete-faker-accounts/index.js | 79 ------ .../delete-faker-accounts/makefile | 55 ---- .../internal-tools/wss-demo-client/README.md | 139 --------- .../wss-demo-client/getToken.js | 19 -- .../internal-tools/wss-demo-client/index.js | 69 ----- .../internal-tools/wss-demo-client/makefile | 108 ------- .../wss-demo-client/package-lock.json | 268 ------------------ .../wss-demo-client/package.json | 10 - 9 files changed, 757 deletions(-) delete mode 100644 services/internal-tools/delete-faker-accounts/README.md delete mode 100644 services/internal-tools/delete-faker-accounts/index.js delete mode 100644 services/internal-tools/delete-faker-accounts/makefile delete mode 100644 services/internal-tools/wss-demo-client/README.md delete mode 100644 services/internal-tools/wss-demo-client/getToken.js delete mode 100644 services/internal-tools/wss-demo-client/index.js delete mode 100644 services/internal-tools/wss-demo-client/makefile delete mode 100644 services/internal-tools/wss-demo-client/package-lock.json delete mode 100644 services/internal-tools/wss-demo-client/package.json diff --git a/services/internal-tools/delete-faker-accounts/README.md b/services/internal-tools/delete-faker-accounts/README.md deleted file mode 100644 index 25796745..00000000 --- a/services/internal-tools/delete-faker-accounts/README.md +++ /dev/null @@ -1,10 +0,0 @@ -

- systemaccounting -

- -### delete-faker-accounts - -1. invoked by cloudwatch cron -1. deletes faker accounts left over by integration tests in dev db - -terraform: none, not deployed \ No newline at end of file diff --git a/services/internal-tools/delete-faker-accounts/index.js b/services/internal-tools/delete-faker-accounts/index.js deleted file mode 100644 index 322c7522..00000000 --- a/services/internal-tools/delete-faker-accounts/index.js +++ /dev/null @@ -1,79 +0,0 @@ -const AWS = require('aws-sdk') -const cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider({ apiVersion: '2016-04-18' }) - -exports.handler = async (event) => { - const params = {} - params.UserPoolId = process.env.COGNITO_POOL_ID - params.AttributesToGet = [] - params.Filter = `username ^= \"Faker\"` - - const listCognitoUsers = await new Promise((resolve, reject) => { - cognitoidentityserviceprovider.listUsers(params, (err, data) => { - if (err) { - console.log(err, err.stack) - reject(err) - return - } - else { - console.log(data) - resolve(data) - return - } - }) - }).catch(err => { - console.log(err, err.stack) - return err - }) - - let fakers = [] - for (let x = 0; x < listCognitoUsers.Users.length; x++) { - fakers.push(listCognitoUsers.Users[x].Username) - } - - const noFakersMsg = "No Faker accounts found" - - //Exit execution if Cognito purge unnecessary - if (fakers.length < 1) { - console.log(noFakersMsg) - return - } - - let responses = [] - - for(let y = 0; y < fakers.length; y++) { - const params = {} - params.UserPoolId = process.env.COGNITO_POOL_ID - params.Username = fakers[y] - - const deleteCognitoUser = await new Promise((resolve, reject) => { - cognitoidentityserviceprovider.adminDeleteUser(params, (err, data) => { - if (err) { - console.log(err, err.stack) - reject(err) - return - } - else { - console.log(data) - resolve(data) - return - } - }) - }).catch(err => { - console.log(err, err.stack) - return err - }) - - responses.push(deleteCognitoUser) - } - - const errorFromCognito = (obj) => { - return JSON.stringify(obj) === '{}' - } - - if (!responses.every(errorFromCognito)) { - console.log('Failing to delete all accounts') - return - } else { - return - } -} \ No newline at end of file diff --git a/services/internal-tools/delete-faker-accounts/makefile b/services/internal-tools/delete-faker-accounts/makefile deleted file mode 100644 index fb9228f0..00000000 --- a/services/internal-tools/delete-faker-accounts/makefile +++ /dev/null @@ -1,55 +0,0 @@ -APP_NAME = delete-faker -ARTIFACT_NAME=$(APP_NAME)-src.zip -RELATIVE_PROJECT_ROOT_PATH=../.. - -test-env-arg: -ifndef ENV - $(error trailing ENV assignment missing, e.g. make test ENV=dev) -endif - -###################### build ###################### - -zip: - zip -r $(ARTIFACT_NAME) index.js - -###################### clean ###################### - -clean: - $(MAKE) clean-artifact - -clean-artifact: - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/clean-artifact.sh \ - --app-name $(APP_NAME) \ - --artifact-name $(ARTIFACT_NAME) - -###################### deploy ###################### - -deploy: - @$(MAKE) -s test-env-arg - @$(MAKE) -s clean - $(MAKE) zip - $(MAKE) put-object - $(MAKE) update-function - -initial-deploy: - @$(MAKE) -s test-env-arg - @$(MAKE) -s clean - $(MAKE) zip - $(MAKE) put-object - -put-object: - @$(MAKE) -s test-env-arg - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/put-object.sh \ - --app-name $(APP_NAME) \ - --artifact-name $(ARTIFACT_NAME) \ - --env $(ENV) - -update-function: - @$(MAKE) -s test-env-arg - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/update-function.sh \ - --app-name $(APP_NAME) \ - --artifact-name $(ARTIFACT_NAME) \ - --env $(ENV) \ No newline at end of file diff --git a/services/internal-tools/wss-demo-client/README.md b/services/internal-tools/wss-demo-client/README.md deleted file mode 100644 index 3036d9ee..00000000 --- a/services/internal-tools/wss-demo-client/README.md +++ /dev/null @@ -1,139 +0,0 @@ -

- systemaccounting -

- -### client websocket integration with javascript -1. create a pending transaction notification by sending a transaction request to a test account from the ui, or postman -1. `cd services/internal-tools/wss-demo-client` -1. `make install` -1. set `TEST_ACCOUNT`, `TEST_PASSWORD`, `LOG_ID_TOKEN` makefile variables -1. `make get-secrets ENV=dev` to create `.env` file from secrets manager -1. `make getnotifications` creates a websocket connection with api gateway, sends a `getnotifications` action and cognito account token, then prints the pending notication from step 1 -1. `make clearnotifications` creates websocket connection with api gateway, sends a `clearnotifications` action and cognito account token, then prints the transaction notification id of the cleared notification - -**print a cognito id token** - -set makefile var `LOG_ID_TOKEN=true` in step 3 - -**javascript websocket connection** - -```js -const WebSocket = require('ws') - -const ws = new WebSocket(process.env.WEBSOCKET_CLIENT_URI) -``` - -**get notifications** -`pending` transaction notifications retrieved with `{"action":"getnotifications","token":"eyJraW..."}` websocket message: - -```js - -const token = await getToken( - cognitoIdsp, - process.env.CLIENT_ID, - process.env.ACCOUNT, - process.env.SECRET -) - -ws.on('open', () => { - console.log('socket opened') - ws.send(JSON.stringify({ - action: "getnotifications", - token // pass token in every getnotifications message - })) -}) -ws.on('message', data => { - console.log(data) - ws.close() -}) - -// => -{ - "pending": [ - { - "notification_id": "13", - "message": { - "id": "10", - "author": "GroceryCo", - "sum_value": "21.8", - "author_role": "creditor", - "equilibrium_time": "2021-05-04T17:48:19.883877Z", - "transaction_items": [ - { - "id": "55", - "price": "0.18", - "debitor": "GroceryCo", - "item_id": "9% state sales tax", - "creditor": "StateOfCalifornia", - "quantity": "1", - "transaction_id": "10", - "units_measured": null, - "rule_instance_id": "1", - "debitor_profile_id": "18", - "creditor_profile_id": "16", - "unit_of_measurement": "", - "debitor_approval_time": "2021-05-04T17:47:54.737050Z", - "creditor_approval_time": "2021-05-04T17:47:54.737050Z" - }, - { - "id": "56", - "price": "0.27", - "debitor": "GroceryCo", - "item_id": "9% state sales tax", - "creditor": "StateOfCalifornia", - "quantity": "2", - "transaction_id": "10", - "units_measured": null, - "rule_instance_id": "1", - "debitor_profile_id": "18", - "creditor_profile_id": "16", - "unit_of_measurement": "", - "debitor_approval_time": "2021-05-04T17:47:54.737050Z", - "creditor_approval_time": "2021-05-04T17:47:54.737050Z" - } - ] - } - } - ] -} -``` -**clear notifications** -transaction notifications cleared by sending `clearnotifications` websocket message: -```js - -const clearMessageRequest = { - "action":"clearnotifications", - "notification_ids": ["4","6"], - "token": "eyJraW...", -} - -ws.send(clearMessageRequest) -``` - -client receives notification cleared confirmation: - -```js -{ cleared: [ '6', '4' ] } -``` - ---- -### local development with wscat - -##### create pending notifications -1. choose an existing user account, or create one from the web client (`make get-secrets ENV=dev` in project root to learn `CLIENT_URI` from root `.env` file) -1. create pending transaction notifications for user account by referencing the account in new request(s)/transaction(s), OPTIONS: - 1. create from webclient, OR - 1. create from postman: - 1. print user account id token with `scripts/print-id-token.sh` (assign `CLIENT_ID` env var value to `client-id` script parameter) - 1. import `services/graphql/postman/graphql.postman_collection.json` collection into postman - 1. open `createRequest` postman collection request - 1. assign id token to `Authorization` header - 1. click postman "Send" button multiple times - -##### print and clear pending notifications -1. `cd services/internal-tools/wss-demo-client` -1. `make get-secrets ENV=dev` to create `.env` with step 1 user account credentials -1. `make save-id-token USER=SomeUser PASS=SomeSecret` to add `ID_TOKEN` assignment from cognito to `.env` file -1. `make get` to return **pending** notifications from `services/notifications-get` in lambda -1. list desired `notification_id` values from notifications returned by websocket endpoint in previous step, e.g. `2,7,12` -1. `make clear IDS=2,7,12` to clear notifications with ids `2`, `7` and `12` from `services/notifications-clear` in lambda \ No newline at end of file diff --git a/services/internal-tools/wss-demo-client/getToken.js b/services/internal-tools/wss-demo-client/getToken.js deleted file mode 100644 index 6d4cb37c..00000000 --- a/services/internal-tools/wss-demo-client/getToken.js +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = (service, clientId, account, secret, enableLogging) => { - let params = { - AuthFlow: 'USER_PASSWORD_AUTH', - ClientId: clientId, - AuthParameters: { - 'USERNAME': account, - 'PASSWORD': secret - } - }; - return service.initiateAuth(params) - .promise() - .then(data => { - if (enableLogging == 'true') { - console.log(data.AuthenticationResult.IdToken); - } - return data.AuthenticationResult.IdToken; - }) - .catch(err => console.log(err)); -} \ No newline at end of file diff --git a/services/internal-tools/wss-demo-client/index.js b/services/internal-tools/wss-demo-client/index.js deleted file mode 100644 index bf051bf9..00000000 --- a/services/internal-tools/wss-demo-client/index.js +++ /dev/null @@ -1,69 +0,0 @@ -const AWS = require('aws-sdk') -const WebSocket = require('ws') - -const getToken = require('./getToken') - -// env var inentory (avoid const assignments): -// process.env.CLIENT_ID -// process.env.ACCOUNT -// process.env.SECRET -// process.env.WEBSOCKET_CLIENT_URI -// process.env.AWS_REGION - -const cognitoIdsp = new AWS.CognitoIdentityServiceProvider({ - region: process.env.AWS_REGION, -}) - -;(async () => { - const token = await getToken( - cognitoIdsp, - process.env.CLIENT_ID, - process.env.ACCOUNT, - process.env.SECRET, - process.env.LOG_ID_TOKEN, - ); - - const ws = new WebSocket(process.env.WEBSOCKET_CLIENT_URI); - - ws.on('open', () => { - console.log('socket opened'); - ws.send(JSON.stringify({ - action: "getnotifications", - // pass token in every getnotifications message - token: token, - })); - }); - - ws.on('message', data => { - if (process.env.ACTION === 'getnotifications') { - console.log('response from get:'); - console.log(data); - ws.close(); - }; - if (process.env.ACTION === 'clearnotifications') { - let event = JSON.parse(data); - if (event.cleared) { - console.log('response from clear:'); - console.log(event); - ws.close(); - } else { - const event = JSON.parse(data); - if (event.pending) { - const IDsToDelete = event.pending.map(x => x.notification_id); - const clearMessageRequest = JSON.stringify({ - action: "clearnotifications", - notification_ids: IDsToDelete, - // pass token in every clearnotifications message - token: token, - }); - console.log('sending clear message request as:'); - console.log(clearMessageRequest); - ws.send(clearMessageRequest); - } else { - console.log('0 pending notifications to clear'); - ws.close(); - }; - }; - }; - }); -})(); \ No newline at end of file diff --git a/services/internal-tools/wss-demo-client/makefile b/services/internal-tools/wss-demo-client/makefile deleted file mode 100644 index cd6c42b6..00000000 --- a/services/internal-tools/wss-demo-client/makefile +++ /dev/null @@ -1,108 +0,0 @@ -ENV_FILE=$(CURDIR)/.env -LOG_ID_TOKEN=false -PROJECT_CONF_FILE_NAME=project.yaml -RELATIVE_PROJECT_ROOT_PATH=../../.. -PROJECT_CONF=$(RELATIVE_PROJECT_ROOT_PATH)/$(PROJECT_CONF_FILE_NAME) -REGION=$(shell yq '.infrastructure.terraform.aws.modules.environment.env_var.set.REGION.default' $(PROJECT_CONF)) -DIR_PATH=services/internal-tools/wss-demo-client - -ENV_VARS := CLIENT_ID \ -WEBSOCKET_CLIENT_URI \ -AWS_REGION - -test-env-arg: -ifndef ENV - $(error trailing ENV assignment missing, e.g. make test ENV=dev) -endif - -test-username-arg: -ifndef ACCT - $(error trailing ACCT assignment missing, e.g. ACCT=SomeAccount) -endif - -test-password-arg: -ifndef PASS - $(error trailing PASS assignment missing, e.g. PASS=SomeSecret) -endif - -test-ids-arg: -ifndef IDS - $(error trailing IDS assignment missing, e.g. IDS=2,7,12) -endif - -getnotifications: - eval $$(cat .env) \ - LOG_ID_TOKEN=$(LOG_ID_TOKEN) \ - ACTION=getnotifications \ - node index.js - -clearnotifications: - eval $$(cat .env) \ - LOG_ID_TOKEN=$(LOG_ID_TOKEN) \ - ACTION=clearnotifications \ - node index.js - -install: - npm install - -clean-deps: - rm -rf node_modules - -clean: - $(MAKE) clean-deps - -###################### secrets ###################### - -test-env-file: -ifeq (,$(wildcard $(ENV_FILE))) - $(error no .env file, run 'make get-secrets ENV=dev USER=SomeUser PASS=SomeSecret') -endif - -get-secrets: - @$(MAKE) -s retrieve-each-secret - @if [ ! -s $(ENV_FILE) ]; then \ - rm $(ENV_FILE); \ - echo 'no env vars required'; \ - else \ - echo 'env vars retrieved'; \ - fi - -retrieve-each-secret: test-env-arg clean-env $(ENV_VARS) -$(ENV_VARS): - @if [ $@ = AWS_REGION ]; then \ - echo AWS_REGION=$(REGION) >> $(ENV_FILE); \ - else \ - ENV_VAR=$$(aws secretsmanager get-secret-value \ - --region $(REGION) \ - --secret-id $(ENV)/$@ \ - --query 'SecretString' \ - --output text); \ - echo $@=$$ENV_VAR >> $(ENV_FILE); \ - fi - -save-id-token: - @$(MAKE) -s test-username-arg - @$(MAKE) -s test-password-arg - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/save-id-token.sh \ - --dir-path $(DIR_PATH) \ - --username $(ACCT) \ - --password $(PASS) \ - --region $(REGION) - -clean-env: - rm -f $(ENV_FILE) - -###################### notifications ###################### - -get: - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/get-notifications.sh \ - --dir-path $(DIR_PATH) - -clear: - @$(MAKE) -s test-ids-arg - @cd $(RELATIVE_PROJECT_ROOT_PATH); \ - bash scripts/clear-notifications.sh \ - --dir-path $(DIR_PATH) \ - --ids '$(IDS)' \ No newline at end of file diff --git a/services/internal-tools/wss-demo-client/package-lock.json b/services/internal-tools/wss-demo-client/package-lock.json deleted file mode 100644 index 7773c320..00000000 --- a/services/internal-tools/wss-demo-client/package-lock.json +++ /dev/null @@ -1,268 +0,0 @@ -{ - "name": "ws", - "version": "1.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "ws", - "version": "1.0.0", - "license": "UNLICENSED", - "dependencies": { - "aws-sdk": "^2.900.0", - "ws": "^7.4.5" - } - }, - "node_modules/aws-sdk": { - "version": "2.952.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.952.0.tgz", - "integrity": "sha512-FZkmOWAyDSQMeD8iioeoSW873ZjPXLfGejr0gNi8kQB7JrllOayPaexpq70aT+7n5bAzArjSIH8OAB+BoHYijA==", - "hasInstallScript": true, - "dependencies": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.3.2", - "xml2js": "0.4.19" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "node_modules/events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "node_modules/jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - }, - "node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" - }, - "node_modules/url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", - "dependencies": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, - "node_modules/uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/ws": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz", - "integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - }, - "node_modules/xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", - "engines": { - "node": ">=4.0" - } - } - }, - "dependencies": { - "aws-sdk": { - "version": "2.952.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.952.0.tgz", - "integrity": "sha512-FZkmOWAyDSQMeD8iioeoSW873ZjPXLfGejr0gNi8kQB7JrllOayPaexpq70aT+7n5bAzArjSIH8OAB+BoHYijA==", - "requires": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.3.2", - "xml2js": "0.4.19" - } - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" - }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" - }, - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" - }, - "sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" - }, - "url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" - }, - "ws": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz", - "integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==", - "requires": {} - }, - "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - }, - "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" - } - } -} diff --git a/services/internal-tools/wss-demo-client/package.json b/services/internal-tools/wss-demo-client/package.json deleted file mode 100644 index 032c5ecf..00000000 --- a/services/internal-tools/wss-demo-client/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "ws", - "version": "1.0.0", - "main": "index.js", - "license": "UNLICENSED", - "dependencies": { - "aws-sdk": "^2.900.0", - "ws": "^7.4.5" - } -} From 950199526b239e088ee84643273be857d42bf745 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:27:04 -0700 Subject: [PATCH 21/37] remove unused go convenience scripts --- scripts/compile-go-linux.sh | 26 --------------- scripts/mock-go-ifaces.sh | 66 ------------------------------------- 2 files changed, 92 deletions(-) delete mode 100644 scripts/compile-go-linux.sh delete mode 100644 scripts/mock-go-ifaces.sh diff --git a/scripts/compile-go-linux.sh b/scripts/compile-go-linux.sh deleted file mode 100644 index 55183159..00000000 --- a/scripts/compile-go-linux.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -if [[ "$#" -ne 2 ]]; then - echo "use: bash scripts/compile-go-linux.sh --app-name request-create" - exit 1 -fi - -while [[ "$#" -gt 0 ]]; do - case $1 in - --app-name) APP_NAME="$2"; shift ;; - *) echo "unknown parameter passed: $1"; exit 1 ;; - esac - shift -done - -PROJECT_CONF=project.yaml - -APP_DIR_PATH=$(source scripts/list-dir-paths.sh --type app | grep --color=never "$APP_NAME") -APP_CONF_PATH=$(source scripts/list-conf-paths.sh --type app | grep --color=never "$APP_NAME") - -BINARY_NAME=$(yq '.services.env_var.set.BINARY_NAME.default' $PROJECT_CONF) -BUILD_SRC_PATH=$(yq "$APP_CONF_PATH.build_src_path" $PROJECT_CONF) - -cd $APP_DIR_PATH - -GOOS=linux CGO_ENABLED=0 go build -o $BINARY_NAME ./$BUILD_SRC_PATH \ No newline at end of file diff --git a/scripts/mock-go-ifaces.sh b/scripts/mock-go-ifaces.sh deleted file mode 100644 index c787d2a5..00000000 --- a/scripts/mock-go-ifaces.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash - -set -e - -# print use -if [[ "$#" -ne 2 ]]; then - cat <<- 'EOF' - use: - bash scripts/mock-go-ifaces.sh --app-or-pkg-name sqls - - *note: set mocked_ifaces list in project.yaml - EOF - exit 1 -fi - -# assign vars to script args -while [[ "$#" -gt 0 ]]; do - case $1 in - --app-or-pkg-name) APP_OR_PKG_NAME="$2"; shift ;; - *) echo "unknown parameter passed: $1"; exit 1 ;; - esac - shift -done - -PROJECT_CONF=project.yaml -GO_MOCK_PACKAGE_NAME_PREFIX=$(yq '.scripts.env_var.set.GO_MOCK_PACKAGE_NAME_PREFIX.default' "$PROJECT_CONF") -GO_MOCK_FILE_NAME_SUFFIX=$(yq '.scripts.env_var.set.GO_MOCK_FILE_NAME_SUFFIX.default' "$PROJECT_CONF") - -# source commonly used functions -source ./scripts/shared-error.sh - -if [[ $(bash scripts/list-dir-paths.sh --type all | grep --color=never "$APP_OR_PKG_NAME$" >/dev/null 2>&1; echo $?) -ne 0 ]]; then - error_exit "\"$APP_OR_PKG_NAME\" NOT in $PROJECT_CONF. exiting." -fi - -APP_DIR_PATH=$(source scripts/list-dir-paths.sh --type all | grep --color=never "$APP_OR_PKG_NAME$") - -CONF_PATH=$(source scripts/dir-to-conf-path.sh $APP_DIR_PATH) - -MOCKED_IFACES_PROPERTY='mocked_interfaces' - -if [[ $(yq "$CONF_PATH | has(\"$MOCKED_IFACES_PROPERTY\")" $PROJECT_CONF) == 'false' ]]; then - # error when mocked_ifaces property not in project.yaml for app or pkg - error_exit "\"$MOCKED_IFACES_PROPERTY\" is NOT set in $PROJECT_CONF under $CONF_PATH. exiting." -fi - -# get list of packages to mock from project.yaml -PKGS_TO_MOCK=($(yq "$CONF_PATH.$MOCKED_IFACES_PROPERTY | keys | join (\" \")" $PROJECT_CONF)) - -for p in "${PKGS_TO_MOCK[@]}"; do - - # e.g. github.com/jackc/pgx/v4 - GO_PKG_IMPORT_PATH="$p" - - # create comma separated list of package interfaces to mock and pass as arg to gomock - # e.g InsertSQLBuilder,UpdateSQLBuilder,SelectSQLBuilder,DeleteSQLBuilder - IFACE_LIST=$(yq "$CONF_PATH.$MOCKED_IFACES_PROPERTY[\"$p\"] | join(\",\")" $PROJECT_CONF) - - MOCK_PACKAGE_NAME="$GO_MOCK_PACKAGE_NAME_PREFIX"_"$APP_OR_PKG_NAME" - MOCK_FILE_PREFIX=$(basename "$GO_PKG_IMPORT_PATH") - MOCK_FILE_NAME="$MOCK_FILE_PREFIX"_"$GO_MOCK_FILE_NAME_SUFFIX" - MOCK_FILE="./$APP_DIR_PATH/$MOCK_PACKAGE_NAME/$MOCK_FILE_NAME" - - # create mock file of interfaces in subdirectory - mockgen -package "$MOCK_PACKAGE_NAME" -destination "$MOCK_FILE" "$GO_PKG_IMPORT_PATH" "$IFACE_LIST" -done \ No newline at end of file From 5e9592b1a0833a4aff17cba99c53ed1037400f9d Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:27:30 -0700 Subject: [PATCH 22/37] remove unused notification testing scripts --- scripts/clear-notifications.sh | 73 ---------------------------------- scripts/get-notifications.sh | 65 ------------------------------ 2 files changed, 138 deletions(-) delete mode 100644 scripts/clear-notifications.sh delete mode 100644 scripts/get-notifications.sh diff --git a/scripts/clear-notifications.sh b/scripts/clear-notifications.sh deleted file mode 100644 index 5bd5b78c..00000000 --- a/scripts/clear-notifications.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -if [[ "$#" -ne 4 ]]; then - cat <<- 'EOF' - use: - bash scripts/clear-notifications.sh \ - --dir-path services/notifications-clear \ - --ids 2,7,12 - EOF - exit 1 -fi - -while [[ "$#" -gt 0 ]]; do - case $1 in - --dir-path) DIR_PATH="$2"; shift ;; - --ids) IDS="$2"; shift ;; - *) echo "unknown parameter passed: $1"; exit 1 ;; - esac - shift -done - -ENV_FILE_NAME=$(yq '.env_var.set.ENV_FILE_NAME.default' project.yaml) -ENV_FILE="$DIR_PATH/$ENV_FILE_NAME" - -# test for .env file availability -if [[ ! -f $ENV_FILE ]]; then - echo "missing $ENV_FILE_NAME file, run 'make get-secrets ENV=dev'" - exit 1 -fi - -# test for USERNAME assignment in .env file -USERNAME_LINE_COUNT=$((grep -e '^USERNAME' $ENV_FILE || true) | wc -l | awk '{print $1}') -if [[ $USERNAME_LINE_COUNT -eq 0 ]]; then - echo "missing json web token credential. run 'make save-id-token'" - exit 1 -fi - -# test for PASSWORD assignment in .env file -PASSWORD_LINE_COUNT=$((grep -e '^PASSWORD' $ENV_FILE || true) | wc -l | awk '{print $1}') -if [[ $PASSWORD_LINE_COUNT -eq 0 ]]; then - echo "missing json web token credential. run 'make save-id-token'" - exit 1 -fi - -# test for ID_TOKEN assignment in .env file -ID_TOKEN_LINE_COUNT=$((grep -e '^ID_TOKEN' $ENV_FILE || true) | wc -l | awk '{print $1}') -if [[ $ID_TOKEN_LINE_COUNT -eq 0 ]]; then - echo "missing json web token credential. run 'make save-id-token'" - exit 1 -fi - -TEMPLATE_JSON_PATH=./pkg/testdata/clearnotifications.json - -source $ENV_FILE - -# convert comma separated integers to strings: 2,7,12 => "2","7","12" -declare IDS_TO_CLEAR -for i in $(echo $IDS | tr , ' '); do - IDS_TO_CLEAR+=\"$i\",; -done - -# remove trailing comma -IDS_TO_CLEAR=${IDS_TO_CLEAR%?} - -WEBSOCKET_MESSAGE=$(yq \ - -I0 \ - -o=json \ - ".token = \"$ID_TOKEN\" | .notification_ids = [$IDS_TO_CLEAR]" \ - $TEMPLATE_JSON_PATH) - -npx wscat -c $WEBSOCKET_CLIENT_URI -x "$WEBSOCKET_MESSAGE" \ No newline at end of file diff --git a/scripts/get-notifications.sh b/scripts/get-notifications.sh deleted file mode 100644 index 3ec6407b..00000000 --- a/scripts/get-notifications.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -if [[ "$#" -ne 2 ]]; then - cat <<- 'EOF' - use: - bash scripts/get-notifications.sh \ - --dir-path services/notifications-get - EOF - exit 1 -fi - -while [[ "$#" -gt 0 ]]; do - case $1 in - --dir-path) DIR_PATH="$2"; shift ;; - *) echo "unknown parameter passed: $1"; exit 1 ;; - esac - shift -done - -ENV_FILE_NAME='.env' -ENV_FILE="$DIR_PATH/$ENV_FILE_NAME" - -# test for .env file availability -if [[ ! -f $ENV_FILE ]]; then - echo "missing $ENV_FILE_NAME file, run 'make get-secrets ENV=dev'" - exit 1 -fi - -# test for USERNAME assignment in .env file -USERNAME_LINE_COUNT=$((grep -e '^USERNAME' $ENV_FILE || true) | wc -l | awk '{print $1}') -if [[ $USERNAME_LINE_COUNT -eq 0 ]]; then - echo "missing json web token credential. run 'make save-id-token'" - exit 1 -fi - -# test for PASSWORD assignment in .env file -PASSWORD_LINE_COUNT=$((grep -e '^PASSWORD' $ENV_FILE || true) | wc -l | awk '{print $1}') -if [[ $PASSWORD_LINE_COUNT -eq 0 ]]; then - echo "missing json web token credential. run 'make save-id-token'" - exit 1 -fi - -# test for ID_TOKEN assignment in .env file -ID_TOKEN_LINE_COUNT=$((grep -e '^ID_TOKEN' $ENV_FILE || true) | wc -l | awk '{print $1}') -if [[ $ID_TOKEN_LINE_COUNT -eq 0 ]]; then - echo "missing json web token credential. run 'make save-id-token'" - exit 1 -fi - -TEMPLATE_JSON_PATH=./pkg/testdata/getnotifications.json - -source $ENV_FILE - -WEBSOCKET_MESSAGE=$(yq -I0 -o=json ".token = \"$ID_TOKEN\"" $TEMPLATE_JSON_PATH) - -RESPONSE=$(npx wscat -c $WEBSOCKET_CLIENT_URI -x "$WEBSOCKET_MESSAGE") - -echo $RESPONSE | yq -o=json - -PENDING_NOTIFICATIONS=$(echo -n $RESPONSE | yq '[.pending[] | .notification_id] | join(",")') - -echo "" -echo "pending notifications: $PENDING_NOTIFICATIONS" \ No newline at end of file From cc112a8e8994b02191c6aced69e83e8ac14a35be Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:28:03 -0700 Subject: [PATCH 23/37] remove notifications param from env file script --- scripts/create-env-file.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts/create-env-file.sh b/scripts/create-env-file.sh index 1e58c50e..dad8fb01 100644 --- a/scripts/create-env-file.sh +++ b/scripts/create-env-file.sh @@ -53,7 +53,6 @@ REGION=$(yq '.infrastructure.terraform.aws.modules.environment.env_var.set.REGIO SECRETS=($(yq "$APP_CONF_PATH.env_var.get | join(\" \")" $PROJECT_CONF)) PARAMS=($(yq "$APP_CONF_PATH.params | join(\" \")" $PROJECT_CONF)) ENABLE_API_AUTH=$(yq '.infrastructure.terraform.aws.modules.environment.env_var.set.ENABLE_API_AUTH.default' $PROJECT_CONF) -ENABLE_NOTIFICATIONS=$(yq '.infrastructure.terraform.aws.modules.environment.env_var.set.ENABLE_NOTIFICATIONS.default' $PROJECT_CONF) ENV_FILE_NAME=$(yq '.env_var.set.ENV_FILE_NAME.default' $PROJECT_CONF) ENV_FILE="$APP_DIR_PATH/$ENV_FILE_NAME" LOCAL_ADDRESS=$(yq '.env_var.set.LOCAL_ADDRESS.default' $PROJECT_CONF) @@ -137,8 +136,6 @@ function set_params() { echo $p=$REGION >> $ENV_FILE elif [[ $p == 'ENABLE_API_AUTH' ]]; then echo ENABLE_API_AUTH=$ENABLE_API_AUTH >> $ENV_FILE - elif [[ $p == 'ENABLE_NOTIFICATIONS' ]]; then - echo ENABLE_NOTIFICATIONS=$ENABLE_NOTIFICATIONS >> $ENV_FILE fi done } From e1eb0efb64556a239db59c3c1b33b2a9342604d9 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:30:09 -0700 Subject: [PATCH 24/37] remove cloud notification and websocket services --- .../terraform/aws/environments/dev/main.tf | 9 +- .../terraform/aws/environments/prod/main.tf | 5 - .../environment/v001/lambda-services.tf | 69 -------- .../modules/environment/v001/notifications.tf | 165 ------------------ .../aws/modules/environment/v001/ssm.tf | 7 - .../aws/modules/environment/v001/variables.tf | 2 - 6 files changed, 2 insertions(+), 255 deletions(-) delete mode 100644 infrastructure/terraform/aws/modules/environment/v001/notifications.tf diff --git a/infrastructure/terraform/aws/environments/dev/main.tf b/infrastructure/terraform/aws/environments/dev/main.tf index 7a6b7764..a3578f9c 100644 --- a/infrastructure/terraform/aws/environments/dev/main.tf +++ b/infrastructure/terraform/aws/environments/dev/main.tf @@ -3,7 +3,7 @@ locals { ENV = "dev" APP_ENV = "${local.APP}-${local.ENV}" PROJECT_CONF = yamldecode(file("../../../../../project.yaml")) - STORAGE_ENV_VAR = local.PROJECT_CONF.infrastructure.terraform.aws.modules.project-storage.env_var.set + STORAGE_ENV_VAR = local.PROJECT_CONF.infrastructure.terraform.aws.modules.project-storage.env_var.set ORIGIN_PREFIX = local.STORAGE_ENV_VAR.CLIENT_ORIGIN_BUCKET_PREFIX.default ARTIFACTS_PREFIX = local.STORAGE_ENV_VAR.ARTIFACTS_BUCKET_PREFIX.default TFSTATE_PREFIX = local.STORAGE_ENV_VAR.TFSTATE_BUCKET_PREFIX.default @@ -46,8 +46,7 @@ module "dev" { ############### lambda ############### - notifications_return_limit = 20 - initial_account_balance = 1000 + initial_account_balance = 1000 ############### rds ############### @@ -69,10 +68,6 @@ module "dev" { // apigw v2 enable_api_auto_deploy = true - ############### notifications ############### - - enable_notifications = local.INFRA_ENV_VAR.ENABLE_NOTIFICATIONS.default - ############### client ############### client_origin_bucket_name = "${local.ORIGIN_PREFIX}-${local.ID_ENV}" diff --git a/infrastructure/terraform/aws/environments/prod/main.tf b/infrastructure/terraform/aws/environments/prod/main.tf index 92be5197..00578691 100644 --- a/infrastructure/terraform/aws/environments/prod/main.tf +++ b/infrastructure/terraform/aws/environments/prod/main.tf @@ -60,7 +60,6 @@ module "prod" { ############### lambda ############### - notifications_return_limit = 20 initial_account_balance = 1000 ############### rds ############### @@ -86,10 +85,6 @@ module "prod" { // apigw v2 enable_api_auto_deploy = true - ############### notifications ############### - - enable_notifications = local.INFRA_ENV_VAR.ENABLE_NOTIFICATIONS.default - ############### client ############### client_origin_bucket_name = "${local.ORIGIN_PREFIX}-${local.ID_ENV}" diff --git a/infrastructure/terraform/aws/modules/environment/v001/lambda-services.tf b/infrastructure/terraform/aws/modules/environment/v001/lambda-services.tf index df408990..8265a160 100644 --- a/infrastructure/terraform/aws/modules/environment/v001/lambda-services.tf +++ b/infrastructure/terraform/aws/modules/environment/v001/lambda-services.tf @@ -16,8 +16,6 @@ module "request_create" { create_secret = true // suppports local testing } -########################## - module "request_approve" { source = "../../provided-lambda/v001" service_name = "request-approve" @@ -114,73 +112,6 @@ module "auto_confirm" { invoke_arn_principals = ["cognito-idp.amazonaws.com"] } -module "wss_connect" { - source = "../../go-lambda/v001" - service_name = "wss-connect" - env = var.env - ssm_prefix = var.ssm_prefix - env_id = var.env_id - env_vars = merge(local.POSTGRES_VARS, {}) - artifacts_bucket_name = var.artifacts_bucket_name - invoke_arn_principals = ["apigateway.amazonaws.com"] -} - -// invoked by request-create or request-approve through sns -module "notifications_send" { - source = "../../go-lambda/v001" - service_name = "notifications-send" - env = var.env - ssm_prefix = var.ssm_prefix - env_id = var.env_id - env_vars = merge(local.POSTGRES_VARS, { - APIGW_CONNECTIONS_URI = local.APIGW_CONNECTIONS_URI - }) - invoke_arn_principals = ["sns.amazonaws.com"] - artifacts_bucket_name = var.artifacts_bucket_name - attached_policy_arns = [aws_iam_policy.wss.arn] -} - -resource "aws_sns_topic_subscription" "notifications_send" { - topic_arn = aws_sns_topic.notifications.arn - protocol = "lambda" - endpoint = module.notifications_send.lambda_arn -} - -// invoked by getnotifications through wss -module "notifications_get" { - source = "../../go-lambda/v001" - service_name = "notifications-get" - env = var.env - ssm_prefix = var.ssm_prefix - env_id = var.env_id - env_vars = merge(local.POSTGRES_VARS, { - NOTIFICATIONS_RETURN_LIMIT = var.notifications_return_limit - APIGW_CONNECTIONS_URI = local.APIGW_CONNECTIONS_URI - COGNITO_JWKS_URI = local.COGNITO_JWKS_URI, - ENABLE_API_AUTH = var.enable_api_auth - }) - artifacts_bucket_name = var.artifacts_bucket_name - invoke_arn_principals = ["apigateway.amazonaws.com"] - attached_policy_arns = [aws_iam_policy.wss.arn] -} - -// invoked by clearnotifications through wss -module "notifications_clear" { - source = "../../go-lambda/v001" - service_name = "notifications-clear" - env = var.env - ssm_prefix = var.ssm_prefix - env_id = var.env_id - env_vars = merge(local.POSTGRES_VARS, { - APIGW_CONNECTIONS_URI = local.APIGW_CONNECTIONS_URI - COGNITO_JWKS_URI = local.COGNITO_JWKS_URI, - ENABLE_API_AUTH = var.enable_api_auth - }) - artifacts_bucket_name = var.artifacts_bucket_name - invoke_arn_principals = ["apigateway.amazonaws.com"] - attached_policy_arns = [aws_iam_policy.wss.arn] -} - module "rule" { source = "../../provided-lambda/v001" service_name = "rule" diff --git a/infrastructure/terraform/aws/modules/environment/v001/notifications.tf b/infrastructure/terraform/aws/modules/environment/v001/notifications.tf deleted file mode 100644 index 06891423..00000000 --- a/infrastructure/terraform/aws/modules/environment/v001/notifications.tf +++ /dev/null @@ -1,165 +0,0 @@ -locals { - // https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-how-to-call-websocket-api.html - APIGW_CONNECTIONS_URI = "https://${aws_apigatewayv2_api.notifications.id}.execute-api.${data.aws_region.current.name}.amazonaws.com/${var.env}" - WEBSOCKET_CLIENT_URI = "${aws_apigatewayv2_api.notifications.api_endpoint}/${var.env}/" -} - -resource "aws_sns_topic" "notifications" { - name = "notifications-${local.ID_ENV}" -} - -resource "aws_apigatewayv2_api" "notifications" { - name = "notifications-wss-${local.ID_ENV}" - description = "websocket in api in ${local.SPACED_ID_ENV}" - protocol_type = "WEBSOCKET" - route_selection_expression = "$request.body.action" -} - -resource "aws_apigatewayv2_stage" "notifications" { - api_id = aws_apigatewayv2_api.notifications.id - name = var.env - description = "wss api stage in ${local.SPACED_ID_ENV}" - deployment_id = aws_apigatewayv2_deployment.notifications.id - default_route_settings { - throttling_rate_limit = 10000 - throttling_burst_limit = 5000 - data_trace_enabled = true - logging_level = "ERROR" - } -} - -resource "aws_apigatewayv2_deployment" "notifications" { - // avoids BadRequestException during apply - depends_on = [ - module.connect_route.integration_id, - module.getnotifications_route.integration_id, - module.clearnotifications_route.integration_id, - module.disconnect_route.integration_id, - aws_apigatewayv2_route.default, - ] - - api_id = aws_apigatewayv2_api.notifications.id - description = "wss notifications deployment in ${local.SPACED_ID_ENV}" - triggers = { - version = 3 - } - lifecycle { - create_before_destroy = true - } -} - -module "connect_route" { - source = "../../apigwv2-route/v001" - env = var.env - apiv2_id = aws_apigatewayv2_api.notifications.id - route_key = "$connect" - lambda_invoke_arn = module.wss_connect.lambda_invoke_arn -} - -module "getnotifications_route" { - source = "../../apigwv2-route/v001" - env = var.env - apiv2_id = aws_apigatewayv2_api.notifications.id - route_key = "getnotifications" - lambda_invoke_arn = module.notifications_get.lambda_invoke_arn -} - -module "clearnotifications_route" { - source = "../../apigwv2-route/v001" - env = var.env - apiv2_id = aws_apigatewayv2_api.notifications.id - route_key = "clearnotifications" - lambda_invoke_arn = module.notifications_clear.lambda_invoke_arn -} - -module "disconnect_route" { - source = "../../apigwv2-route/v001" - env = var.env - apiv2_id = aws_apigatewayv2_api.notifications.id - route_key = "$disconnect" - lambda_invoke_arn = module.wss_connect.lambda_invoke_arn -} - -resource "aws_apigatewayv2_route" "default" { - api_id = aws_apigatewayv2_api.notifications.id - route_key = "$default" - operation_name = "default" - target = "integrations/${aws_apigatewayv2_integration.default.id}" - # https://github.com/hashicorp/terraform-provider-aws/issues/17528#issuecomment-778278823 - route_response_selection_expression = "$default" -} - -resource "aws_apigatewayv2_integration" "default" { - api_id = aws_apigatewayv2_api.notifications.id - integration_type = "MOCK" - description = "returns error describing available actions in ${local.SPACED_ID_ENV}" - passthrough_behavior = "WHEN_NO_MATCH" - request_templates = { - "200" = "{\"statusCode\": 200}" - } - template_selection_expression = "200" -} - -resource "aws_apigatewayv2_integration_response" "default" { - api_id = aws_apigatewayv2_api.notifications.id - integration_id = aws_apigatewayv2_integration.default.id - integration_response_key = aws_apigatewayv2_route.default.route_key - response_templates = { - "404" = "\"only getnotifications and clearnotifications actions available\"" - } - template_selection_expression = "404" -} - -resource "aws_apigatewayv2_route_response" "default" { - api_id = aws_apigatewayv2_api.notifications.id - route_id = aws_apigatewayv2_route.default.id - route_response_key = aws_apigatewayv2_route.default.route_key -} - -resource "aws_iam_policy" "wss" { - name = "allow-wss-stack-access-${local.ID_ENV}" - description = "allows lambda websocket stack perms in ${local.SPACED_ID_ENV}" - policy = jsonencode({ - Version = "2012-10-17" - Statement = [ - { - Sid = "AllowAPIGatewayV2Invoke${local.TITLED_ID_ENV}" - Action = [ - "execute-api:ManageConnections", - "execute-api:Invoke", - ] - Effect = "Allow" - Resource = "${aws_apigatewayv2_api.notifications.execution_arn}/${var.env}/*" - }, - { - Sid = "ListCognitoUserPools${local.TITLED_ID_ENV}" - Action = [ - "cognito-idp:ListUserPools", - ] - Effect = "Allow" - Resource = "*" - }, - ] - }) -} - -resource "aws_ssm_parameter" "apigw_connections_uri" { - name = "/${var.ssm_prefix}/api/websocket/connections/uri" - description = "api gateway connections uri in ${local.SPACED_ID_ENV}" - type = "SecureString" - value = local.APIGW_CONNECTIONS_URI -} - -resource "aws_ssm_parameter" "websocket_client_uri" { - name = "/${var.ssm_prefix}/api/websocket/client/uri" - description = "api gateway websocket client uri in ${local.SPACED_ID_ENV}" - type = "SecureString" - value = local.WEBSOCKET_CLIENT_URI -} - -resource "aws_ssm_parameter" "notifications_return_limit" { - name = "/${var.ssm_prefix}/notifications/return_limit" - description = "notifications return limit in ${local.SPACED_ID_ENV}" - type = "SecureString" - value = var.notifications_return_limit -} diff --git a/infrastructure/terraform/aws/modules/environment/v001/ssm.tf b/infrastructure/terraform/aws/modules/environment/v001/ssm.tf index 3cebdd9e..cf263bb1 100644 --- a/infrastructure/terraform/aws/modules/environment/v001/ssm.tf +++ b/infrastructure/terraform/aws/modules/environment/v001/ssm.tf @@ -56,13 +56,6 @@ resource "aws_ssm_parameter" "test_account" { value = random_password.test_account.result } -resource "aws_ssm_parameter" "notifications_topic_arn" { - name = "/${var.ssm_prefix}/notifications/sns/topic/arn" - description = "notifications topic arn in ${local.SPACED_ID_ENV}" - type = "SecureString" - value = aws_sns_topic.notifications.arn -} - resource "aws_ssm_parameter" "postgres_db_name" { count = var.build_db ? 1 : 0 // false during terraform development name = "/${var.ssm_prefix}/database/sql/postgres/pgdatabase" diff --git a/infrastructure/terraform/aws/modules/environment/v001/variables.tf b/infrastructure/terraform/aws/modules/environment/v001/variables.tf index 11ba228c..58212dd4 100644 --- a/infrastructure/terraform/aws/modules/environment/v001/variables.tf +++ b/infrastructure/terraform/aws/modules/environment/v001/variables.tf @@ -4,10 +4,8 @@ variable "rds_allow_major_version_upgrade" {} variable "rds_instance_class" {} variable "rds_parameter_group" {} variable "rds_instance_name" {} -variable "notifications_return_limit" {} variable "apigw_authorization_header_key" {} variable "enable_api_auth" {} -variable "enable_notifications" {} variable "graphql_deployment_version" {} variable "initial_account_balance" {} variable "client_origin_bucket_name" {} From daa554a3cf73271779b0345c2276000c93882999 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:30:25 -0700 Subject: [PATCH 25/37] doc current scripts --- scripts/README.md | 64 ++++++++++++++++------------------------------- 1 file changed, 22 insertions(+), 42 deletions(-) diff --git a/scripts/README.md b/scripts/README.md index 21265442..4e11c01f 100755 --- a/scripts/README.md +++ b/scripts/README.md @@ -113,10 +113,9 @@ adds a mix of requests and transactions in docker postgres (requires `cd migrati 1. `cd migrations && make insert` 1. drops and up migrates postgres in docker -1. inserts requests from `pkg/testdata/requests.json` using `services/request-create` +1. inserts requests from `tests/testdata/requests.json` using `services/request-create` 1. converts every other request into a transaction using `services/request-approve` - ##### `dump-db.sh` dumps postgres db to path passed as parameter, e.g. `bash scripts/dump-db.sh --path migrations/dumps/testseed.sql` @@ -129,33 +128,6 @@ restores postgres db from path passed as parameter script sourced to standardize error handling in other scripts -##### `mock-go-ifaces.sh` - -creates go mocks from list of interfaces inside `mock` subdirectory using [gomock](https://github.com/golang/mock) and `project.yaml` assignments - -`//go:generate mockgen...` not used, script and `project.yaml` preferred for convenient interface use and mock coverage audit - -1. set `.pkgs.lambdapg.mocked_interfaces` property under package or service in `project.yaml` to map of go package import paths and desired list of interfaces: - - ```json5 - "mocked_interfaces": { - "github.com/systemaccounting/mxfactorial/pkg/lambdapg": [ - "Connector", - "SQLDB" - ], - "github.com/jackc/pgx/v4": [ - "Rows" - ] - } - ``` -1. `make -C './pkg/lambdapg' mock` - -creates: -``` -pkg/lambdapg/lambdapg_mock/lambdapg_mock.go -pkg/lambdapg/lambdapg_mock/v4_mock.go -``` - ##### `create-accounts.sh` creates testseed migration accounts in cognito @@ -168,22 +140,10 @@ deletes testseed migration accounts from cognito sums value in json `transaction_item` list -##### `save-id-token.sh` - -references a manually entered `USERNAME` and `PASSWWORD` assignment in a `.env` file, requests an id token from cognito, then saves the `ID_TOKEN` in the `.env` file - ##### `print-id-token.sh` prints cognito user id token for convenient testing -##### `get-notifications.sh` - -gets pending notifications from websocket endpoint - -##### `clear-notifications.sh` - -clears (deletes) pending notifications through websocket endpoint - ##### `create-all-env-files.sh` loops through `project.yaml` apps and creates `.env` files in each directory requring secrets fetched from systems manager parameter store @@ -290,4 +250,24 @@ print the value of an `env-var` in `project.yaml` ##### `post-go-migrate.sh` -send a http request to the internal `migrations/go-migrate` tool \ No newline at end of file +send a http request to the internal `migrations/go-migrate` tool + +##### `auth-ecr-repo.sh` + +authenticate with ecr + +##### `push-ecr-image.sh` + +push docker image to ecr repo + +##### `update-function-image.sh` + +update lambda with latest ecr repository image + +##### `import-tf-init-env.sh` + +imports resources into the `infrastructure/terraform/aws/environments/init-$ENV`terraform configuration files + +##### `rust-coverage.sh` + +prints rust crate test coverage \ No newline at end of file From f31f493ab5e97c166428d33cdb3e8c22398854d5 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:31:05 -0700 Subject: [PATCH 26/37] remove go services from project config --- project.yaml | 274 ++++----------------------------------------------- 1 file changed, 20 insertions(+), 254 deletions(-) diff --git a/project.yaml b/project.yaml index fcb72520..cbe66927 100644 --- a/project.yaml +++ b/project.yaml @@ -93,9 +93,6 @@ infrastructure: environment: env_var: set: - NOTIFY_TOPIC_ARN: - ssm: notifications/sns/topic/arn - default: null PGDATABASE: ssm: database/sql/postgres/pgdatabase default: mxfactorial @@ -117,30 +114,15 @@ infrastructure: POOL_ID: ssm: auth/cognito/pool_id default: null - APIGW_CONNECTIONS_URI: - ssm: api/websocket/connections/uri - default: null COGNITO_JWKS_URI: ssm: auth/cognito/jwks/uri default: null - NOTIFICATIONS_RETURN_LIMIT: - ssm: notifications/return_limit - default: null SECRET: ssm: auth/cognito/test_account/secret default: null - WEBSOCKET_CLIENT_URI: - ssm: api/websocket/client/uri - default: null ENABLE_API_AUTH: ssm: null default: false - ENABLE_NOTIFICATIONS: - ssm: null - default: false - DB_RESET_PASSPHRASE: - ssm: tool/lambda/db_reset/passphrase - default: null REGION: ssm: null default: us-east-1 @@ -180,9 +162,6 @@ infrastructure: RDS_INSTANCE_NAME_PREFIX: ssm: null default: mxfactorial - GO_MIGRATE_LAYER_PREFIX: - ssm: null - default: go-migrate-provided-deps READINESS_CHECK_PATH: ssm: service/lambda/readiness_check_path default: /healthz @@ -217,6 +196,20 @@ infrastructure: ssm: null default: mxfactorial-tfstate migrations: + type: lib + params: [] + env_var: + set: + SQL_TYPE: + ssm: null + default: postgres + get: + - SQL_TYPE + - PGHOST + - PGPORT + - PGUSER + - PGPASSWORD + - PGDATABASE dumps: env_var: set: @@ -224,23 +217,19 @@ migrations: ssm: null default: ./migrations/dumps/testseed.sql go-migrate: - runtime: go1.x + runtime: bash min_code_cov: null - type: app - local_dev: true + type: lib + local_dev: false params: - AWS_REGION deploy: true - build_src_path: cmd + build_src_path: null dependents: env_var: - set: - GO_MIGRATE_PORT: - ssm: null - default: 11000 + set: [] get: - - READINESS_CHECK_PATH - - GO_MIGRATE_PORT + - SQL_TYPE - PGHOST - PGPORT - PGUSER @@ -273,12 +262,6 @@ scripts: TEST_ACCOUNTS_MIGRATION_FILE: ssm: null default: ./migrations/testseed/000001_accounts.up.sql - GO_MOCK_PACKAGE_NAME_PREFIX: - ssm: null - default: mock - GO_MOCK_FILE_NAME_SUFFIX: - ssm: null - default: mock.go REQUIRED_PID_COUNT: ssm: null default: 10 @@ -534,66 +517,6 @@ services: - PGDATABASE - READINESS_CHECK_PATH - RETURN_RECORD_LIMIT - notifications-send: - runtime: go1.x - min_code_cov: null - type: app - params: - - AWS_REGION - deploy: true - build_src_path: cmd - dependents: [] - env_var: - get: - - NOTIFY_TOPIC_ARN - - APIGW_CONNECTIONS_URI - - PGHOST - - PGPORT - - PGUSER - - PGPASSWORD - - PGDATABASE - notifications-get: - runtime: go1.x - min_code_cov: null - type: app - params: - - AWS_REGION - - ENABLE_API_AUTH - deploy: true - build_src_path: cmd - dependents: [] - env_var: - get: - - COGNITO_JWKS_URI - - NOTIFICATIONS_RETURN_LIMIT - - CLIENT_ID - - SECRET - - WEBSOCKET_CLIENT_URI - - PGHOST - - PGPORT - - PGUSER - - PGPASSWORD - - PGDATABASE - notifications-clear: - runtime: go1.x - min_code_cov: null - type: app - params: - - AWS_REGION - - ENABLE_API_AUTH - deploy: true - build_src_path: cmd - dependents: [] - env_var: - get: - - COGNITO_JWKS_URI - - CLIENT_ID - - WEBSOCKET_CLIENT_URI - - PGHOST - - PGPORT - - PGUSER - - PGPASSWORD - - PGDATABASE balance-by-account: runtime: rust1.x min_code_cov: null @@ -617,17 +540,6 @@ services: - PGPASSWORD - PGDATABASE - READINESS_CHECK_PATH - wss-connect: - runtime: go1.x - type: app - min_code_cov: null - secrets: [] - params: [] - deploy: true - build_src_path: cmd - dependents: [] - env_var: - get: [] auto-confirm: runtime: rust1.x min_code_cov: null @@ -661,132 +573,6 @@ tests: - BALANCE_BY_ACCOUNT_URL - AWS_LAMBDA_FUNCTION_NAME # used when testing cloud envs params: [] -pkg: - lambda: - runtime: go1.x - type: lib - path: pkg/aws/lambda - dependents: [] - mocked_interfaces: - github.com/systemaccounting/mxfactorial/pkg/aws/lambda: - - IAWSLambda - - ILambdaService - service: - runtime: go1.x - type: lib - path: pkg/service - dependents: - - request-create - - request-approve - - request-by-id - - requests-by-account - - transaction-by-id - - transactions-by-account - - notifications-send - - notifications-get - - notifications-clear - - balance-by-account - - wss-connect - - auto-confirm - mocked_interfaces: - github.com/systemaccounting/mxfactorial/pkg/service: - - IAccountService - - IApproveService - - IBalanceService - - ICreateAccountService - - ITransactionNotificationService - - IProfileService - - IRuleInstanceService - - ITransactionService - - IWebsocketService - postgres: - runtime: go1.x - type: lib - path: pkg/postgres - dependents: - - service - mocked_interfaces: - github.com/systemaccounting/mxfactorial/pkg/postgres: - - SQLDB - github.com/jackc/pgx/v4: - - Rows - - Row - sqls: - runtime: go1.x - type: lib - path: pkg/sqls - dependents: - - postgres - testdata: - runtime: go1.x - type: lib - path: pkg/testdata - dependents: [] - print: - runtime: go1.x - type: lib - path: pkg/print - dependents: [] - mocked_interfaces: - github.com/systemaccounting/mxfactorial/pkg/print: - - Marshaler - types: - runtime: go1.x - type: lib - path: pkg/types - dependents: - - testdata - - postgres - - service - - tools - - sqls - - lambdasdk - - request-create - - request-approve - - request-by-id - - requests-by-account - - transaction-by-id - - transactions-by-account - - notifications-send - - notifications-get - - notifications-clear - - balance-by-account - - wss-connect - - auto-confirm - mocked_interfaces: - github.com/systemaccounting/mxfactorial/pkg/types: - - TrItemListHelper - - IScanRow - - IScanRows - - IEncodingJSON - sns: - runtime: go1.x - type: lib - path: pkg/aws/sns - dependents: - - notifications-send - mocked_interfaces: - github.com/systemaccounting/mxfactorial/pkg/aws/sns: - - ISNS - apigwma: - runtime: go1.x - type: lib - path: pkg/aws/apigwma - dependents: [] - mocked_interfaces: - github.com/systemaccounting/mxfactorial/pkg/aws/apigwma: - - IAWSAPIGWMA - cognitoidp: - runtime: go1.x - type: lib - path: pkg/aws/cognitoidp - dependents: [] - mocked_interfaces: - github.com/systemaccounting/mxfactorial/pkg/aws/cognitoidp: - - IJwtDeps - - IGetClaimedKeyID - - IIdpDeps - - IJwToken env_var: set: ENV_FILE_NAME: @@ -812,18 +598,6 @@ params: [] os: osx: install: '/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"' - - name: go - os: - osx: - install: 'brew install go' - - name: gqlgen - os: - osx: - install: 'go install github.com/99designs/gqlgen@latest' - - name: mockgen - os: - osx: - install: 'go install github.com/golang/mock/mockgen@latest' - name: node os: osx: @@ -848,14 +622,6 @@ params: [] os: osx: install: 'brew install golang-migrate' - env_var: - set: - MOCK_FILE_SUFFIX: - ssm: null - default: mock.go - MOCK_PACKAGE_PREFIX: - ssm: null - default: mock - name: yq os: osx: From bcb76b8c7e6bbcf3337085e73b38ed7d75579354 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:31:44 -0700 Subject: [PATCH 27/37] reference current env var in terraform local --- infrastructure/terraform/aws/modules/environment/v001/locals.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/terraform/aws/modules/environment/v001/locals.tf b/infrastructure/terraform/aws/modules/environment/v001/locals.tf index d249cd26..60990a09 100644 --- a/infrastructure/terraform/aws/modules/environment/v001/locals.tf +++ b/infrastructure/terraform/aws/modules/environment/v001/locals.tf @@ -17,7 +17,7 @@ locals { RETURN_RECORD_LIMIT = local.SERVICES_CONF.env_var.set.RETURN_RECORD_LIMIT.default WEB_ADAPTER_LAYER_VERSION = local.PROJECT_CONF.infrastructure.terraform.aws.modules.environment.env_var.set.WEB_ADAPTER_LAYER_VERSION.default WEB_ADAPTER_LAYER_ARN = "arn:aws:lambda:${data.aws_region.current.name}:753240598075:layer:LambdaAdapterLayerX86:${local.WEB_ADAPTER_LAYER_VERSION}" - GO_MIGRATE_PORT = local.PROJECT_CONF.migrations.go-migrate.env_var.set.GO_MIGRATE_PORT.default BINARY_NAME = local.SERVICES_CONF.env_var.set.BINARY_NAME.default LAMBDA_RUNTIME = local.PROJECT_CONF.infrastructure.terraform.aws.modules.env_var.set.LAMBDA_RUNTIME.default + SQL_TYPE = local.PROJECT_CONF.migrations.env_var.set.SQL_TYPE.default } From 5560c8c7b7c9d0a94bc5414cea5f14b841b05d04 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:32:58 -0700 Subject: [PATCH 28/37] remove go workflows --- .github/workflows/REUSE_go-lambda.yaml | 40 ------------------- .github/workflows/dev-gopkg-apigwma.yaml | 20 ---------- .github/workflows/dev-gopkg-cognitoidp.yaml | 20 ---------- .github/workflows/dev-gopkg-lambda.yaml | 20 ---------- .github/workflows/dev-gopkg-sns.yaml | 20 ---------- .github/workflows/dev-gopkg-sqls.yaml | 20 ---------- .../workflows/dev-notifications-clear.yaml | 32 --------------- .github/workflows/dev-notifications-get.yaml | 32 --------------- .github/workflows/dev-notifications-send.yaml | 32 --------------- .github/workflows/dev-wss-connect.yaml | 32 --------------- .github/workflows/prod-go-docker-base.yaml | 24 ----------- .../workflows/prod-notifications-clear.yaml | 32 --------------- .github/workflows/prod-notifications-get.yaml | 32 --------------- .../workflows/prod-notifications-send.yaml | 32 --------------- .github/workflows/prod-wss-connect.yaml | 32 --------------- 15 files changed, 420 deletions(-) delete mode 100644 .github/workflows/REUSE_go-lambda.yaml delete mode 100644 .github/workflows/dev-gopkg-apigwma.yaml delete mode 100644 .github/workflows/dev-gopkg-cognitoidp.yaml delete mode 100644 .github/workflows/dev-gopkg-lambda.yaml delete mode 100644 .github/workflows/dev-gopkg-sns.yaml delete mode 100644 .github/workflows/dev-gopkg-sqls.yaml delete mode 100644 .github/workflows/dev-notifications-clear.yaml delete mode 100644 .github/workflows/dev-notifications-get.yaml delete mode 100644 .github/workflows/dev-notifications-send.yaml delete mode 100644 .github/workflows/dev-wss-connect.yaml delete mode 100644 .github/workflows/prod-go-docker-base.yaml delete mode 100644 .github/workflows/prod-notifications-clear.yaml delete mode 100644 .github/workflows/prod-notifications-get.yaml delete mode 100644 .github/workflows/prod-notifications-send.yaml delete mode 100644 .github/workflows/prod-wss-connect.yaml diff --git a/.github/workflows/REUSE_go-lambda.yaml b/.github/workflows/REUSE_go-lambda.yaml deleted file mode 100644 index 91024e07..00000000 --- a/.github/workflows/REUSE_go-lambda.yaml +++ /dev/null @@ -1,40 +0,0 @@ -name: go lambda reusable workflow - -on: - workflow_call: - inputs: - environment: - required: true - type: string - directory: - required: true - type: string - aws_region: - required: true - type: string - app_or_pkg_name: - required: true - type: string - secrets: - aws_access_key_id: - required: true - aws_secret_access_key: - required: true - -jobs: - test: - name: test ${{ inputs.app_or_pkg_name }} placeholder - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: '1.18.x' - - name: unit test - run: echo "go test -race -covermode=atomic -coverprofile=coverage.out" - working-directory: ${{ inputs.directory }} - - name: reduce PENDING_TESTS - run: bash scripts/remove-pending-test.sh --app-or-pkg-name ${{ inputs.app_or_pkg_name }} --sha ${{ github.sha }} --region ${{ inputs.aws_region }} --env ${{ inputs.environment }} - env: - AWS_ACCESS_KEY_ID: ${{ secrets.aws_access_key_id }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.aws_secret_access_key }} \ No newline at end of file diff --git a/.github/workflows/dev-gopkg-apigwma.yaml b/.github/workflows/dev-gopkg-apigwma.yaml deleted file mode 100644 index 271dee38..00000000 --- a/.github/workflows/dev-gopkg-apigwma.yaml +++ /dev/null @@ -1,20 +0,0 @@ -name: dev-pkg-apigwma - -on: - push: - paths: - - 'pkg/aws/apigwma/**' - branches-ignore: - - 'master' - -jobs: - api-gateway-management-api: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: '1.19.x' - - name: unit test - run: make test - working-directory: pkg/aws/apigwma \ No newline at end of file diff --git a/.github/workflows/dev-gopkg-cognitoidp.yaml b/.github/workflows/dev-gopkg-cognitoidp.yaml deleted file mode 100644 index 28bedc88..00000000 --- a/.github/workflows/dev-gopkg-cognitoidp.yaml +++ /dev/null @@ -1,20 +0,0 @@ -name: dev-pkg-cognitoidp - -on: - push: - paths: - - 'pkg/aws/cognitoidp/**' - branches-ignore: - - 'master' - -jobs: - cognitoidp: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: '1.19.x' - - name: unit test - run: make test - working-directory: pkg/aws/cognitoidp \ No newline at end of file diff --git a/.github/workflows/dev-gopkg-lambda.yaml b/.github/workflows/dev-gopkg-lambda.yaml deleted file mode 100644 index 48c7a8fa..00000000 --- a/.github/workflows/dev-gopkg-lambda.yaml +++ /dev/null @@ -1,20 +0,0 @@ -name: dev-pkg-lambda - -on: - push: - paths: - - 'pkg/aws/lambda/**' - branches-ignore: - - 'master' - -jobs: - lambda: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: '1.19.x' - - name: unit test - run: make test - working-directory: pkg/aws/lambda \ No newline at end of file diff --git a/.github/workflows/dev-gopkg-sns.yaml b/.github/workflows/dev-gopkg-sns.yaml deleted file mode 100644 index 3e78be01..00000000 --- a/.github/workflows/dev-gopkg-sns.yaml +++ /dev/null @@ -1,20 +0,0 @@ -name: dev-pkg-sns - -on: - push: - paths: - - 'pkg/aws/sns/**' - branches-ignore: - - 'master' - -jobs: - sns: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: '1.19.x' - - name: unit test - run: make test - working-directory: pkg/aws/sns \ No newline at end of file diff --git a/.github/workflows/dev-gopkg-sqls.yaml b/.github/workflows/dev-gopkg-sqls.yaml deleted file mode 100644 index 597b7b45..00000000 --- a/.github/workflows/dev-gopkg-sqls.yaml +++ /dev/null @@ -1,20 +0,0 @@ -name: dev-pkg-sqls - -on: - push: - paths: - - 'pkg/sqls/**' - branches-ignore: - - 'master' - -jobs: - sqls: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: '1.19.x' - - name: unit test - run: make test - working-directory: pkg/sqls \ No newline at end of file diff --git a/.github/workflows/dev-notifications-clear.yaml b/.github/workflows/dev-notifications-clear.yaml deleted file mode 100644 index d72e80b9..00000000 --- a/.github/workflows/dev-notifications-clear.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: dev-notifications-clear - -on: - push: - paths: - - 'services/notifications-clear/**' - branches-ignore: - - 'master' - -jobs: - test: - name: notifications-clear - runs-on: ubuntu-latest - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_DEFAULT_REGION: us-east-1 - CI: true - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: '1.19.x' - - name: compile - run: make compile - working-directory: services/notifications-clear - - name: zip - run: make zip - working-directory: services/notifications-clear - - name: deploy to dev - run: ENV_ID=${{ secrets.DEV_ENV_ID }} make deploy-only ENV=dev - working-directory: services/notifications-clear \ No newline at end of file diff --git a/.github/workflows/dev-notifications-get.yaml b/.github/workflows/dev-notifications-get.yaml deleted file mode 100644 index 6e2ff628..00000000 --- a/.github/workflows/dev-notifications-get.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: dev-notifications-get - -on: - push: - paths: - - 'services/notifications-get/**' - branches-ignore: - - 'master' - -jobs: - test: - name: notifications-get - runs-on: ubuntu-latest - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_DEFAULT_REGION: us-east-1 - CI: true - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: '1.19.x' - - name: compile - run: make compile - working-directory: services/notifications-get - - name: zip - run: make zip - working-directory: services/notifications-get - - name: deploy to dev - run: ENV_ID=${{ secrets.DEV_ENV_ID }} make deploy-only ENV=dev - working-directory: services/notifications-get \ No newline at end of file diff --git a/.github/workflows/dev-notifications-send.yaml b/.github/workflows/dev-notifications-send.yaml deleted file mode 100644 index da092eda..00000000 --- a/.github/workflows/dev-notifications-send.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: dev-notifications-send - -on: - push: - paths: - - 'services/notifications-send/**' - branches-ignore: - - 'master' - -jobs: - test: - name: notifications-send - runs-on: ubuntu-latest - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_DEFAULT_REGION: us-east-1 - CI: true - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: '1.19.x' - - name: compile - run: make compile - working-directory: services/notifications-send - - name: zip - run: make zip - working-directory: services/notifications-send - - name: deploy to dev - run: ENV_ID=${{ secrets.DEV_ENV_ID }} make deploy-only ENV=dev - working-directory: services/notifications-send \ No newline at end of file diff --git a/.github/workflows/dev-wss-connect.yaml b/.github/workflows/dev-wss-connect.yaml deleted file mode 100644 index 5b63d648..00000000 --- a/.github/workflows/dev-wss-connect.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: dev-wss-connect - -on: - push: - paths: - - 'services/wss-connect/**' - branches-ignore: - - 'master' - -jobs: - test: - name: wss-connect - runs-on: ubuntu-latest - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_DEFAULT_REGION: us-east-1 - CI: true - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: '1.19.x' - - name: compile - run: make compile - working-directory: services/wss-connect - - name: zip - run: make zip - working-directory: services/wss-connect - - name: deploy to dev - run: ENV_ID=${{ secrets.DEV_ENV_ID }} make deploy-only ENV=dev - working-directory: services/wss-connect \ No newline at end of file diff --git a/.github/workflows/prod-go-docker-base.yaml b/.github/workflows/prod-go-docker-base.yaml deleted file mode 100644 index 6c00a430..00000000 --- a/.github/workflows/prod-go-docker-base.yaml +++ /dev/null @@ -1,24 +0,0 @@ -name: prod-go-base-image - -on: - push: - paths: - - go.mod - - go.sum - - docker/prod/go-base.Dockerfile - -jobs: - deploy: - name: deploy go-base image - runs-on: ubuntu-latest - env: - IMAGE_NAME: mxfactorial/go-base:v1 - CI: true - steps: - - uses: actions/checkout@v3 - - name: docker login - run: echo "${{ secrets.DOCKER_TOKEN }}" | docker login -u mxfactorial --password-stdin - - name: docker build - run: docker build -f ./docker/prod/go-base.Dockerfile -t "$IMAGE_NAME" . - - name: docker push - run: docker image push "$IMAGE_NAME" \ No newline at end of file diff --git a/.github/workflows/prod-notifications-clear.yaml b/.github/workflows/prod-notifications-clear.yaml deleted file mode 100644 index 61ea0782..00000000 --- a/.github/workflows/prod-notifications-clear.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: prod-notifications-clear - -on: - push: - paths: - - 'services/notifications-clear/**' - branches: - - 'master' - -jobs: - test: - name: notifications-clear - runs-on: ubuntu-latest - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_DEFAULT_REGION: us-east-1 - CI: true - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: '1.19.x' - - name: compile - run: make compile - working-directory: services/notifications-clear - - name: zip - run: make zip - working-directory: services/notifications-clear - - name: deploy to prod - run: ENV_ID=${{ secrets.PROD_ENV_ID }} make deploy-only ENV=prod - working-directory: services/notifications-clear \ No newline at end of file diff --git a/.github/workflows/prod-notifications-get.yaml b/.github/workflows/prod-notifications-get.yaml deleted file mode 100644 index 8aad0616..00000000 --- a/.github/workflows/prod-notifications-get.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: prod-notifications-get - -on: - push: - paths: - - 'services/notifications-get/**' - branches: - - 'master' - -jobs: - test: - name: notifications-get - runs-on: ubuntu-latest - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_DEFAULT_REGION: us-east-1 - CI: true - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: '1.19.x' - - name: compile - run: make compile - working-directory: services/notifications-get - - name: zip - run: make zip - working-directory: services/notifications-get - - name: deploy to prod - run: ENV_ID=${{ secrets.PROD_ENV_ID }} make deploy-only ENV=prod - working-directory: services/notifications-get \ No newline at end of file diff --git a/.github/workflows/prod-notifications-send.yaml b/.github/workflows/prod-notifications-send.yaml deleted file mode 100644 index 6ed40e30..00000000 --- a/.github/workflows/prod-notifications-send.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: prod-notifications-send - -on: - push: - paths: - - 'services/notifications-send/**' - branches: - - 'master' - -jobs: - test: - name: notifications-send - runs-on: ubuntu-latest - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_DEFAULT_REGION: us-east-1 - CI: true - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: '1.19.x' - - name: compile - run: make compile - working-directory: services/notifications-send - - name: zip - run: make zip - working-directory: services/notifications-send - - name: deploy to prod - run: ENV_ID=${{ secrets.PROD_ENV_ID }} make deploy-only ENV=prod - working-directory: services/notifications-send \ No newline at end of file diff --git a/.github/workflows/prod-wss-connect.yaml b/.github/workflows/prod-wss-connect.yaml deleted file mode 100644 index 8036cf4b..00000000 --- a/.github/workflows/prod-wss-connect.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: prod-wss-connect - -on: - push: - paths: - - 'services/wss-connect/**' - branches: - - 'master' - -jobs: - test: - name: wss-connect - runs-on: ubuntu-latest - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_DEFAULT_REGION: us-east-1 - CI: true - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: '1.19.x' - - name: compile - run: make compile - working-directory: services/wss-connect - - name: zip - run: make zip - working-directory: services/wss-connect - - name: deploy to prod - run: ENV_ID=${{ secrets.PROD_ENV_ID }} make deploy-only ENV=prod - working-directory: services/wss-connect \ No newline at end of file From 8593d0dafb3498a9ab0af1649127d51aa4ea7497 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:33:37 -0700 Subject: [PATCH 29/37] remove unused lambda layer workflow --- .../workflows/go-migrate-lambda-layer.yaml | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 .github/workflows/go-migrate-lambda-layer.yaml diff --git a/.github/workflows/go-migrate-lambda-layer.yaml b/.github/workflows/go-migrate-lambda-layer.yaml deleted file mode 100644 index b495d815..00000000 --- a/.github/workflows/go-migrate-lambda-layer.yaml +++ /dev/null @@ -1,25 +0,0 @@ -name: go-migrate-lambda-layer - -on: - push: - paths: - - 'docker/go-migrate.Dockerfile' - -jobs: - deploy: - name: deploy go-migrate lambda layer image - runs-on: ubuntu-latest - env: - IMAGE_NAME: mxfactorial/go-migrate-lambda-layer:v1 - CI: true - steps: - - uses: actions/checkout@v3 - - name: docker login - run: echo "${{ secrets.DOCKER_TOKEN }}" | docker login -u mxfactorial --password-stdin - working-directory: docker - - name: docker build - run: docker build -f go-migrate.Dockerfile -t "$IMAGE_NAME" . - working-directory: docker - - name: docker push - run: docker image push "$IMAGE_NAME" - working-directory: docker \ No newline at end of file From d17a0dbfd799a140b1cdc0b987f06b1065adc28c Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:34:07 -0700 Subject: [PATCH 30/37] switch to v4 checkout action --- .github/workflows/dev-integration.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dev-integration.yaml b/.github/workflows/dev-integration.yaml index 64c83f3b..03ec55ab 100644 --- a/.github/workflows/dev-integration.yaml +++ b/.github/workflows/dev-integration.yaml @@ -27,7 +27,7 @@ jobs: AWS_DEFAULT_REGION: us-east-1 CI: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: install latest psql client run: | sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' From 3413c9fc4f6d3bb4764e05d2f4a475f203f73726 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:35:43 -0700 Subject: [PATCH 31/37] switch prod go workflows to rust --- .github/workflows/prod-auto-confirm.yaml | 9 +++++---- .github/workflows/prod-balance-by-account.yaml | 7 ++++--- .github/workflows/prod-graphql.yaml | 7 ++++--- .github/workflows/prod-request-approve.yaml | 7 ++++--- .github/workflows/prod-request-by-id.yaml | 7 ++++--- .github/workflows/prod-request-create.yaml | 7 ++++--- .github/workflows/prod-requests-by-account.yaml | 7 ++++--- .github/workflows/prod-transaction-by-id.yaml | 7 ++++--- .github/workflows/prod-transactions-by-account.yaml | 7 ++++--- 9 files changed, 37 insertions(+), 28 deletions(-) diff --git a/.github/workflows/prod-auto-confirm.yaml b/.github/workflows/prod-auto-confirm.yaml index 39e7e7e2..6f92b2c5 100644 --- a/.github/workflows/prod-auto-confirm.yaml +++ b/.github/workflows/prod-auto-confirm.yaml @@ -6,7 +6,7 @@ on: - 'services/auto-confirm/**' branches: - 'master' - +# todo: promote artifacts with s3 cp instead of rebuilding jobs: build: name: auto-confirm @@ -17,10 +17,11 @@ jobs: AWS_DEFAULT_REGION: us-east-1 CI: true steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master with: - go-version: '1.19.x' + toolchain: stable + components: clippy, rustfmt - name: compile run: make compile working-directory: services/auto-confirm diff --git a/.github/workflows/prod-balance-by-account.yaml b/.github/workflows/prod-balance-by-account.yaml index 5c1e31e9..e025ed83 100644 --- a/.github/workflows/prod-balance-by-account.yaml +++ b/.github/workflows/prod-balance-by-account.yaml @@ -17,10 +17,11 @@ jobs: AWS_DEFAULT_REGION: us-east-1 CI: true steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master with: - go-version: '1.19.x' + toolchain: stable + components: clippy, rustfmt - name: compile run: make compile working-directory: services/balance-by-account diff --git a/.github/workflows/prod-graphql.yaml b/.github/workflows/prod-graphql.yaml index 2879508c..ef17f169 100644 --- a/.github/workflows/prod-graphql.yaml +++ b/.github/workflows/prod-graphql.yaml @@ -17,10 +17,11 @@ jobs: AWS_DEFAULT_REGION: us-east-1 CI: true steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master with: - go-version: '1.19.x' + toolchain: stable + components: clippy, rustfmt - name: compile run: make compile working-directory: services/graphql diff --git a/.github/workflows/prod-request-approve.yaml b/.github/workflows/prod-request-approve.yaml index f9ec5617..88fb9bfa 100644 --- a/.github/workflows/prod-request-approve.yaml +++ b/.github/workflows/prod-request-approve.yaml @@ -17,10 +17,11 @@ jobs: AWS_DEFAULT_REGION: us-east-1 CI: true steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master with: - go-version: '1.19.x' + toolchain: stable + components: clippy, rustfmt - name: compile run: make compile working-directory: services/request-approve diff --git a/.github/workflows/prod-request-by-id.yaml b/.github/workflows/prod-request-by-id.yaml index 6c9788b6..aeb9c8c9 100644 --- a/.github/workflows/prod-request-by-id.yaml +++ b/.github/workflows/prod-request-by-id.yaml @@ -17,10 +17,11 @@ jobs: AWS_DEFAULT_REGION: us-east-1 CI: true steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master with: - go-version: '1.19.x' + toolchain: stable + components: clippy, rustfmt - name: compile run: make compile working-directory: services/request-by-id diff --git a/.github/workflows/prod-request-create.yaml b/.github/workflows/prod-request-create.yaml index da3d14b3..46de1f17 100644 --- a/.github/workflows/prod-request-create.yaml +++ b/.github/workflows/prod-request-create.yaml @@ -17,10 +17,11 @@ jobs: AWS_DEFAULT_REGION: us-east-1 CI: true steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master with: - go-version: '1.19.x' + toolchain: stable + components: clippy, rustfmt - name: compile run: make compile working-directory: services/request-create diff --git a/.github/workflows/prod-requests-by-account.yaml b/.github/workflows/prod-requests-by-account.yaml index 41111053..0347f4af 100644 --- a/.github/workflows/prod-requests-by-account.yaml +++ b/.github/workflows/prod-requests-by-account.yaml @@ -17,10 +17,11 @@ jobs: AWS_DEFAULT_REGION: us-east-1 CI: true steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master with: - go-version: '1.19.x' + toolchain: stable + components: clippy, rustfmt - name: compile run: make compile working-directory: services/requests-by-account diff --git a/.github/workflows/prod-transaction-by-id.yaml b/.github/workflows/prod-transaction-by-id.yaml index b5b77032..a9ffef6b 100644 --- a/.github/workflows/prod-transaction-by-id.yaml +++ b/.github/workflows/prod-transaction-by-id.yaml @@ -17,10 +17,11 @@ jobs: AWS_DEFAULT_REGION: us-east-1 CI: true steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master with: - go-version: '1.19.x' + toolchain: stable + components: clippy, rustfmt - name: compile run: make compile working-directory: services/transaction-by-id diff --git a/.github/workflows/prod-transactions-by-account.yaml b/.github/workflows/prod-transactions-by-account.yaml index 6a9e245f..7d0f69d6 100644 --- a/.github/workflows/prod-transactions-by-account.yaml +++ b/.github/workflows/prod-transactions-by-account.yaml @@ -17,10 +17,11 @@ jobs: AWS_DEFAULT_REGION: us-east-1 CI: true steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master with: - go-version: '1.19.x' + toolchain: stable + components: clippy, rustfmt - name: compile run: make compile working-directory: services/transactions-by-account From 740ce5b661827a57f4ecf3e4b68baa4dcfc93dda Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:38:08 -0700 Subject: [PATCH 32/37] switch prod rule workflow to v4 checkout action --- .github/workflows/prod-rule.yaml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/prod-rule.yaml b/.github/workflows/prod-rule.yaml index 663b1d8f..4327aa75 100644 --- a/.github/workflows/prod-rule.yaml +++ b/.github/workflows/prod-rule.yaml @@ -17,9 +17,11 @@ jobs: AWS_DEFAULT_REGION: us-east-1 CI: true steps: - - uses: actions/checkout@v3 - - name: install cargo cross - run: cargo install cross --git https://github.com/cross-rs/cross + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + components: clippy, rustfmt - name: deploy working-directory: services/rule run: ENV_ID=${{ secrets.PROD_ENV_ID }} make deploy ENV=prod \ No newline at end of file From f3e3ce45a039a242193a2ab42723443e39389dd2 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:38:43 -0700 Subject: [PATCH 33/37] remove go from devcontainers --- .devcontainer/devcontainer.json | 4 ---- .gitpod.yml | 1 - docker/.gitpod.Dockerfile | 2 -- 3 files changed, 7 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 6403968f..828175d9 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -19,9 +19,6 @@ "vscode": { // Set *default* container specific settings.json values on container create. "settings": { - "go.toolsManagement.checkForUpdates": "local", - "go.useLanguageServer": true, - "go.gopath": "/go", "lldb.executable": "/usr/bin/lldb", "workbench.colorTheme": "Default Dark+" }, @@ -31,7 +28,6 @@ "mutantdino.resourcemonitor", "rangav.vscode-thunder-client@2.5.3", "hashicorp.terraform", - "golang.go", "svelte.svelte-vscode", "shd101wyy.markdown-preview-enhanced", "GraphQL.vscode-graphql", diff --git a/.gitpod.yml b/.gitpod.yml index cb8f3b6f..492a6ea8 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -52,7 +52,6 @@ vscode: extensions: - rangav.vscode-thunder-client@2.5.3 - hashicorp.terraform - - golang.go - svelte.svelte-vscode - shd101wyy.markdown-preview-enhanced - GraphQL.vscode-graphql diff --git a/docker/.gitpod.Dockerfile b/docker/.gitpod.Dockerfile index a8e51d69..de874ea1 100644 --- a/docker/.gitpod.Dockerfile +++ b/docker/.gitpod.Dockerfile @@ -3,8 +3,6 @@ FROM gitpod/workspace-full:latest ARG TF_VERSION=1.2.7 RUN bash -lc "rustup default stable" && \ - go install github.com/99designs/gqlgen@latest && \ - go install github.com/golang/mock/mockgen@latest && \ go install github.com/mikefarah/yq/v4@latest && \ sudo apt-get install bc -y && \ sudo apt-get clean && \ From 500e0cfdc4b8a35b362abc15f83252faffc9b294 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:39:05 -0700 Subject: [PATCH 34/37] doc arch --- README.md | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index b56b524f..ce235445 100644 --- a/README.md +++ b/README.md @@ -220,20 +220,23 @@ private, receiving added value is sustained & acknowledged by sending value ``` client (typescript, svelte, cloudfront/s3: demo web client targeting graphql) - ├── graphql (go, api gateway/lambda: public interface for below services) - │   ├── balance-by-account (go, lambda: returns account balances) - │   ├── request-approve (go, lambda: approves a transaction request) - │   ├── request-by-id (go, lambda: returns a transaction request by id) - │   ├── request-create (go, lambda: creates a transaction request between a buyer and seller) - │   ├── requests-by-account (go, lambda: returns transaction requests by account) - │   ├── rule (rust, lambda: returns transactions with user defined rules applied, e.g. taxes, dividends, etc.) - │   ├── transaction-by-id (go, lambda: returns a transaction by id) - │   └── transactions-by-account (go, lambda: returns transactions by account) - └── websockets (api-gatewayv2: creates websockets and delivers client notifications through below services) - ├── notifications-clear (go, lambda: deletes delivered notifications) - ├── notifications-get (go, lambda: returns pending notifications) - ├── notifications-send (go, lambda: sends notifications) - └── wss-connect (go, lambda: stores and clears websocket connections managed by api gateway) + └── graphql (rust, api gateway/lambda: public interface for below services) + ├── balance-by-account (rust, lambda: returns account balances) + │ └── postgres + ├── request-approve (rust, lambda: approves a transaction request) + │ └── postgres + ├── request-by-id (rust, lambda: returns a transaction request by id) + │ └── postgres + ├── request-create (rust, lambda: creates a transaction request between a buyer and seller) + │ └── postgres + ├── requests-by-account (rust, lambda: returns transaction requests by account) + │ └── postgres + ├── rule (rust, lambda: returns transactions with user defined rules applied, e.g. taxes, dividends, etc.) + │ └── postgres + ├── transaction-by-id (rust, lambda: returns a transaction by id) + │ └── postgres + └── transactions-by-account (rust, lambda: returns transactions by account) + └── postgres ``` ### development From a260084c9f8263f94a43b7e33bff815fd64f4811 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:46:32 -0700 Subject: [PATCH 35/37] remove go services from app inventory --- inventory | 4 ---- project.yaml | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/inventory b/inventory index 9c63dc3e..17df16d5 100644 --- a/inventory +++ b/inventory @@ -1,4 +1,3 @@ -services/wss-connect services/transactions-by-account services/transaction-by-id services/rule @@ -6,9 +5,6 @@ services/requests-by-account services/request-create services/request-by-id services/request-approve -services/notifications-send -services/notifications-get -services/notifications-clear services/graphql services/balance-by-account services/auto-confirm diff --git a/project.yaml b/project.yaml index cbe66927..ccdc8a3e 100644 --- a/project.yaml +++ b/project.yaml @@ -219,7 +219,7 @@ migrations: go-migrate: runtime: bash min_code_cov: null - type: lib + type: app local_dev: false params: - AWS_REGION From 417f47bde0f8c915544853a1c3ad6157ceb7f344 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:47:40 -0700 Subject: [PATCH 36/37] doc rust services deploy time --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index 03f19368..3b857014 100644 --- a/makefile +++ b/makefile @@ -16,7 +16,7 @@ TFSTATE_ENV_FILE=$(TFSTATE_ENV_SUFFIX).$(TFSTATE_EXT) COMPOSE_DIR=./docker NOHUP_LOG=$(shell yq '.env_var.set.NOHUP_LOG.default' $(PROJECT_CONF)) -# approx 5 minutes +# approx 10 minutes all: @$(MAKE) -s test-inv-file @$(MAKE) -s test-env-arg From 1cee32f46add8d457cadf2445f5eb10fd5f70839 Mon Sep 17 00:00:00 2001 From: max funk Date: Fri, 29 Mar 2024 17:51:01 -0700 Subject: [PATCH 37/37] use bash in go-migrate makefile --- migrations/go-migrate/makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/migrations/go-migrate/makefile b/migrations/go-migrate/makefile index 0c7246f0..59f1c53f 100644 --- a/migrations/go-migrate/makefile +++ b/migrations/go-migrate/makefile @@ -1,3 +1,4 @@ +SHELL:=/bin/bash APP_NAME=$(shell basename $(CURDIR)) RELATIVE_PROJECT_ROOT_PATH=$(shell REL_PATH="."; while [ $$(ls "$$REL_PATH" | grep project.yaml | wc -l | xargs) -eq 0 ]; do REL_PATH="$$REL_PATH./.."; done; printf '%s' "$$REL_PATH") PROJECT_CONF_FILE_NAME=project.yaml