diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 87730fb..285b897 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -35,6 +35,6 @@ // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. "remoteUser": "node", "features": { - "golang": "1.21" + "golang": "1.19" } } diff --git a/.dockerignore b/.dockerignore index 804ab22..720e7a0 100644 --- a/.dockerignore +++ b/.dockerignore @@ -22,4 +22,3 @@ **/secrets.dev.yaml **/values.dev.yaml README.md -!Dockerfile.rootless diff --git a/.github/workflows/partial-backend.yaml b/.github/workflows/partial-backend.yaml index fe4dac2..7753b8d 100644 --- a/.github/workflows/partial-backend.yaml +++ b/.github/workflows/partial-backend.yaml @@ -7,12 +7,12 @@ jobs: Go: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v4 with: - go-version: "1.21" + go-version: "1.20" - name: Install Task uses: arduino/setup-task@v1 @@ -20,7 +20,7 @@ jobs: repo-token: ${{ secrets.GITHUB_TOKEN }} - name: golangci-lint - uses: golangci/golangci-lint-action@v4 + uses: golangci/golangci-lint-action@v3 with: # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version version: latest diff --git a/.github/workflows/partial-frontend.yaml b/.github/workflows/partial-frontend.yaml index f849406..8880c7f 100644 --- a/.github/workflows/partial-frontend.yaml +++ b/.github/workflows/partial-frontend.yaml @@ -9,11 +9,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v3 with: fetch-depth: 0 - - uses: pnpm/action-setup@v3.0.0 + - uses: pnpm/action-setup@v2.2.4 with: version: 6.0.2 @@ -34,7 +34,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v3 with: fetch-depth: 0 @@ -44,15 +44,15 @@ jobs: repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v4 with: - go-version: "1.21" + go-version: "1.20" - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v3 with: node-version: 18 - - uses: pnpm/action-setup@v3.0.0 + - uses: pnpm/action-setup@v2.2.4 with: version: 6.0.2 diff --git a/.github/workflows/partial-publish.yaml b/.github/workflows/partial-publish.yaml index 542171d..4b80f19 100644 --- a/.github/workflows/partial-publish.yaml +++ b/.github/workflows/partial-publish.yaml @@ -20,22 +20,22 @@ jobs: name: "Publish Homebox" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v4 with: go-version: "1.20" - name: Set up QEMU id: qemu - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v2 with: image: tonistiigi/binfmt:latest platforms: all - name: install buildx id: buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v2 with: install: true @@ -44,7 +44,7 @@ jobs: env: CR_PAT: ${{ secrets.GH_TOKEN }} - - name: build nightly image + - name: build nightly the image if: ${{ inputs.release == false }} run: | docker build --push --no-cache \ @@ -53,16 +53,6 @@ jobs: --build-arg=BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \ --platform=linux/amd64,linux/arm64,linux/arm/v7 . - - name: build nightly-rootless image - if: ${{ inputs.release == false }} - run: | - docker build --push --no-cache \ - --tag=ghcr.io/hay-kot/homebox:${{ inputs.tag }}-rootless \ - --build-arg=COMMIT=$(git rev-parse HEAD) \ - --build-arg=BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \ - --file Dockerfile.rootless \ - --platform=linux/amd64,linux/arm64,linux/arm/v7 . - - name: build release tagged the image if: ${{ inputs.release == true }} run: | @@ -74,16 +64,3 @@ jobs: --build-arg COMMIT=$(git rev-parse HEAD) \ --build-arg BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \ --platform linux/amd64,linux/arm64,linux/arm/v7 . - - - name: build release tagged the rootless image - if: ${{ inputs.release == true }} - run: | - docker build --push --no-cache \ - --tag ghcr.io/hay-kot/homebox:nightly-rootless \ - --tag ghcr.io/hay-kot/homebox:latest-rootless \ - --tag ghcr.io/hay-kot/homebox:${{ inputs.tag }}-rootless \ - --build-arg VERSION=${{ inputs.tag }} \ - --build-arg COMMIT=$(git rev-parse HEAD) \ - --build-arg BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \ - --platform linux/amd64,linux/arm64,linux/arm/v7 \ - --file Dockerfile.rootless . diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index e91e8ec..5adc0ab 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -4,6 +4,9 @@ on: push: branches: - main + release: + types: + - published env: FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} @@ -13,7 +16,7 @@ jobs: name: "Deploy Nightly to Fly.io" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v3 - uses: superfly/flyctl-actions/setup-flyctl@master - run: flyctl deploy --remote-only @@ -26,4 +29,28 @@ jobs: secrets: GH_TOKEN: ${{ secrets.CR_PAT }} + publish-tag: + name: "Publish Tag" + if: github.event_name == 'release' + uses: hay-kot/homebox/.github/workflows/partial-publish.yaml@main + with: + release: true + tag: ${{ github.event.release.tag_name }} + secrets: + GH_TOKEN: ${{ secrets.CR_PAT }} + deploy-docs: + name: Deploy docs + needs: + - publish-tag + runs-on: ubuntu-latest + steps: + - name: Checkout main + uses: actions/checkout@v3 + + - name: Deploy docs + uses: mhausenblas/mkdocs-deploy-gh-pages@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CONFIG_FILE: docs/mkdocs.yml + EXTRA_PACKAGES: build-base diff --git a/.github/workflows/tag.yaml b/.github/workflows/tag.yaml index 8ac7c54..f36d6df 100644 --- a/.github/workflows/tag.yaml +++ b/.github/workflows/tag.yaml @@ -17,17 +17,17 @@ jobs: name: "Frontend and End-to-End Tests" uses: hay-kot/homebox/.github/workflows/partial-frontend.yaml@main + goreleaser: - name: goreleaser runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v3 with: fetch-depth: 0 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v3 - uses: pnpm/action-setup@v2 with: @@ -41,7 +41,7 @@ jobs: cp -r ./.output/public ../backend/app/api/static/ - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v5 + uses: goreleaser/goreleaser-action@v4 with: workdir: "backend" distribution: goreleaser @@ -49,29 +49,3 @@ jobs: args: release --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - publish-tag: - name: "Publish Tag" - uses: hay-kot/homebox/.github/workflows/partial-publish.yaml@main - with: - release: true - tag: ${{ github.ref_name }} - secrets: - GH_TOKEN: ${{ secrets.CR_PAT }} - - deploy-docs: - name: Deploy docs - needs: - - publish-tag - - goreleaser - runs-on: ubuntu-latest - steps: - - name: Checkout main - uses: actions/checkout@v4 - - - name: Deploy docs - uses: mhausenblas/mkdocs-deploy-gh-pages@master - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CONFIG_FILE: docs/mkdocs.yml - EXTRA_PACKAGES: build-base \ No newline at end of file diff --git a/.gitignore b/.gitignore index d247138..410fc61 100644 --- a/.gitignore +++ b/.gitignore @@ -53,5 +53,4 @@ dist/ # Nuxt Publish Dir backend/app/api/static/public/* -!backend/app/api/static/public/.gitkeep -backend/api \ No newline at end of file +!backend/app/api/static/public/.gitkeep \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 09c7a0e..2383c21 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -16,7 +16,7 @@ "editor.formatOnSave": false, "editor.defaultFormatter": "dbaeumer.vscode-eslint", "editor.codeActionsOnSave": { - "source.fixAll.eslint": "explicit" + "source.fixAll.eslint": true }, "[typescript]": { "editor.defaultFormatter": "dbaeumer.vscode-eslint" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 52b2a0f..a6fb29f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,16 +1,16 @@ # Contributing -## We Develop with GitHub +## We Develop with Github -We use GitHub to host code, to track issues and feature requests, as well as accept pull requests. +We use github to host code, to track issues and feature requests, as well as accept pull requests. ## Branch Flow -We use the `main` branch as the development branch. All PRs should be made to the `main` branch from a feature branch. To create a pull request, you can use the following steps: +We use the `main` branch as the development branch. All PRs should be made to the `main` branch from a feature branch. To create a pull request you can use the following steps: 1. Fork the repository and create a new branch from `main`. 2. If you've added code that should be tested, add tests. -3. If you've changed APIs, update the documentation. +3. If you've changed API's, update the documentation. 4. Ensure that the test suite and linters pass 5. Issue your pull request @@ -18,7 +18,7 @@ We use the `main` branch as the development branch. All PRs should be made to th ### Prerequisites -There is a devcontainer available for this project. If you are using VSCode, you can use the devcontainer to get started. If you are not using VSCode, you need to ensure that you have the following tools installed: +There is a devcontainer available for this project. If you are using VSCode, you can use the devcontainer to get started. If you are not using VSCode, you can need to ensure that you have the following tools installed: - [Go 1.19+](https://golang.org/doc/install) - [Swaggo](https://github.com/swaggo/swag) @@ -31,27 +31,27 @@ If you're using `taskfile` you can run `task --list-all` for a list of all comma ### Setup -If you're using the taskfile, you can use the `task setup` command to run the required setup commands. Otherwise, you can review the commands required in the `Taskfile.yml` file. +If you're using the taskfile you can use the `task setup` command to run the required setup commands. Otherwise you can review the commands required in the `Taskfile.yml` file. -Note that when installing dependencies with pnpm you must use the `--shamefully-hoist` flag. If you don't use this flag, you will get an error when running the frontend server. +Note that when installing dependencies with pnpm you must use the `--shamefully-hoist` flag. If you don't use this flag you will get an error when running the the frontend server. ### API Development Notes start command `task go:run` 1. API Server does not auto reload. You'll need to restart the server after making changes. -2. Unit tests should be written in Go, however, end-to-end or user story tests should be written in TypeScript using the client library in the frontend directory. +2. Unit tests should be written in Go, however end-to-end or user story tests should be written in TypeScript using the client library in the frontend directory. ### Frontend Development Notes start command `task: ui:dev` 1. The frontend is a Vue 3 app with Nuxt.js that uses Tailwind and DaisyUI for styling. -2. We're using Vitest for our automated testing. You can run these with `task ui:watch`. -3. Tests require the API server to be running, and in some cases the first run will fail due to a race condition. If this happens, just run the tests again and they should pass. +2. We're using Vitest for our automated testing. you can run these with `task ui:watch`. +3. Tests require the API server to be running and in some cases the first run will fail due to a race condition. If this happens just run the tests again and they should pass. ## Publishing Release -Create a new tag in GitHub with the version number vX.X.X. This will trigger a new release to be created. +Create a new tag in github with the version number vX.X.X. This will trigger a new release to be created. Test -> Goreleaser -> Publish Release -> Trigger Docker Builds -> Deploy Docs + Fly.io Demo \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 11d5c74..8734c66 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,48 +1,50 @@ - -# Build Nuxt -FROM r.batts.cloud/nodejs:18 as frontend-builder -WORKDIR /app -RUN npm install -g pnpm@latest-9 -COPY frontend/package.json frontend/pnpm-lock.yaml ./ -RUN pnpm install --frozen-lockfile --shamefully-hoist -COPY frontend . -RUN pnpm build - -# Build API -FROM r.batts.cloud/golang:1.24 AS builder -ARG BUILD_TIME -ARG COMMIT -ARG VERSION -RUN apt update && \ - apt install -y git build-essential gcc g++ - -WORKDIR /go/src/app -COPY ./backend . -RUN go get -d -v ./... -RUN rm -rf ./app/api/public -COPY --from=frontend-builder /app/.output/public ./app/api/static/public -RUN CGO_ENABLED=0 GOOS=linux go build \ - -ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \ - -o /go/bin/api \ - -v ./app/api/*.go - -# Production Stage -FROM r.batts.cloud/debian:trixie - -ENV HBOX_MODE=production -ENV HBOX_STORAGE_DATA=/data/ -ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_pragma=busy_timeout=2000&_pragma=journal_mode=WAL&_fk=1 - -RUN mkdir /app -COPY --from=builder /go/bin/api /app - -RUN chmod +x /app/api - -LABEL Name=homebox Version=0.0.1 -LABEL org.opencontainers.image.source="https://github.com/hay-kot/homebox" -EXPOSE 7745 -WORKDIR /app -VOLUME [ "/data" ] - -ENTRYPOINT [ "/app/api" ] -CMD [ "/data/config.yml" ] + +# Build Nuxt +FROM node:17-alpine as frontend-builder +WORKDIR /app +RUN npm install -g pnpm +COPY frontend/package.json frontend/pnpm-lock.yaml ./ +RUN pnpm install --frozen-lockfile --shamefully-hoist +COPY frontend . +RUN pnpm build + +# Build API +FROM golang:alpine AS builder +ARG BUILD_TIME +ARG COMMIT +ARG VERSION +RUN apk update && \ + apk upgrade && \ + apk add --update git build-base gcc g++ + +WORKDIR /go/src/app +COPY ./backend . +RUN go get -d -v ./... +RUN rm -rf ./app/api/public +COPY --from=frontend-builder /app/.output/public ./app/api/static/public +RUN CGO_ENABLED=0 GOOS=linux go build \ + -ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \ + -o /go/bin/api \ + -v ./app/api/*.go + +# Production Stage +FROM alpine:latest + +ENV HBOX_MODE=production +ENV HBOX_STORAGE_DATA=/data/ +ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_fk=1 + +RUN apk --no-cache add ca-certificates +RUN mkdir /app +COPY --from=builder /go/bin/api /app + +RUN chmod +x /app/api + +LABEL Name=homebox Version=0.0.1 +LABEL org.opencontainers.image.source="https://github.com/hay-kot/homebox" +EXPOSE 7745 +WORKDIR /app +VOLUME [ "/data" ] + +ENTRYPOINT [ "/app/api" ] +CMD [ "/data/config.yml" ] diff --git a/Dockerfile.rootless b/Dockerfile.rootless deleted file mode 100644 index e1c98aa..0000000 --- a/Dockerfile.rootless +++ /dev/null @@ -1,53 +0,0 @@ - -# Build Nuxt -FROM node:17-alpine as frontend-builder -WORKDIR /app -RUN npm install -g pnpm -COPY frontend/package.json frontend/pnpm-lock.yaml ./ -RUN pnpm install --frozen-lockfile --shamefully-hoist -COPY frontend . -RUN pnpm build - -# Build API -FROM golang:alpine AS builder -ARG BUILD_TIME -ARG COMMIT -ARG VERSION -RUN apk update && \ - apk upgrade && \ - apk add --update git build-base gcc g++ - -WORKDIR /go/src/app -COPY ./backend . -RUN go get -d -v ./... -RUN rm -rf ./app/api/public -COPY --from=frontend-builder /app/.output/public ./app/api/static/public -RUN CGO_ENABLED=0 GOOS=linux go build \ - -ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \ - -o /go/bin/api \ - -v ./app/api/*.go && \ - chmod +x /go/bin/api && \ - # create a directory so that we can copy it in the next stage - mkdir /data - -# Production Stage -FROM gcr.io/distroless/static - -ENV HBOX_MODE=production -ENV HBOX_STORAGE_DATA=/data/ -ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_fk=1 - -# Copy the binary and the (empty) /data dir and -# change the ownership to the low-privileged user -COPY --from=builder --chown=nonroot /go/bin/api /app -COPY --from=builder --chown=nonroot /data /data - -LABEL Name=homebox Version=0.0.1 -LABEL org.opencontainers.image.source="https://github.com/hay-kot/homebox" -EXPOSE 7745 -VOLUME [ "/data" ] - -# Drop root and run as low-privileged user -USER nonroot -ENTRYPOINT [ "/app" ] -CMD [ "/data/config.yml" ] diff --git a/README.md b/README.md index 148322b..611a530 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,6 @@ [Configuration & Docker Compose](https://hay-kot.github.io/homebox/quick-start) ```bash -# If using the rootless image, ensure data -# folder has correct permissions -mkdir -p /path/to/data/folder -chown 65532:65532 -R /path/to/data/folder docker run -d \ --name homebox \ --restart unless-stopped \ @@ -27,17 +23,8 @@ docker run -d \ --env TZ=Europe/Bucharest \ --volume /path/to/data/folder/:/data \ ghcr.io/hay-kot/homebox:latest -# ghcr.io/hay-kot/homebox:latest-rootless ``` - -## Contributing - -Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. - -If you are not a coder, you can still contribute financially. Financial contributions help me prioritize working on this project over others and helps me know that there is a real demand for project development. - -Buy Me A Coffee ## Credits - Logo by [@lakotelman](https://github.com/lakotelman) diff --git a/Taskfile.yml b/Taskfile.yml index 4d9c1aa..45a8f29 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -1,7 +1,6 @@ version: "3" env: - HBOX_LOG_LEVEL: debug HBOX_STORAGE_SQLITE_URL: .data/homebox.db?_pragma=busy_timeout=1000&_pragma=journal_mode=WAL&_fk=1 HBOX_OPTIONS_ALLOW_REGISTRATION: true UNSAFE_DISABLE_PASSWORD_PROJECTION: "yes_i_am_sure" @@ -13,25 +12,15 @@ tasks: - cd backend && go mod tidy - cd frontend && pnpm install --shamefully-hoist - swag: - desc: Generate swagger docs - dir: backend/app/api/static/ - vars: - API: "../" - INTERNAL: "../../../internal" - PKGS: "../../../pkgs" - cmds: - - swag fmt --dir={{ .API }} - - swag init --dir={{ .API }},{{ .INTERNAL }}/core/services,{{ .INTERNAL }}/data/repo --parseDependency - sources: - - "./backend/app/api/**/*" - - "./backend/internal/data/**" - - "./backend/internal/core/services/**/*" - - "./backend/app/tools/typegen/main.go" - - typescript-types: - desc: Generates typescript types from swagger definition + generate: + desc: | + Generates collateral files from the backend project + including swagger docs and typescripts type for the frontend + deps: + - db:generate cmds: + - cd backend/app/api/static && swag fmt --dir=../ + - cd backend/app/api/static && swag init --dir=../,../../../internal,../../../pkgs - | npx swagger-typescript-api \ --no-client \ @@ -39,17 +28,12 @@ tasks: --path ./backend/app/api/static/docs/swagger.json \ --output ./frontend/lib/api/types - go run ./backend/app/tools/typegen/main.go ./frontend/lib/api/types/data-contracts.ts - sources: - - ./backend/app/tools/typegen/main.go - - ./backend/app/api/static/docs/swagger.json - - generate: - deps: - - db:generate - cmds: - - task: swag - - task: typescript-types - cp ./backend/app/api/static/docs/swagger.json docs/docs/api/openapi-2.0.json + sources: + - "./backend/app/api/**/*" + - "./backend/internal/data/**" + - "./backend/internal/core/services/**/*" + - "./backend/app/tools/typegen/main.go" go:run: desc: Starts the backend api server (depends on generate task) @@ -103,7 +87,8 @@ tasks: dir: backend/internal/ cmds: - | - go generate ./... + go generate ./... \ + --template=./data/ent/schema/templates/has_id.tmpl sources: - "./backend/internal/data/ent/schema/**/*" @@ -154,4 +139,4 @@ tasks: - task: go:all - task: ui:check - task: ui:fix - - task: test:ci + - task: test:ci \ No newline at end of file diff --git a/backend/.golangci.yml b/backend/.golangci.yml deleted file mode 100644 index 8f63110..0000000 --- a/backend/.golangci.yml +++ /dev/null @@ -1,74 +0,0 @@ -run: - timeout: 10m - skip-dirs: - - internal/data/ent.* -linters-settings: - goconst: - min-len: 5 - min-occurrences: 5 - exhaustive: - default-signifies-exhaustive: true - revive: - ignore-generated-header: false - severity: warning - confidence: 3 - depguard: - rules: - main: - deny: - - pkg: io/util - desc: | - Deprecated: As of Go 1.16, the same functionality is now provided by - package io or package os, and those implementations should be - preferred in new code. See the specific function documentation for - details. - gocritic: - enabled-checks: - - ruleguard - testifylint: - enable-all: true - tagalign: - order: - - json - - schema - - yaml - - yml - - toml - - validate -linters: - disable-all: true - enable: - - asciicheck - - bodyclose - - depguard - - dogsled - - errcheck - - errorlint - - exhaustive - - exportloopref - - gochecknoinits - - goconst - - gocritic - - gocyclo - - gofmt - - goprintffuncname - - gosimple - - govet - - ineffassign - - misspell - - nakedret - - revive - - staticcheck - - stylecheck - - tagalign - - testifylint - - typecheck - - typecheck - - unconvert - - unused - - whitespace - - zerologlint - - sqlclosecheck -issues: - exclude-use-default: false - fix: true diff --git a/backend/app/api/app.go b/backend/app/api/app.go index 5d285d3..0f44297 100644 --- a/backend/app/api/app.go +++ b/backend/app/api/app.go @@ -1,21 +1,23 @@ package main import ( + "time" + "github.com/hay-kot/homebox/backend/internal/core/services" - "github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus" "github.com/hay-kot/homebox/backend/internal/data/ent" "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/sys/config" "github.com/hay-kot/homebox/backend/pkgs/mailer" + "github.com/hay-kot/safeserve/server" ) type app struct { conf *config.Config mailer mailer.Mailer db *ent.Client + server *server.Server repos *repo.AllRepos services *services.AllServices - bus *eventbus.EventBus } func new(conf *config.Config) *app { @@ -33,3 +35,13 @@ func new(conf *config.Config) *app { return s } + +func (a *app) startBgTask(t time.Duration, fn func()) { + timer := time.NewTimer(t) + + for { + timer.Reset(t) + a.server.Background(fn) + <-timer.C + } +} diff --git a/backend/app/api/bgrunner.go b/backend/app/api/bgrunner.go deleted file mode 100644 index ce4b7cc..0000000 --- a/backend/app/api/bgrunner.go +++ /dev/null @@ -1,37 +0,0 @@ -package main - -import ( - "context" - "time" -) - -type BackgroundTask struct { - name string - Interval time.Duration - Fn func(context.Context) -} - -func (tsk *BackgroundTask) Name() string { - return tsk.name -} - -func NewTask(name string, interval time.Duration, fn func(context.Context)) *BackgroundTask { - return &BackgroundTask{ - Interval: interval, - Fn: fn, - } -} - -func (tsk *BackgroundTask) Start(ctx context.Context) error { - timer := time.NewTimer(tsk.Interval) - - for { - select { - case <-ctx.Done(): - return nil - case <-timer.C: - timer.Reset(tsk.Interval) - tsk.Fn(ctx) - } - } -} diff --git a/backend/app/api/demo.go b/backend/app/api/demo.go index 183e0e0..5b8f7d6 100644 --- a/backend/app/api/demo.go +++ b/backend/app/api/demo.go @@ -3,7 +3,6 @@ package main import ( "context" "strings" - "time" "github.com/hay-kot/homebox/backend/internal/core/services" "github.com/rs/zerolog/log" @@ -16,12 +15,9 @@ func (a *app) SetupDemo() { ,Office,IOT;Home Assistant; Z-Wave,1,Zooz 110v Power Switch,"Zooz Z-Wave Plus Power Switch ZEN15 for 110V AC Units, Sump Pumps, Humidifiers, and More",,,ZEN15,Zooz,,Amazon,39.95,10/13/2021,,,,,,, ,Downstairs,IOT;Home Assistant; Z-Wave,1,Ecolink Z-Wave PIR Motion Sensor,"Ecolink Z-Wave PIR Motion Detector Pet Immune, White (PIRZWAVE2.5-ECO)",,,PIRZWAVE2.5-ECO,Ecolink,,Amazon,35.58,10/21/2020,,,,,,, ,Entry,IOT;Home Assistant; Z-Wave,1,Yale Security Touchscreen Deadbolt,"Yale Security YRD226-ZW2-619 YRD226ZW2619 Touchscreen Deadbolt, Satin Nickel",,,YRD226ZW2619,Yale,,Amazon,120.39,10/14/2020,,,,,,, -,Kitchen,IOT;Home Assistant; Z-Wave,1,Smart Rocker Light Dimmer,"UltraPro Z-Wave Smart Rocker Light Dimmer with QuickFit and SimpleWire, 3-Way Ready, Compatible with Alexa, Google Assistant, ZWave Hub Required, Repeater/Range Extender, White Paddle Only, 39351",,,39351,Honeywell,,Amazon,65.98,09/30/0202,,,,,,, +,Kitchen,IOT;Home Assistant; Z-Wave,1,Smart Rocker Light Dimmer,"UltraPro Z-Wave Smart Rocker Light Dimmer with QuickFit and SimpleWire, 3-Way Ready, Compatible with Alexa, Google Assistant, ZWave Hub Required, Repeater/Range Extender, White Paddle Only, 39351",,,‎39351,Honeywell,,Amazon,65.98,09/30/0202,,,,,,, ` - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - registration := services.UserRegistration{ Email: "demo@example.com", Name: "Demo", @@ -29,34 +25,21 @@ func (a *app) SetupDemo() { } // First check if we've already setup a demo user and skip if so - log.Debug().Msg("Checking if demo user already exists") - _, err := a.services.User.Login(ctx, registration.Email, registration.Password, false) + _, err := a.services.User.Login(context.Background(), registration.Email, registration.Password, false) if err == nil { - log.Info().Msg("Demo user already exists, skipping setup") return } - log.Debug().Msg("Demo user does not exist, setting up demo") - _, err = a.services.User.RegisterUser(ctx, registration) + _, err = a.services.User.RegisterUser(context.Background(), registration) if err != nil { log.Err(err).Msg("Failed to register demo user") log.Fatal().Msg("Failed to setup demo") } - token, err := a.services.User.Login(ctx, registration.Email, registration.Password, false) - if err != nil { - log.Err(err).Msg("Failed to login demo user") - log.Fatal().Msg("Failed to setup demo") - return - } - self, err := a.services.User.GetSelf(ctx, token.Raw) - if err != nil { - log.Err(err).Msg("Failed to get self") - log.Fatal().Msg("Failed to setup demo") - return - } + token, _ := a.services.User.Login(context.Background(), registration.Email, registration.Password, false) + self, _ := a.services.User.GetSelf(context.Background(), token.Raw) - _, err = a.services.Items.CsvImport(ctx, self.GroupID, strings.NewReader(csvText)) + _, err = a.services.Items.CsvImport(context.Background(), self.GroupID, strings.NewReader(csvText)) if err != nil { log.Err(err).Msg("Failed to import CSV") log.Fatal().Msg("Failed to setup demo") diff --git a/backend/app/api/handlers/debughandlers/debug.go b/backend/app/api/handlers/debughandlers/debug.go index 5f66fed..ffba624 100644 --- a/backend/app/api/handlers/debughandlers/debug.go +++ b/backend/app/api/handlers/debughandlers/debug.go @@ -1,4 +1,3 @@ -// Package debughandlers provides handlers for debugging. package debughandlers import ( diff --git a/backend/app/api/handlers/v1/controller.go b/backend/app/api/handlers/v1/controller.go index eb60212..bf14a9d 100644 --- a/backend/app/api/handlers/v1/controller.go +++ b/backend/app/api/handlers/v1/controller.go @@ -1,20 +1,12 @@ -// Package v1 provides the API handlers for version 1 of the API. package v1 import ( - "encoding/json" "net/http" - "time" - "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/core/services" - "github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus" "github.com/hay-kot/homebox/backend/internal/data/repo" - "github.com/hay-kot/httpkit/errchain" - "github.com/hay-kot/httpkit/server" - "github.com/rs/zerolog/log" - - "github.com/olahol/melody" + "github.com/hay-kot/safeserve/errchain" + "github.com/hay-kot/safeserve/server" ) type Results[T any] struct { @@ -51,20 +43,12 @@ func WithRegistration(allowRegistration bool) func(*V1Controller) { } } -func WithSecureCookies(secure bool) func(*V1Controller) { - return func(ctrl *V1Controller) { - ctrl.cookieSecure = secure - } -} - type V1Controller struct { - cookieSecure bool repo *repo.AllRepos svc *services.AllServices maxUploadSize int64 isDemo bool allowRegistration bool - bus *eventbus.EventBus } type ( @@ -76,7 +60,7 @@ type ( BuildTime string `json:"buildTime"` } - APISummary struct { + ApiSummary struct { Healthy bool `json:"health"` Versions []string `json:"versions"` Title string `json:"title"` @@ -87,18 +71,17 @@ type ( } ) -func BaseURLFunc(prefix string) func(s string) string { +func BaseUrlFunc(prefix string) func(s string) string { return func(s string) string { return prefix + "/v1" + s } } -func NewControllerV1(svc *services.AllServices, repos *repo.AllRepos, bus *eventbus.EventBus, options ...func(*V1Controller)) *V1Controller { +func NewControllerV1(svc *services.AllServices, repos *repo.AllRepos, options ...func(*V1Controller)) *V1Controller { ctrl := &V1Controller{ repo: repos, svc: svc, allowRegistration: true, - bus: bus, } for _, opt := range options { @@ -113,11 +96,11 @@ func NewControllerV1(svc *services.AllServices, repos *repo.AllRepos, bus *event // @Summary Application Info // @Tags Base // @Produce json -// @Success 200 {object} APISummary +// @Success 200 {object} ApiSummary // @Router /v1/status [GET] func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) errchain.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) error { - return server.JSON(w, http.StatusOK, APISummary{ + return server.JSON(w, http.StatusOK, ApiSummary{ Healthy: ready(), Title: "Homebox", Message: "Track, Manage, and Organize your Things", @@ -127,87 +110,3 @@ func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) errchain.Hand }) } } - -// HandleCurrency godoc -// -// @Summary Currency -// @Tags Base -// @Produce json -// @Success 200 {object} currencies.Currency -// @Router /v1/currency [GET] -func (ctrl *V1Controller) HandleCurrency() errchain.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) error { - // Set Cache for 10 Minutes - w.Header().Set("Cache-Control", "max-age=600") - - return server.JSON(w, http.StatusOK, ctrl.svc.Currencies.Slice()) - } -} - -func (ctrl *V1Controller) HandleCacheWS() errchain.HandlerFunc { - type eventMsg struct { - Event string `json:"event"` - } - - m := melody.New() - - m.HandleConnect(func(s *melody.Session) { - auth := services.NewContext(s.Request.Context()) - s.Set("gid", auth.GID) - }) - - factory := func(e string) func(data any) { - return func(data any) { - eventData, ok := data.(eventbus.GroupMutationEvent) - if !ok { - log.Log().Msgf("invalid event data: %v", data) - return - } - - msg := &eventMsg{Event: e} - - jsonBytes, err := json.Marshal(msg) - if err != nil { - log.Log().Msgf("error marshling event data %v: %v", data, err) - return - } - - _ = m.BroadcastFilter(jsonBytes, func(s *melody.Session) bool { - groupIDStr, ok := s.Get("gid") - if !ok { - return false - } - - GID := groupIDStr.(uuid.UUID) - return GID == eventData.GID - }) - } - } - - ctrl.bus.Subscribe(eventbus.EventLabelMutation, factory("label.mutation")) - ctrl.bus.Subscribe(eventbus.EventLocationMutation, factory("location.mutation")) - ctrl.bus.Subscribe(eventbus.EventItemMutation, factory("item.mutation")) - - // Persistent asynchronous ticker that keeps all websocket connections alive with periodic pings. - go func() { - const interval = 10 * time.Second - - ping := time.NewTicker(interval) - defer ping.Stop() - - for range ping.C { - msg := &eventMsg{Event: "ping"} - - pingBytes, err := json.Marshal(msg) - if err != nil { - log.Log().Msgf("error marshaling ping: %v", err) - } else { - _ = m.Broadcast(pingBytes) - } - } - }() - - return func(w http.ResponseWriter, r *http.Request) error { - return m.HandleRequest(w, r) - } -} diff --git a/backend/app/api/handlers/v1/v1_ctrl_actions.go b/backend/app/api/handlers/v1/v1_ctrl_actions.go index 75f39a5..10c9f2e 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_actions.go +++ b/backend/app/api/handlers/v1/v1_ctrl_actions.go @@ -7,8 +7,8 @@ import ( "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/core/services" "github.com/hay-kot/homebox/backend/internal/sys/validate" - "github.com/hay-kot/httpkit/errchain" - "github.com/hay-kot/httpkit/server" + "github.com/hay-kot/safeserve/errchain" + "github.com/hay-kot/safeserve/server" "github.com/rs/zerolog/log" ) @@ -68,16 +68,3 @@ func (ctrl *V1Controller) HandleEnsureImportRefs() errchain.HandlerFunc { func (ctrl *V1Controller) HandleItemDateZeroOut() errchain.HandlerFunc { return actionHandlerFactory("zero out date time", ctrl.repo.Items.ZeroOutTimeFields) } - -// HandleSetPrimaryPhotos godoc -// -// @Summary Set Primary Photos -// @Description Sets the first photo of each item as the primary photo -// @Tags Actions -// @Produce json -// @Success 200 {object} ActionAmountResult -// @Router /v1/actions/set-primary-photos [Post] -// @Security Bearer -func (ctrl *V1Controller) HandleSetPrimaryPhotos() errchain.HandlerFunc { - return actionHandlerFactory("ensure asset IDs", ctrl.repo.Items.SetPrimaryPhotos) -} diff --git a/backend/app/api/handlers/v1/v1_ctrl_assets.go b/backend/app/api/handlers/v1/v1_ctrl_assets.go index 91e9a3c..117ebe4 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_assets.go +++ b/backend/app/api/handlers/v1/v1_ctrl_assets.go @@ -9,8 +9,8 @@ import ( "github.com/hay-kot/homebox/backend/internal/core/services" "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/sys/validate" - "github.com/hay-kot/httpkit/errchain" - "github.com/hay-kot/httpkit/server" + "github.com/hay-kot/safeserve/errchain" + "github.com/hay-kot/safeserve/server" "github.com/rs/zerolog/log" ) @@ -27,10 +27,10 @@ import ( func (ctrl *V1Controller) HandleAssetGet() errchain.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) error { ctx := services.NewContext(r.Context()) - assetIDParam := chi.URLParam(r, "id") - assetIDParam = strings.ReplaceAll(assetIDParam, "-", "") // Remove dashes + assetIdParam := chi.URLParam(r, "id") + assetIdParam = strings.ReplaceAll(assetIdParam, "-", "") // Remove dashes // Convert the asset ID to an int64 - assetID, err := strconv.ParseInt(assetIDParam, 10, 64) + assetId, err := strconv.ParseInt(assetIdParam, 10, 64) if err != nil { return err } @@ -52,7 +52,7 @@ func (ctrl *V1Controller) HandleAssetGet() errchain.HandlerFunc { } } - items, err := ctrl.repo.Items.QueryByAssetID(r.Context(), ctx.GID, repo.AssetID(assetID), int(page), int(pageSize)) + items, err := ctrl.repo.Items.QueryByAssetID(r.Context(), ctx.GID, repo.AssetID(assetId), int(page), int(pageSize)) if err != nil { log.Err(err).Msg("failed to get item") return validate.NewRequestError(err, http.StatusInternalServerError) diff --git a/backend/app/api/handlers/v1/v1_ctrl_auth.go b/backend/app/api/handlers/v1/v1_ctrl_auth.go index 47b69fd..936f38e 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_auth.go +++ b/backend/app/api/handlers/v1/v1_ctrl_auth.go @@ -3,23 +3,16 @@ package v1 import ( "errors" "net/http" - "strconv" "strings" "time" "github.com/hay-kot/homebox/backend/internal/core/services" "github.com/hay-kot/homebox/backend/internal/sys/validate" - "github.com/hay-kot/httpkit/errchain" - "github.com/hay-kot/httpkit/server" + "github.com/hay-kot/safeserve/errchain" + "github.com/hay-kot/safeserve/server" "github.com/rs/zerolog/log" ) -const ( - cookieNameToken = "hb.auth.token" - cookieNameRemember = "hb.auth.remember" - cookieNameSession = "hb.auth.session" -) - type ( TokenResponse struct { Token string `json:"token"` @@ -34,49 +27,6 @@ type ( } ) -type CookieContents struct { - Token string - ExpiresAt time.Time - Remember bool -} - -func GetCookies(r *http.Request) (*CookieContents, error) { - cookie, err := r.Cookie(cookieNameToken) - if err != nil { - return nil, errors.New("authorization cookie is required") - } - - rememberCookie, err := r.Cookie(cookieNameRemember) - if err != nil { - return nil, errors.New("remember cookie is required") - } - - return &CookieContents{ - Token: cookie.Value, - ExpiresAt: cookie.Expires, - Remember: rememberCookie.Value == "true", - }, nil -} - -// AuthProvider is an interface that can be implemented by any authentication provider. -// to extend authentication methods for the API. -type AuthProvider interface { - // Name returns the name of the authentication provider. This should be a unique name. - // that is URL friendly. - // - // Example: "local", "ldap" - Name() string - // Authenticate is called when a user attempts to login to the API. The implementation - // should return an error if the user cannot be authenticated. If an error is returned - // the API controller will return a vague error message to the user. - // - // Authenticate should do the following: - // - // 1. Ensure that the user exists within the database (either create, or get) - // 2. On successful authentication, they must set the user cookies. - Authenticate(w http.ResponseWriter, r *http.Request) (services.UserAuthTokenDetail, error) -} - // HandleAuthLogin godoc // // @Summary User Login @@ -85,42 +35,52 @@ type AuthProvider interface { // @Accept application/json // @Param username formData string false "string" example(admin@admin.com) // @Param password formData string false "string" example(admin) -// @Param payload body LoginForm true "Login Data" -// @Param provider query string false "auth provider" +// @Param payload body LoginForm true "Login Data" // @Produce json // @Success 200 {object} TokenResponse // @Router /v1/users/login [POST] -func (ctrl *V1Controller) HandleAuthLogin(ps ...AuthProvider) errchain.HandlerFunc { - if len(ps) == 0 { - panic("no auth providers provided") - } - - providers := make(map[string]AuthProvider) - for _, p := range ps { - log.Info().Str("name", p.Name()).Msg("registering auth provider") - providers[p.Name()] = p - } - +func (ctrl *V1Controller) HandleAuthLogin() errchain.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) error { - // Extract provider query - provider := r.URL.Query().Get("provider") - if provider == "" { - provider = "local" + loginForm := &LoginForm{} + + switch r.Header.Get("Content-Type") { + case "application/x-www-form-urlencoded": + err := r.ParseForm() + if err != nil { + return errors.New("failed to parse form") + } + + loginForm.Username = r.PostFormValue("username") + loginForm.Password = r.PostFormValue("password") + loginForm.StayLoggedIn = r.PostFormValue("stayLoggedIn") == "true" + case "application/json": + err := server.Decode(r, loginForm) + if err != nil { + log.Err(err).Msg("failed to decode login form") + return errors.New("failed to decode login form") + } + default: + return server.JSON(w, http.StatusBadRequest, errors.New("invalid content type")) } - // Get the provider - p, ok := providers[provider] - if !ok { - return validate.NewRequestError(errors.New("invalid auth provider"), http.StatusBadRequest) + if loginForm.Username == "" || loginForm.Password == "" { + return validate.NewFieldErrors( + validate.FieldError{ + Field: "username", + Error: "username or password is empty", + }, + validate.FieldError{ + Field: "password", + Error: "username or password is empty", + }, + ) } - newToken, err := p.Authenticate(w, r) + newToken, err := ctrl.svc.User.Login(r.Context(), strings.ToLower(loginForm.Username), loginForm.Password, loginForm.StayLoggedIn) if err != nil { - log.Err(err).Msg("failed to authenticate") - return server.JSON(w, http.StatusInternalServerError, err.Error()) + return validate.NewRequestError(errors.New("authentication failed"), http.StatusInternalServerError) } - ctrl.setCookies(w, noPort(r.Host), newToken.Raw, newToken.ExpiresAt, true) return server.JSON(w, http.StatusOK, TokenResponse{ Token: "Bearer " + newToken.Raw, ExpiresAt: newToken.ExpiresAt, @@ -148,12 +108,11 @@ func (ctrl *V1Controller) HandleAuthLogout() errchain.HandlerFunc { return validate.NewRequestError(err, http.StatusInternalServerError) } - ctrl.unsetCookies(w, noPort(r.Host)) return server.JSON(w, http.StatusNoContent, nil) } } -// HandleAuthRefresh godoc +// HandleAuthLogout godoc // // @Summary User Token Refresh // @Description handleAuthRefresh returns a handler that will issue a new token from an existing token. @@ -174,78 +133,6 @@ func (ctrl *V1Controller) HandleAuthRefresh() errchain.HandlerFunc { return validate.NewUnauthorizedError() } - ctrl.setCookies(w, noPort(r.Host), newToken.Raw, newToken.ExpiresAt, false) return server.JSON(w, http.StatusOK, newToken) } } - -func noPort(host string) string { - return strings.Split(host, ":")[0] -} - -func (ctrl *V1Controller) setCookies(w http.ResponseWriter, domain, token string, expires time.Time, remember bool) { - http.SetCookie(w, &http.Cookie{ - Name: cookieNameRemember, - Value: strconv.FormatBool(remember), - Expires: expires, - Domain: domain, - Secure: ctrl.cookieSecure, - HttpOnly: true, - Path: "/", - }) - - // Set HTTP only cookie - http.SetCookie(w, &http.Cookie{ - Name: cookieNameToken, - Value: token, - Expires: expires, - Domain: domain, - Secure: ctrl.cookieSecure, - HttpOnly: true, - Path: "/", - }) - - // Set Fake Session cookie - http.SetCookie(w, &http.Cookie{ - Name: cookieNameSession, - Value: "true", - Expires: expires, - Domain: domain, - Secure: ctrl.cookieSecure, - HttpOnly: false, - Path: "/", - }) -} - -func (ctrl *V1Controller) unsetCookies(w http.ResponseWriter, domain string) { - http.SetCookie(w, &http.Cookie{ - Name: cookieNameToken, - Value: "", - Expires: time.Unix(0, 0), - Domain: domain, - Secure: ctrl.cookieSecure, - HttpOnly: true, - Path: "/", - }) - - http.SetCookie(w, &http.Cookie{ - Name: cookieNameRemember, - Value: "false", - Expires: time.Unix(0, 0), - Domain: domain, - Secure: ctrl.cookieSecure, - HttpOnly: true, - Path: "/", - }) - - // Set Fake Session cookie - http.SetCookie(w, &http.Cookie{ - Name: cookieNameSession, - Value: "false", - Expires: time.Unix(0, 0), - Domain: domain, - Secure: ctrl.cookieSecure, - HttpOnly: false, - Path: "/", - }) -} diff --git a/backend/app/api/handlers/v1/v1_ctrl_group.go b/backend/app/api/handlers/v1/v1_ctrl_group.go index 69bc024..bd9ff4c 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_group.go +++ b/backend/app/api/handlers/v1/v1_ctrl_group.go @@ -6,14 +6,13 @@ import ( "github.com/hay-kot/homebox/backend/internal/core/services" "github.com/hay-kot/homebox/backend/internal/data/repo" - "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/internal/web/adapters" - "github.com/hay-kot/httpkit/errchain" + "github.com/hay-kot/safeserve/errchain" ) type ( GroupInvitationCreate struct { - Uses int `json:"uses" validate:"required,min=1,max=100"` + Uses int `json:"uses" validate:"required,min=1,max=100"` ExpiresAt time.Time `json:"expiresAt"` } @@ -53,14 +52,6 @@ func (ctrl *V1Controller) HandleGroupGet() errchain.HandlerFunc { func (ctrl *V1Controller) HandleGroupUpdate() errchain.HandlerFunc { fn := func(r *http.Request, body repo.GroupUpdate) (repo.Group, error) { auth := services.NewContext(r.Context()) - - ok := ctrl.svc.Currencies.IsSupported(body.Currency) - if !ok { - return repo.Group{}, validate.NewFieldErrors( - validate.NewFieldError("currency", "currency '"+body.Currency+"' is not supported"), - ) - } - return ctrl.svc.Group.UpdateGroup(auth, body) } diff --git a/backend/app/api/handlers/v1/v1_ctrl_items.go b/backend/app/api/handlers/v1/v1_ctrl_items.go index 6a25663..062fbad 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_items.go +++ b/backend/app/api/handlers/v1/v1_ctrl_items.go @@ -12,8 +12,8 @@ import ( "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/internal/web/adapters" - "github.com/hay-kot/httpkit/errchain" - "github.com/hay-kot/httpkit/server" + "github.com/hay-kot/safeserve/errchain" + "github.com/hay-kot/safeserve/server" "github.com/rs/zerolog/log" ) @@ -27,7 +27,6 @@ import ( // @Param pageSize query int false "items per page" // @Param labels query []string false "label Ids" collectionFormat(multi) // @Param locations query []string false "location Ids" collectionFormat(multi) -// @Param parentIds query []string false "parent Ids" collectionFormat(multi) // @Success 200 {object} repo.PaginationResult[repo.ItemSummary]{} // @Router /v1/items [GET] // @Security Bearer @@ -57,10 +56,8 @@ func (ctrl *V1Controller) HandleItemsGetAll() errchain.HandlerFunc { Search: params.Get("q"), LocationIDs: queryUUIDList(params, "locations"), LabelIDs: queryUUIDList(params, "labels"), - ParentItemIDs: queryUUIDList(params, "parentIds"), IncludeArchived: queryBool(params.Get("includeArchived")), Fields: filterFieldItems(params["fields"]), - OrderBy: params.Get("orderBy"), } if strings.HasPrefix(v.Search, "#") { @@ -93,48 +90,6 @@ func (ctrl *V1Controller) HandleItemsGetAll() errchain.HandlerFunc { } } -// HandleItemFullPath godoc -// -// @Summary Get the full path of an item -// @Tags Items -// @Produce json -// @Param id path string true "Item ID" -// @Success 200 {object} []repo.ItemPath -// @Router /v1/items/{id}/path [GET] -// @Security Bearer -func (ctrl *V1Controller) HandleItemFullPath() errchain.HandlerFunc { - fn := func(r *http.Request, ID uuid.UUID) ([]repo.ItemPath, error) { - auth := services.NewContext(r.Context()) - item, err := ctrl.repo.Items.GetOneByGroup(auth, auth.GID, ID) - if err != nil { - return nil, err - } - - paths, err := ctrl.repo.Locations.PathForLoc(auth, auth.GID, item.Location.ID) - if err != nil { - return nil, err - } - - if item.Parent != nil { - paths = append(paths, repo.ItemPath{ - Type: repo.ItemTypeItem, - ID: item.Parent.ID, - Name: item.Parent.Name, - }) - } - - paths = append(paths, repo.ItemPath{ - Type: repo.ItemTypeItem, - ID: item.ID, - Name: item.Name, - }) - - return paths, nil - } - - return adapters.CommandID("id", fn, http.StatusOK) -} - // HandleItemsCreate godoc // // @Summary Create Item @@ -211,32 +166,6 @@ func (ctrl *V1Controller) HandleItemUpdate() errchain.HandlerFunc { return adapters.ActionID("id", fn, http.StatusOK) } -// HandleItemPatch godocs -// -// @Summary Update Item -// @Tags Items -// @Produce json -// @Param id path string true "Item ID" -// @Param payload body repo.ItemPatch true "Item Data" -// @Success 200 {object} repo.ItemOut -// @Router /v1/items/{id} [Patch] -// @Security Bearer -func (ctrl *V1Controller) HandleItemPatch() errchain.HandlerFunc { - fn := func(r *http.Request, ID uuid.UUID, body repo.ItemPatch) (repo.ItemOut, error) { - auth := services.NewContext(r.Context()) - - body.ID = ID - err := ctrl.repo.Items.Patch(auth, auth.GID, ID, body) - if err != nil { - return repo.ItemOut{}, err - } - - return ctrl.repo.Items.GetOneByGroup(auth, auth.GID, ID) - } - - return adapters.ActionID("id", fn, http.StatusOK) -} - // HandleGetAllCustomFieldNames godocs // // @Summary Get All Custom Field Names @@ -274,7 +203,8 @@ func (ctrl *V1Controller) HandleGetAllCustomFieldValues() errchain.HandlerFunc { return ctrl.repo.Items.GetAllCustomFieldValues(auth, auth.GID, q.Field) } - return adapters.Query(fn, http.StatusOK) + return adapters.Action(fn, http.StatusOK) + } // HandleItemsImport godocs diff --git a/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go b/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go index ae2782a..9745538 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go +++ b/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go @@ -3,15 +3,13 @@ package v1 import ( "errors" "net/http" - "path/filepath" - "strings" "github.com/hay-kot/homebox/backend/internal/core/services" "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/sys/validate" - "github.com/hay-kot/httpkit/errchain" - "github.com/hay-kot/httpkit/server" + "github.com/hay-kot/safeserve/errchain" + "github.com/hay-kot/safeserve/server" "github.com/rs/zerolog/log" ) @@ -31,7 +29,7 @@ type ( // @Param type formData string true "Type of file" // @Param name formData string true "name of the file including extension" // @Success 200 {object} repo.ItemOut -// @Failure 422 {object} validate.ErrorResponse +// @Failure 422 {object} mid.ErrorResponse // @Router /v1/items/{id}/attachments [POST] // @Security Bearer func (ctrl *V1Controller) HandleItemAttachmentCreate() errchain.HandlerFunc { @@ -40,6 +38,7 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() errchain.HandlerFunc { if err != nil { log.Err(err).Msg("failed to parse multipart form") return validate.NewRequestError(errors.New("failed to parse multipart form"), http.StatusBadRequest) + } errs := validate.NewFieldErrors() @@ -68,15 +67,7 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() errchain.HandlerFunc { attachmentType := r.FormValue("type") if attachmentType == "" { - // Attempt to auto-detect the type of the file - ext := filepath.Ext(attachmentName) - - switch strings.ToLower(ext) { - case ".jpg", ".jpeg", ".png", ".webp", ".gif", ".bmp", ".tiff": - attachmentType = attachment.TypePhoto.String() - default: - attachmentType = attachment.TypeAttachment.String() - } + attachmentType = attachment.TypeAttachment.String() } id, err := ctrl.routeID(r) diff --git a/backend/app/api/handlers/v1/v1_ctrl_labels.go b/backend/app/api/handlers/v1/v1_ctrl_labels.go index dae23db..e21036d 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_labels.go +++ b/backend/app/api/handlers/v1/v1_ctrl_labels.go @@ -7,7 +7,7 @@ import ( "github.com/hay-kot/homebox/backend/internal/core/services" "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/web/adapters" - "github.com/hay-kot/httpkit/errchain" + "github.com/hay-kot/safeserve/errchain" ) // HandleLabelsGetAll godoc diff --git a/backend/app/api/handlers/v1/v1_ctrl_locations.go b/backend/app/api/handlers/v1/v1_ctrl_locations.go index d84ce31..c9ffa57 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_locations.go +++ b/backend/app/api/handlers/v1/v1_ctrl_locations.go @@ -7,10 +7,10 @@ import ( "github.com/hay-kot/homebox/backend/internal/core/services" "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/web/adapters" - "github.com/hay-kot/httpkit/errchain" + "github.com/hay-kot/safeserve/errchain" ) -// HandleLocationTreeQuery godoc +// HandleLocationTreeQuery // // @Summary Get Locations Tree // @Tags Locations @@ -28,7 +28,7 @@ func (ctrl *V1Controller) HandleLocationTreeQuery() errchain.HandlerFunc { return adapters.Query(fn, http.StatusOK) } -// HandleLocationGetAll godoc +// HandleLocationGetAll // // @Summary Get All Locations // @Tags Locations @@ -46,7 +46,7 @@ func (ctrl *V1Controller) HandleLocationGetAll() errchain.HandlerFunc { return adapters.Query(fn, http.StatusOK) } -// HandleLocationCreate godoc +// HandleLocationCreate // // @Summary Create Location // @Tags Locations @@ -64,7 +64,7 @@ func (ctrl *V1Controller) HandleLocationCreate() errchain.HandlerFunc { return adapters.Action(fn, http.StatusCreated) } -// HandleLocationDelete godoc +// HandleLocationDelete // // @Summary Delete Location // @Tags Locations @@ -83,7 +83,7 @@ func (ctrl *V1Controller) HandleLocationDelete() errchain.HandlerFunc { return adapters.CommandID("id", fn, http.StatusNoContent) } -// HandleLocationGet godoc +// HandleLocationGet // // @Summary Get Location // @Tags Locations @@ -101,7 +101,7 @@ func (ctrl *V1Controller) HandleLocationGet() errchain.HandlerFunc { return adapters.CommandID("id", fn, http.StatusOK) } -// HandleLocationUpdate godoc +// HandleLocationUpdate // // @Summary Update Location // @Tags Locations diff --git a/backend/app/api/handlers/v1/v1_ctrl_maint_entry.go b/backend/app/api/handlers/v1/v1_ctrl_maint_entry.go index e94c12a..eeed717 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_maint_entry.go +++ b/backend/app/api/handlers/v1/v1_ctrl_maint_entry.go @@ -7,10 +7,10 @@ import ( "github.com/hay-kot/homebox/backend/internal/core/services" "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/web/adapters" - "github.com/hay-kot/httpkit/errchain" + "github.com/hay-kot/safeserve/errchain" ) -// HandleMaintenanceLogGet godoc +// HandleMaintenanceGetLog godoc // // @Summary Get Maintenance Log // @Tags Maintenance diff --git a/backend/app/api/handlers/v1/v1_ctrl_notifiers.go b/backend/app/api/handlers/v1/v1_ctrl_notifiers.go index 3c64dc7..da561c4 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_notifiers.go +++ b/backend/app/api/handlers/v1/v1_ctrl_notifiers.go @@ -8,7 +8,7 @@ import ( "github.com/hay-kot/homebox/backend/internal/core/services" "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/web/adapters" - "github.com/hay-kot/httpkit/errchain" + "github.com/hay-kot/safeserve/errchain" ) // HandleGetUserNotifiers godoc diff --git a/backend/app/api/handlers/v1/v1_ctrl_qrcode.go b/backend/app/api/handlers/v1/v1_ctrl_qrcode.go index 25f7c75..1f06e2f 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_qrcode.go +++ b/backend/app/api/handlers/v1/v1_ctrl_qrcode.go @@ -5,10 +5,9 @@ import ( "image/png" "io" "net/http" - "net/url" "github.com/hay-kot/homebox/backend/internal/web/adapters" - "github.com/hay-kot/httpkit/errchain" + "github.com/hay-kot/safeserve/errchain" "github.com/yeqown/go-qrcode/v2" "github.com/yeqown/go-qrcode/writer/standard" @@ -44,12 +43,7 @@ func (ctrl *V1Controller) HandleGenerateQRCode() errchain.HandlerFunc { panic(err) } - decodedStr, err := url.QueryUnescape(q.Data) - if err != nil { - return err - } - - qrc, err := qrcode.New(decodedStr) + qrc, err := qrcode.New(q.Data) if err != nil { return err } diff --git a/backend/app/api/handlers/v1/v1_ctrl_reporting.go b/backend/app/api/handlers/v1/v1_ctrl_reporting.go index 40f0d22..030a1ff 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_reporting.go +++ b/backend/app/api/handlers/v1/v1_ctrl_reporting.go @@ -4,7 +4,7 @@ import ( "net/http" "github.com/hay-kot/homebox/backend/internal/core/services" - "github.com/hay-kot/httpkit/errchain" + "github.com/hay-kot/safeserve/errchain" ) // HandleBillOfMaterialsExport godoc diff --git a/backend/app/api/handlers/v1/v1_ctrl_statistics.go b/backend/app/api/handlers/v1/v1_ctrl_statistics.go index 0a5a319..55a8dcb 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_statistics.go +++ b/backend/app/api/handlers/v1/v1_ctrl_statistics.go @@ -8,11 +8,11 @@ import ( "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/internal/web/adapters" - "github.com/hay-kot/httpkit/errchain" - "github.com/hay-kot/httpkit/server" + "github.com/hay-kot/safeserve/errchain" + "github.com/hay-kot/safeserve/server" ) -// HandleGroupStatisticsLocations godoc +// HandleGroupGet godoc // // @Summary Get Location Statistics // @Tags Statistics diff --git a/backend/app/api/handlers/v1/v1_ctrl_user.go b/backend/app/api/handlers/v1/v1_ctrl_user.go index 8708d24..cc57305 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_user.go +++ b/backend/app/api/handlers/v1/v1_ctrl_user.go @@ -8,8 +8,8 @@ import ( "github.com/hay-kot/homebox/backend/internal/core/services" "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/sys/validate" - "github.com/hay-kot/httpkit/errchain" - "github.com/hay-kot/httpkit/server" + "github.com/hay-kot/safeserve/errchain" + "github.com/hay-kot/safeserve/server" "github.com/rs/zerolog/log" ) diff --git a/backend/app/api/logger.go b/backend/app/api/logger.go index 34659c6..ddc574f 100644 --- a/backend/app/api/logger.go +++ b/backend/app/api/logger.go @@ -2,6 +2,7 @@ package main import ( "os" + "strings" "github.com/hay-kot/homebox/backend/internal/sys/config" "github.com/rs/zerolog" @@ -17,8 +18,24 @@ func (a *app) setupLogger() { log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).With().Caller().Logger() } - level, err := zerolog.ParseLevel(a.conf.Log.Level) - if err == nil { - zerolog.SetGlobalLevel(level) + log.Level(getLevel(a.conf.Log.Level)) +} + +func getLevel(l string) zerolog.Level { + switch strings.ToLower(l) { + case "debug": + return zerolog.DebugLevel + case "info": + return zerolog.InfoLevel + case "warn": + return zerolog.WarnLevel + case "error": + return zerolog.ErrorLevel + case "fatal": + return zerolog.FatalLevel + case "panic": + return zerolog.PanicLevel + default: + return zerolog.InfoLevel } } diff --git a/backend/app/api/main.go b/backend/app/api/main.go index 4811bfa..d966a48 100644 --- a/backend/app/api/main.go +++ b/backend/app/api/main.go @@ -1,7 +1,6 @@ package main import ( - "bytes" "context" "fmt" "net/http" @@ -14,16 +13,15 @@ import ( "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" - "github.com/hay-kot/homebox/backend/internal/core/currencies" + "github.com/hay-kot/homebox/backend/app/api/static/docs" "github.com/hay-kot/homebox/backend/internal/core/services" - "github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus" "github.com/hay-kot/homebox/backend/internal/data/ent" "github.com/hay-kot/homebox/backend/internal/data/migrations" "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/sys/config" "github.com/hay-kot/homebox/backend/internal/web/mid" - "github.com/hay-kot/httpkit/errchain" - "github.com/hay-kot/httpkit/graceful" + "github.com/hay-kot/safeserve/errchain" + "github.com/hay-kot/safeserve/server" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/rs/zerolog/pkgerrors" @@ -37,19 +35,11 @@ var ( buildTime = "now" ) -func build() string { - short := commit - if len(short) > 7 { - short = short[:7] - } - - return fmt.Sprintf("%s, commit %s, built at %s", version, short, buildTime) -} - // @title Homebox API // @version 1.0 // @description Track, Manage, and Organize your Things. // @contact.name Don't +// @license.name MIT // @BasePath /api // @securityDefinitions.apikey Bearer // @in header @@ -58,11 +48,13 @@ func build() string { func main() { zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack - cfg, err := config.New(build(), "Homebox inventory management system") + cfg, err := config.New() if err != nil { panic(err) } + docs.SwaggerInfo.Host = cfg.Swagger.Host + if err := run(cfg); err != nil { panic(err) } @@ -80,12 +72,12 @@ func run(cfg *config.Config) error { log.Fatal().Err(err).Msg("failed to create data directory") } - c, err := ent.Open("sqlite3", cfg.Storage.SqliteURL) + c, err := ent.Open("sqlite3", cfg.Storage.SqliteUrl) if err != nil { log.Fatal(). Err(err). Str("driver", "sqlite"). - Str("url", cfg.Storage.SqliteURL). + Str("url", cfg.Storage.SqliteUrl). Msg("failed opening connection to sqlite") } defer func(c *ent.Client) { @@ -118,7 +110,7 @@ func run(cfg *config.Config) error { log.Fatal(). Err(err). Str("driver", "sqlite"). - Str("url", cfg.Storage.SqliteURL). + Str("url", cfg.Storage.SqliteUrl). Msg("failed creating schema resources") } @@ -128,40 +120,11 @@ func run(cfg *config.Config) error { return err } - collectFuncs := []currencies.CollectorFunc{ - currencies.CollectDefaults(), - } - - if cfg.Options.CurrencyConfig != "" { - log.Info(). - Str("path", cfg.Options.CurrencyConfig). - Msg("loading currency config file") - - content, err := os.ReadFile(cfg.Options.CurrencyConfig) - if err != nil { - log.Fatal(). - Err(err). - Str("path", cfg.Options.CurrencyConfig). - Msg("failed to read currency config file") - } - - collectFuncs = append(collectFuncs, currencies.CollectJSON(bytes.NewReader(content))) - } - - currencies, err := currencies.CollectionCurrencies(collectFuncs...) - if err != nil { - log.Fatal(). - Err(err). - Msg("failed to collect currencies") - } - - app.bus = eventbus.New() app.db = c - app.repos = repo.New(c, app.bus, cfg.Storage.Data) + app.repos = repo.New(c, cfg.Storage.Data) app.services = services.New( app.repos, services.WithAutoIncrementAssetID(cfg.Options.AutoIncrementAssetID), - services.WithCurrencies(currencies), ) // ========================================================================= @@ -178,63 +141,36 @@ func run(cfg *config.Config) error { middleware.StripSlashes, ) - chain := errchain.New(mid.Errors(logger)) + chain := errchain.New(mid.Errors(app.server, logger)) app.mountRoutes(router, chain, app.repos) - runner := graceful.NewRunner() - - runner.AddFunc("server", func(ctx context.Context) error { - httpserver := http.Server{ - Addr: fmt.Sprintf("%s:%s", cfg.Web.Host, cfg.Web.Port), - Handler: router, - ReadTimeout: cfg.Web.ReadTimeout, - WriteTimeout: cfg.Web.WriteTimeout, - IdleTimeout: cfg.Web.IdleTimeout, - } - - go func() { - <-ctx.Done() - _ = httpserver.Shutdown(context.Background()) - }() - - log.Info().Msgf("Server is running on %s:%s", cfg.Web.Host, cfg.Web.Port) - return httpserver.ListenAndServe() - }) + app.server = server.NewServer( + server.WithHost(app.conf.Web.Host), + server.WithPort(app.conf.Web.Port), + ) + log.Info().Msgf("Starting HTTP Server on %s:%s", app.server.Host, app.server.Port) // ========================================================================= // Start Reoccurring Tasks - runner.AddFunc("eventbus", app.bus.Run) - - runner.AddFunc("seed_database", func(ctx context.Context) error { - // TODO: Remove through external API that does setup - if cfg.Demo { - log.Info().Msg("Running in demo mode, creating demo data") - app.SetupDemo() - } - return nil - }) - - runner.AddPlugin(NewTask("purge-tokens", time.Duration(24)*time.Hour, func(ctx context.Context) { - _, err := app.repos.AuthTokens.PurgeExpiredTokens(ctx) + go app.startBgTask(time.Duration(24)*time.Hour, func() { + _, err := app.repos.AuthTokens.PurgeExpiredTokens(context.Background()) if err != nil { log.Error(). Err(err). Msg("failed to purge expired tokens") } - })) - - runner.AddPlugin(NewTask("purge-invitations", time.Duration(24)*time.Hour, func(ctx context.Context) { - _, err := app.repos.Groups.InvitationPurge(ctx) + }) + go app.startBgTask(time.Duration(24)*time.Hour, func() { + _, err := app.repos.Groups.InvitationPurge(context.Background()) if err != nil { log.Error(). Err(err). Msg("failed to purge expired invitations") } - })) - - runner.AddPlugin(NewTask("send-notifications", time.Duration(1)*time.Hour, func(ctx context.Context) { + }) + go app.startBgTask(time.Duration(1)*time.Hour, func() { now := time.Now() if now.Hour() == 8 { @@ -246,27 +182,22 @@ func run(cfg *config.Config) error { Msg("failed to send notifiers") } } - })) + }) - if cfg.Debug.Enabled { - runner.AddFunc("debug", func(ctx context.Context) error { - debugserver := http.Server{ - Addr: fmt.Sprintf("%s:%s", cfg.Web.Host, cfg.Debug.Port), - Handler: app.debugRouter(), - ReadTimeout: cfg.Web.ReadTimeout, - WriteTimeout: cfg.Web.WriteTimeout, - IdleTimeout: cfg.Web.IdleTimeout, - } - - go func() { - <-ctx.Done() - _ = debugserver.Shutdown(context.Background()) - }() - - log.Info().Msgf("Debug server is running on %s:%s", cfg.Web.Host, cfg.Debug.Port) - return debugserver.ListenAndServe() - }) + // TODO: Remove through external API that does setup + if cfg.Demo { + log.Info().Msg("Running in demo mode, creating demo data") + app.SetupDemo() } - return runner.Start(context.Background()) + if cfg.Debug.Enabled { + debugrouter := app.debugRouter() + go func() { + if err := http.ListenAndServe(":"+cfg.Debug.Port, debugrouter); err != nil { + log.Fatal().Err(err).Msg("failed to start debug server") + } + }() + } + + return app.server.Start(router) } diff --git a/backend/app/api/middleware.go b/backend/app/api/middleware.go index 02b3a6c..3617c09 100644 --- a/backend/app/api/middleware.go +++ b/backend/app/api/middleware.go @@ -7,11 +7,9 @@ import ( "net/url" "strings" - v1 "github.com/hay-kot/homebox/backend/app/api/handlers/v1" "github.com/hay-kot/homebox/backend/internal/core/services" - "github.com/hay-kot/homebox/backend/internal/data/ent" "github.com/hay-kot/homebox/backend/internal/sys/validate" - "github.com/hay-kot/httpkit/errchain" + "github.com/hay-kot/safeserve/errchain" ) type tokenHasKey struct { @@ -96,6 +94,20 @@ func getQuery(r *http.Request) (string, error) { return token, nil } +func getCookie(r *http.Request) (string, error) { + cookie, err := r.Cookie("hb.auth.token") + if err != nil { + return "", errors.New("access_token cookie is required") + } + + token, err := url.QueryUnescape(cookie.Value) + if err != nil { + return "", errors.New("access_token cookie is required") + } + + return token, nil +} + // mwAuthToken is a middleware that will check the database for a stateful token // and attach it's user to the request context, or return an appropriate error. // Authorization support is by token via Headers or Query Parameter @@ -103,35 +115,26 @@ func getQuery(r *http.Request) (string, error) { // Example: // - header = "Bearer 1234567890" // - query = "?access_token=1234567890" +// - cookie = hb.auth.token = 1234567890 func (a *app) mwAuthToken(next errchain.Handler) errchain.Handler { return errchain.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error { + keyFuncs := [...]KeyFunc{ + getBearer, + getCookie, + getQuery, + } + var requestToken string - - // We ignore the error to allow the next strategy to be attempted - { - cookies, _ := v1.GetCookies(r) - if cookies != nil { - requestToken = cookies.Token + for _, keyFunc := range keyFuncs { + token, err := keyFunc(r) + if err == nil { + requestToken = token + break } } if requestToken == "" { - keyFuncs := [...]KeyFunc{ - getBearer, - getQuery, - } - - for _, keyFunc := range keyFuncs { - token, err := keyFunc(r) - if err == nil { - requestToken = token - break - } - } - } - - if requestToken == "" { - return validate.NewRequestError(errors.New("authorization header or query is required"), http.StatusUnauthorized) + return validate.NewRequestError(errors.New("Authorization header or query is required"), http.StatusUnauthorized) } requestToken = strings.TrimPrefix(requestToken, "Bearer ") @@ -141,11 +144,7 @@ func (a *app) mwAuthToken(next errchain.Handler) errchain.Handler { usr, err := a.services.User.GetSelf(r.Context(), requestToken) // Check the database for the token if err != nil { - if ent.IsNotFound(err) { - return validate.NewRequestError(errors.New("valid authorization token is required"), http.StatusUnauthorized) - } - - return err + return validate.NewRequestError(errors.New("valid authorization header is required"), http.StatusUnauthorized) } r = r.WithContext(services.SetUserCtx(r.Context(), &usr, requestToken)) diff --git a/backend/app/api/providers/doc.go b/backend/app/api/providers/doc.go deleted file mode 100644 index f58615d..0000000 --- a/backend/app/api/providers/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package providers provides a authentication abstraction for the backend. -package providers diff --git a/backend/app/api/providers/extractors.go b/backend/app/api/providers/extractors.go deleted file mode 100644 index bc042a4..0000000 --- a/backend/app/api/providers/extractors.go +++ /dev/null @@ -1,55 +0,0 @@ -package providers - -import ( - "errors" - "net/http" - - "github.com/hay-kot/homebox/backend/internal/sys/validate" - "github.com/hay-kot/httpkit/server" - "github.com/rs/zerolog/log" -) - -type LoginForm struct { - Username string `json:"username"` - Password string `json:"password"` - StayLoggedIn bool `json:"stayLoggedIn"` -} - -func getLoginForm(r *http.Request) (LoginForm, error) { - loginForm := LoginForm{} - - switch r.Header.Get("Content-Type") { - case "application/x-www-form-urlencoded": - err := r.ParseForm() - if err != nil { - return loginForm, errors.New("failed to parse form") - } - - loginForm.Username = r.PostFormValue("username") - loginForm.Password = r.PostFormValue("password") - loginForm.StayLoggedIn = r.PostFormValue("stayLoggedIn") == "true" - case "application/json": - err := server.Decode(r, &loginForm) - if err != nil { - log.Err(err).Msg("failed to decode login form") - return loginForm, errors.New("failed to decode login form") - } - default: - return loginForm, errors.New("invalid content type") - } - - if loginForm.Username == "" || loginForm.Password == "" { - return loginForm, validate.NewFieldErrors( - validate.FieldError{ - Field: "username", - Error: "username or password is empty", - }, - validate.FieldError{ - Field: "password", - Error: "username or password is empty", - }, - ) - } - - return loginForm, nil -} diff --git a/backend/app/api/providers/local.go b/backend/app/api/providers/local.go deleted file mode 100644 index 991f51a..0000000 --- a/backend/app/api/providers/local.go +++ /dev/null @@ -1,30 +0,0 @@ -package providers - -import ( - "net/http" - - "github.com/hay-kot/homebox/backend/internal/core/services" -) - -type LocalProvider struct { - service *services.UserService -} - -func NewLocalProvider(service *services.UserService) *LocalProvider { - return &LocalProvider{ - service: service, - } -} - -func (p *LocalProvider) Name() string { - return "local" -} - -func (p *LocalProvider) Authenticate(w http.ResponseWriter, r *http.Request) (services.UserAuthTokenDetail, error) { - loginForm, err := getLoginForm(r) - if err != nil { - return services.UserAuthTokenDetail{}, err - } - - return p.service.Login(r.Context(), loginForm.Username, loginForm.Password, loginForm.StayLoggedIn) -} diff --git a/backend/app/api/routes.go b/backend/app/api/routes.go index de10942..e36ee02 100644 --- a/backend/app/api/routes.go +++ b/backend/app/api/routes.go @@ -3,6 +3,7 @@ package main import ( "embed" "errors" + "fmt" "io" "mime" "net/http" @@ -12,12 +13,11 @@ import ( "github.com/go-chi/chi/v5" "github.com/hay-kot/homebox/backend/app/api/handlers/debughandlers" v1 "github.com/hay-kot/homebox/backend/app/api/handlers/v1" - "github.com/hay-kot/homebox/backend/app/api/providers" _ "github.com/hay-kot/homebox/backend/app/api/static/docs" "github.com/hay-kot/homebox/backend/internal/data/ent/authroles" "github.com/hay-kot/homebox/backend/internal/data/repo" - "github.com/hay-kot/httpkit/errchain" - httpSwagger "github.com/swaggo/http-swagger/v2" // http-swagger middleware + "github.com/hay-kot/safeserve/errchain" + httpSwagger "github.com/swaggo/http-swagger" // http-swagger middleware ) const prefix = "/api" @@ -41,18 +41,17 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR registerMimes() r.Get("/swagger/*", httpSwagger.Handler( - httpSwagger.URL("/swagger/doc.json"), + httpSwagger.URL(fmt.Sprintf("%s://%s/swagger/doc.json", a.conf.Swagger.Scheme, a.conf.Swagger.Host)), )) // ========================================================================= // API Version 1 - v1Base := v1.BaseURLFunc(prefix) + v1Base := v1.BaseUrlFunc(prefix) v1Ctrl := v1.NewControllerV1( a.services, a.repos, - a.bus, v1.WithMaxUploadSize(a.conf.Web.MaxUploadSize), v1.WithRegistration(a.conf.Options.AllowRegistration), v1.WithDemoStatus(a.conf.Demo), // Disable Password Change in Demo Mode @@ -64,21 +63,14 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR BuildTime: buildTime, }))) - r.Get(v1Base("/currencies"), chain.ToHandlerFunc(v1Ctrl.HandleCurrency())) - - providers := []v1.AuthProvider{ - providers.NewLocalProvider(a.services.User), - } - r.Post(v1Base("/users/register"), chain.ToHandlerFunc(v1Ctrl.HandleUserRegistration())) - r.Post(v1Base("/users/login"), chain.ToHandlerFunc(v1Ctrl.HandleAuthLogin(providers...))) + r.Post(v1Base("/users/login"), chain.ToHandlerFunc(v1Ctrl.HandleAuthLogin())) userMW := []errchain.Middleware{ a.mwAuthToken, a.mwRoles(RoleModeOr, authroles.RoleUser.String()), } - r.Get(v1Base("/ws/events"), chain.ToHandlerFunc(v1Ctrl.HandleCacheWS(), userMW...)) r.Get(v1Base("/users/self"), chain.ToHandlerFunc(v1Ctrl.HandleUserSelf(), userMW...)) r.Put(v1Base("/users/self"), chain.ToHandlerFunc(v1Ctrl.HandleUserSelfUpdate(), userMW...)) r.Delete(v1Base("/users/self"), chain.ToHandlerFunc(v1Ctrl.HandleUserSelfDelete(), userMW...)) @@ -99,7 +91,6 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR r.Post(v1Base("/actions/ensure-asset-ids"), chain.ToHandlerFunc(v1Ctrl.HandleEnsureAssetID(), userMW...)) r.Post(v1Base("/actions/zero-item-time-fields"), chain.ToHandlerFunc(v1Ctrl.HandleItemDateZeroOut(), userMW...)) r.Post(v1Base("/actions/ensure-import-refs"), chain.ToHandlerFunc(v1Ctrl.HandleEnsureImportRefs(), userMW...)) - r.Post(v1Base("/actions/set-primary-photos"), chain.ToHandlerFunc(v1Ctrl.HandleSetPrimaryPhotos(), userMW...)) r.Get(v1Base("/locations"), chain.ToHandlerFunc(v1Ctrl.HandleLocationGetAll(), userMW...)) r.Post(v1Base("/locations"), chain.ToHandlerFunc(v1Ctrl.HandleLocationCreate(), userMW...)) @@ -122,9 +113,7 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR r.Get(v1Base("/items/fields/values"), chain.ToHandlerFunc(v1Ctrl.HandleGetAllCustomFieldValues(), userMW...)) r.Get(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemGet(), userMW...)) - r.Get(v1Base("/items/{id}/path"), chain.ToHandlerFunc(v1Ctrl.HandleItemFullPath(), userMW...)) r.Put(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemUpdate(), userMW...)) - r.Patch(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemPatch(), userMW...)) r.Delete(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemDelete(), userMW...)) r.Post(v1Base("/items/{id}/attachments"), chain.ToHandlerFunc(v1Ctrl.HandleItemAttachmentCreate(), userMW...)) @@ -136,7 +125,7 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR r.Put(v1Base("/items/{id}/maintenance/{entry_id}"), chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceEntryUpdate(), userMW...)) r.Delete(v1Base("/items/{id}/maintenance/{entry_id}"), chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceEntryDelete(), userMW...)) - r.Get(v1Base("/assets/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleAssetGet(), userMW...)) + r.Get(v1Base("/asset/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleAssetGet(), userMW...)) // Notifiers r.Get(v1Base("/notifiers"), chain.ToHandlerFunc(v1Ctrl.HandleGetUserNotifiers(), userMW...)) @@ -164,6 +153,7 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR r.Get(v1Base("/reporting/bill-of-materials"), chain.ToHandlerFunc(v1Ctrl.HandleBillOfMaterialsExport(), userMW...)) r.NotFound(chain.ToHandlerFunc(notFoundHandler())) + } func registerMimes() { @@ -186,7 +176,7 @@ func notFoundHandler() errchain.HandlerFunc { if err != nil { return err } - defer func() { _ = f.Close() }() + defer f.Close() stat, _ := f.Stat() if stat.IsDir() { diff --git a/backend/app/api/static/docs/docs.go b/backend/app/api/static/docs/docs.go index 7c9a748..b927d87 100644 --- a/backend/app/api/static/docs/docs.go +++ b/backend/app/api/static/docs/docs.go @@ -1,4 +1,5 @@ -// Package docs Code generated by swaggo/swag. DO NOT EDIT +// Package docs GENERATED BY SWAG; DO NOT EDIT +// This file was generated by swaggo/swag package docs import "github.com/swaggo/swag" @@ -12,6 +13,9 @@ const docTemplate = `{ "contact": { "name": "Don't" }, + "license": { + "name": "MIT" + }, "version": "{{.Version}}" }, "host": "{{.Host}}", @@ -67,31 +71,6 @@ const docTemplate = `{ } } }, - "/v1/actions/set-primary-photos": { - "post": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Sets the first photo of each item as the primary photo", - "produces": [ - "application/json" - ], - "tags": [ - "Actions" - ], - "summary": "Set Primary Photos", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/v1.ActionAmountResult" - } - } - } - } - }, "/v1/actions/zero-item-time-fields": { "post": { "security": [ @@ -150,25 +129,6 @@ const docTemplate = `{ } } }, - "/v1/currency": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "Base" - ], - "summary": "Currency", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/currencies.Currency" - } - } - } - } - }, "/v1/groups": { "get": { "security": [ @@ -429,16 +389,6 @@ const docTemplate = `{ "description": "location Ids", "name": "locations", "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "parent Ids", - "name": "parentIds", - "in": "query" } ], "responses": { @@ -688,46 +638,6 @@ const docTemplate = `{ "description": "No Content" } } - }, - "patch": { - "security": [ - { - "Bearer": [] - } - ], - "produces": [ - "application/json" - ], - "tags": [ - "Items" - ], - "summary": "Update Item", - "parameters": [ - { - "type": "string", - "description": "Item ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "Item Data", - "name": "payload", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/repo.ItemPatch" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/repo.ItemOut" - } - } - } } }, "/v1/items/{id}/attachments": { @@ -784,7 +694,7 @@ const docTemplate = `{ "422": { "description": "Unprocessable Entity", "schema": { - "$ref": "#/definitions/validate.ErrorResponse" + "$ref": "#/definitions/mid.ErrorResponse" } } } @@ -1017,42 +927,6 @@ const docTemplate = `{ } } }, - "/v1/items/{id}/path": { - "get": { - "security": [ - { - "Bearer": [] - } - ], - "produces": [ - "application/json" - ], - "tags": [ - "Items" - ], - "summary": "Get the full path of an item", - "parameters": [ - { - "type": "string", - "description": "Item ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/repo.ItemPath" - } - } - } - } - } - }, "/v1/labels": { "get": { "security": [ @@ -1639,7 +1513,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/v1.APISummary" + "$ref": "#/definitions/v1.ApiSummary" } } } @@ -1710,12 +1584,6 @@ const docTemplate = `{ "schema": { "$ref": "#/definitions/v1.LoginForm" } - }, - { - "type": "string", - "description": "auth provider", - "name": "provider", - "in": "query" } ], "responses": { @@ -1894,20 +1762,17 @@ const docTemplate = `{ } }, "definitions": { - "currencies.Currency": { + "mid.ErrorResponse": { "type": "object", "properties": { - "code": { + "error": { "type": "string" }, - "local": { - "type": "string" - }, - "name": { - "type": "string" - }, - "symbol": { - "type": "string" + "fields": { + "type": "object", + "additionalProperties": { + "type": "string" + } } } }, @@ -1991,9 +1856,6 @@ const docTemplate = `{ "id": { "type": "string" }, - "primary": { - "type": "boolean" - }, "type": { "type": "string" }, @@ -2005,9 +1867,6 @@ const docTemplate = `{ "repo.ItemAttachmentUpdate": { "type": "object", "properties": { - "primary": { - "type": "boolean" - }, "title": { "type": "string" }, @@ -2086,6 +1945,12 @@ const docTemplate = `{ "$ref": "#/definitions/repo.ItemAttachment" } }, + "children": { + "type": "array", + "items": { + "$ref": "#/definitions/repo.ItemSummary" + } + }, "createdAt": { "type": "string" }, @@ -2101,9 +1966,6 @@ const docTemplate = `{ "id": { "type": "string" }, - "imageId": { - "type": "string" - }, "insured": { "type": "boolean" }, @@ -2119,13 +1981,9 @@ const docTemplate = `{ }, "location": { "description": "Edges", - "allOf": [ - { - "$ref": "#/definitions/repo.LocationSummary" - } - ], "x-nullable": true, - "x-omitempty": true + "x-omitempty": true, + "$ref": "#/definitions/repo.LocationSummary" }, "manufacturer": { "type": "string" @@ -2141,13 +1999,9 @@ const docTemplate = `{ "type": "string" }, "parent": { - "allOf": [ - { - "$ref": "#/definitions/repo.ItemSummary" - } - ], "x-nullable": true, - "x-omitempty": true + "x-omitempty": true, + "$ref": "#/definitions/repo.ItemSummary" }, "purchaseFrom": { "type": "string" @@ -2191,33 +2045,6 @@ const docTemplate = `{ } } }, - "repo.ItemPatch": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "quantity": { - "type": "integer", - "x-nullable": true, - "x-omitempty": true - } - } - }, - "repo.ItemPath": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "type": { - "$ref": "#/definitions/repo.ItemType" - } - } - }, "repo.ItemSummary": { "type": "object", "properties": { @@ -2233,9 +2060,6 @@ const docTemplate = `{ "id": { "type": "string" }, - "imageId": { - "type": "string" - }, "insured": { "type": "boolean" }, @@ -2247,13 +2071,9 @@ const docTemplate = `{ }, "location": { "description": "Edges", - "allOf": [ - { - "$ref": "#/definitions/repo.LocationSummary" - } - ], "x-nullable": true, - "x-omitempty": true + "x-omitempty": true, + "$ref": "#/definitions/repo.LocationSummary" }, "name": { "type": "string" @@ -2270,17 +2090,6 @@ const docTemplate = `{ } } }, - "repo.ItemType": { - "type": "string", - "enum": [ - "location", - "item" - ], - "x-enum-varnames": [ - "ItemTypeLocation", - "ItemTypeItem" - ] - }, "repo.ItemUpdate": { "type": "object", "properties": { @@ -2373,6 +2182,7 @@ const docTemplate = `{ "type": "string" }, "warrantyExpires": { + "description": "Sold", "type": "string" } } @@ -2409,6 +2219,12 @@ const docTemplate = `{ "id": { "type": "string" }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/repo.ItemSummary" + } + }, "name": { "type": "string" }, @@ -2470,6 +2286,12 @@ const docTemplate = `{ "id": { "type": "string" }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/repo.ItemSummary" + } + }, "name": { "type": "string" }, @@ -2546,6 +2368,7 @@ const docTemplate = `{ "type": "object", "properties": { "completedDate": { + "description": "Sold", "type": "string" }, "cost": { @@ -2562,6 +2385,7 @@ const docTemplate = `{ "type": "string" }, "scheduledDate": { + "description": "Sold", "type": "string" } } @@ -2573,6 +2397,7 @@ const docTemplate = `{ ], "properties": { "completedDate": { + "description": "Sold", "type": "string" }, "cost": { @@ -2586,6 +2411,7 @@ const docTemplate = `{ "type": "string" }, "scheduledDate": { + "description": "Sold", "type": "string" } } @@ -2594,6 +2420,7 @@ const docTemplate = `{ "type": "object", "properties": { "completedDate": { + "description": "Sold", "type": "string" }, "cost": { @@ -2607,6 +2434,7 @@ const docTemplate = `{ "type": "string" }, "scheduledDate": { + "description": "Sold", "type": "string" } } @@ -2842,7 +2670,15 @@ const docTemplate = `{ } } }, - "v1.APISummary": { + "v1.ActionAmountResult": { + "type": "object", + "properties": { + "completed": { + "type": "integer" + } + } + }, + "v1.ApiSummary": { "type": "object", "properties": { "allowRegistration": { @@ -2871,14 +2707,6 @@ const docTemplate = `{ } } }, - "v1.ActionAmountResult": { - "type": "object", - "properties": { - "completed": { - "type": "integer" - } - } - }, "v1.Build": { "type": "object", "properties": { @@ -2975,17 +2803,6 @@ const docTemplate = `{ "properties": { "item": {} } - }, - "validate.ErrorResponse": { - "type": "object", - "properties": { - "error": { - "type": "string" - }, - "fields": { - "type": "string" - } - } } }, "securityDefinitions": { @@ -3008,8 +2825,6 @@ var SwaggerInfo = &swag.Spec{ Description: "Track, Manage, and Organize your Things.", InfoInstanceName: "swagger", SwaggerTemplate: docTemplate, - LeftDelim: "{{", - RightDelim: "}}", } func init() { diff --git a/backend/app/api/static/docs/swagger.json b/backend/app/api/static/docs/swagger.json index b10c93a..d5e71d2 100644 --- a/backend/app/api/static/docs/swagger.json +++ b/backend/app/api/static/docs/swagger.json @@ -6,6 +6,9 @@ "contact": { "name": "Don't" }, + "license": { + "name": "MIT" + }, "version": "1.0" }, "basePath": "/api", @@ -60,31 +63,6 @@ } } }, - "/v1/actions/set-primary-photos": { - "post": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Sets the first photo of each item as the primary photo", - "produces": [ - "application/json" - ], - "tags": [ - "Actions" - ], - "summary": "Set Primary Photos", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/v1.ActionAmountResult" - } - } - } - } - }, "/v1/actions/zero-item-time-fields": { "post": { "security": [ @@ -143,25 +121,6 @@ } } }, - "/v1/currency": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "Base" - ], - "summary": "Currency", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/currencies.Currency" - } - } - } - } - }, "/v1/groups": { "get": { "security": [ @@ -422,16 +381,6 @@ "description": "location Ids", "name": "locations", "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "parent Ids", - "name": "parentIds", - "in": "query" } ], "responses": { @@ -681,46 +630,6 @@ "description": "No Content" } } - }, - "patch": { - "security": [ - { - "Bearer": [] - } - ], - "produces": [ - "application/json" - ], - "tags": [ - "Items" - ], - "summary": "Update Item", - "parameters": [ - { - "type": "string", - "description": "Item ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "Item Data", - "name": "payload", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/repo.ItemPatch" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/repo.ItemOut" - } - } - } } }, "/v1/items/{id}/attachments": { @@ -777,7 +686,7 @@ "422": { "description": "Unprocessable Entity", "schema": { - "$ref": "#/definitions/validate.ErrorResponse" + "$ref": "#/definitions/mid.ErrorResponse" } } } @@ -1010,42 +919,6 @@ } } }, - "/v1/items/{id}/path": { - "get": { - "security": [ - { - "Bearer": [] - } - ], - "produces": [ - "application/json" - ], - "tags": [ - "Items" - ], - "summary": "Get the full path of an item", - "parameters": [ - { - "type": "string", - "description": "Item ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/repo.ItemPath" - } - } - } - } - } - }, "/v1/labels": { "get": { "security": [ @@ -1632,7 +1505,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/v1.APISummary" + "$ref": "#/definitions/v1.ApiSummary" } } } @@ -1703,12 +1576,6 @@ "schema": { "$ref": "#/definitions/v1.LoginForm" } - }, - { - "type": "string", - "description": "auth provider", - "name": "provider", - "in": "query" } ], "responses": { @@ -1887,20 +1754,17 @@ } }, "definitions": { - "currencies.Currency": { + "mid.ErrorResponse": { "type": "object", "properties": { - "code": { + "error": { "type": "string" }, - "local": { - "type": "string" - }, - "name": { - "type": "string" - }, - "symbol": { - "type": "string" + "fields": { + "type": "object", + "additionalProperties": { + "type": "string" + } } } }, @@ -1984,9 +1848,6 @@ "id": { "type": "string" }, - "primary": { - "type": "boolean" - }, "type": { "type": "string" }, @@ -1998,9 +1859,6 @@ "repo.ItemAttachmentUpdate": { "type": "object", "properties": { - "primary": { - "type": "boolean" - }, "title": { "type": "string" }, @@ -2079,6 +1937,12 @@ "$ref": "#/definitions/repo.ItemAttachment" } }, + "children": { + "type": "array", + "items": { + "$ref": "#/definitions/repo.ItemSummary" + } + }, "createdAt": { "type": "string" }, @@ -2094,9 +1958,6 @@ "id": { "type": "string" }, - "imageId": { - "type": "string" - }, "insured": { "type": "boolean" }, @@ -2112,13 +1973,9 @@ }, "location": { "description": "Edges", - "allOf": [ - { - "$ref": "#/definitions/repo.LocationSummary" - } - ], "x-nullable": true, - "x-omitempty": true + "x-omitempty": true, + "$ref": "#/definitions/repo.LocationSummary" }, "manufacturer": { "type": "string" @@ -2134,13 +1991,9 @@ "type": "string" }, "parent": { - "allOf": [ - { - "$ref": "#/definitions/repo.ItemSummary" - } - ], "x-nullable": true, - "x-omitempty": true + "x-omitempty": true, + "$ref": "#/definitions/repo.ItemSummary" }, "purchaseFrom": { "type": "string" @@ -2184,33 +2037,6 @@ } } }, - "repo.ItemPatch": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "quantity": { - "type": "integer", - "x-nullable": true, - "x-omitempty": true - } - } - }, - "repo.ItemPath": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "type": { - "$ref": "#/definitions/repo.ItemType" - } - } - }, "repo.ItemSummary": { "type": "object", "properties": { @@ -2226,9 +2052,6 @@ "id": { "type": "string" }, - "imageId": { - "type": "string" - }, "insured": { "type": "boolean" }, @@ -2240,13 +2063,9 @@ }, "location": { "description": "Edges", - "allOf": [ - { - "$ref": "#/definitions/repo.LocationSummary" - } - ], "x-nullable": true, - "x-omitempty": true + "x-omitempty": true, + "$ref": "#/definitions/repo.LocationSummary" }, "name": { "type": "string" @@ -2263,17 +2082,6 @@ } } }, - "repo.ItemType": { - "type": "string", - "enum": [ - "location", - "item" - ], - "x-enum-varnames": [ - "ItemTypeLocation", - "ItemTypeItem" - ] - }, "repo.ItemUpdate": { "type": "object", "properties": { @@ -2366,6 +2174,7 @@ "type": "string" }, "warrantyExpires": { + "description": "Sold", "type": "string" } } @@ -2402,6 +2211,12 @@ "id": { "type": "string" }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/repo.ItemSummary" + } + }, "name": { "type": "string" }, @@ -2463,6 +2278,12 @@ "id": { "type": "string" }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/repo.ItemSummary" + } + }, "name": { "type": "string" }, @@ -2539,6 +2360,7 @@ "type": "object", "properties": { "completedDate": { + "description": "Sold", "type": "string" }, "cost": { @@ -2555,6 +2377,7 @@ "type": "string" }, "scheduledDate": { + "description": "Sold", "type": "string" } } @@ -2566,6 +2389,7 @@ ], "properties": { "completedDate": { + "description": "Sold", "type": "string" }, "cost": { @@ -2579,6 +2403,7 @@ "type": "string" }, "scheduledDate": { + "description": "Sold", "type": "string" } } @@ -2587,6 +2412,7 @@ "type": "object", "properties": { "completedDate": { + "description": "Sold", "type": "string" }, "cost": { @@ -2600,6 +2426,7 @@ "type": "string" }, "scheduledDate": { + "description": "Sold", "type": "string" } } @@ -2835,7 +2662,15 @@ } } }, - "v1.APISummary": { + "v1.ActionAmountResult": { + "type": "object", + "properties": { + "completed": { + "type": "integer" + } + } + }, + "v1.ApiSummary": { "type": "object", "properties": { "allowRegistration": { @@ -2864,14 +2699,6 @@ } } }, - "v1.ActionAmountResult": { - "type": "object", - "properties": { - "completed": { - "type": "integer" - } - } - }, "v1.Build": { "type": "object", "properties": { @@ -2968,17 +2795,6 @@ "properties": { "item": {} } - }, - "validate.ErrorResponse": { - "type": "object", - "properties": { - "error": { - "type": "string" - }, - "fields": { - "type": "string" - } - } } }, "securityDefinitions": { diff --git a/backend/app/api/static/docs/swagger.yaml b/backend/app/api/static/docs/swagger.yaml index dbb31e6..ccdb538 100644 --- a/backend/app/api/static/docs/swagger.yaml +++ b/backend/app/api/static/docs/swagger.yaml @@ -1,15 +1,13 @@ basePath: /api definitions: - currencies.Currency: + mid.ErrorResponse: properties: - code: - type: string - local: - type: string - name: - type: string - symbol: + error: type: string + fields: + additionalProperties: + type: string + type: object type: object repo.DocumentOut: properties: @@ -63,8 +61,6 @@ definitions: $ref: '#/definitions/repo.DocumentOut' id: type: string - primary: - type: boolean type: type: string updatedAt: @@ -72,8 +68,6 @@ definitions: type: object repo.ItemAttachmentUpdate: properties: - primary: - type: boolean title: type: string type: @@ -127,6 +121,10 @@ definitions: items: $ref: '#/definitions/repo.ItemAttachment' type: array + children: + items: + $ref: '#/definitions/repo.ItemSummary' + type: array createdAt: type: string description: @@ -137,8 +135,6 @@ definitions: type: array id: type: string - imageId: - type: string insured: type: boolean labels: @@ -149,8 +145,7 @@ definitions: description: Warranty type: boolean location: - allOf: - - $ref: '#/definitions/repo.LocationSummary' + $ref: '#/definitions/repo.LocationSummary' description: Edges x-nullable: true x-omitempty: true @@ -164,8 +159,7 @@ definitions: description: Extras type: string parent: - allOf: - - $ref: '#/definitions/repo.ItemSummary' + $ref: '#/definitions/repo.ItemSummary' x-nullable: true x-omitempty: true purchaseFrom: @@ -197,24 +191,6 @@ definitions: warrantyExpires: type: string type: object - repo.ItemPatch: - properties: - id: - type: string - quantity: - type: integer - x-nullable: true - x-omitempty: true - type: object - repo.ItemPath: - properties: - id: - type: string - name: - type: string - type: - $ref: '#/definitions/repo.ItemType' - type: object repo.ItemSummary: properties: archived: @@ -225,8 +201,6 @@ definitions: type: string id: type: string - imageId: - type: string insured: type: boolean labels: @@ -234,8 +208,7 @@ definitions: $ref: '#/definitions/repo.LabelSummary' type: array location: - allOf: - - $ref: '#/definitions/repo.LocationSummary' + $ref: '#/definitions/repo.LocationSummary' description: Edges x-nullable: true x-omitempty: true @@ -249,14 +222,6 @@ definitions: updatedAt: type: string type: object - repo.ItemType: - enum: - - location - - item - type: string - x-enum-varnames: - - ItemTypeLocation - - ItemTypeItem repo.ItemUpdate: properties: archived: @@ -322,6 +287,7 @@ definitions: warrantyDetails: type: string warrantyExpires: + description: Sold type: string type: object repo.LabelCreate: @@ -346,6 +312,10 @@ definitions: type: string id: type: string + items: + items: + $ref: '#/definitions/repo.ItemSummary' + type: array name: type: string updatedAt: @@ -386,6 +356,10 @@ definitions: type: string id: type: string + items: + items: + $ref: '#/definitions/repo.ItemSummary' + type: array name: type: string parent: @@ -436,6 +410,7 @@ definitions: repo.MaintenanceEntry: properties: completedDate: + description: Sold type: string cost: example: "0" @@ -447,11 +422,13 @@ definitions: name: type: string scheduledDate: + description: Sold type: string type: object repo.MaintenanceEntryCreate: properties: completedDate: + description: Sold type: string cost: example: "0" @@ -461,6 +438,7 @@ definitions: name: type: string scheduledDate: + description: Sold type: string required: - name @@ -468,6 +446,7 @@ definitions: repo.MaintenanceEntryUpdate: properties: completedDate: + description: Sold type: string cost: example: "0" @@ -477,6 +456,7 @@ definitions: name: type: string scheduledDate: + description: Sold type: string type: object repo.MaintenanceLog: @@ -631,7 +611,12 @@ definitions: token: type: string type: object - v1.APISummary: + v1.ActionAmountResult: + properties: + completed: + type: integer + type: object + v1.ApiSummary: properties: allowRegistration: type: boolean @@ -650,11 +635,6 @@ definitions: type: string type: array type: object - v1.ActionAmountResult: - properties: - completed: - type: integer - type: object v1.Build: properties: buildTime: @@ -718,17 +698,12 @@ definitions: properties: item: {} type: object - validate.ErrorResponse: - properties: - error: - type: string - fields: - type: string - type: object info: contact: name: Don't description: Track, Manage, and Organize your Things. + license: + name: MIT title: Homebox API version: "1.0" paths: @@ -762,21 +737,6 @@ paths: summary: Ensures Import Refs tags: - Actions - /v1/actions/set-primary-photos: - post: - description: Sets the first photo of each item as the primary photo - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/v1.ActionAmountResult' - security: - - Bearer: [] - summary: Set Primary Photos - tags: - - Actions /v1/actions/zero-item-time-fields: post: description: Resets all item date fields to the beginning of the day @@ -812,18 +772,6 @@ paths: summary: Get Item by Asset ID tags: - Items - /v1/currency: - get: - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/currencies.Currency' - summary: Currency - tags: - - Base /v1/groups: get: produces: @@ -977,13 +925,6 @@ paths: type: string name: locations type: array - - collectionFormat: multi - description: parent Ids - in: query - items: - type: string - name: parentIds - type: array produces: - application/json responses: @@ -1053,31 +994,6 @@ paths: summary: Get Item tags: - Items - patch: - parameters: - - description: Item ID - in: path - name: id - required: true - type: string - - description: Item Data - in: body - name: payload - required: true - schema: - $ref: '#/definitions/repo.ItemPatch' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/repo.ItemOut' - security: - - Bearer: [] - summary: Update Item - tags: - - Items put: parameters: - description: Item ID @@ -1136,7 +1052,7 @@ paths: "422": description: Unprocessable Entity schema: - $ref: '#/definitions/validate.ErrorResponse' + $ref: '#/definitions/mid.ErrorResponse' security: - Bearer: [] summary: Create Item Attachment @@ -1281,28 +1197,6 @@ paths: summary: Update Maintenance Entry tags: - Maintenance - /v1/items/{id}/path: - get: - parameters: - - description: Item ID - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/repo.ItemPath' - type: array - security: - - Bearer: [] - summary: Get the full path of an item - tags: - - Items /v1/items/export: get: responses: @@ -1720,7 +1614,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/v1.APISummary' + $ref: '#/definitions/v1.ApiSummary' summary: Application Info tags: - Base @@ -1763,10 +1657,6 @@ paths: required: true schema: $ref: '#/definitions/v1.LoginForm' - - description: auth provider - in: query - name: provider - type: string produces: - application/json responses: diff --git a/backend/app/tools/typegen/main.go b/backend/app/tools/typegen/main.go index 5f4d8da..bc04cc9 100644 --- a/backend/app/tools/typegen/main.go +++ b/backend/app/tools/typegen/main.go @@ -54,7 +54,6 @@ func main() { NewReReplace(` Services`, " "), NewReReplace(` V1`, " "), NewReReplace(`\?:`, ":"), - NewReReplace(`(\w+):\s(.*null.*)`, "$1?: $2"), // make null union types optional NewReDate("createdAt"), NewReDate("updatedAt"), NewReDate("soldTime"), diff --git a/backend/go.mod b/backend/go.mod index d29a620..bae9413 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -1,77 +1,74 @@ module github.com/hay-kot/homebox/backend -go 1.23.0 - -toolchain go1.24.2 +go 1.20 require ( - ariga.io/atlas v0.32.0 - entgo.io/ent v0.14.4 - github.com/ardanlabs/conf/v3 v3.7.1 - github.com/containrrr/shoutrrr v0.8.0 - github.com/go-chi/chi/v5 v5.2.1 - github.com/go-playground/validator/v10 v10.26.0 - github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 - github.com/google/uuid v1.6.0 - github.com/gorilla/schema v1.4.1 - github.com/hay-kot/httpkit v0.0.11 - github.com/mattn/go-sqlite3 v1.14.27 - github.com/olahol/melody v1.2.1 + ariga.io/atlas v0.10.0 + entgo.io/ent v0.11.10 + github.com/ardanlabs/conf/v3 v3.1.5 + github.com/containrrr/shoutrrr v0.7.1 + github.com/go-chi/chi/v5 v5.0.8 + github.com/go-playground/validator/v10 v10.12.0 + github.com/gocarina/gocsv v0.0.0-20230226133904-70c27cb2918a + github.com/google/uuid v1.3.0 + github.com/gorilla/schema v1.2.0 + github.com/hay-kot/safeserve v0.0.1 + github.com/mattn/go-sqlite3 v1.14.16 github.com/pkg/errors v0.9.1 - github.com/rs/zerolog v1.34.0 - github.com/stretchr/testify v1.10.0 - github.com/swaggo/http-swagger/v2 v2.0.2 - github.com/swaggo/swag v1.16.4 - github.com/yeqown/go-qrcode/v2 v2.2.5 - github.com/yeqown/go-qrcode/writer/standard v1.2.5 - golang.org/x/crypto v0.37.0 - modernc.org/sqlite v1.37.0 + github.com/rs/zerolog v1.29.0 + github.com/stretchr/testify v1.8.2 + github.com/swaggo/http-swagger v1.3.4 + github.com/swaggo/swag v1.8.11 + github.com/yeqown/go-qrcode/v2 v2.2.1 + github.com/yeqown/go-qrcode/writer/standard v1.2.1 + golang.org/x/crypto v0.7.0 + modernc.org/sqlite v1.21.0 ) require ( github.com/KyleBanks/depth v1.2.1 // indirect github.com/agext/levenshtein v1.2.3 // indirect - github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect - github.com/bmatcuk/doublestar v1.3.4 // indirect + github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect - github.com/fatih/color v1.18.0 // indirect + github.com/dustin/go-humanize v1.0.0 // indirect + github.com/fatih/color v1.13.0 // indirect github.com/fogleman/gg v1.3.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.8 // indirect - github.com/go-openapi/inflect v0.21.2 // indirect - github.com/go-openapi/jsonpointer v0.21.1 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.1 // indirect + github.com/go-openapi/inflect v0.19.0 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/spec v0.20.7 // indirect + github.com/go-openapi/swag v0.22.3 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect - github.com/google/go-cmp v0.7.0 // indirect - github.com/gorilla/websocket v1.5.3 // indirect - github.com/hashicorp/hcl/v2 v2.23.0 // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/hashicorp/hcl/v2 v2.15.0 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/leodido/go-urn v1.4.0 // indirect - github.com/mailru/easyjson v0.9.0 // indirect - github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect + github.com/leodido/go-urn v1.2.2 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect - github.com/ncruces/go-strftime v0.1.9 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - github.com/swaggo/files/v2 v2.0.2 // indirect + github.com/swaggo/files v1.0.0 // indirect github.com/yeqown/reedsolomon v1.0.0 // indirect - github.com/zclconf/go-cty v1.16.2 // indirect - github.com/zclconf/go-cty-yaml v1.1.0 // indirect - golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect - golang.org/x/image v0.26.0 // indirect - golang.org/x/mod v0.24.0 // indirect - golang.org/x/net v0.39.0 // indirect - golang.org/x/sync v0.13.0 // indirect - golang.org/x/sys v0.32.0 // indirect - golang.org/x/text v0.24.0 // indirect - golang.org/x/tools v0.32.0 // indirect + github.com/zclconf/go-cty v1.12.1 // indirect + golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 // indirect + golang.org/x/mod v0.8.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + golang.org/x/tools v0.6.1-0.20230222164832-25d2519c8696 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - modernc.org/libc v1.62.1 // indirect - modernc.org/mathutil v1.7.1 // indirect - modernc.org/memory v1.9.1 // indirect + lukechampine.com/uint128 v1.2.0 // indirect + modernc.org/cc/v3 v3.40.0 // indirect + modernc.org/ccgo/v3 v3.16.13 // indirect + modernc.org/libc v1.22.3 // indirect + modernc.org/mathutil v1.5.0 // indirect + modernc.org/memory v1.5.0 // indirect + modernc.org/opt v0.1.3 // indirect + modernc.org/strutil v1.1.3 // indirect + modernc.org/token v1.0.1 // indirect ) diff --git a/backend/go.sum b/backend/go.sum index 6e0ebbf..5544f85 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -1,190 +1,1281 @@ -ariga.io/atlas v0.32.0 h1:y+77nueMrExLiKlz1CcPKh/nU7VSlWfBbwCShsJyvCw= -ariga.io/atlas v0.32.0/go.mod h1:Oe1xWPuu5q9LzyrWfbZmEZxFYeu4BHTyzfjeW2aZp/w= -entgo.io/ent v0.14.4 h1:/DhDraSLXIkBhyiVoJeSshr4ZYi7femzhj6/TckzZuI= -entgo.io/ent v0.14.4/go.mod h1:aDPE/OziPEu8+OWbzy4UlvWmD2/kbRuWfK2A40hcxJM= +ariga.io/atlas v0.10.0 h1:B1aCP6gSDQET6j8ybn7m6MArjQuoLH5d4DQBT+NP5k8= +ariga.io/atlas v0.10.0/go.mod h1:+TR129FJZ5Lvzms6dvCeGWh1yR6hMvmXBhug4hrNIGk= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= +cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/firestore v1.8.0/go.mod h1:r3KB8cAdRIe8znzoPWLw8S6gpDVd9treohhn8b09424= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +entgo.io/ent v0.11.10 h1:iqn32ybY5HRW3xSAyMNdNKpZhKgMf1Zunsej9yPKUI8= +entgo.io/ent v0.11.10/go.mod h1:mzTZ0trE+jCQw/fnzijbm5Mck/l8Gbg7gC/+L1COyzM= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= -github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= -github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= -github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= -github.com/ardanlabs/conf/v3 v3.7.1 h1:GIV7ylesF/0NexhnJdLmzsi2NIVYY2wVhR0UfvpmAeQ= -github.com/ardanlabs/conf/v3 v3.7.1/go.mod h1:IIucqD+601gt3jfhMXVukxoT16LnoGVd2DzRC2GhHiA= -github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0= -github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE= -github.com/containrrr/shoutrrr v0.8.0 h1:mfG2ATzIS7NR2Ec6XL+xyoHzN97H8WPjir8aYzJUSec= -github.com/containrrr/shoutrrr v0.8.0/go.mod h1:ioyQAyu1LJY6sILuNyKaQaw+9Ttik5QePU8atnAdO2o= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= +github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= +github.com/ardanlabs/conf/v3 v3.1.5 h1:G6df2AxKnGHAK+ur2p50Ys8Vo1HnKcsvqSj9lxVeczk= +github.com/ardanlabs/conf/v3 v3.1.5/go.mod h1:zclexWKe0NVj6LHQ8NgDDZ7bQ1spE0KeKPFficdtAjU= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containrrr/shoutrrr v0.7.1 h1:19j+YbYXRgj3PJHMzqdQ4dEoQ6teapGdjx0aB8asyho= +github.com/containrrr/shoutrrr v0.7.1/go.mod h1:wz7j7NfcSA+HUlOIj4sDKYXYpgKopfgxcCYGuto8J3s= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +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/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= -github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= -github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= -github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8= -github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= +github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-openapi/inflect v0.21.2 h1:0gClGlGcxifcJR56zwvhaOulnNgnhc4qTAkob5ObnSM= -github.com/go-openapi/inflect v0.21.2/go.mod h1:INezMuUu7SJQc2AyR3WO0DqqYUJSj8Kb4hBd7WtjlAw= -github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic= -github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= +github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4= +github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/spec v0.20.7 h1:1Rlu/ZrOCCob0n+JKKJAWhNWMPW8bOZRg8FJaY+0SKI= +github.com/go-openapi/spec v0.20.7/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= -github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= -github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-playground/validator/v10 v10.12.0 h1:E4gtWgxWxp8YSxExrQFv5BpCahla0PVF2oTTEYaWQGI= +github.com/go-playground/validator/v10 v10.12.0/go.mod h1:hCAPuzYvKdP33pxWa+2+6AIKXEKqjIUyqsNCtbsSJrA= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= -github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 h1:FWNFq4fM1wPfcK40yHE5UO3RUdSNPaBC+j3PokzA6OQ= -github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI= +github.com/gocarina/gocsv v0.0.0-20230226133904-70c27cb2918a h1:/5o1ejt5M0fNAN2lU1NBLtPzUSZru689EWJq01ptr+E= +github.com/gocarina/gocsv v0.0.0-20230226133904-70c27cb2918a/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= -github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= -github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E= -github.com/gorilla/schema v1.4.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM= -github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= -github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos= -github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA= -github.com/hay-kot/httpkit v0.0.11 h1:ZdB2uqsFBSDpfUoClGK5c5orjBjQkEVSXh7fZX5FKEk= -github.com/hay-kot/httpkit v0.0.11/go.mod h1:0kZdk5/swzdfqfg2c6pBWimcgeJ9PTyO97EbHnYl2Sw= -github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc= -github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= +github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/consul/api v1.15.3/go.mod h1:/g/qgcoBcEXALCNZgRRisyTW0nY86++L0KbeAMXYCeY= +github.com/hashicorp/consul/sdk v0.11.0/go.mod h1:yPkX5Q6CsxTFMjQQDJwzeNmUUF5NUGGbrDsv9wTb8cw= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/hcl/v2 v2.15.0 h1:CPDXO6+uORPjKflkWCCwoWc9uRp+zSIPcCQ+BrxV7m8= +github.com/hashicorp/hcl/v2 v2.15.0/go.mod h1:JRmR89jycNkrrqnMmvPDMd56n1rQJ2Q6KocSLCMCXng= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.3.1/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hashicorp/serf v0.9.8/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hay-kot/safeserve v0.0.1 h1:9u8Ooyk8NNkqgxrqkLMWtMqauWEl/VZVtEUTLbHuAU8= +github.com/hay-kot/safeserve v0.0.1/go.mod h1:RUvwyfQTmbNgm5sHt+tQOqtdcpWadXWMhLty74Vedzw= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jarcoal/httpmock v1.2.0 h1:gSvTxxFR/MEMfsGrvRbdfpRUMBStovlSRLw0Ep1bwwc= +github.com/jarcoal/httpmock v1.2.0/go.mod h1:oCoTsnAz4+UoOUIf5lJOWV2QQIW5UoeUI6aM2YnWAZk= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/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.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +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.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= -github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= -github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4= +github.com/leodido/go-urn v1.2.2 h1:7z68G0FCGvDk646jz1AelTYNYWrTNm0bEcFAo147wt4= +github.com/leodido/go-urn v1.2.2/go.mod h1:kUaIbLZWttglzwNuG0pgsh5vuV6u2YcGBYz1hIPjtOQ= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= -github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.27 h1:drZCnuvf37yPfs95E5jd9s3XhdVWLal+6BOK6qrv6IU= -github.com/mattn/go-sqlite3 v1.14.27/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/maxatome/go-testdeep v1.11.0/go.mod h1:011SgQ6efzZYAen6fDn4BqQ+lUR72ysdyKe7Dyogw70= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= -github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= -github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= -github.com/olahol/melody v1.2.1 h1:xdwRkzHxf+B0w4TKbGpUSSkV516ZucQZJIWLztOWICQ= -github.com/olahol/melody v1.2.1/go.mod h1:GgkTl6Y7yWj/HtfD48Q5vLKPVoZOH+Qqgfa7CvJgJM4= -github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= -github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= -github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= +github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= +github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0= +github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs= +github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= +github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc= +github.com/onsi/gomega v1.22.1 h1:pY8O4lBfsHKZHM/6nrxkhVPUznOlIu3quZcKP/M20KI= +github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= 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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= -github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= -github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/swaggo/files/v2 v2.0.2 h1:Bq4tgS/yxLB/3nwOMcul5oLEUKa877Ykgz3CJMVbQKU= -github.com/swaggo/files/v2 v2.0.2/go.mod h1:TVqetIzZsO9OhHX1Am9sRf9LdrFZqoK49N37KON/jr0= -github.com/swaggo/http-swagger/v2 v2.0.2 h1:FKCdLsl+sFCx60KFsyM0rDarwiUSZ8DqbfSyIKC9OBg= -github.com/swaggo/http-swagger/v2 v2.0.2/go.mod h1:r7/GBkAWIfK6E/OLnE8fXnviHiDeAHmgIyooa4xm3AQ= -github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A= -github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg= -github.com/yeqown/go-qrcode/v2 v2.2.5 h1:HCOe2bSjkhZyYoyyNaXNzh4DJZll6inVJQQw+8228Zk= -github.com/yeqown/go-qrcode/v2 v2.2.5/go.mod h1:uHpt9CM0V1HeXLz+Wg5MN50/sI/fQhfkZlOM+cOTHxw= -github.com/yeqown/go-qrcode/writer/standard v1.2.5 h1:m+5BUIcbsaG2md76FIqI/oZULrAju8tsk47eOohovQ0= -github.com/yeqown/go-qrcode/writer/standard v1.2.5/go.mod h1:O4MbzsotGCvy8upYPCR91j81dr5XLT7heuljcNXW+oQ= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w= +github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/rwtodd/Go.Sed v0.0.0-20210816025313-55464686f9ef/go.mod h1:8AEUvGVi2uQ5b24BIhcr0GCcpd/RNAFWaN2CJFrWIIQ= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.8.0/go.mod h1:TmKwZAo97S4Fy4sfMH/HX/cQP5D+ijra2NyLpNNmttY= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= +github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/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.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/swaggo/files v1.0.0 h1:1gGXVIeUFCS/dta17rnP0iOpr6CXFwKD7EO5ID233e4= +github.com/swaggo/files v1.0.0/go.mod h1:N59U6URJLyU1PQgFqPM7wXLMhJx7QAolnvfQkqO13kc= +github.com/swaggo/http-swagger v1.3.4 h1:q7t/XLx0n15H1Q9/tk3Y9L4n210XzJF5WtnDX64a5ww= +github.com/swaggo/http-swagger v1.3.4/go.mod h1:9dAh0unqMBAlbp1uE2Uc2mQTxNMU/ha4UbucIg1MFkQ= +github.com/swaggo/swag v1.8.11 h1:Fp1dNNtDvbCf+8kvehZbHQnlF6AxHGjmw6H/xAMrZfY= +github.com/swaggo/swag v1.8.11/go.mod h1:2GXgpNI9iy5OdsYWu8zXfRAGnOAPxYxTWTyM0XOTYZQ= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/yeqown/go-qrcode/v2 v2.2.1 h1:Jc1Q916fwC05R8C7mpWDbrT9tyLPaLLKDABoC5XBCe8= +github.com/yeqown/go-qrcode/v2 v2.2.1/go.mod h1:2Qsk2APUCPne0TsRo40DIkI5MYnbzYKCnKGEFWrxd24= +github.com/yeqown/go-qrcode/writer/standard v1.2.1 h1:FMRZiur5yApUIe4fqtqmcdl/XQTZAZWt2DhkPx4VIW0= +github.com/yeqown/go-qrcode/writer/standard v1.2.1/go.mod h1:ZelyDFiVymrauRjUn454iF7bjsabmB1vixkDA5kq2bw= github.com/yeqown/reedsolomon v1.0.0 h1:x1h/Ej/uJnNu8jaX7GLHBWmZKCAWjEJTetkqaabr4B0= github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw/Iy6g1WiiM= -github.com/zclconf/go-cty v1.16.2 h1:LAJSwc3v81IRBZyUVQDUdZ7hs3SYs9jv0eZJDWHD/70= -github.com/zclconf/go-cty v1.16.2/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= -github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= -github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM= -github.com/zclconf/go-cty-yaml v1.1.0 h1:nP+jp0qPHv2IhUVqmQSzjvqAWcObN0KBkUl2rWBdig0= -github.com/zclconf/go-cty-yaml v1.1.0/go.mod h1:9YLUH4g7lOhVWqUbctnVlZ5KLpg7JAprQNgxSZ1Gyxs= -golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= -golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= -golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= -golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= -golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY= -golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c= -golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= -golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= -golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= -golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= -golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +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/zclconf/go-cty v1.12.1 h1:PcupnljUm9EIvbgSHQnHhUr3fO6oFmkOrvs2BAFNXXY= +github.com/zclconf/go-cty v1.12.1/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA= +go.etcd.io/etcd/api/v3 v3.5.5/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8= +go.etcd.io/etcd/client/pkg/v3 v3.5.5/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ= +go.etcd.io/etcd/client/v2 v2.305.5/go.mod h1:zQjKllfqfBVyVStbt4FaosoX2iYd8fV/GRy/PbowgP4= +go.etcd.io/etcd/client/v3 v3.5.5/go.mod h1:aApjR4WGlSumpnJ2kloS75h6aHUmAyaPLjHMxpc7E7c= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM= +golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +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.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +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-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +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.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/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-20220601150217-0de741cfad7f/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.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190312061237-fead79001313/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-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/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-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/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-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/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-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/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-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/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-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/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.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= -golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= -golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= -golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= -golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= +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/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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.5/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.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/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-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/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.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.6.1-0.20230222164832-25d2519c8696 h1:8985/C5IvACpd9DDXckSnjSBLKDgbxXiyODgi94zOPM= +golang.org/x/tools v0.6.1-0.20230222164832-25d2519c8696/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +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= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +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/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 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-20200227125254-8fa46927fb4f/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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/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.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/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= -modernc.org/cc/v4 v4.25.2 h1:T2oH7sZdGvTaie0BRNFbIYsabzCxUQg8nLqCdQ2i0ic= -modernc.org/cc/v4 v4.25.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= -modernc.org/ccgo/v4 v4.25.1 h1:TFSzPrAGmDsdnhT9X2UrcPMI3N/mJ9/X9ykKXwLhDsU= -modernc.org/ccgo/v4 v4.25.1/go.mod h1:njjuAYiPflywOOrm3B7kCB444ONP5pAVr8PIEoE0uDw= -modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= -modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= -modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= -modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= -modernc.org/libc v1.62.1 h1:s0+fv5E3FymN8eJVmnk0llBe6rOxCu/DEU+XygRbS8s= -modernc.org/libc v1.62.1/go.mod h1:iXhATfJQLjG3NWy56a6WVU73lWOcdYVxsvwCgoPljuo= -modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= -modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= -modernc.org/memory v1.9.1 h1:V/Z1solwAVmMW1yttq3nDdZPJqV1rM05Ccq6KMSZ34g= -modernc.org/memory v1.9.1/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= -modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= -modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= -modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= -modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= -modernc.org/sqlite v1.37.0 h1:s1TMe7T3Q3ovQiK2Ouz4Jwh7dw4ZDqbebSDTlSJdfjI= -modernc.org/sqlite v1.37.0/go.mod h1:5YiWv+YviqGMuGw4V+PNplcyaJ5v+vQd7TQOgkACoJM= -modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= -modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= -modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= -modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw= +modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= +modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw= +modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= +modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= +modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= +modernc.org/libc v1.22.3 h1:D/g6O5ftAfavceqlLOFwaZuA5KYafKwmr30A6iSqoyY= +modernc.org/libc v1.22.3/go.mod h1:MQrloYP209xa2zHome2a8HLiLm6k0UT8CoHpV74tOFw= +modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= +modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.21.0 h1:4aP4MdUf15i3R3M2mx6Q90WHKz3nZLoz96zlB6tNdow= +modernc.org/sqlite v1.21.0/go.mod h1:XwQ0wZPIh1iKb5mkvCJ3szzbhk+tykC8ZWqTRTgYRwI= +modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/tcl v1.15.1 h1:mOQwiEK4p7HruMZcwKTZPw/aqtGM4aY00uzWhlKKYws= +modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= +modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.7.0 h1:xkDw/KepgEjeizO2sNco+hqYkU12taxQFqPEmgm1GWE= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/backend/internal/core/currencies/currencies.go b/backend/internal/core/currencies/currencies.go deleted file mode 100644 index 4cc8766..0000000 --- a/backend/internal/core/currencies/currencies.go +++ /dev/null @@ -1,104 +0,0 @@ -// Package currencies provides a shared definition of currencies. This uses a global -// variable to hold the currencies. -package currencies - -import ( - "bytes" - _ "embed" - "encoding/json" - "io" - "slices" - "strings" - "sync" -) - -//go:embed currencies.json -var defaults []byte - -type CollectorFunc func() ([]Currency, error) - -func CollectJSON(reader io.Reader) CollectorFunc { - return func() ([]Currency, error) { - var currencies []Currency - err := json.NewDecoder(reader).Decode(¤cies) - if err != nil { - return nil, err - } - - return currencies, nil - } -} - -func CollectDefaults() CollectorFunc { - return CollectJSON(bytes.NewReader(defaults)) -} - -func CollectionCurrencies(collectors ...CollectorFunc) ([]Currency, error) { - out := make([]Currency, 0, len(collectors)) - for i := range collectors { - c, err := collectors[i]() - if err != nil { - return nil, err - } - - out = append(out, c...) - } - - return out, nil -} - -type Currency struct { - Name string `json:"name"` - Code string `json:"code"` - Local string `json:"local"` - Symbol string `json:"symbol"` -} - -type CurrencyRegistry struct { - mu sync.RWMutex - registry map[string]Currency -} - -func NewCurrencyService(currencies []Currency) *CurrencyRegistry { - registry := make(map[string]Currency, len(currencies)) - for i := range currencies { - registry[currencies[i].Code] = currencies[i] - } - - return &CurrencyRegistry{ - registry: registry, - } -} - -func (cs *CurrencyRegistry) Slice() []Currency { - cs.mu.RLock() - defer cs.mu.RUnlock() - - out := make([]Currency, 0, len(cs.registry)) - for key := range cs.registry { - out = append(out, cs.registry[key]) - } - - slices.SortFunc(out, func(a, b Currency) int { - if a.Name < b.Name { - return -1 - } - - if a.Name > b.Name { - return 1 - } - - return 0 - }) - - return out -} - -func (cs *CurrencyRegistry) IsSupported(code string) bool { - upper := strings.ToUpper(code) - - cs.mu.RLock() - defer cs.mu.RUnlock() - _, ok := cs.registry[upper] - return ok -} diff --git a/backend/internal/core/currencies/currencies.json b/backend/internal/core/currencies/currencies.json deleted file mode 100644 index c7b2630..0000000 --- a/backend/internal/core/currencies/currencies.json +++ /dev/null @@ -1,638 +0,0 @@ -[ - { - "code": "USD", - "local": "United States", - "symbol": "$", - "name": "United States Dollar" - }, - { - "code": "AED", - "local": "United Arab Emirates", - "symbol": "د.إ", - "name": "United Arab Emirates Dirham" - }, - { - "code": "AFN", - "local": "Afghanistan", - "symbol": "؋", - "name": "Afghan Afghani" - }, - { - "code": "ALL", - "local": "Albania", - "symbol": "L", - "name": "Albanian Lek" - }, - { - "code": "AMD", - "local": "Armenia", - "symbol": "֏", - "name": "Armenian Dram" - }, - { - "code": "ANG", - "local": "Netherlands Antilles", - "symbol": "ƒ", - "name": "Netherlands Antillean Guilder" - }, - { - "code": "AOA", - "local": "Angola", - "symbol": "Kz", - "name": "Angolan Kwanza" - }, - { - "code": "ARS", - "local": "Argentina", - "symbol": "$", - "name": "Argentine Peso" - }, - { - "code": "AUD", - "local": "Australia", - "symbol": "A$", - "name": "Australian Dollar" - }, - { - "code": "AWG", - "local": "Aruba", - "symbol": "ƒ", - "name": "Aruban Florin" - }, - { - "code": "AZN", - "local": "Azerbaijan", - "symbol": "₼", - "name": "Azerbaijani Manat" - }, - { - "code": "BAM", - "local": "Bosnia and Herzegovina", - "symbol": "KM", - "name": "Bosnia and Herzegovina Convertible Mark" - }, - { - "code": "BBD", - "local": "Barbados", - "symbol": "Bds$", - "name": "Barbadian Dollar" - }, - { - "code": "BDT", - "local": "Bangladesh", - "symbol": "৳", - "name": "Bangladeshi Taka" - }, - { - "code": "BGN", - "local": "Bulgaria", - "symbol": "лв", - "name": "Bulgarian lev" - }, - { - "code": "BHD", - "local": "Bahrain", - "symbol": "ب.د", - "name": "Bahraini Dinar" - }, - { - "code": "BIF", - "local": "Burundi", - "symbol": "FBu", - "name": "Burundian Franc" - }, - { - "code": "BMD", - "local": "Bermuda", - "symbol": "BD$", - "name": "Bermudian Dollar" - }, - { - "code": "BND", - "local": "Brunei", - "symbol": "B$", - "name": "Brunei Dollar" - }, - { - "code": "BOB", - "local": "Bolivia", - "symbol": "Bs.", - "name": "Bolivian Boliviano" - }, - { - "code": "BRL", - "local": "Brazil", - "symbol": "R$", - "name": "Brazilian Real" - }, - { - "code": "BSD", - "local": "Bahamas", - "symbol": "B$", - "name": "Bahamian Dollar" - }, - { - "code": "BTN", - "local": "Bhutan", - "symbol": "Nu.", - "name": "Bhutanese Ngultrum" - }, - { - "code": "BWP", - "local": "Botswana", - "symbol": "P", - "name": "Botswana Pula" - }, - { - "code": "BYN", - "local": "Belarus", - "symbol": "Br", - "name": "Belarusian Ruble" - }, - { - "code": "BZD", - "local": "Belize", - "symbol": "BZ$", - "name": "Belize Dollar" - }, - { - "code": "CAD", - "local": "Canada", - "symbol": "C$", - "name": "Canadian Dollar" - }, - { - "code": "CDF", - "local": "Democratic Republic of the Congo", - "symbol": "FC", - "name": "Congolese Franc" - }, - { - "code": "CHF", - "local": "Switzerland", - "symbol": "CHF", - "name": "Swiss Franc" - }, - { - "code": "CLP", - "local": "Chile", - "symbol": "CL$", - "name": "Chilean Peso" - }, - { - "code": "CNY", - "local": "China", - "symbol": "¥", - "name": "Chinese Yuan" - }, - { - "code": "COP", - "local": "Colombia", - "symbol": "COL$", - "name": "Colombian Peso" - }, - { - "code": "CRC", - "local": "Costa Rica", - "symbol": "₡", - "name": "Costa Rican Colón" - }, - { - "code": "CUP", - "local": "Cuba", - "symbol": "₱", - "name": "Cuban Peso" - }, - { - "code": "CVE", - "local": "Cape Verde", - "symbol": "$", - "name": "Cape Verdean Escudo" - }, - { - "code": "CZK", - "local": "Czech Republic", - "symbol": "Kč", - "name": "Czech Koruna" - }, - { - "code": "DJF", - "local": "Djibouti", - "symbol": "Fdj", - "name": "Djiboutian Franc" - }, - { - "code": "DKK", - "local": "Denmark", - "symbol": "kr", - "name": "Danish Krone" - }, - { - "code": "DOP", - "local": "Dominican Republic", - "symbol": "RD$", - "name": "Dominican Peso" - }, - { - "code": "DZD", - "local": "Algeria", - "symbol": "د.ج", - "name": "Algerian Dinar" - }, - { - "code": "EGP", - "local": "Egypt", - "symbol": "£", - "name": "Egyptian Pound" - }, - { - "code": "ERN", - "local": "Eritrea", - "symbol": "Nfk", - "name": "Eritrean Nakfa" - }, - { - "code": "ETB", - "local": "Ethiopia", - "symbol": "Br", - "name": "Ethiopian Birr" - }, - { - "code": "EUR", - "local": "Eurozone", - "symbol": "€", - "name": "Euro" - }, - { - "code": "FJD", - "local": "Fiji", - "symbol": "FJ$", - "name": "Fijian Dollar" - }, - { - "code": "FKP", - "local": "Falkland Islands", - "symbol": "£", - "name": "Falkland Islands Pound" - }, - { - "code": "FOK", - "local": "Faroe Islands", - "symbol": "kr", - "name": "Faroese Króna" - }, - { - "code": "GBP", - "local": "United Kingdom", - "symbol": "£", - "name": "British Pound Sterling" - }, - { - "code": "GEL", - "local": "Georgia", - "symbol": "₾", - "name": "Georgian Lari" - }, - { - "code": "GGP", - "local": "Guernsey", - "symbol": "£", - "name": "Guernsey Pound" - }, - { - "code": "GHS", - "local": "Ghana", - "symbol": "GH₵", - "name": "Ghanaian Cedi" - }, - { - "code": "GIP", - "local": "Gibraltar", - "symbol": "£", - "name": "Gibraltar Pound" - }, - { - "code": "GMD", - "local": "Gambia", - "symbol": "D", - "name": "Gambian Dalasi" - }, - { - "code": "GNF", - "local": "Guinea", - "symbol": "FG", - "name": "Guinean Franc" - }, - { - "code": "GTQ", - "local": "Guatemala", - "symbol": "Q", - "name": "Guatemalan Quetzal" - }, - { - "code": "GYD", - "local": "Guyana", - "symbol": "GY$", - "name": "Guyanese Dollar" - }, - { - "code": "HKD", - "local": "Hong Kong", - "symbol": "HK$", - "name": "Hong Kong Dollar" - }, - { - "code": "HNL", - "local": "Honduras", - "symbol": "L", - "name": "Honduran Lempira" - }, - { - "code": "HRK", - "local": "Croatia", - "symbol": "kn", - "name": "Croatian Kuna" - }, - { - "code": "HTG", - "local": "Haiti", - "symbol": "G", - "name": "Haitian Gourde" - }, - { - "code": "HUF", - "local": "Hungary", - "symbol": "Ft", - "name": "Hungarian Forint" - }, - { - "code": "IDR", - "local": "Indonesia", - "symbol": "Rp", - "name": "Indonesian Rupiah" - }, - { - "code": "ILS", - "local": "Israel", - "symbol": "₪", - "name": "Israeli New Shekel" - }, - { - "code": "IMP", - "local": "Isle of Man", - "symbol": "£", - "name": "Manx Pound" - }, - { - "code": "INR", - "local": "India", - "symbol": "₹", - "name": "Indian Rupee" - }, - { - "code": "IQD", - "local": "Iraq", - "symbol": "ع.د", - "name": "Iraqi Dinar" - }, - { - "code": "IRR", - "local": "Iran", - "symbol": "﷼", - "name": "Iranian Rial" - }, - { - "code": "ISK", - "local": "Iceland", - "symbol": "kr", - "name": "Icelandic Króna" - }, - { - "code": "JEP", - "local": "Jersey", - "symbol": "£", - "name": "Jersey Pound" - }, - { - "code": "JMD", - "local": "Jamaica", - "symbol": "J$", - "name": "Jamaican Dollar" - }, - { - "code": "JOD", - "local": "Jordan", - "symbol": "د.ا", - "name": "Jordanian Dinar" - }, - { - "code": "JPY", - "local": "Japan", - "symbol": "¥", - "name": "Japanese Yen" - }, - { - "code": "KES", - "local": "Kenya", - "symbol": "KSh", - "name": "Kenyan Shilling" - }, - { - "code": "KGS", - "local": "Kyrgyzstan", - "symbol": "с", - "name": "Kyrgyzstani Som" - }, - { - "code": "KHR", - "local": "Cambodia", - "symbol": "៛", - "name": "Cambodian Riel" - }, - { - "code": "KID", - "local": "Kiribati", - "symbol": "$", - "name": "Kiribati Dollar" - }, - { - "code": "KMF", - "local": "Comoros", - "symbol": "CF", - "name": "Comorian Franc" - }, - { - "code": "KRW", - "local": "South Korea", - "symbol": "₩", - "name": "South Korean Won" - }, - { - "code": "KWD", - "local": "Kuwait", - "symbol": "د.ك", - "name": "Kuwaiti Dinar" - }, - { - "code": "KYD", - "local": "Cayman Islands", - "symbol": "CI$", - "name": "Cayman Islands Dollar" - }, - { - "code": "KZT", - "local": "Kazakhstan", - "symbol": "₸", - "name": "Kazakhstani Tenge" - }, - { - "code": "LAK", - "local": "Laos", - "symbol": "₭", - "name": "Lao Kip" - }, - { - "code": "LBP", - "local": "Lebanon", - "symbol": "ل.ل", - "name": "Lebanese Pound" - }, - { - "code": "LKR", - "local": "Sri Lanka", - "symbol": "₨", - "name": "Sri Lankan Rupee" - }, - { - "code": "LRD", - "local": "Liberia", - "symbol": "L$", - "name": "Liberian Dollar" - }, - { - "code": "LSL", - "local": "Lesotho", - "symbol": "M", - "name": "Lesotho Loti" - }, - { - "code": "LYD", - "local": "Libya", - "symbol": "ل.د", - "name": "Libyan Dinar" - }, - { - "code": "MAD", - "local": "Morocco", - "symbol": "د.م.", - "name": "Moroccan Dirham" - }, - { - "code": "MDL", - "local": "Moldova", - "symbol": "lei", - "name": "Moldovan Leu" - }, - { - "code": "MGA", - "local": "Madagascar", - "symbol": "Ar", - "name": "Malagasy Ariary" - }, - { - "code": "MKD", - "local": "North Macedonia", - "symbol": "ден", - "name": "Macedonian Denar" - }, - { - "code": "MMK", - "local": "Myanmar", - "symbol": "K", - "name": "Myanmar Kyat" - }, - { - "code": "MNT", - "local": "Mongolia", - "symbol": "₮", - "name": "Mongolian Tugrik" - }, - { - "code": "MOP", - "local": "Macau", - "symbol": "MOP$", - "name": "Macanese Pataca" - }, - { - "code": "MRU", - "local": "Mauritania", - "symbol": "UM", - "name": "Mauritanian Ouguiya" - }, - { - "code": "MUR", - "local": "Mauritius", - "symbol": "₨", - "name": "Mauritian Rupee" - }, - { - "code": "MVR", - "local": "Maldives", - "symbol": "Rf", - "name": "Maldivian Rufiyaa" - }, - { - "code": "MWK", - "local": "Malawi", - "symbol": "MK", - "name": "Malawian Kwacha" - }, - { - "code": "MXN", - "local": "Mexico", - "symbol": "Mex$", - "name": "Mexican Peso" - }, - { - "code": "MYR", - "local": "Malaysia", - "symbol": "RM", - "name": "Malaysian Ringgit" - }, - { - "code": "MZN", - "local": "Mozambique", - "symbol": "MT", - "name": "Mozambican Metical" - }, - { - "code": "NAD", - "local": "Namibia", - "symbol": "N$", - "name": "Namibian Dollar" - }, - { - "code": "NGN", - "local": "Nigeria", - "symbol": "₦", - "name": "Nigerian Naira" - }, - { - "code": "NIO", - "local": "Nicaragua", - "symbol": "C$", - "name": "Nicaraguan Córdoba" - }, - { - "code": "NOK", - "local": "Norway", - "symbol": "kr", - "name": "Norwegian Krone" - }, - { - "code": "UAH", - "local": "Ukraine", - "symbol": "₴", - "name": "Ukrainian Hryvnia" - } -] diff --git a/backend/internal/core/services/all.go b/backend/internal/core/services/all.go index 3c03a4e..8cbe896 100644 --- a/backend/internal/core/services/all.go +++ b/backend/internal/core/services/all.go @@ -1,8 +1,6 @@ -// Package services provides the core business logic for the application. package services import ( - "github.com/hay-kot/homebox/backend/internal/core/currencies" "github.com/hay-kot/homebox/backend/internal/data/repo" ) @@ -11,14 +9,12 @@ type AllServices struct { Group *GroupService Items *ItemService BackgroundService *BackgroundService - Currencies *currencies.CurrencyRegistry } type OptionsFunc func(*options) type options struct { autoIncrementAssetID bool - currencies []currencies.Currency } func WithAutoIncrementAssetID(v bool) func(*options) { @@ -27,27 +23,13 @@ func WithAutoIncrementAssetID(v bool) func(*options) { } } -func WithCurrencies(v []currencies.Currency) func(*options) { - return func(o *options) { - o.currencies = v - } -} - func New(repos *repo.AllRepos, opts ...OptionsFunc) *AllServices { if repos == nil { panic("repos cannot be nil") } - defaultCurrencies, err := currencies.CollectionCurrencies( - currencies.CollectDefaults(), - ) - if err != nil { - panic("failed to collect default currencies") - } - options := &options{ autoIncrementAssetID: true, - currencies: defaultCurrencies, } for _, opt := range opts { @@ -62,6 +44,5 @@ func New(repos *repo.AllRepos, opts ...OptionsFunc) *AllServices { autoIncrementAssetID: options.autoIncrementAssetID, }, BackgroundService: &BackgroundService{repos}, - Currencies: currencies.NewCurrencyService(options.currencies), } } diff --git a/backend/internal/core/services/main_test.go b/backend/internal/core/services/main_test.go index ecb07b0..c79bfcf 100644 --- a/backend/internal/core/services/main_test.go +++ b/backend/internal/core/services/main_test.go @@ -6,8 +6,6 @@ import ( "os" "testing" - "github.com/hay-kot/homebox/backend/internal/core/currencies" - "github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus" "github.com/hay-kot/homebox/backend/internal/data/ent" "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/pkgs/faker" @@ -15,8 +13,7 @@ import ( ) var ( - fk = faker.NewFaker() - tbus = eventbus.New() + fk = faker.NewFaker() tCtx = Context{} tClient *ent.Client @@ -61,14 +58,9 @@ func TestMain(m *testing.M) { } tClient = client - tRepos = repo.New(tClient, tbus, os.TempDir()+"/homebox") - - defaults, _ := currencies.CollectionCurrencies( - currencies.CollectDefaults(), - ) - - tSvc = New(tRepos, WithCurrencies(defaults)) - defer func() { _ = client.Close() }() + tRepos = repo.New(tClient, os.TempDir()+"/homebox") + tSvc = New(tRepos) + defer client.Close() bootstrap() tCtx = Context{ diff --git a/backend/internal/core/services/reporting/.testdata/import.csv b/backend/internal/core/services/reporting/.testdata/import.csv new file mode 100644 index 0000000..08bd9c8 --- /dev/null +++ b/backend/internal/core/services/reporting/.testdata/import.csv @@ -0,0 +1,7 @@ +Import Ref,Location,Labels,Quantity,Name,Description,Insured,Serial Number,Mode Number,Manufacturer,Notes,Purchase From,Purchased Price,Purchased Time,Lifetime Warranty,Warranty Expires,Warranty Details,Sold To,Sold Price,Sold Time,Sold Notes +A,Garage,IOT;Home Assistant; Z-Wave,1,Zooz Universal Relay ZEN17,Description 1,TRUE,,ZEN17,Zooz,,Amazon,39.95,10/13/2021,,10/13/2021,,,,10/13/2021, +B,Living Room,IOT;Home Assistant; Z-Wave,1,Zooz Motion Sensor,Description 2,FALSE,,ZSE18,Zooz,,Amazon,29.95,10/15/2021,,10/15/2021,,,,10/15/2021, +C,Office,IOT;Home Assistant; Z-Wave,1,Zooz 110v Power Switch,Description 3,TRUE,,ZEN15,Zooz,,Amazon,39.95,10/13/2021,,10/13/2021,,,,10/13/2021, +D,Downstairs,IOT;Home Assistant; Z-Wave,1,Ecolink Z-Wave PIR Motion Sensor,Description 4,FALSE,,PIRZWAVE2.5-ECO,Ecolink,,Amazon,35.58,10/21/2020,,10/21/2020,,,,10/21/2020, +E,Entry,IOT;Home Assistant; Z-Wave,1,Yale Security Touchscreen Deadbolt,Description 5,TRUE,,YRD226ZW2619,Yale,,Amazon,120.39,10/14/2020,,10/14/2020,,,,10/14/2020, +F,Kitchen,IOT;Home Assistant; Z-Wave,1,Smart Rocker Light Dimmer,Description 6,FALSE,,39351,Honeywell,,Amazon,65.98,09/30/2020,,09/30/2020,,,,09/30/2020, \ No newline at end of file diff --git a/backend/internal/core/services/reporting/.testdata/import.tsv b/backend/internal/core/services/reporting/.testdata/import.tsv new file mode 100644 index 0000000..503c777 --- /dev/null +++ b/backend/internal/core/services/reporting/.testdata/import.tsv @@ -0,0 +1,7 @@ +Import Ref Location Labels Quantity Name Description Insured Serial Number Mode Number Manufacturer Notes Purchase From Purchased Price Purchased Time Lifetime Warranty Warranty Expires Warranty Details Sold To Sold Price Sold Time Sold Notes +A Garage IOT;Home Assistant; Z-Wave 1 Zooz Universal Relay ZEN17 Description 1 TRUE ZEN17 Zooz Amazon 39.95 10/13/2021 10/13/2021 10/13/2021 +B Living Room IOT;Home Assistant; Z-Wave 1 Zooz Motion Sensor Description 2 FALSE ZSE18 Zooz Amazon 29.95 10/15/2021 10/15/2021 10/15/2021 +C Office IOT;Home Assistant; Z-Wave 1 Zooz 110v Power Switch Description 3 TRUE ZEN15 Zooz Amazon 39.95 10/13/2021 10/13/2021 10/13/2021 +D Downstairs IOT;Home Assistant; Z-Wave 1 Ecolink Z-Wave PIR Motion Sensor Description 4 FALSE PIRZWAVE2.5-ECO Ecolink Amazon 35.58 10/21/2020 10/21/2020 10/21/2020 +E Entry IOT;Home Assistant; Z-Wave 1 Yale Security Touchscreen Deadbolt Description 5 TRUE YRD226ZW2619 Yale Amazon 120.39 10/14/2020 10/14/2020 10/14/2020 +F Kitchen IOT;Home Assistant; Z-Wave 1 Smart Rocker Light Dimmer Description 6 FALSE 39351 Honeywell Amazon 65.98 09/30/2020 09/30/2020 09/30/2020 \ No newline at end of file diff --git a/backend/internal/core/services/reporting/eventbus/eventbus.go b/backend/internal/core/services/reporting/eventbus/eventbus.go deleted file mode 100644 index 581bc38..0000000 --- a/backend/internal/core/services/reporting/eventbus/eventbus.go +++ /dev/null @@ -1,91 +0,0 @@ -// Package eventbus provides an interface for event bus. -package eventbus - -import ( - "context" - "sync" - - "github.com/google/uuid" -) - -type Event string - -const ( - EventLabelMutation Event = "label.mutation" - EventLocationMutation Event = "location.mutation" - EventItemMutation Event = "item.mutation" -) - -type GroupMutationEvent struct { - GID uuid.UUID -} - -type eventData struct { - event Event - data any -} - -type EventBus struct { - started bool - ch chan eventData - - mu sync.RWMutex - subscribers map[Event][]func(any) -} - -func New() *EventBus { - return &EventBus{ - ch: make(chan eventData, 100), - subscribers: map[Event][]func(any){ - EventLabelMutation: {}, - EventLocationMutation: {}, - EventItemMutation: {}, - }, - } -} - -func (e *EventBus) Run(ctx context.Context) error { - if e.started { - panic("event bus already started") - } - - e.started = true - - for { - select { - case <-ctx.Done(): - return nil - case event := <-e.ch: - e.mu.RLock() - arr, ok := e.subscribers[event.event] - e.mu.RUnlock() - - if !ok { - continue - } - - for _, fn := range arr { - fn(event.data) - } - } - } -} - -func (e *EventBus) Publish(event Event, data any) { - e.ch <- eventData{ - event: event, - data: data, - } -} - -func (e *EventBus) Subscribe(event Event, fn func(any)) { - e.mu.Lock() - defer e.mu.Unlock() - - arr, ok := e.subscribers[event] - if !ok { - panic("event not found") - } - - e.subscribers[event] = append(arr, fn) -} diff --git a/backend/internal/core/services/reporting/import.go b/backend/internal/core/services/reporting/import.go index 6f01b1b..b608e62 100644 --- a/backend/internal/core/services/reporting/import.go +++ b/backend/internal/core/services/reporting/import.go @@ -1,4 +1,3 @@ -// Package reporting provides a way to import CSV files into the database. package reporting import ( diff --git a/backend/internal/core/services/reporting/io_row.go b/backend/internal/core/services/reporting/io_row.go index c80e00d..faa5d25 100644 --- a/backend/internal/core/services/reporting/io_row.go +++ b/backend/internal/core/services/reporting/io_row.go @@ -83,13 +83,3 @@ func parseLocationString(s string) LocationString { func (csf LocationString) String() string { return strings.Join(csf, " / ") } - -func fromPathSlice(s []repo.ItemPath) LocationString { - v := make(LocationString, len(s)) - - for i := range s { - v[i] = s[i].Name - } - - return v -} diff --git a/backend/internal/core/services/reporting/io_sheet.go b/backend/internal/core/services/reporting/io_sheet.go index 5877f3e..88d1d36 100644 --- a/backend/internal/core/services/reporting/io_sheet.go +++ b/backend/internal/core/services/reporting/io_sheet.go @@ -1,7 +1,6 @@ package reporting import ( - "context" "fmt" "io" "reflect" @@ -9,7 +8,6 @@ import ( "strconv" "strings" - "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/data/types" "github.com/rs/zerolog/log" @@ -152,8 +150,8 @@ func (s *IOSheet) Read(data io.Reader) error { return nil } -// ReadItems writes the sheet to a writer. -func (s *IOSheet) ReadItems(ctx context.Context, items []repo.ItemOut, GID uuid.UUID, repos *repo.AllRepos) error { +// Write writes the sheet to a writer. +func (s *IOSheet) ReadItems(items []repo.ItemOut) { s.Rows = make([]ExportTSVRow, len(items)) extraHeaders := map[string]struct{}{} @@ -162,15 +160,7 @@ func (s *IOSheet) ReadItems(ctx context.Context, items []repo.ItemOut, GID uuid. item := items[i] // TODO: Support fetching nested locations - locID := item.Location.ID - - locPaths, err := repos.Locations.PathForLoc(context.Background(), GID, locID) - if err != nil { - log.Error().Err(err).Msg("could not get location path") - return err - } - - locString := fromPathSlice(locPaths) + locString := LocationString{item.Location.Name} labelString := make([]string, len(item.Labels)) @@ -248,11 +238,9 @@ func (s *IOSheet) ReadItems(ctx context.Context, items []repo.ItemOut, GID uuid. for _, h := range customHeaders { s.headers = append(s.headers, "HB.field."+h) } - - return nil } -// TSV writes the current sheet to a writer in TSV format. +// Writes the current sheet to a writer in TSV format. func (s *IOSheet) TSV() ([][]string, error) { memcsv := make([][]string, len(s.Rows)+1) diff --git a/backend/internal/core/services/reporting/io_sheet_test.go b/backend/internal/core/services/reporting/io_sheet_test.go index f056e31..9d7f9a0 100644 --- a/backend/internal/core/services/reporting/io_sheet_test.go +++ b/backend/internal/core/services/reporting/io_sheet_test.go @@ -9,7 +9,6 @@ import ( "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) var ( @@ -21,6 +20,12 @@ var ( //go:embed .testdata/import/types.csv customTypesImportCSV []byte + + //go:embed .testdata/import.csv + CSVData_Comma []byte + + //go:embed .testdata/import.tsv + CSVData_Tab []byte ) func TestSheet_Read(t *testing.T) { @@ -104,9 +109,9 @@ func TestSheet_Read(t *testing.T) { switch { case tt.wantErr: - require.Error(t, err) + assert.Error(t, err) default: - require.NoError(t, err) + assert.NoError(t, err) assert.ElementsMatch(t, tt.want, sheet.Rows) } }) @@ -184,7 +189,7 @@ func Test_determineSeparator(t *testing.T) { { name: "comma", args: args{ - data: []byte("a,b,c"), + data: CSVData_Comma, }, want: ',', wantErr: false, @@ -192,7 +197,7 @@ func Test_determineSeparator(t *testing.T) { { name: "tab", args: args{ - data: []byte("a\tb\tc"), + data: CSVData_Tab, }, want: '\t', wantErr: false, diff --git a/backend/internal/core/services/service_items.go b/backend/internal/core/services/service_items.go index 4d510e5..c1a37d5 100644 --- a/backend/internal/core/services/service_items.go +++ b/backend/internal/core/services/service_items.go @@ -32,7 +32,7 @@ func (svc *ItemService) Create(ctx Context, item repo.ItemCreate) (repo.ItemOut, return repo.ItemOut{}, err } - item.AssetID = highest + 1 + item.AssetID = repo.AssetID(highest + 1) } return svc.repo.Items.Create(ctx, ctx.GID, item) @@ -53,7 +53,7 @@ func (svc *ItemService) EnsureAssetID(ctx context.Context, GID uuid.UUID) (int, for _, item := range items { highest++ - err = svc.repo.Items.SetAssetID(ctx, GID, item.ID, highest) + err = svc.repo.Items.SetAssetID(ctx, GID, item.ID, repo.AssetID(highest)) if err != nil { return 0, err } @@ -337,10 +337,7 @@ func (svc *ItemService) ExportTSV(ctx context.Context, GID uuid.UUID) ([][]strin sheet := reporting.IOSheet{} - err = sheet.ReadItems(ctx, items, GID, svc.repo) - if err != nil { - return nil, err - } + sheet.ReadItems(items) return sheet.TSV() } diff --git a/backend/internal/core/services/service_items_attachments.go b/backend/internal/core/services/service_items_attachments.go index 43835c6..4a7b197 100644 --- a/backend/internal/core/services/service_items_attachments.go +++ b/backend/internal/core/services/service_items_attachments.go @@ -12,8 +12,8 @@ import ( "github.com/rs/zerolog/log" ) -func (svc *ItemService) AttachmentPath(ctx context.Context, attachmentID uuid.UUID) (*ent.Document, error) { - attachment, err := svc.repo.Attachments.Get(ctx, attachmentID) +func (svc *ItemService) AttachmentPath(ctx context.Context, attachmentId uuid.UUID) (*ent.Document, error) { + attachment, err := svc.repo.Attachments.Get(ctx, attachmentId) if err != nil { return nil, err } @@ -21,9 +21,9 @@ func (svc *ItemService) AttachmentPath(ctx context.Context, attachmentID uuid.UU return attachment.Edges.Document, nil } -func (svc *ItemService) AttachmentUpdate(ctx Context, itemID uuid.UUID, data *repo.ItemAttachmentUpdate) (repo.ItemOut, error) { +func (svc *ItemService) AttachmentUpdate(ctx Context, itemId uuid.UUID, data *repo.ItemAttachmentUpdate) (repo.ItemOut, error) { // Update Attachment - attachment, err := svc.repo.Attachments.Update(ctx, data.ID, data) + attachment, err := svc.repo.Attachments.Update(ctx, data.ID, attachment.Type(data.Type)) if err != nil { return repo.ItemOut{}, err } @@ -35,15 +35,15 @@ func (svc *ItemService) AttachmentUpdate(ctx Context, itemID uuid.UUID, data *re return repo.ItemOut{}, err } - return svc.repo.Items.GetOneByGroup(ctx, ctx.GID, itemID) + return svc.repo.Items.GetOneByGroup(ctx, ctx.GID, itemId) } // AttachmentAdd adds an attachment to an item by creating an entry in the Documents table and linking it to the Attachment // Table and Items table. The file provided via the reader is stored on the file system based on the provided // relative path during construction of the service. -func (svc *ItemService) AttachmentAdd(ctx Context, itemID uuid.UUID, filename string, attachmentType attachment.Type, file io.Reader) (repo.ItemOut, error) { +func (svc *ItemService) AttachmentAdd(ctx Context, itemId uuid.UUID, filename string, attachmentType attachment.Type, file io.Reader) (repo.ItemOut, error) { // Get the Item - _, err := svc.repo.Items.GetOneByGroup(ctx, ctx.GID, itemID) + _, err := svc.repo.Items.GetOneByGroup(ctx, ctx.GID, itemId) if err != nil { return repo.ItemOut{}, err } @@ -56,29 +56,29 @@ func (svc *ItemService) AttachmentAdd(ctx Context, itemID uuid.UUID, filename st } // Create the attachment - _, err = svc.repo.Attachments.Create(ctx, itemID, doc.ID, attachmentType) + _, err = svc.repo.Attachments.Create(ctx, itemId, doc.ID, attachmentType) if err != nil { log.Err(err).Msg("failed to create attachment") return repo.ItemOut{}, err } - return svc.repo.Items.GetOneByGroup(ctx, ctx.GID, itemID) + return svc.repo.Items.GetOneByGroup(ctx, ctx.GID, itemId) } -func (svc *ItemService) AttachmentDelete(ctx context.Context, gid, itemID, attachmentID uuid.UUID) error { +func (svc *ItemService) AttachmentDelete(ctx context.Context, gid, itemId, attachmentId uuid.UUID) error { // Get the Item - _, err := svc.repo.Items.GetOneByGroup(ctx, gid, itemID) + _, err := svc.repo.Items.GetOneByGroup(ctx, gid, itemId) if err != nil { return err } - attachment, err := svc.repo.Attachments.Get(ctx, attachmentID) + attachment, err := svc.repo.Attachments.Get(ctx, attachmentId) if err != nil { return err } // Delete the attachment - err = svc.repo.Attachments.Delete(ctx, attachmentID) + err = svc.repo.Attachments.Delete(ctx, attachmentId) if err != nil { return err } diff --git a/backend/internal/core/services/service_items_attachments_test.go b/backend/internal/core/services/service_items_attachments_test.go index 4e2315e..f9db0f6 100644 --- a/backend/internal/core/services/service_items_attachments_test.go +++ b/backend/internal/core/services/service_items_attachments_test.go @@ -9,7 +9,6 @@ import ( "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestItemService_AddAttachment(t *testing.T) { @@ -24,7 +23,7 @@ func TestItemService_AddAttachment(t *testing.T) { Description: "test", Name: "test", }) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, loc) itmC := repo.ItemCreate{ @@ -34,11 +33,11 @@ func TestItemService_AddAttachment(t *testing.T) { } itm, err := svc.repo.Items.Create(context.Background(), tGroup.ID, itmC) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, itm) t.Cleanup(func() { err := svc.repo.Items.Delete(context.Background(), itm.ID) - require.NoError(t, err) + assert.NoError(t, err) }) contents := fk.Str(1000) @@ -46,7 +45,7 @@ func TestItemService_AddAttachment(t *testing.T) { // Setup afterAttachment, err := svc.AttachmentAdd(tCtx, itm.ID, "testfile.txt", "attachment", reader) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, afterAttachment) // Check that the file exists @@ -57,6 +56,6 @@ func TestItemService_AddAttachment(t *testing.T) { // Check that the file contents are correct bts, err := os.ReadFile(storedPath) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, contents, string(bts)) } diff --git a/backend/internal/core/services/service_user.go b/backend/internal/core/services/service_user.go index d86c39b..52da946 100644 --- a/backend/internal/core/services/service_user.go +++ b/backend/internal/core/services/service_user.go @@ -16,7 +16,7 @@ var ( oneWeek = time.Hour * 24 * 7 ErrorInvalidLogin = errors.New("invalid username or password") ErrorInvalidToken = errors.New("invalid token") - ErrorTokenIDMismatch = errors.New("token id mismatch") + ErrorTokenIdMismatch = errors.New("token id mismatch") ) type UserService struct { @@ -92,11 +92,9 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration) if err != nil { return repo.UserOut{}, err } - log.Debug().Msg("user created") // Create the default labels and locations for the group. if creatingGroup { - log.Debug().Msg("creating default labels") for _, label := range defaultLabels() { _, err := svc.repos.Labels.Create(ctx, usr.GroupID, label) if err != nil { @@ -104,7 +102,6 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration) } } - log.Debug().Msg("creating default locations") for _, location := range defaultLocations() { _, err := svc.repos.Locations.Create(ctx, usr.GroupID, location) if err != nil { @@ -115,7 +112,6 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration) // Decrement the invitation token if it was used. if token.ID != uuid.Nil { - log.Debug().Msg("decrementing invitation token") err = svc.repos.Groups.InvitationUpdate(ctx, token.ID, token.Uses-1) if err != nil { log.Err(err).Msg("Failed to update invitation token") @@ -138,13 +134,13 @@ func (svc *UserService) UpdateSelf(ctx context.Context, ID uuid.UUID, data repo. return repo.UserOut{}, err } - return svc.repos.Users.GetOneID(ctx, ID) + return svc.repos.Users.GetOneId(ctx, ID) } // ============================================================================ // User Authentication -func (svc *UserService) createSessionToken(ctx context.Context, userID uuid.UUID, extendedSession bool) (UserAuthTokenDetail, error) { +func (svc *UserService) createSessionToken(ctx context.Context, userId uuid.UUID, extendedSession bool) (UserAuthTokenDetail, error) { attachmentToken := hasher.GenerateToken() expiresAt := time.Now().Add(oneWeek) @@ -153,7 +149,7 @@ func (svc *UserService) createSessionToken(ctx context.Context, userID uuid.UUID } attachmentData := repo.UserAuthTokenCreate{ - UserID: userID, + UserID: userId, TokenHash: attachmentToken.Hash, ExpiresAt: expiresAt, } @@ -165,7 +161,7 @@ func (svc *UserService) createSessionToken(ctx context.Context, userID uuid.UUID userToken := hasher.GenerateToken() data := repo.UserAuthTokenCreate{ - UserID: userID, + UserID: userId, TokenHash: userToken.Hash, ExpiresAt: expiresAt, } @@ -222,7 +218,7 @@ func (svc *UserService) DeleteSelf(ctx context.Context, ID uuid.UUID) error { } func (svc *UserService) ChangePassword(ctx Context, current string, new string) (ok bool) { - usr, err := svc.repos.Users.GetOneID(ctx, ctx.UID) + usr, err := svc.repos.Users.GetOneId(ctx, ctx.UID) if err != nil { return false } diff --git a/backend/internal/data/ent/attachment.go b/backend/internal/data/ent/attachment.go index bfb7de2..25d2df4 100644 --- a/backend/internal/data/ent/attachment.go +++ b/backend/internal/data/ent/attachment.go @@ -7,7 +7,6 @@ import ( "strings" "time" - "entgo.io/ent" "entgo.io/ent/dialect/sql" "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" @@ -26,14 +25,11 @@ type Attachment struct { UpdatedAt time.Time `json:"updated_at,omitempty"` // Type holds the value of the "type" field. Type attachment.Type `json:"type,omitempty"` - // Primary holds the value of the "primary" field. - Primary bool `json:"primary,omitempty"` // Edges holds the relations/edges for other nodes in the graph. // The values are being populated by the AttachmentQuery when eager-loading is set. Edges AttachmentEdges `json:"edges"` document_attachments *uuid.UUID item_attachments *uuid.UUID - selectValues sql.SelectValues } // AttachmentEdges holds the relations/edges for other nodes in the graph. @@ -78,8 +74,6 @@ func (*Attachment) scanValues(columns []string) ([]any, error) { values := make([]any, len(columns)) for i := range columns { switch columns[i] { - case attachment.FieldPrimary: - values[i] = new(sql.NullBool) case attachment.FieldType: values[i] = new(sql.NullString) case attachment.FieldCreatedAt, attachment.FieldUpdatedAt: @@ -91,7 +85,7 @@ func (*Attachment) scanValues(columns []string) ([]any, error) { case attachment.ForeignKeys[1]: // item_attachments values[i] = &sql.NullScanner{S: new(uuid.UUID)} default: - values[i] = new(sql.UnknownType) + return nil, fmt.Errorf("unexpected column %q for type Attachment", columns[i]) } } return values, nil @@ -129,12 +123,6 @@ func (a *Attachment) assignValues(columns []string, values []any) error { } else if value.Valid { a.Type = attachment.Type(value.String) } - case attachment.FieldPrimary: - if value, ok := values[i].(*sql.NullBool); !ok { - return fmt.Errorf("unexpected type %T for field primary", values[i]) - } else if value.Valid { - a.Primary = value.Bool - } case attachment.ForeignKeys[0]: if value, ok := values[i].(*sql.NullScanner); !ok { return fmt.Errorf("unexpected type %T for field document_attachments", values[i]) @@ -149,19 +137,11 @@ func (a *Attachment) assignValues(columns []string, values []any) error { a.item_attachments = new(uuid.UUID) *a.item_attachments = *value.S.(*uuid.UUID) } - default: - a.selectValues.Set(columns[i], values[i]) } } return nil } -// Value returns the ent.Value that was dynamically selected and assigned to the Attachment. -// This includes values selected through modifiers, order, etc. -func (a *Attachment) Value(name string) (ent.Value, error) { - return a.selectValues.Get(name) -} - // QueryItem queries the "item" edge of the Attachment entity. func (a *Attachment) QueryItem() *ItemQuery { return NewAttachmentClient(a.config).QueryItem(a) @@ -203,9 +183,6 @@ func (a *Attachment) String() string { builder.WriteString(", ") builder.WriteString("type=") builder.WriteString(fmt.Sprintf("%v", a.Type)) - builder.WriteString(", ") - builder.WriteString("primary=") - builder.WriteString(fmt.Sprintf("%v", a.Primary)) builder.WriteByte(')') return builder.String() } diff --git a/backend/internal/data/ent/attachment/attachment.go b/backend/internal/data/ent/attachment/attachment.go index 4bbac72..f7aef63 100644 --- a/backend/internal/data/ent/attachment/attachment.go +++ b/backend/internal/data/ent/attachment/attachment.go @@ -6,8 +6,6 @@ import ( "fmt" "time" - "entgo.io/ent/dialect/sql" - "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" ) @@ -22,8 +20,6 @@ const ( FieldUpdatedAt = "updated_at" // FieldType holds the string denoting the type field in the database. FieldType = "type" - // FieldPrimary holds the string denoting the primary field in the database. - FieldPrimary = "primary" // EdgeItem holds the string denoting the item edge name in mutations. EdgeItem = "item" // EdgeDocument holds the string denoting the document edge name in mutations. @@ -52,7 +48,6 @@ var Columns = []string{ FieldCreatedAt, FieldUpdatedAt, FieldType, - FieldPrimary, } // ForeignKeys holds the SQL foreign-keys that are owned by the "attachments" @@ -84,8 +79,6 @@ var ( DefaultUpdatedAt func() time.Time // UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field. UpdateDefaultUpdatedAt func() time.Time - // DefaultPrimary holds the default value on creation for the "primary" field. - DefaultPrimary bool // DefaultID holds the default value on creation for the "id" field. DefaultID func() uuid.UUID ) @@ -118,59 +111,3 @@ func TypeValidator(_type Type) error { return fmt.Errorf("attachment: invalid enum value for type field: %q", _type) } } - -// OrderOption defines the ordering options for the Attachment queries. -type OrderOption func(*sql.Selector) - -// ByID orders the results by the id field. -func ByID(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldID, opts...).ToFunc() -} - -// ByCreatedAt orders the results by the created_at field. -func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() -} - -// ByUpdatedAt orders the results by the updated_at field. -func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc() -} - -// ByType orders the results by the type field. -func ByType(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldType, opts...).ToFunc() -} - -// ByPrimary orders the results by the primary field. -func ByPrimary(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldPrimary, opts...).ToFunc() -} - -// ByItemField orders the results by item field. -func ByItemField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newItemStep(), sql.OrderByField(field, opts...)) - } -} - -// ByDocumentField orders the results by document field. -func ByDocumentField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newDocumentStep(), sql.OrderByField(field, opts...)) - } -} -func newItemStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(ItemInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, ItemTable, ItemColumn), - ) -} -func newDocumentStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(DocumentInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, DocumentTable, DocumentColumn), - ) -} diff --git a/backend/internal/data/ent/attachment/where.go b/backend/internal/data/ent/attachment/where.go index f6950f3..dd1981f 100644 --- a/backend/internal/data/ent/attachment/where.go +++ b/backend/internal/data/ent/attachment/where.go @@ -66,11 +66,6 @@ func UpdatedAt(v time.Time) predicate.Attachment { return predicate.Attachment(sql.FieldEQ(FieldUpdatedAt, v)) } -// Primary applies equality check predicate on the "primary" field. It's identical to PrimaryEQ. -func Primary(v bool) predicate.Attachment { - return predicate.Attachment(sql.FieldEQ(FieldPrimary, v)) -} - // CreatedAtEQ applies the EQ predicate on the "created_at" field. func CreatedAtEQ(v time.Time) predicate.Attachment { return predicate.Attachment(sql.FieldEQ(FieldCreatedAt, v)) @@ -171,16 +166,6 @@ func TypeNotIn(vs ...Type) predicate.Attachment { return predicate.Attachment(sql.FieldNotIn(FieldType, vs...)) } -// PrimaryEQ applies the EQ predicate on the "primary" field. -func PrimaryEQ(v bool) predicate.Attachment { - return predicate.Attachment(sql.FieldEQ(FieldPrimary, v)) -} - -// PrimaryNEQ applies the NEQ predicate on the "primary" field. -func PrimaryNEQ(v bool) predicate.Attachment { - return predicate.Attachment(sql.FieldNEQ(FieldPrimary, v)) -} - // HasItem applies the HasEdge predicate on the "item" edge. func HasItem() predicate.Attachment { return predicate.Attachment(func(s *sql.Selector) { @@ -195,7 +180,11 @@ func HasItem() predicate.Attachment { // HasItemWith applies the HasEdge predicate on the "item" edge with a given conditions (other predicates). func HasItemWith(preds ...predicate.Item) predicate.Attachment { return predicate.Attachment(func(s *sql.Selector) { - step := newItemStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(ItemInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, ItemTable, ItemColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -218,7 +207,11 @@ func HasDocument() predicate.Attachment { // HasDocumentWith applies the HasEdge predicate on the "document" edge with a given conditions (other predicates). func HasDocumentWith(preds ...predicate.Document) predicate.Attachment { return predicate.Attachment(func(s *sql.Selector) { - step := newDocumentStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(DocumentInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, DocumentTable, DocumentColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -229,15 +222,32 @@ func HasDocumentWith(preds ...predicate.Document) predicate.Attachment { // And groups predicates with the AND operator between them. func And(predicates ...predicate.Attachment) predicate.Attachment { - return predicate.Attachment(sql.AndPredicates(predicates...)) + return predicate.Attachment(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for _, p := range predicates { + p(s1) + } + s.Where(s1.P()) + }) } // Or groups predicates with the OR operator between them. func Or(predicates ...predicate.Attachment) predicate.Attachment { - return predicate.Attachment(sql.OrPredicates(predicates...)) + return predicate.Attachment(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for i, p := range predicates { + if i > 0 { + s1.Or() + } + p(s1) + } + s.Where(s1.P()) + }) } // Not applies the not operator on the given predicate. func Not(p predicate.Attachment) predicate.Attachment { - return predicate.Attachment(sql.NotPredicates(p)) + return predicate.Attachment(func(s *sql.Selector) { + p(s.Not()) + }) } diff --git a/backend/internal/data/ent/attachment_create.go b/backend/internal/data/ent/attachment_create.go index d1a0b5b..0c8e239 100644 --- a/backend/internal/data/ent/attachment_create.go +++ b/backend/internal/data/ent/attachment_create.go @@ -65,20 +65,6 @@ func (ac *AttachmentCreate) SetNillableType(a *attachment.Type) *AttachmentCreat return ac } -// SetPrimary sets the "primary" field. -func (ac *AttachmentCreate) SetPrimary(b bool) *AttachmentCreate { - ac.mutation.SetPrimary(b) - return ac -} - -// SetNillablePrimary sets the "primary" field if the given value is not nil. -func (ac *AttachmentCreate) SetNillablePrimary(b *bool) *AttachmentCreate { - if b != nil { - ac.SetPrimary(*b) - } - return ac -} - // SetID sets the "id" field. func (ac *AttachmentCreate) SetID(u uuid.UUID) *AttachmentCreate { ac.mutation.SetID(u) @@ -123,7 +109,7 @@ func (ac *AttachmentCreate) Mutation() *AttachmentMutation { // Save creates the Attachment in the database. func (ac *AttachmentCreate) Save(ctx context.Context) (*Attachment, error) { ac.defaults() - return withHooks(ctx, ac.sqlSave, ac.mutation, ac.hooks) + return withHooks[*Attachment, AttachmentMutation](ctx, ac.sqlSave, ac.mutation, ac.hooks) } // SaveX calls Save and panics if Save returns an error. @@ -162,10 +148,6 @@ func (ac *AttachmentCreate) defaults() { v := attachment.DefaultType ac.mutation.SetType(v) } - if _, ok := ac.mutation.Primary(); !ok { - v := attachment.DefaultPrimary - ac.mutation.SetPrimary(v) - } if _, ok := ac.mutation.ID(); !ok { v := attachment.DefaultID() ac.mutation.SetID(v) @@ -188,9 +170,6 @@ func (ac *AttachmentCreate) check() error { return &ValidationError{Name: "type", err: fmt.Errorf(`ent: validator failed for field "Attachment.type": %w`, err)} } } - if _, ok := ac.mutation.Primary(); !ok { - return &ValidationError{Name: "primary", err: errors.New(`ent: missing required field "Attachment.primary"`)} - } if _, ok := ac.mutation.ItemID(); !ok { return &ValidationError{Name: "item", err: errors.New(`ent: missing required edge "Attachment.item"`)} } @@ -244,10 +223,6 @@ func (ac *AttachmentCreate) createSpec() (*Attachment, *sqlgraph.CreateSpec) { _spec.SetField(attachment.FieldType, field.TypeEnum, value) _node.Type = value } - if value, ok := ac.mutation.Primary(); ok { - _spec.SetField(attachment.FieldPrimary, field.TypeBool, value) - _node.Primary = value - } if nodes := ac.mutation.ItemIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.M2O, @@ -288,15 +263,11 @@ func (ac *AttachmentCreate) createSpec() (*Attachment, *sqlgraph.CreateSpec) { // AttachmentCreateBulk is the builder for creating many Attachment entities in bulk. type AttachmentCreateBulk struct { config - err error builders []*AttachmentCreate } // Save creates the Attachment entities in the database. func (acb *AttachmentCreateBulk) Save(ctx context.Context) ([]*Attachment, error) { - if acb.err != nil { - return nil, acb.err - } specs := make([]*sqlgraph.CreateSpec, len(acb.builders)) nodes := make([]*Attachment, len(acb.builders)) mutators := make([]Mutator, len(acb.builders)) @@ -313,8 +284,8 @@ func (acb *AttachmentCreateBulk) Save(ctx context.Context) ([]*Attachment, error return nil, err } builder.mutation = mutation - var err error nodes[i], specs[i] = builder.createSpec() + var err error if i < len(mutators)-1 { _, err = mutators[i+1].Mutate(root, acb.builders[i+1].mutation) } else { diff --git a/backend/internal/data/ent/attachment_delete.go b/backend/internal/data/ent/attachment_delete.go index 1be608a..8185ac1 100644 --- a/backend/internal/data/ent/attachment_delete.go +++ b/backend/internal/data/ent/attachment_delete.go @@ -27,7 +27,7 @@ func (ad *AttachmentDelete) Where(ps ...predicate.Attachment) *AttachmentDelete // Exec executes the deletion query and returns how many vertices were deleted. func (ad *AttachmentDelete) Exec(ctx context.Context) (int, error) { - return withHooks(ctx, ad.sqlExec, ad.mutation, ad.hooks) + return withHooks[int, AttachmentMutation](ctx, ad.sqlExec, ad.mutation, ad.hooks) } // ExecX is like Exec, but panics if an error occurs. diff --git a/backend/internal/data/ent/attachment_query.go b/backend/internal/data/ent/attachment_query.go index 976e436..de5821a 100644 --- a/backend/internal/data/ent/attachment_query.go +++ b/backend/internal/data/ent/attachment_query.go @@ -21,7 +21,7 @@ import ( type AttachmentQuery struct { config ctx *QueryContext - order []attachment.OrderOption + order []OrderFunc inters []Interceptor predicates []predicate.Attachment withItem *ItemQuery @@ -58,7 +58,7 @@ func (aq *AttachmentQuery) Unique(unique bool) *AttachmentQuery { } // Order specifies how the records should be ordered. -func (aq *AttachmentQuery) Order(o ...attachment.OrderOption) *AttachmentQuery { +func (aq *AttachmentQuery) Order(o ...OrderFunc) *AttachmentQuery { aq.order = append(aq.order, o...) return aq } @@ -296,7 +296,7 @@ func (aq *AttachmentQuery) Clone() *AttachmentQuery { return &AttachmentQuery{ config: aq.config, ctx: aq.ctx.Clone(), - order: append([]attachment.OrderOption{}, aq.order...), + order: append([]OrderFunc{}, aq.order...), inters: append([]Interceptor{}, aq.inters...), predicates: append([]predicate.Attachment{}, aq.predicates...), withItem: aq.withItem.Clone(), diff --git a/backend/internal/data/ent/attachment_update.go b/backend/internal/data/ent/attachment_update.go index bdf10a5..7ee7117 100644 --- a/backend/internal/data/ent/attachment_update.go +++ b/backend/internal/data/ent/attachment_update.go @@ -51,20 +51,6 @@ func (au *AttachmentUpdate) SetNillableType(a *attachment.Type) *AttachmentUpdat return au } -// SetPrimary sets the "primary" field. -func (au *AttachmentUpdate) SetPrimary(b bool) *AttachmentUpdate { - au.mutation.SetPrimary(b) - return au -} - -// SetNillablePrimary sets the "primary" field if the given value is not nil. -func (au *AttachmentUpdate) SetNillablePrimary(b *bool) *AttachmentUpdate { - if b != nil { - au.SetPrimary(*b) - } - return au -} - // SetItemID sets the "item" edge to the Item entity by ID. func (au *AttachmentUpdate) SetItemID(id uuid.UUID) *AttachmentUpdate { au.mutation.SetItemID(id) @@ -107,7 +93,7 @@ func (au *AttachmentUpdate) ClearDocument() *AttachmentUpdate { // Save executes the query and returns the number of nodes affected by the update operation. func (au *AttachmentUpdate) Save(ctx context.Context) (int, error) { au.defaults() - return withHooks(ctx, au.sqlSave, au.mutation, au.hooks) + return withHooks[int, AttachmentMutation](ctx, au.sqlSave, au.mutation, au.hooks) } // SaveX is like Save, but panics if an error occurs. @@ -174,9 +160,6 @@ func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) { if value, ok := au.mutation.GetType(); ok { _spec.SetField(attachment.FieldType, field.TypeEnum, value) } - if value, ok := au.mutation.Primary(); ok { - _spec.SetField(attachment.FieldPrimary, field.TypeBool, value) - } if au.mutation.ItemCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.M2O, @@ -275,20 +258,6 @@ func (auo *AttachmentUpdateOne) SetNillableType(a *attachment.Type) *AttachmentU return auo } -// SetPrimary sets the "primary" field. -func (auo *AttachmentUpdateOne) SetPrimary(b bool) *AttachmentUpdateOne { - auo.mutation.SetPrimary(b) - return auo -} - -// SetNillablePrimary sets the "primary" field if the given value is not nil. -func (auo *AttachmentUpdateOne) SetNillablePrimary(b *bool) *AttachmentUpdateOne { - if b != nil { - auo.SetPrimary(*b) - } - return auo -} - // SetItemID sets the "item" edge to the Item entity by ID. func (auo *AttachmentUpdateOne) SetItemID(id uuid.UUID) *AttachmentUpdateOne { auo.mutation.SetItemID(id) @@ -344,7 +313,7 @@ func (auo *AttachmentUpdateOne) Select(field string, fields ...string) *Attachme // Save executes the query and returns the updated Attachment entity. func (auo *AttachmentUpdateOne) Save(ctx context.Context) (*Attachment, error) { auo.defaults() - return withHooks(ctx, auo.sqlSave, auo.mutation, auo.hooks) + return withHooks[*Attachment, AttachmentMutation](ctx, auo.sqlSave, auo.mutation, auo.hooks) } // SaveX is like Save, but panics if an error occurs. @@ -428,9 +397,6 @@ func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment, if value, ok := auo.mutation.GetType(); ok { _spec.SetField(attachment.FieldType, field.TypeEnum, value) } - if value, ok := auo.mutation.Primary(); ok { - _spec.SetField(attachment.FieldPrimary, field.TypeBool, value) - } if auo.mutation.ItemCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.M2O, diff --git a/backend/internal/data/ent/authroles.go b/backend/internal/data/ent/authroles.go index 4daa0f6..4dcd733 100644 --- a/backend/internal/data/ent/authroles.go +++ b/backend/internal/data/ent/authroles.go @@ -6,7 +6,6 @@ import ( "fmt" "strings" - "entgo.io/ent" "entgo.io/ent/dialect/sql" "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/data/ent/authroles" @@ -24,7 +23,6 @@ type AuthRoles struct { // The values are being populated by the AuthRolesQuery when eager-loading is set. Edges AuthRolesEdges `json:"edges"` auth_tokens_roles *uuid.UUID - selectValues sql.SelectValues } // AuthRolesEdges holds the relations/edges for other nodes in the graph. @@ -61,7 +59,7 @@ func (*AuthRoles) scanValues(columns []string) ([]any, error) { case authroles.ForeignKeys[0]: // auth_tokens_roles values[i] = &sql.NullScanner{S: new(uuid.UUID)} default: - values[i] = new(sql.UnknownType) + return nil, fmt.Errorf("unexpected column %q for type AuthRoles", columns[i]) } } return values, nil @@ -94,19 +92,11 @@ func (ar *AuthRoles) assignValues(columns []string, values []any) error { ar.auth_tokens_roles = new(uuid.UUID) *ar.auth_tokens_roles = *value.S.(*uuid.UUID) } - default: - ar.selectValues.Set(columns[i], values[i]) } } return nil } -// Value returns the ent.Value that was dynamically selected and assigned to the AuthRoles. -// This includes values selected through modifiers, order, etc. -func (ar *AuthRoles) Value(name string) (ent.Value, error) { - return ar.selectValues.Get(name) -} - // QueryToken queries the "token" edge of the AuthRoles entity. func (ar *AuthRoles) QueryToken() *AuthTokensQuery { return NewAuthRolesClient(ar.config).QueryToken(ar) diff --git a/backend/internal/data/ent/authroles/authroles.go b/backend/internal/data/ent/authroles/authroles.go index bb5e87a..b414e60 100644 --- a/backend/internal/data/ent/authroles/authroles.go +++ b/backend/internal/data/ent/authroles/authroles.go @@ -4,9 +4,6 @@ package authroles import ( "fmt" - - "entgo.io/ent/dialect/sql" - "entgo.io/ent/dialect/sql/sqlgraph" ) const ( @@ -82,30 +79,3 @@ func RoleValidator(r Role) error { return fmt.Errorf("authroles: invalid enum value for role field: %q", r) } } - -// OrderOption defines the ordering options for the AuthRoles queries. -type OrderOption func(*sql.Selector) - -// ByID orders the results by the id field. -func ByID(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldID, opts...).ToFunc() -} - -// ByRole orders the results by the role field. -func ByRole(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldRole, opts...).ToFunc() -} - -// ByTokenField orders the results by token field. -func ByTokenField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newTokenStep(), sql.OrderByField(field, opts...)) - } -} -func newTokenStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(TokenInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.O2O, true, TokenTable, TokenColumn), - ) -} diff --git a/backend/internal/data/ent/authroles/where.go b/backend/internal/data/ent/authroles/where.go index bb5b54a..53978b0 100644 --- a/backend/internal/data/ent/authroles/where.go +++ b/backend/internal/data/ent/authroles/where.go @@ -87,7 +87,11 @@ func HasToken() predicate.AuthRoles { // HasTokenWith applies the HasEdge predicate on the "token" edge with a given conditions (other predicates). func HasTokenWith(preds ...predicate.AuthTokens) predicate.AuthRoles { return predicate.AuthRoles(func(s *sql.Selector) { - step := newTokenStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(TokenInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2O, true, TokenTable, TokenColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -98,15 +102,32 @@ func HasTokenWith(preds ...predicate.AuthTokens) predicate.AuthRoles { // And groups predicates with the AND operator between them. func And(predicates ...predicate.AuthRoles) predicate.AuthRoles { - return predicate.AuthRoles(sql.AndPredicates(predicates...)) + return predicate.AuthRoles(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for _, p := range predicates { + p(s1) + } + s.Where(s1.P()) + }) } // Or groups predicates with the OR operator between them. func Or(predicates ...predicate.AuthRoles) predicate.AuthRoles { - return predicate.AuthRoles(sql.OrPredicates(predicates...)) + return predicate.AuthRoles(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for i, p := range predicates { + if i > 0 { + s1.Or() + } + p(s1) + } + s.Where(s1.P()) + }) } // Not applies the not operator on the given predicate. func Not(p predicate.AuthRoles) predicate.AuthRoles { - return predicate.AuthRoles(sql.NotPredicates(p)) + return predicate.AuthRoles(func(s *sql.Selector) { + p(s.Not()) + }) } diff --git a/backend/internal/data/ent/authroles_create.go b/backend/internal/data/ent/authroles_create.go index 19e594f..64e717c 100644 --- a/backend/internal/data/ent/authroles_create.go +++ b/backend/internal/data/ent/authroles_create.go @@ -62,7 +62,7 @@ func (arc *AuthRolesCreate) Mutation() *AuthRolesMutation { // Save creates the AuthRoles in the database. func (arc *AuthRolesCreate) Save(ctx context.Context) (*AuthRoles, error) { arc.defaults() - return withHooks(ctx, arc.sqlSave, arc.mutation, arc.hooks) + return withHooks[*AuthRoles, AuthRolesMutation](ctx, arc.sqlSave, arc.mutation, arc.hooks) } // SaveX calls Save and panics if Save returns an error. @@ -158,15 +158,11 @@ func (arc *AuthRolesCreate) createSpec() (*AuthRoles, *sqlgraph.CreateSpec) { // AuthRolesCreateBulk is the builder for creating many AuthRoles entities in bulk. type AuthRolesCreateBulk struct { config - err error builders []*AuthRolesCreate } // Save creates the AuthRoles entities in the database. func (arcb *AuthRolesCreateBulk) Save(ctx context.Context) ([]*AuthRoles, error) { - if arcb.err != nil { - return nil, arcb.err - } specs := make([]*sqlgraph.CreateSpec, len(arcb.builders)) nodes := make([]*AuthRoles, len(arcb.builders)) mutators := make([]Mutator, len(arcb.builders)) @@ -183,8 +179,8 @@ func (arcb *AuthRolesCreateBulk) Save(ctx context.Context) ([]*AuthRoles, error) return nil, err } builder.mutation = mutation - var err error nodes[i], specs[i] = builder.createSpec() + var err error if i < len(mutators)-1 { _, err = mutators[i+1].Mutate(root, arcb.builders[i+1].mutation) } else { diff --git a/backend/internal/data/ent/authroles_delete.go b/backend/internal/data/ent/authroles_delete.go index 68a0dfc..13a2518 100644 --- a/backend/internal/data/ent/authroles_delete.go +++ b/backend/internal/data/ent/authroles_delete.go @@ -27,7 +27,7 @@ func (ard *AuthRolesDelete) Where(ps ...predicate.AuthRoles) *AuthRolesDelete { // Exec executes the deletion query and returns how many vertices were deleted. func (ard *AuthRolesDelete) Exec(ctx context.Context) (int, error) { - return withHooks(ctx, ard.sqlExec, ard.mutation, ard.hooks) + return withHooks[int, AuthRolesMutation](ctx, ard.sqlExec, ard.mutation, ard.hooks) } // ExecX is like Exec, but panics if an error occurs. diff --git a/backend/internal/data/ent/authroles_query.go b/backend/internal/data/ent/authroles_query.go index bf47577..14042ff 100644 --- a/backend/internal/data/ent/authroles_query.go +++ b/backend/internal/data/ent/authroles_query.go @@ -20,7 +20,7 @@ import ( type AuthRolesQuery struct { config ctx *QueryContext - order []authroles.OrderOption + order []OrderFunc inters []Interceptor predicates []predicate.AuthRoles withToken *AuthTokensQuery @@ -56,7 +56,7 @@ func (arq *AuthRolesQuery) Unique(unique bool) *AuthRolesQuery { } // Order specifies how the records should be ordered. -func (arq *AuthRolesQuery) Order(o ...authroles.OrderOption) *AuthRolesQuery { +func (arq *AuthRolesQuery) Order(o ...OrderFunc) *AuthRolesQuery { arq.order = append(arq.order, o...) return arq } @@ -272,7 +272,7 @@ func (arq *AuthRolesQuery) Clone() *AuthRolesQuery { return &AuthRolesQuery{ config: arq.config, ctx: arq.ctx.Clone(), - order: append([]authroles.OrderOption{}, arq.order...), + order: append([]OrderFunc{}, arq.order...), inters: append([]Interceptor{}, arq.inters...), predicates: append([]predicate.AuthRoles{}, arq.predicates...), withToken: arq.withToken.Clone(), diff --git a/backend/internal/data/ent/authroles_update.go b/backend/internal/data/ent/authroles_update.go index fbec4f9..9f16e35 100644 --- a/backend/internal/data/ent/authroles_update.go +++ b/backend/internal/data/ent/authroles_update.go @@ -75,7 +75,7 @@ func (aru *AuthRolesUpdate) ClearToken() *AuthRolesUpdate { // Save executes the query and returns the number of nodes affected by the update operation. func (aru *AuthRolesUpdate) Save(ctx context.Context) (int, error) { - return withHooks(ctx, aru.sqlSave, aru.mutation, aru.hooks) + return withHooks[int, AuthRolesMutation](ctx, aru.sqlSave, aru.mutation, aru.hooks) } // SaveX is like Save, but panics if an error occurs. @@ -233,7 +233,7 @@ func (aruo *AuthRolesUpdateOne) Select(field string, fields ...string) *AuthRole // Save executes the query and returns the updated AuthRoles entity. func (aruo *AuthRolesUpdateOne) Save(ctx context.Context) (*AuthRoles, error) { - return withHooks(ctx, aruo.sqlSave, aruo.mutation, aruo.hooks) + return withHooks[*AuthRoles, AuthRolesMutation](ctx, aruo.sqlSave, aruo.mutation, aruo.hooks) } // SaveX is like Save, but panics if an error occurs. diff --git a/backend/internal/data/ent/authtokens.go b/backend/internal/data/ent/authtokens.go index 14299ba..a2b6589 100644 --- a/backend/internal/data/ent/authtokens.go +++ b/backend/internal/data/ent/authtokens.go @@ -7,7 +7,6 @@ import ( "strings" "time" - "entgo.io/ent" "entgo.io/ent/dialect/sql" "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/data/ent/authroles" @@ -32,7 +31,6 @@ type AuthTokens struct { // The values are being populated by the AuthTokensQuery when eager-loading is set. Edges AuthTokensEdges `json:"edges"` user_auth_tokens *uuid.UUID - selectValues sql.SelectValues } // AuthTokensEdges holds the relations/edges for other nodes in the graph. @@ -86,7 +84,7 @@ func (*AuthTokens) scanValues(columns []string) ([]any, error) { case authtokens.ForeignKeys[0]: // user_auth_tokens values[i] = &sql.NullScanner{S: new(uuid.UUID)} default: - values[i] = new(sql.UnknownType) + return nil, fmt.Errorf("unexpected column %q for type AuthTokens", columns[i]) } } return values, nil @@ -137,19 +135,11 @@ func (at *AuthTokens) assignValues(columns []string, values []any) error { at.user_auth_tokens = new(uuid.UUID) *at.user_auth_tokens = *value.S.(*uuid.UUID) } - default: - at.selectValues.Set(columns[i], values[i]) } } return nil } -// Value returns the ent.Value that was dynamically selected and assigned to the AuthTokens. -// This includes values selected through modifiers, order, etc. -func (at *AuthTokens) Value(name string) (ent.Value, error) { - return at.selectValues.Get(name) -} - // QueryUser queries the "user" edge of the AuthTokens entity. func (at *AuthTokens) QueryUser() *UserQuery { return NewAuthTokensClient(at.config).QueryUser(at) diff --git a/backend/internal/data/ent/authtokens/authtokens.go b/backend/internal/data/ent/authtokens/authtokens.go index ff555df..2d809f4 100644 --- a/backend/internal/data/ent/authtokens/authtokens.go +++ b/backend/internal/data/ent/authtokens/authtokens.go @@ -5,8 +5,6 @@ package authtokens import ( "time" - "entgo.io/ent/dialect/sql" - "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" ) @@ -87,54 +85,3 @@ var ( // DefaultID holds the default value on creation for the "id" field. DefaultID func() uuid.UUID ) - -// OrderOption defines the ordering options for the AuthTokens queries. -type OrderOption func(*sql.Selector) - -// ByID orders the results by the id field. -func ByID(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldID, opts...).ToFunc() -} - -// ByCreatedAt orders the results by the created_at field. -func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() -} - -// ByUpdatedAt orders the results by the updated_at field. -func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc() -} - -// ByExpiresAt orders the results by the expires_at field. -func ByExpiresAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldExpiresAt, opts...).ToFunc() -} - -// ByUserField orders the results by user field. -func ByUserField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newUserStep(), sql.OrderByField(field, opts...)) - } -} - -// ByRolesField orders the results by roles field. -func ByRolesField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newRolesStep(), sql.OrderByField(field, opts...)) - } -} -func newUserStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(UserInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, UserTable, UserColumn), - ) -} -func newRolesStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(RolesInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.O2O, false, RolesTable, RolesColumn), - ) -} diff --git a/backend/internal/data/ent/authtokens/where.go b/backend/internal/data/ent/authtokens/where.go index d3642d8..fc2983f 100644 --- a/backend/internal/data/ent/authtokens/where.go +++ b/backend/internal/data/ent/authtokens/where.go @@ -250,7 +250,11 @@ func HasUser() predicate.AuthTokens { // HasUserWith applies the HasEdge predicate on the "user" edge with a given conditions (other predicates). func HasUserWith(preds ...predicate.User) predicate.AuthTokens { return predicate.AuthTokens(func(s *sql.Selector) { - step := newUserStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(UserInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, UserTable, UserColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -273,7 +277,11 @@ func HasRoles() predicate.AuthTokens { // HasRolesWith applies the HasEdge predicate on the "roles" edge with a given conditions (other predicates). func HasRolesWith(preds ...predicate.AuthRoles) predicate.AuthTokens { return predicate.AuthTokens(func(s *sql.Selector) { - step := newRolesStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(RolesInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2O, false, RolesTable, RolesColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -284,15 +292,32 @@ func HasRolesWith(preds ...predicate.AuthRoles) predicate.AuthTokens { // And groups predicates with the AND operator between them. func And(predicates ...predicate.AuthTokens) predicate.AuthTokens { - return predicate.AuthTokens(sql.AndPredicates(predicates...)) + return predicate.AuthTokens(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for _, p := range predicates { + p(s1) + } + s.Where(s1.P()) + }) } // Or groups predicates with the OR operator between them. func Or(predicates ...predicate.AuthTokens) predicate.AuthTokens { - return predicate.AuthTokens(sql.OrPredicates(predicates...)) + return predicate.AuthTokens(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for i, p := range predicates { + if i > 0 { + s1.Or() + } + p(s1) + } + s.Where(s1.P()) + }) } // Not applies the not operator on the given predicate. func Not(p predicate.AuthTokens) predicate.AuthTokens { - return predicate.AuthTokens(sql.NotPredicates(p)) + return predicate.AuthTokens(func(s *sql.Selector) { + p(s.Not()) + }) } diff --git a/backend/internal/data/ent/authtokens_create.go b/backend/internal/data/ent/authtokens_create.go index afddb3b..8ef18d6 100644 --- a/backend/internal/data/ent/authtokens_create.go +++ b/backend/internal/data/ent/authtokens_create.go @@ -131,7 +131,7 @@ func (atc *AuthTokensCreate) Mutation() *AuthTokensMutation { // Save creates the AuthTokens in the database. func (atc *AuthTokensCreate) Save(ctx context.Context) (*AuthTokens, error) { atc.defaults() - return withHooks(ctx, atc.sqlSave, atc.mutation, atc.hooks) + return withHooks[*AuthTokens, AuthTokensMutation](ctx, atc.sqlSave, atc.mutation, atc.hooks) } // SaveX calls Save and panics if Save returns an error. @@ -280,15 +280,11 @@ func (atc *AuthTokensCreate) createSpec() (*AuthTokens, *sqlgraph.CreateSpec) { // AuthTokensCreateBulk is the builder for creating many AuthTokens entities in bulk. type AuthTokensCreateBulk struct { config - err error builders []*AuthTokensCreate } // Save creates the AuthTokens entities in the database. func (atcb *AuthTokensCreateBulk) Save(ctx context.Context) ([]*AuthTokens, error) { - if atcb.err != nil { - return nil, atcb.err - } specs := make([]*sqlgraph.CreateSpec, len(atcb.builders)) nodes := make([]*AuthTokens, len(atcb.builders)) mutators := make([]Mutator, len(atcb.builders)) @@ -305,8 +301,8 @@ func (atcb *AuthTokensCreateBulk) Save(ctx context.Context) ([]*AuthTokens, erro return nil, err } builder.mutation = mutation - var err error nodes[i], specs[i] = builder.createSpec() + var err error if i < len(mutators)-1 { _, err = mutators[i+1].Mutate(root, atcb.builders[i+1].mutation) } else { diff --git a/backend/internal/data/ent/authtokens_delete.go b/backend/internal/data/ent/authtokens_delete.go index 4c29851..1d46fe3 100644 --- a/backend/internal/data/ent/authtokens_delete.go +++ b/backend/internal/data/ent/authtokens_delete.go @@ -27,7 +27,7 @@ func (atd *AuthTokensDelete) Where(ps ...predicate.AuthTokens) *AuthTokensDelete // Exec executes the deletion query and returns how many vertices were deleted. func (atd *AuthTokensDelete) Exec(ctx context.Context) (int, error) { - return withHooks(ctx, atd.sqlExec, atd.mutation, atd.hooks) + return withHooks[int, AuthTokensMutation](ctx, atd.sqlExec, atd.mutation, atd.hooks) } // ExecX is like Exec, but panics if an error occurs. diff --git a/backend/internal/data/ent/authtokens_query.go b/backend/internal/data/ent/authtokens_query.go index 238ab88..5b4302a 100644 --- a/backend/internal/data/ent/authtokens_query.go +++ b/backend/internal/data/ent/authtokens_query.go @@ -22,7 +22,7 @@ import ( type AuthTokensQuery struct { config ctx *QueryContext - order []authtokens.OrderOption + order []OrderFunc inters []Interceptor predicates []predicate.AuthTokens withUser *UserQuery @@ -59,7 +59,7 @@ func (atq *AuthTokensQuery) Unique(unique bool) *AuthTokensQuery { } // Order specifies how the records should be ordered. -func (atq *AuthTokensQuery) Order(o ...authtokens.OrderOption) *AuthTokensQuery { +func (atq *AuthTokensQuery) Order(o ...OrderFunc) *AuthTokensQuery { atq.order = append(atq.order, o...) return atq } @@ -297,7 +297,7 @@ func (atq *AuthTokensQuery) Clone() *AuthTokensQuery { return &AuthTokensQuery{ config: atq.config, ctx: atq.ctx.Clone(), - order: append([]authtokens.OrderOption{}, atq.order...), + order: append([]OrderFunc{}, atq.order...), inters: append([]Interceptor{}, atq.inters...), predicates: append([]predicate.AuthTokens{}, atq.predicates...), withUser: atq.withUser.Clone(), @@ -494,7 +494,7 @@ func (atq *AuthTokensQuery) loadRoles(ctx context.Context, query *AuthRolesQuery } query.withFKs = true query.Where(predicate.AuthRoles(func(s *sql.Selector) { - s.Where(sql.InValues(s.C(authtokens.RolesColumn), fks...)) + s.Where(sql.InValues(authtokens.RolesColumn, fks...)) })) neighbors, err := query.All(ctx) if err != nil { @@ -507,7 +507,7 @@ func (atq *AuthTokensQuery) loadRoles(ctx context.Context, query *AuthRolesQuery } node, ok := nodeids[*fk] if !ok { - return fmt.Errorf(`unexpected referenced foreign-key "auth_tokens_roles" returned %v for node %v`, *fk, n.ID) + return fmt.Errorf(`unexpected foreign-key "auth_tokens_roles" returned %v for node %v`, *fk, n.ID) } assign(node, n) } diff --git a/backend/internal/data/ent/authtokens_update.go b/backend/internal/data/ent/authtokens_update.go index 776888e..2ed3e83 100644 --- a/backend/internal/data/ent/authtokens_update.go +++ b/backend/internal/data/ent/authtokens_update.go @@ -115,7 +115,7 @@ func (atu *AuthTokensUpdate) ClearRoles() *AuthTokensUpdate { // Save executes the query and returns the number of nodes affected by the update operation. func (atu *AuthTokensUpdate) Save(ctx context.Context) (int, error) { atu.defaults() - return withHooks(ctx, atu.sqlSave, atu.mutation, atu.hooks) + return withHooks[int, AuthTokensMutation](ctx, atu.sqlSave, atu.mutation, atu.hooks) } // SaveX is like Save, but panics if an error occurs. @@ -341,7 +341,7 @@ func (atuo *AuthTokensUpdateOne) Select(field string, fields ...string) *AuthTok // Save executes the query and returns the updated AuthTokens entity. func (atuo *AuthTokensUpdateOne) Save(ctx context.Context) (*AuthTokens, error) { atuo.defaults() - return withHooks(ctx, atuo.sqlSave, atuo.mutation, atuo.hooks) + return withHooks[*AuthTokens, AuthTokensMutation](ctx, atuo.sqlSave, atuo.mutation, atuo.hooks) } // SaveX is like Save, but panics if an error occurs. diff --git a/backend/internal/data/ent/client.go b/backend/internal/data/ent/client.go index 2fb9b53..6b4fbe3 100644 --- a/backend/internal/data/ent/client.go +++ b/backend/internal/data/ent/client.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "log" - "reflect" "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/data/ent/migrate" @@ -66,7 +65,9 @@ type Client struct { // NewClient creates a new client configured with the given options. func NewClient(opts ...Option) *Client { - client := &Client{config: newConfig(opts...)} + cfg := config{log: log.Println, hooks: &hooks{}, inters: &inters{}} + cfg.options(opts...) + client := &Client{config: cfg} client.init() return client } @@ -106,13 +107,6 @@ type ( Option func(*config) ) -// newConfig creates a new config for the client. -func newConfig(opts ...Option) config { - cfg := config{log: log.Println, hooks: &hooks{}, inters: &inters{}} - cfg.options(opts...) - return cfg -} - // options applies the options on the config object. func (c *config) options(opts ...Option) { for _, opt := range opts { @@ -160,14 +154,11 @@ func Open(driverName, dataSourceName string, options ...Option) (*Client, error) } } -// ErrTxStarted is returned when trying to start a new transaction from a transactional client. -var ErrTxStarted = errors.New("ent: cannot start a transaction within a transaction") - // Tx returns a new transactional client. The provided context // is used until the transaction is committed or rolled back. func (c *Client) Tx(ctx context.Context) (*Tx, error) { if _, ok := c.driver.(*txDriver); ok { - return nil, ErrTxStarted + return nil, errors.New("ent: cannot start a transaction within a transaction") } tx, err := newTx(ctx, c.driver) if err != nil { @@ -339,21 +330,6 @@ func (c *AttachmentClient) CreateBulk(builders ...*AttachmentCreate) *Attachment return &AttachmentCreateBulk{config: c.config, builders: builders} } -// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates -// a builder and applies setFunc on it. -func (c *AttachmentClient) MapCreateBulk(slice any, setFunc func(*AttachmentCreate, int)) *AttachmentCreateBulk { - rv := reflect.ValueOf(slice) - if rv.Kind() != reflect.Slice { - return &AttachmentCreateBulk{err: fmt.Errorf("calling to AttachmentClient.MapCreateBulk with wrong type %T, need slice", slice)} - } - builders := make([]*AttachmentCreate, rv.Len()) - for i := 0; i < rv.Len(); i++ { - builders[i] = c.Create() - setFunc(builders[i], i) - } - return &AttachmentCreateBulk{config: c.config, builders: builders} -} - // Update returns an update builder for Attachment. func (c *AttachmentClient) Update() *AttachmentUpdate { mutation := newAttachmentMutation(c.config, OpUpdate) @@ -504,21 +480,6 @@ func (c *AuthRolesClient) CreateBulk(builders ...*AuthRolesCreate) *AuthRolesCre return &AuthRolesCreateBulk{config: c.config, builders: builders} } -// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates -// a builder and applies setFunc on it. -func (c *AuthRolesClient) MapCreateBulk(slice any, setFunc func(*AuthRolesCreate, int)) *AuthRolesCreateBulk { - rv := reflect.ValueOf(slice) - if rv.Kind() != reflect.Slice { - return &AuthRolesCreateBulk{err: fmt.Errorf("calling to AuthRolesClient.MapCreateBulk with wrong type %T, need slice", slice)} - } - builders := make([]*AuthRolesCreate, rv.Len()) - for i := 0; i < rv.Len(); i++ { - builders[i] = c.Create() - setFunc(builders[i], i) - } - return &AuthRolesCreateBulk{config: c.config, builders: builders} -} - // Update returns an update builder for AuthRoles. func (c *AuthRolesClient) Update() *AuthRolesUpdate { mutation := newAuthRolesMutation(c.config, OpUpdate) @@ -653,21 +614,6 @@ func (c *AuthTokensClient) CreateBulk(builders ...*AuthTokensCreate) *AuthTokens return &AuthTokensCreateBulk{config: c.config, builders: builders} } -// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates -// a builder and applies setFunc on it. -func (c *AuthTokensClient) MapCreateBulk(slice any, setFunc func(*AuthTokensCreate, int)) *AuthTokensCreateBulk { - rv := reflect.ValueOf(slice) - if rv.Kind() != reflect.Slice { - return &AuthTokensCreateBulk{err: fmt.Errorf("calling to AuthTokensClient.MapCreateBulk with wrong type %T, need slice", slice)} - } - builders := make([]*AuthTokensCreate, rv.Len()) - for i := 0; i < rv.Len(); i++ { - builders[i] = c.Create() - setFunc(builders[i], i) - } - return &AuthTokensCreateBulk{config: c.config, builders: builders} -} - // Update returns an update builder for AuthTokens. func (c *AuthTokensClient) Update() *AuthTokensUpdate { mutation := newAuthTokensMutation(c.config, OpUpdate) @@ -818,21 +764,6 @@ func (c *DocumentClient) CreateBulk(builders ...*DocumentCreate) *DocumentCreate return &DocumentCreateBulk{config: c.config, builders: builders} } -// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates -// a builder and applies setFunc on it. -func (c *DocumentClient) MapCreateBulk(slice any, setFunc func(*DocumentCreate, int)) *DocumentCreateBulk { - rv := reflect.ValueOf(slice) - if rv.Kind() != reflect.Slice { - return &DocumentCreateBulk{err: fmt.Errorf("calling to DocumentClient.MapCreateBulk with wrong type %T, need slice", slice)} - } - builders := make([]*DocumentCreate, rv.Len()) - for i := 0; i < rv.Len(); i++ { - builders[i] = c.Create() - setFunc(builders[i], i) - } - return &DocumentCreateBulk{config: c.config, builders: builders} -} - // Update returns an update builder for Document. func (c *DocumentClient) Update() *DocumentUpdate { mutation := newDocumentMutation(c.config, OpUpdate) @@ -983,21 +914,6 @@ func (c *GroupClient) CreateBulk(builders ...*GroupCreate) *GroupCreateBulk { return &GroupCreateBulk{config: c.config, builders: builders} } -// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates -// a builder and applies setFunc on it. -func (c *GroupClient) MapCreateBulk(slice any, setFunc func(*GroupCreate, int)) *GroupCreateBulk { - rv := reflect.ValueOf(slice) - if rv.Kind() != reflect.Slice { - return &GroupCreateBulk{err: fmt.Errorf("calling to GroupClient.MapCreateBulk with wrong type %T, need slice", slice)} - } - builders := make([]*GroupCreate, rv.Len()) - for i := 0; i < rv.Len(); i++ { - builders[i] = c.Create() - setFunc(builders[i], i) - } - return &GroupCreateBulk{config: c.config, builders: builders} -} - // Update returns an update builder for Group. func (c *GroupClient) Update() *GroupUpdate { mutation := newGroupMutation(c.config, OpUpdate) @@ -1228,21 +1144,6 @@ func (c *GroupInvitationTokenClient) CreateBulk(builders ...*GroupInvitationToke return &GroupInvitationTokenCreateBulk{config: c.config, builders: builders} } -// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates -// a builder and applies setFunc on it. -func (c *GroupInvitationTokenClient) MapCreateBulk(slice any, setFunc func(*GroupInvitationTokenCreate, int)) *GroupInvitationTokenCreateBulk { - rv := reflect.ValueOf(slice) - if rv.Kind() != reflect.Slice { - return &GroupInvitationTokenCreateBulk{err: fmt.Errorf("calling to GroupInvitationTokenClient.MapCreateBulk with wrong type %T, need slice", slice)} - } - builders := make([]*GroupInvitationTokenCreate, rv.Len()) - for i := 0; i < rv.Len(); i++ { - builders[i] = c.Create() - setFunc(builders[i], i) - } - return &GroupInvitationTokenCreateBulk{config: c.config, builders: builders} -} - // Update returns an update builder for GroupInvitationToken. func (c *GroupInvitationTokenClient) Update() *GroupInvitationTokenUpdate { mutation := newGroupInvitationTokenMutation(c.config, OpUpdate) @@ -1377,21 +1278,6 @@ func (c *ItemClient) CreateBulk(builders ...*ItemCreate) *ItemCreateBulk { return &ItemCreateBulk{config: c.config, builders: builders} } -// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates -// a builder and applies setFunc on it. -func (c *ItemClient) MapCreateBulk(slice any, setFunc func(*ItemCreate, int)) *ItemCreateBulk { - rv := reflect.ValueOf(slice) - if rv.Kind() != reflect.Slice { - return &ItemCreateBulk{err: fmt.Errorf("calling to ItemClient.MapCreateBulk with wrong type %T, need slice", slice)} - } - builders := make([]*ItemCreate, rv.Len()) - for i := 0; i < rv.Len(); i++ { - builders[i] = c.Create() - setFunc(builders[i], i) - } - return &ItemCreateBulk{config: c.config, builders: builders} -} - // Update returns an update builder for Item. func (c *ItemClient) Update() *ItemUpdate { mutation := newItemMutation(c.config, OpUpdate) @@ -1638,21 +1524,6 @@ func (c *ItemFieldClient) CreateBulk(builders ...*ItemFieldCreate) *ItemFieldCre return &ItemFieldCreateBulk{config: c.config, builders: builders} } -// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates -// a builder and applies setFunc on it. -func (c *ItemFieldClient) MapCreateBulk(slice any, setFunc func(*ItemFieldCreate, int)) *ItemFieldCreateBulk { - rv := reflect.ValueOf(slice) - if rv.Kind() != reflect.Slice { - return &ItemFieldCreateBulk{err: fmt.Errorf("calling to ItemFieldClient.MapCreateBulk with wrong type %T, need slice", slice)} - } - builders := make([]*ItemFieldCreate, rv.Len()) - for i := 0; i < rv.Len(); i++ { - builders[i] = c.Create() - setFunc(builders[i], i) - } - return &ItemFieldCreateBulk{config: c.config, builders: builders} -} - // Update returns an update builder for ItemField. func (c *ItemFieldClient) Update() *ItemFieldUpdate { mutation := newItemFieldMutation(c.config, OpUpdate) @@ -1787,21 +1658,6 @@ func (c *LabelClient) CreateBulk(builders ...*LabelCreate) *LabelCreateBulk { return &LabelCreateBulk{config: c.config, builders: builders} } -// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates -// a builder and applies setFunc on it. -func (c *LabelClient) MapCreateBulk(slice any, setFunc func(*LabelCreate, int)) *LabelCreateBulk { - rv := reflect.ValueOf(slice) - if rv.Kind() != reflect.Slice { - return &LabelCreateBulk{err: fmt.Errorf("calling to LabelClient.MapCreateBulk with wrong type %T, need slice", slice)} - } - builders := make([]*LabelCreate, rv.Len()) - for i := 0; i < rv.Len(); i++ { - builders[i] = c.Create() - setFunc(builders[i], i) - } - return &LabelCreateBulk{config: c.config, builders: builders} -} - // Update returns an update builder for Label. func (c *LabelClient) Update() *LabelUpdate { mutation := newLabelMutation(c.config, OpUpdate) @@ -1952,21 +1808,6 @@ func (c *LocationClient) CreateBulk(builders ...*LocationCreate) *LocationCreate return &LocationCreateBulk{config: c.config, builders: builders} } -// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates -// a builder and applies setFunc on it. -func (c *LocationClient) MapCreateBulk(slice any, setFunc func(*LocationCreate, int)) *LocationCreateBulk { - rv := reflect.ValueOf(slice) - if rv.Kind() != reflect.Slice { - return &LocationCreateBulk{err: fmt.Errorf("calling to LocationClient.MapCreateBulk with wrong type %T, need slice", slice)} - } - builders := make([]*LocationCreate, rv.Len()) - for i := 0; i < rv.Len(); i++ { - builders[i] = c.Create() - setFunc(builders[i], i) - } - return &LocationCreateBulk{config: c.config, builders: builders} -} - // Update returns an update builder for Location. func (c *LocationClient) Update() *LocationUpdate { mutation := newLocationMutation(c.config, OpUpdate) @@ -2149,21 +1990,6 @@ func (c *MaintenanceEntryClient) CreateBulk(builders ...*MaintenanceEntryCreate) return &MaintenanceEntryCreateBulk{config: c.config, builders: builders} } -// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates -// a builder and applies setFunc on it. -func (c *MaintenanceEntryClient) MapCreateBulk(slice any, setFunc func(*MaintenanceEntryCreate, int)) *MaintenanceEntryCreateBulk { - rv := reflect.ValueOf(slice) - if rv.Kind() != reflect.Slice { - return &MaintenanceEntryCreateBulk{err: fmt.Errorf("calling to MaintenanceEntryClient.MapCreateBulk with wrong type %T, need slice", slice)} - } - builders := make([]*MaintenanceEntryCreate, rv.Len()) - for i := 0; i < rv.Len(); i++ { - builders[i] = c.Create() - setFunc(builders[i], i) - } - return &MaintenanceEntryCreateBulk{config: c.config, builders: builders} -} - // Update returns an update builder for MaintenanceEntry. func (c *MaintenanceEntryClient) Update() *MaintenanceEntryUpdate { mutation := newMaintenanceEntryMutation(c.config, OpUpdate) @@ -2298,21 +2124,6 @@ func (c *NotifierClient) CreateBulk(builders ...*NotifierCreate) *NotifierCreate return &NotifierCreateBulk{config: c.config, builders: builders} } -// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates -// a builder and applies setFunc on it. -func (c *NotifierClient) MapCreateBulk(slice any, setFunc func(*NotifierCreate, int)) *NotifierCreateBulk { - rv := reflect.ValueOf(slice) - if rv.Kind() != reflect.Slice { - return &NotifierCreateBulk{err: fmt.Errorf("calling to NotifierClient.MapCreateBulk with wrong type %T, need slice", slice)} - } - builders := make([]*NotifierCreate, rv.Len()) - for i := 0; i < rv.Len(); i++ { - builders[i] = c.Create() - setFunc(builders[i], i) - } - return &NotifierCreateBulk{config: c.config, builders: builders} -} - // Update returns an update builder for Notifier. func (c *NotifierClient) Update() *NotifierUpdate { mutation := newNotifierMutation(c.config, OpUpdate) @@ -2463,21 +2274,6 @@ func (c *UserClient) CreateBulk(builders ...*UserCreate) *UserCreateBulk { return &UserCreateBulk{config: c.config, builders: builders} } -// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates -// a builder and applies setFunc on it. -func (c *UserClient) MapCreateBulk(slice any, setFunc func(*UserCreate, int)) *UserCreateBulk { - rv := reflect.ValueOf(slice) - if rv.Kind() != reflect.Slice { - return &UserCreateBulk{err: fmt.Errorf("calling to UserClient.MapCreateBulk with wrong type %T, need slice", slice)} - } - builders := make([]*UserCreate, rv.Len()) - for i := 0; i < rv.Len(); i++ { - builders[i] = c.Create() - setFunc(builders[i], i) - } - return &UserCreateBulk{config: c.config, builders: builders} -} - // Update returns an update builder for User. func (c *UserClient) Update() *UserUpdate { mutation := newUserMutation(c.config, OpUpdate) diff --git a/backend/internal/data/ent/document.go b/backend/internal/data/ent/document.go index 3141bac..bcaae9a 100644 --- a/backend/internal/data/ent/document.go +++ b/backend/internal/data/ent/document.go @@ -7,7 +7,6 @@ import ( "strings" "time" - "entgo.io/ent" "entgo.io/ent/dialect/sql" "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/data/ent/document" @@ -31,7 +30,6 @@ type Document struct { // The values are being populated by the DocumentQuery when eager-loading is set. Edges DocumentEdges `json:"edges"` group_documents *uuid.UUID - selectValues sql.SelectValues } // DocumentEdges holds the relations/edges for other nodes in the graph. @@ -81,7 +79,7 @@ func (*Document) scanValues(columns []string) ([]any, error) { case document.ForeignKeys[0]: // group_documents values[i] = &sql.NullScanner{S: new(uuid.UUID)} default: - values[i] = new(sql.UnknownType) + return nil, fmt.Errorf("unexpected column %q for type Document", columns[i]) } } return values, nil @@ -132,19 +130,11 @@ func (d *Document) assignValues(columns []string, values []any) error { d.group_documents = new(uuid.UUID) *d.group_documents = *value.S.(*uuid.UUID) } - default: - d.selectValues.Set(columns[i], values[i]) } } return nil } -// Value returns the ent.Value that was dynamically selected and assigned to the Document. -// This includes values selected through modifiers, order, etc. -func (d *Document) Value(name string) (ent.Value, error) { - return d.selectValues.Get(name) -} - // QueryGroup queries the "group" edge of the Document entity. func (d *Document) QueryGroup() *GroupQuery { return NewDocumentClient(d.config).QueryGroup(d) diff --git a/backend/internal/data/ent/document/document.go b/backend/internal/data/ent/document/document.go index 95380f4..b6a15eb 100644 --- a/backend/internal/data/ent/document/document.go +++ b/backend/internal/data/ent/document/document.go @@ -5,8 +5,6 @@ package document import ( "time" - "entgo.io/ent/dialect/sql" - "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" ) @@ -89,66 +87,3 @@ var ( // DefaultID holds the default value on creation for the "id" field. DefaultID func() uuid.UUID ) - -// OrderOption defines the ordering options for the Document queries. -type OrderOption func(*sql.Selector) - -// ByID orders the results by the id field. -func ByID(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldID, opts...).ToFunc() -} - -// ByCreatedAt orders the results by the created_at field. -func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() -} - -// ByUpdatedAt orders the results by the updated_at field. -func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc() -} - -// ByTitle orders the results by the title field. -func ByTitle(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldTitle, opts...).ToFunc() -} - -// ByPath orders the results by the path field. -func ByPath(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldPath, opts...).ToFunc() -} - -// ByGroupField orders the results by group field. -func ByGroupField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newGroupStep(), sql.OrderByField(field, opts...)) - } -} - -// ByAttachmentsCount orders the results by attachments count. -func ByAttachmentsCount(opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborsCount(s, newAttachmentsStep(), opts...) - } -} - -// ByAttachments orders the results by attachments terms. -func ByAttachments(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newAttachmentsStep(), append([]sql.OrderTerm{term}, terms...)...) - } -} -func newGroupStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(GroupInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn), - ) -} -func newAttachmentsStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(AttachmentsInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, AttachmentsTable, AttachmentsColumn), - ) -} diff --git a/backend/internal/data/ent/document/where.go b/backend/internal/data/ent/document/where.go index 3e491ad..614cf4e 100644 --- a/backend/internal/data/ent/document/where.go +++ b/backend/internal/data/ent/document/where.go @@ -300,7 +300,11 @@ func HasGroup() predicate.Document { // HasGroupWith applies the HasEdge predicate on the "group" edge with a given conditions (other predicates). func HasGroupWith(preds ...predicate.Group) predicate.Document { return predicate.Document(func(s *sql.Selector) { - step := newGroupStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(GroupInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -323,7 +327,11 @@ func HasAttachments() predicate.Document { // HasAttachmentsWith applies the HasEdge predicate on the "attachments" edge with a given conditions (other predicates). func HasAttachmentsWith(preds ...predicate.Attachment) predicate.Document { return predicate.Document(func(s *sql.Selector) { - step := newAttachmentsStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(AttachmentsInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, AttachmentsTable, AttachmentsColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -334,15 +342,32 @@ func HasAttachmentsWith(preds ...predicate.Attachment) predicate.Document { // And groups predicates with the AND operator between them. func And(predicates ...predicate.Document) predicate.Document { - return predicate.Document(sql.AndPredicates(predicates...)) + return predicate.Document(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for _, p := range predicates { + p(s1) + } + s.Where(s1.P()) + }) } // Or groups predicates with the OR operator between them. func Or(predicates ...predicate.Document) predicate.Document { - return predicate.Document(sql.OrPredicates(predicates...)) + return predicate.Document(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for i, p := range predicates { + if i > 0 { + s1.Or() + } + p(s1) + } + s.Where(s1.P()) + }) } // Not applies the not operator on the given predicate. func Not(p predicate.Document) predicate.Document { - return predicate.Document(sql.NotPredicates(p)) + return predicate.Document(func(s *sql.Selector) { + p(s.Not()) + }) } diff --git a/backend/internal/data/ent/document_create.go b/backend/internal/data/ent/document_create.go index fe61e98..efda81f 100644 --- a/backend/internal/data/ent/document_create.go +++ b/backend/internal/data/ent/document_create.go @@ -111,7 +111,7 @@ func (dc *DocumentCreate) Mutation() *DocumentMutation { // Save creates the Document in the database. func (dc *DocumentCreate) Save(ctx context.Context) (*Document, error) { dc.defaults() - return withHooks(ctx, dc.sqlSave, dc.mutation, dc.hooks) + return withHooks[*Document, DocumentMutation](ctx, dc.sqlSave, dc.mutation, dc.hooks) } // SaveX calls Save and panics if Save returns an error. @@ -269,15 +269,11 @@ func (dc *DocumentCreate) createSpec() (*Document, *sqlgraph.CreateSpec) { // DocumentCreateBulk is the builder for creating many Document entities in bulk. type DocumentCreateBulk struct { config - err error builders []*DocumentCreate } // Save creates the Document entities in the database. func (dcb *DocumentCreateBulk) Save(ctx context.Context) ([]*Document, error) { - if dcb.err != nil { - return nil, dcb.err - } specs := make([]*sqlgraph.CreateSpec, len(dcb.builders)) nodes := make([]*Document, len(dcb.builders)) mutators := make([]Mutator, len(dcb.builders)) @@ -294,8 +290,8 @@ func (dcb *DocumentCreateBulk) Save(ctx context.Context) ([]*Document, error) { return nil, err } builder.mutation = mutation - var err error nodes[i], specs[i] = builder.createSpec() + var err error if i < len(mutators)-1 { _, err = mutators[i+1].Mutate(root, dcb.builders[i+1].mutation) } else { diff --git a/backend/internal/data/ent/document_delete.go b/backend/internal/data/ent/document_delete.go index 5901c03..d0481d3 100644 --- a/backend/internal/data/ent/document_delete.go +++ b/backend/internal/data/ent/document_delete.go @@ -27,7 +27,7 @@ func (dd *DocumentDelete) Where(ps ...predicate.Document) *DocumentDelete { // Exec executes the deletion query and returns how many vertices were deleted. func (dd *DocumentDelete) Exec(ctx context.Context) (int, error) { - return withHooks(ctx, dd.sqlExec, dd.mutation, dd.hooks) + return withHooks[int, DocumentMutation](ctx, dd.sqlExec, dd.mutation, dd.hooks) } // ExecX is like Exec, but panics if an error occurs. diff --git a/backend/internal/data/ent/document_query.go b/backend/internal/data/ent/document_query.go index 34f4801..e22abe2 100644 --- a/backend/internal/data/ent/document_query.go +++ b/backend/internal/data/ent/document_query.go @@ -22,7 +22,7 @@ import ( type DocumentQuery struct { config ctx *QueryContext - order []document.OrderOption + order []OrderFunc inters []Interceptor predicates []predicate.Document withGroup *GroupQuery @@ -59,7 +59,7 @@ func (dq *DocumentQuery) Unique(unique bool) *DocumentQuery { } // Order specifies how the records should be ordered. -func (dq *DocumentQuery) Order(o ...document.OrderOption) *DocumentQuery { +func (dq *DocumentQuery) Order(o ...OrderFunc) *DocumentQuery { dq.order = append(dq.order, o...) return dq } @@ -297,7 +297,7 @@ func (dq *DocumentQuery) Clone() *DocumentQuery { return &DocumentQuery{ config: dq.config, ctx: dq.ctx.Clone(), - order: append([]document.OrderOption{}, dq.order...), + order: append([]OrderFunc{}, dq.order...), inters: append([]Interceptor{}, dq.inters...), predicates: append([]predicate.Document{}, dq.predicates...), withGroup: dq.withGroup.Clone(), @@ -498,7 +498,7 @@ func (dq *DocumentQuery) loadAttachments(ctx context.Context, query *AttachmentQ } query.withFKs = true query.Where(predicate.Attachment(func(s *sql.Selector) { - s.Where(sql.InValues(s.C(document.AttachmentsColumn), fks...)) + s.Where(sql.InValues(document.AttachmentsColumn, fks...)) })) neighbors, err := query.All(ctx) if err != nil { @@ -511,7 +511,7 @@ func (dq *DocumentQuery) loadAttachments(ctx context.Context, query *AttachmentQ } node, ok := nodeids[*fk] if !ok { - return fmt.Errorf(`unexpected referenced foreign-key "document_attachments" returned %v for node %v`, *fk, n.ID) + return fmt.Errorf(`unexpected foreign-key "document_attachments" returned %v for node %v`, *fk, n.ID) } assign(node, n) } diff --git a/backend/internal/data/ent/document_update.go b/backend/internal/data/ent/document_update.go index 23e6d9c..0d4a028 100644 --- a/backend/internal/data/ent/document_update.go +++ b/backend/internal/data/ent/document_update.go @@ -43,28 +43,12 @@ func (du *DocumentUpdate) SetTitle(s string) *DocumentUpdate { return du } -// SetNillableTitle sets the "title" field if the given value is not nil. -func (du *DocumentUpdate) SetNillableTitle(s *string) *DocumentUpdate { - if s != nil { - du.SetTitle(*s) - } - return du -} - // SetPath sets the "path" field. func (du *DocumentUpdate) SetPath(s string) *DocumentUpdate { du.mutation.SetPath(s) return du } -// SetNillablePath sets the "path" field if the given value is not nil. -func (du *DocumentUpdate) SetNillablePath(s *string) *DocumentUpdate { - if s != nil { - du.SetPath(*s) - } - return du -} - // SetGroupID sets the "group" edge to the Group entity by ID. func (du *DocumentUpdate) SetGroupID(id uuid.UUID) *DocumentUpdate { du.mutation.SetGroupID(id) @@ -126,7 +110,7 @@ func (du *DocumentUpdate) RemoveAttachments(a ...*Attachment) *DocumentUpdate { // Save executes the query and returns the number of nodes affected by the update operation. func (du *DocumentUpdate) Save(ctx context.Context) (int, error) { du.defaults() - return withHooks(ctx, du.sqlSave, du.mutation, du.hooks) + return withHooks[int, DocumentMutation](ctx, du.sqlSave, du.mutation, du.hooks) } // SaveX is like Save, but panics if an error occurs. @@ -304,28 +288,12 @@ func (duo *DocumentUpdateOne) SetTitle(s string) *DocumentUpdateOne { return duo } -// SetNillableTitle sets the "title" field if the given value is not nil. -func (duo *DocumentUpdateOne) SetNillableTitle(s *string) *DocumentUpdateOne { - if s != nil { - duo.SetTitle(*s) - } - return duo -} - // SetPath sets the "path" field. func (duo *DocumentUpdateOne) SetPath(s string) *DocumentUpdateOne { duo.mutation.SetPath(s) return duo } -// SetNillablePath sets the "path" field if the given value is not nil. -func (duo *DocumentUpdateOne) SetNillablePath(s *string) *DocumentUpdateOne { - if s != nil { - duo.SetPath(*s) - } - return duo -} - // SetGroupID sets the "group" edge to the Group entity by ID. func (duo *DocumentUpdateOne) SetGroupID(id uuid.UUID) *DocumentUpdateOne { duo.mutation.SetGroupID(id) @@ -400,7 +368,7 @@ func (duo *DocumentUpdateOne) Select(field string, fields ...string) *DocumentUp // Save executes the query and returns the updated Document entity. func (duo *DocumentUpdateOne) Save(ctx context.Context) (*Document, error) { duo.defaults() - return withHooks(ctx, duo.sqlSave, duo.mutation, duo.hooks) + return withHooks[*Document, DocumentMutation](ctx, duo.sqlSave, duo.mutation, duo.hooks) } // SaveX is like Save, but panics if an error occurs. diff --git a/backend/internal/data/ent/ent.go b/backend/internal/data/ent/ent.go index 6e52ac8..ba8d451 100644 --- a/backend/internal/data/ent/ent.go +++ b/backend/internal/data/ent/ent.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "reflect" - "sync" "entgo.io/ent" "entgo.io/ent/dialect/sql" @@ -73,41 +72,45 @@ func NewTxContext(parent context.Context, tx *Tx) context.Context { } // OrderFunc applies an ordering on the sql selector. -// Deprecated: Use Asc/Desc functions or the package builders instead. type OrderFunc func(*sql.Selector) -var ( - initCheck sync.Once - columnCheck sql.ColumnCheck -) - -// columnChecker checks if the column exists in the given table. -func checkColumn(table, column string) error { - initCheck.Do(func() { - columnCheck = sql.NewColumnCheck(map[string]func(string) bool{ - attachment.Table: attachment.ValidColumn, - authroles.Table: authroles.ValidColumn, - authtokens.Table: authtokens.ValidColumn, - document.Table: document.ValidColumn, - group.Table: group.ValidColumn, - groupinvitationtoken.Table: groupinvitationtoken.ValidColumn, - item.Table: item.ValidColumn, - itemfield.Table: itemfield.ValidColumn, - label.Table: label.ValidColumn, - location.Table: location.ValidColumn, - maintenanceentry.Table: maintenanceentry.ValidColumn, - notifier.Table: notifier.ValidColumn, - user.Table: user.ValidColumn, - }) - }) - return columnCheck(table, column) +// columnChecker returns a function indicates if the column exists in the given column. +func columnChecker(table string) func(string) error { + checks := map[string]func(string) bool{ + attachment.Table: attachment.ValidColumn, + authroles.Table: authroles.ValidColumn, + authtokens.Table: authtokens.ValidColumn, + document.Table: document.ValidColumn, + group.Table: group.ValidColumn, + groupinvitationtoken.Table: groupinvitationtoken.ValidColumn, + item.Table: item.ValidColumn, + itemfield.Table: itemfield.ValidColumn, + label.Table: label.ValidColumn, + location.Table: location.ValidColumn, + maintenanceentry.Table: maintenanceentry.ValidColumn, + notifier.Table: notifier.ValidColumn, + user.Table: user.ValidColumn, + } + check, ok := checks[table] + if !ok { + return func(string) error { + return fmt.Errorf("unknown table %q", table) + } + } + return func(column string) error { + if !check(column) { + return fmt.Errorf("unknown column %q for table %q", column, table) + } + return nil + } } // Asc applies the given fields in ASC order. -func Asc(fields ...string) func(*sql.Selector) { +func Asc(fields ...string) OrderFunc { return func(s *sql.Selector) { + check := columnChecker(s.TableName()) for _, f := range fields { - if err := checkColumn(s.TableName(), f); err != nil { + if err := check(f); err != nil { s.AddError(&ValidationError{Name: f, err: fmt.Errorf("ent: %w", err)}) } s.OrderBy(sql.Asc(s.C(f))) @@ -116,10 +119,11 @@ func Asc(fields ...string) func(*sql.Selector) { } // Desc applies the given fields in DESC order. -func Desc(fields ...string) func(*sql.Selector) { +func Desc(fields ...string) OrderFunc { return func(s *sql.Selector) { + check := columnChecker(s.TableName()) for _, f := range fields { - if err := checkColumn(s.TableName(), f); err != nil { + if err := check(f); err != nil { s.AddError(&ValidationError{Name: f, err: fmt.Errorf("ent: %w", err)}) } s.OrderBy(sql.Desc(s.C(f))) @@ -151,7 +155,8 @@ func Count() AggregateFunc { // Max applies the "max" aggregation function on the given field of each group. func Max(field string) AggregateFunc { return func(s *sql.Selector) string { - if err := checkColumn(s.TableName(), field); err != nil { + check := columnChecker(s.TableName()) + if err := check(field); err != nil { s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) return "" } @@ -162,7 +167,8 @@ func Max(field string) AggregateFunc { // Mean applies the "mean" aggregation function on the given field of each group. func Mean(field string) AggregateFunc { return func(s *sql.Selector) string { - if err := checkColumn(s.TableName(), field); err != nil { + check := columnChecker(s.TableName()) + if err := check(field); err != nil { s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) return "" } @@ -173,7 +179,8 @@ func Mean(field string) AggregateFunc { // Min applies the "min" aggregation function on the given field of each group. func Min(field string) AggregateFunc { return func(s *sql.Selector) string { - if err := checkColumn(s.TableName(), field); err != nil { + check := columnChecker(s.TableName()) + if err := check(field); err != nil { s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) return "" } @@ -184,7 +191,8 @@ func Min(field string) AggregateFunc { // Sum applies the "sum" aggregation function on the given field of each group. func Sum(field string) AggregateFunc { return func(s *sql.Selector) string { - if err := checkColumn(s.TableName(), field); err != nil { + check := columnChecker(s.TableName()) + if err := check(field); err != nil { s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) return "" } diff --git a/backend/internal/data/ent/group.go b/backend/internal/data/ent/group.go index 69c67de..f7ad99c 100644 --- a/backend/internal/data/ent/group.go +++ b/backend/internal/data/ent/group.go @@ -7,7 +7,6 @@ import ( "strings" "time" - "entgo.io/ent" "entgo.io/ent/dialect/sql" "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/data/ent/group" @@ -25,11 +24,10 @@ type Group struct { // Name holds the value of the "name" field. Name string `json:"name,omitempty"` // Currency holds the value of the "currency" field. - Currency string `json:"currency,omitempty"` + Currency group.Currency `json:"currency,omitempty"` // Edges holds the relations/edges for other nodes in the graph. // The values are being populated by the GroupQuery when eager-loading is set. - Edges GroupEdges `json:"edges"` - selectValues sql.SelectValues + Edges GroupEdges `json:"edges"` } // GroupEdges holds the relations/edges for other nodes in the graph. @@ -128,7 +126,7 @@ func (*Group) scanValues(columns []string) ([]any, error) { case group.FieldID: values[i] = new(uuid.UUID) default: - values[i] = new(sql.UnknownType) + return nil, fmt.Errorf("unexpected column %q for type Group", columns[i]) } } return values, nil @@ -170,21 +168,13 @@ func (gr *Group) assignValues(columns []string, values []any) error { if value, ok := values[i].(*sql.NullString); !ok { return fmt.Errorf("unexpected type %T for field currency", values[i]) } else if value.Valid { - gr.Currency = value.String + gr.Currency = group.Currency(value.String) } - default: - gr.selectValues.Set(columns[i], values[i]) } } return nil } -// Value returns the ent.Value that was dynamically selected and assigned to the Group. -// This includes values selected through modifiers, order, etc. -func (gr *Group) Value(name string) (ent.Value, error) { - return gr.selectValues.Get(name) -} - // QueryUsers queries the "users" edge of the Group entity. func (gr *Group) QueryUsers() *UserQuery { return NewGroupClient(gr.config).QueryUsers(gr) @@ -253,7 +243,7 @@ func (gr *Group) String() string { builder.WriteString(gr.Name) builder.WriteString(", ") builder.WriteString("currency=") - builder.WriteString(gr.Currency) + builder.WriteString(fmt.Sprintf("%v", gr.Currency)) builder.WriteByte(')') return builder.String() } diff --git a/backend/internal/data/ent/group/group.go b/backend/internal/data/ent/group/group.go index 32cb101..835bd96 100644 --- a/backend/internal/data/ent/group/group.go +++ b/backend/internal/data/ent/group/group.go @@ -3,10 +3,9 @@ package group import ( + "fmt" "time" - "entgo.io/ent/dialect/sql" - "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" ) @@ -118,183 +117,48 @@ var ( UpdateDefaultUpdatedAt func() time.Time // NameValidator is a validator for the "name" field. It is called by the builders before save. NameValidator func(string) error - // DefaultCurrency holds the default value on creation for the "currency" field. - DefaultCurrency string // DefaultID holds the default value on creation for the "id" field. DefaultID func() uuid.UUID ) -// OrderOption defines the ordering options for the Group queries. -type OrderOption func(*sql.Selector) +// Currency defines the type for the "currency" enum field. +type Currency string -// ByID orders the results by the id field. -func ByID(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldID, opts...).ToFunc() +// CurrencyUsd is the default value of the Currency enum. +const DefaultCurrency = CurrencyUsd + +// Currency values. +const ( + CurrencyUsd Currency = "usd" + CurrencyEur Currency = "eur" + CurrencyGbp Currency = "gbp" + CurrencyJpy Currency = "jpy" + CurrencyZar Currency = "zar" + CurrencyAud Currency = "aud" + CurrencyNok Currency = "nok" + CurrencyNzd Currency = "nzd" + CurrencySek Currency = "sek" + CurrencyDkk Currency = "dkk" + CurrencyInr Currency = "inr" + CurrencyRmb Currency = "rmb" + CurrencyBgn Currency = "bgn" + CurrencyChf Currency = "chf" + CurrencyPln Currency = "pln" + CurrencyTry Currency = "try" + CurrencyRon Currency = "ron" + CurrencyCzk Currency = "czk" +) + +func (c Currency) String() string { + return string(c) } -// ByCreatedAt orders the results by the created_at field. -func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() -} - -// ByUpdatedAt orders the results by the updated_at field. -func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc() -} - -// ByName orders the results by the name field. -func ByName(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldName, opts...).ToFunc() -} - -// ByCurrency orders the results by the currency field. -func ByCurrency(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldCurrency, opts...).ToFunc() -} - -// ByUsersCount orders the results by users count. -func ByUsersCount(opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborsCount(s, newUsersStep(), opts...) +// CurrencyValidator is a validator for the "currency" field enum values. It is called by the builders before save. +func CurrencyValidator(c Currency) error { + switch c { + case CurrencyUsd, CurrencyEur, CurrencyGbp, CurrencyJpy, CurrencyZar, CurrencyAud, CurrencyNok, CurrencyNzd, CurrencySek, CurrencyDkk, CurrencyInr, CurrencyRmb, CurrencyBgn, CurrencyChf, CurrencyPln, CurrencyTry, CurrencyRon, CurrencyCzk: + return nil + default: + return fmt.Errorf("group: invalid enum value for currency field: %q", c) } } - -// ByUsers orders the results by users terms. -func ByUsers(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newUsersStep(), append([]sql.OrderTerm{term}, terms...)...) - } -} - -// ByLocationsCount orders the results by locations count. -func ByLocationsCount(opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborsCount(s, newLocationsStep(), opts...) - } -} - -// ByLocations orders the results by locations terms. -func ByLocations(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newLocationsStep(), append([]sql.OrderTerm{term}, terms...)...) - } -} - -// ByItemsCount orders the results by items count. -func ByItemsCount(opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborsCount(s, newItemsStep(), opts...) - } -} - -// ByItems orders the results by items terms. -func ByItems(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newItemsStep(), append([]sql.OrderTerm{term}, terms...)...) - } -} - -// ByLabelsCount orders the results by labels count. -func ByLabelsCount(opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborsCount(s, newLabelsStep(), opts...) - } -} - -// ByLabels orders the results by labels terms. -func ByLabels(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newLabelsStep(), append([]sql.OrderTerm{term}, terms...)...) - } -} - -// ByDocumentsCount orders the results by documents count. -func ByDocumentsCount(opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborsCount(s, newDocumentsStep(), opts...) - } -} - -// ByDocuments orders the results by documents terms. -func ByDocuments(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newDocumentsStep(), append([]sql.OrderTerm{term}, terms...)...) - } -} - -// ByInvitationTokensCount orders the results by invitation_tokens count. -func ByInvitationTokensCount(opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborsCount(s, newInvitationTokensStep(), opts...) - } -} - -// ByInvitationTokens orders the results by invitation_tokens terms. -func ByInvitationTokens(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newInvitationTokensStep(), append([]sql.OrderTerm{term}, terms...)...) - } -} - -// ByNotifiersCount orders the results by notifiers count. -func ByNotifiersCount(opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborsCount(s, newNotifiersStep(), opts...) - } -} - -// ByNotifiers orders the results by notifiers terms. -func ByNotifiers(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newNotifiersStep(), append([]sql.OrderTerm{term}, terms...)...) - } -} -func newUsersStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(UsersInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, UsersTable, UsersColumn), - ) -} -func newLocationsStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(LocationsInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, LocationsTable, LocationsColumn), - ) -} -func newItemsStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(ItemsInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, ItemsTable, ItemsColumn), - ) -} -func newLabelsStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(LabelsInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, LabelsTable, LabelsColumn), - ) -} -func newDocumentsStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(DocumentsInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, DocumentsTable, DocumentsColumn), - ) -} -func newInvitationTokensStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(InvitationTokensInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, InvitationTokensTable, InvitationTokensColumn), - ) -} -func newNotifiersStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(NotifiersInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, NotifiersTable, NotifiersColumn), - ) -} diff --git a/backend/internal/data/ent/group/where.go b/backend/internal/data/ent/group/where.go index d18faa7..6a1fba2 100644 --- a/backend/internal/data/ent/group/where.go +++ b/backend/internal/data/ent/group/where.go @@ -71,11 +71,6 @@ func Name(v string) predicate.Group { return predicate.Group(sql.FieldEQ(FieldName, v)) } -// Currency applies equality check predicate on the "currency" field. It's identical to CurrencyEQ. -func Currency(v string) predicate.Group { - return predicate.Group(sql.FieldEQ(FieldCurrency, v)) -} - // CreatedAtEQ applies the EQ predicate on the "created_at" field. func CreatedAtEQ(v time.Time) predicate.Group { return predicate.Group(sql.FieldEQ(FieldCreatedAt, v)) @@ -222,70 +217,25 @@ func NameContainsFold(v string) predicate.Group { } // CurrencyEQ applies the EQ predicate on the "currency" field. -func CurrencyEQ(v string) predicate.Group { +func CurrencyEQ(v Currency) predicate.Group { return predicate.Group(sql.FieldEQ(FieldCurrency, v)) } // CurrencyNEQ applies the NEQ predicate on the "currency" field. -func CurrencyNEQ(v string) predicate.Group { +func CurrencyNEQ(v Currency) predicate.Group { return predicate.Group(sql.FieldNEQ(FieldCurrency, v)) } // CurrencyIn applies the In predicate on the "currency" field. -func CurrencyIn(vs ...string) predicate.Group { +func CurrencyIn(vs ...Currency) predicate.Group { return predicate.Group(sql.FieldIn(FieldCurrency, vs...)) } // CurrencyNotIn applies the NotIn predicate on the "currency" field. -func CurrencyNotIn(vs ...string) predicate.Group { +func CurrencyNotIn(vs ...Currency) predicate.Group { return predicate.Group(sql.FieldNotIn(FieldCurrency, vs...)) } -// CurrencyGT applies the GT predicate on the "currency" field. -func CurrencyGT(v string) predicate.Group { - return predicate.Group(sql.FieldGT(FieldCurrency, v)) -} - -// CurrencyGTE applies the GTE predicate on the "currency" field. -func CurrencyGTE(v string) predicate.Group { - return predicate.Group(sql.FieldGTE(FieldCurrency, v)) -} - -// CurrencyLT applies the LT predicate on the "currency" field. -func CurrencyLT(v string) predicate.Group { - return predicate.Group(sql.FieldLT(FieldCurrency, v)) -} - -// CurrencyLTE applies the LTE predicate on the "currency" field. -func CurrencyLTE(v string) predicate.Group { - return predicate.Group(sql.FieldLTE(FieldCurrency, v)) -} - -// CurrencyContains applies the Contains predicate on the "currency" field. -func CurrencyContains(v string) predicate.Group { - return predicate.Group(sql.FieldContains(FieldCurrency, v)) -} - -// CurrencyHasPrefix applies the HasPrefix predicate on the "currency" field. -func CurrencyHasPrefix(v string) predicate.Group { - return predicate.Group(sql.FieldHasPrefix(FieldCurrency, v)) -} - -// CurrencyHasSuffix applies the HasSuffix predicate on the "currency" field. -func CurrencyHasSuffix(v string) predicate.Group { - return predicate.Group(sql.FieldHasSuffix(FieldCurrency, v)) -} - -// CurrencyEqualFold applies the EqualFold predicate on the "currency" field. -func CurrencyEqualFold(v string) predicate.Group { - return predicate.Group(sql.FieldEqualFold(FieldCurrency, v)) -} - -// CurrencyContainsFold applies the ContainsFold predicate on the "currency" field. -func CurrencyContainsFold(v string) predicate.Group { - return predicate.Group(sql.FieldContainsFold(FieldCurrency, v)) -} - // HasUsers applies the HasEdge predicate on the "users" edge. func HasUsers() predicate.Group { return predicate.Group(func(s *sql.Selector) { @@ -300,7 +250,11 @@ func HasUsers() predicate.Group { // HasUsersWith applies the HasEdge predicate on the "users" edge with a given conditions (other predicates). func HasUsersWith(preds ...predicate.User) predicate.Group { return predicate.Group(func(s *sql.Selector) { - step := newUsersStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(UsersInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, UsersTable, UsersColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -323,7 +277,11 @@ func HasLocations() predicate.Group { // HasLocationsWith applies the HasEdge predicate on the "locations" edge with a given conditions (other predicates). func HasLocationsWith(preds ...predicate.Location) predicate.Group { return predicate.Group(func(s *sql.Selector) { - step := newLocationsStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(LocationsInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, LocationsTable, LocationsColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -346,7 +304,11 @@ func HasItems() predicate.Group { // HasItemsWith applies the HasEdge predicate on the "items" edge with a given conditions (other predicates). func HasItemsWith(preds ...predicate.Item) predicate.Group { return predicate.Group(func(s *sql.Selector) { - step := newItemsStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(ItemsInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, ItemsTable, ItemsColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -369,7 +331,11 @@ func HasLabels() predicate.Group { // HasLabelsWith applies the HasEdge predicate on the "labels" edge with a given conditions (other predicates). func HasLabelsWith(preds ...predicate.Label) predicate.Group { return predicate.Group(func(s *sql.Selector) { - step := newLabelsStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(LabelsInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, LabelsTable, LabelsColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -392,7 +358,11 @@ func HasDocuments() predicate.Group { // HasDocumentsWith applies the HasEdge predicate on the "documents" edge with a given conditions (other predicates). func HasDocumentsWith(preds ...predicate.Document) predicate.Group { return predicate.Group(func(s *sql.Selector) { - step := newDocumentsStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(DocumentsInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, DocumentsTable, DocumentsColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -415,7 +385,11 @@ func HasInvitationTokens() predicate.Group { // HasInvitationTokensWith applies the HasEdge predicate on the "invitation_tokens" edge with a given conditions (other predicates). func HasInvitationTokensWith(preds ...predicate.GroupInvitationToken) predicate.Group { return predicate.Group(func(s *sql.Selector) { - step := newInvitationTokensStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(InvitationTokensInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, InvitationTokensTable, InvitationTokensColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -438,7 +412,11 @@ func HasNotifiers() predicate.Group { // HasNotifiersWith applies the HasEdge predicate on the "notifiers" edge with a given conditions (other predicates). func HasNotifiersWith(preds ...predicate.Notifier) predicate.Group { return predicate.Group(func(s *sql.Selector) { - step := newNotifiersStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(NotifiersInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, NotifiersTable, NotifiersColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -449,15 +427,32 @@ func HasNotifiersWith(preds ...predicate.Notifier) predicate.Group { // And groups predicates with the AND operator between them. func And(predicates ...predicate.Group) predicate.Group { - return predicate.Group(sql.AndPredicates(predicates...)) + return predicate.Group(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for _, p := range predicates { + p(s1) + } + s.Where(s1.P()) + }) } // Or groups predicates with the OR operator between them. func Or(predicates ...predicate.Group) predicate.Group { - return predicate.Group(sql.OrPredicates(predicates...)) + return predicate.Group(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for i, p := range predicates { + if i > 0 { + s1.Or() + } + p(s1) + } + s.Where(s1.P()) + }) } // Not applies the not operator on the given predicate. func Not(p predicate.Group) predicate.Group { - return predicate.Group(sql.NotPredicates(p)) + return predicate.Group(func(s *sql.Selector) { + p(s.Not()) + }) } diff --git a/backend/internal/data/ent/group_create.go b/backend/internal/data/ent/group_create.go index be56ba0..f10f2c7 100644 --- a/backend/internal/data/ent/group_create.go +++ b/backend/internal/data/ent/group_create.go @@ -63,15 +63,15 @@ func (gc *GroupCreate) SetName(s string) *GroupCreate { } // SetCurrency sets the "currency" field. -func (gc *GroupCreate) SetCurrency(s string) *GroupCreate { - gc.mutation.SetCurrency(s) +func (gc *GroupCreate) SetCurrency(gr group.Currency) *GroupCreate { + gc.mutation.SetCurrency(gr) return gc } // SetNillableCurrency sets the "currency" field if the given value is not nil. -func (gc *GroupCreate) SetNillableCurrency(s *string) *GroupCreate { - if s != nil { - gc.SetCurrency(*s) +func (gc *GroupCreate) SetNillableCurrency(gr *group.Currency) *GroupCreate { + if gr != nil { + gc.SetCurrency(*gr) } return gc } @@ -203,7 +203,7 @@ func (gc *GroupCreate) Mutation() *GroupMutation { // Save creates the Group in the database. func (gc *GroupCreate) Save(ctx context.Context) (*Group, error) { gc.defaults() - return withHooks(ctx, gc.sqlSave, gc.mutation, gc.hooks) + return withHooks[*Group, GroupMutation](ctx, gc.sqlSave, gc.mutation, gc.hooks) } // SaveX calls Save and panics if Save returns an error. @@ -267,6 +267,11 @@ func (gc *GroupCreate) check() error { if _, ok := gc.mutation.Currency(); !ok { return &ValidationError{Name: "currency", err: errors.New(`ent: missing required field "Group.currency"`)} } + if v, ok := gc.mutation.Currency(); ok { + if err := group.CurrencyValidator(v); err != nil { + return &ValidationError{Name: "currency", err: fmt.Errorf(`ent: validator failed for field "Group.currency": %w`, err)} + } + } return nil } @@ -315,7 +320,7 @@ func (gc *GroupCreate) createSpec() (*Group, *sqlgraph.CreateSpec) { _node.Name = value } if value, ok := gc.mutation.Currency(); ok { - _spec.SetField(group.FieldCurrency, field.TypeString, value) + _spec.SetField(group.FieldCurrency, field.TypeEnum, value) _node.Currency = value } if nodes := gc.mutation.UsersIDs(); len(nodes) > 0 { @@ -436,15 +441,11 @@ func (gc *GroupCreate) createSpec() (*Group, *sqlgraph.CreateSpec) { // GroupCreateBulk is the builder for creating many Group entities in bulk. type GroupCreateBulk struct { config - err error builders []*GroupCreate } // Save creates the Group entities in the database. func (gcb *GroupCreateBulk) Save(ctx context.Context) ([]*Group, error) { - if gcb.err != nil { - return nil, gcb.err - } specs := make([]*sqlgraph.CreateSpec, len(gcb.builders)) nodes := make([]*Group, len(gcb.builders)) mutators := make([]Mutator, len(gcb.builders)) @@ -461,8 +462,8 @@ func (gcb *GroupCreateBulk) Save(ctx context.Context) ([]*Group, error) { return nil, err } builder.mutation = mutation - var err error nodes[i], specs[i] = builder.createSpec() + var err error if i < len(mutators)-1 { _, err = mutators[i+1].Mutate(root, gcb.builders[i+1].mutation) } else { diff --git a/backend/internal/data/ent/group_delete.go b/backend/internal/data/ent/group_delete.go index b8c3e59..29e0ffc 100644 --- a/backend/internal/data/ent/group_delete.go +++ b/backend/internal/data/ent/group_delete.go @@ -27,7 +27,7 @@ func (gd *GroupDelete) Where(ps ...predicate.Group) *GroupDelete { // Exec executes the deletion query and returns how many vertices were deleted. func (gd *GroupDelete) Exec(ctx context.Context) (int, error) { - return withHooks(ctx, gd.sqlExec, gd.mutation, gd.hooks) + return withHooks[int, GroupMutation](ctx, gd.sqlExec, gd.mutation, gd.hooks) } // ExecX is like Exec, but panics if an error occurs. diff --git a/backend/internal/data/ent/group_query.go b/backend/internal/data/ent/group_query.go index f17bd3b..415ab7a 100644 --- a/backend/internal/data/ent/group_query.go +++ b/backend/internal/data/ent/group_query.go @@ -27,7 +27,7 @@ import ( type GroupQuery struct { config ctx *QueryContext - order []group.OrderOption + order []OrderFunc inters []Interceptor predicates []predicate.Group withUsers *UserQuery @@ -68,7 +68,7 @@ func (gq *GroupQuery) Unique(unique bool) *GroupQuery { } // Order specifies how the records should be ordered. -func (gq *GroupQuery) Order(o ...group.OrderOption) *GroupQuery { +func (gq *GroupQuery) Order(o ...OrderFunc) *GroupQuery { gq.order = append(gq.order, o...) return gq } @@ -416,7 +416,7 @@ func (gq *GroupQuery) Clone() *GroupQuery { return &GroupQuery{ config: gq.config, ctx: gq.ctx.Clone(), - order: append([]group.OrderOption{}, gq.order...), + order: append([]OrderFunc{}, gq.order...), inters: append([]Interceptor{}, gq.inters...), predicates: append([]predicate.Group{}, gq.predicates...), withUsers: gq.withUsers.Clone(), @@ -681,7 +681,7 @@ func (gq *GroupQuery) loadUsers(ctx context.Context, query *UserQuery, nodes []* } query.withFKs = true query.Where(predicate.User(func(s *sql.Selector) { - s.Where(sql.InValues(s.C(group.UsersColumn), fks...)) + s.Where(sql.InValues(group.UsersColumn, fks...)) })) neighbors, err := query.All(ctx) if err != nil { @@ -694,7 +694,7 @@ func (gq *GroupQuery) loadUsers(ctx context.Context, query *UserQuery, nodes []* } node, ok := nodeids[*fk] if !ok { - return fmt.Errorf(`unexpected referenced foreign-key "group_users" returned %v for node %v`, *fk, n.ID) + return fmt.Errorf(`unexpected foreign-key "group_users" returned %v for node %v`, *fk, n.ID) } assign(node, n) } @@ -712,7 +712,7 @@ func (gq *GroupQuery) loadLocations(ctx context.Context, query *LocationQuery, n } query.withFKs = true query.Where(predicate.Location(func(s *sql.Selector) { - s.Where(sql.InValues(s.C(group.LocationsColumn), fks...)) + s.Where(sql.InValues(group.LocationsColumn, fks...)) })) neighbors, err := query.All(ctx) if err != nil { @@ -725,7 +725,7 @@ func (gq *GroupQuery) loadLocations(ctx context.Context, query *LocationQuery, n } node, ok := nodeids[*fk] if !ok { - return fmt.Errorf(`unexpected referenced foreign-key "group_locations" returned %v for node %v`, *fk, n.ID) + return fmt.Errorf(`unexpected foreign-key "group_locations" returned %v for node %v`, *fk, n.ID) } assign(node, n) } @@ -743,7 +743,7 @@ func (gq *GroupQuery) loadItems(ctx context.Context, query *ItemQuery, nodes []* } query.withFKs = true query.Where(predicate.Item(func(s *sql.Selector) { - s.Where(sql.InValues(s.C(group.ItemsColumn), fks...)) + s.Where(sql.InValues(group.ItemsColumn, fks...)) })) neighbors, err := query.All(ctx) if err != nil { @@ -756,7 +756,7 @@ func (gq *GroupQuery) loadItems(ctx context.Context, query *ItemQuery, nodes []* } node, ok := nodeids[*fk] if !ok { - return fmt.Errorf(`unexpected referenced foreign-key "group_items" returned %v for node %v`, *fk, n.ID) + return fmt.Errorf(`unexpected foreign-key "group_items" returned %v for node %v`, *fk, n.ID) } assign(node, n) } @@ -774,7 +774,7 @@ func (gq *GroupQuery) loadLabels(ctx context.Context, query *LabelQuery, nodes [ } query.withFKs = true query.Where(predicate.Label(func(s *sql.Selector) { - s.Where(sql.InValues(s.C(group.LabelsColumn), fks...)) + s.Where(sql.InValues(group.LabelsColumn, fks...)) })) neighbors, err := query.All(ctx) if err != nil { @@ -787,7 +787,7 @@ func (gq *GroupQuery) loadLabels(ctx context.Context, query *LabelQuery, nodes [ } node, ok := nodeids[*fk] if !ok { - return fmt.Errorf(`unexpected referenced foreign-key "group_labels" returned %v for node %v`, *fk, n.ID) + return fmt.Errorf(`unexpected foreign-key "group_labels" returned %v for node %v`, *fk, n.ID) } assign(node, n) } @@ -805,7 +805,7 @@ func (gq *GroupQuery) loadDocuments(ctx context.Context, query *DocumentQuery, n } query.withFKs = true query.Where(predicate.Document(func(s *sql.Selector) { - s.Where(sql.InValues(s.C(group.DocumentsColumn), fks...)) + s.Where(sql.InValues(group.DocumentsColumn, fks...)) })) neighbors, err := query.All(ctx) if err != nil { @@ -818,7 +818,7 @@ func (gq *GroupQuery) loadDocuments(ctx context.Context, query *DocumentQuery, n } node, ok := nodeids[*fk] if !ok { - return fmt.Errorf(`unexpected referenced foreign-key "group_documents" returned %v for node %v`, *fk, n.ID) + return fmt.Errorf(`unexpected foreign-key "group_documents" returned %v for node %v`, *fk, n.ID) } assign(node, n) } @@ -836,7 +836,7 @@ func (gq *GroupQuery) loadInvitationTokens(ctx context.Context, query *GroupInvi } query.withFKs = true query.Where(predicate.GroupInvitationToken(func(s *sql.Selector) { - s.Where(sql.InValues(s.C(group.InvitationTokensColumn), fks...)) + s.Where(sql.InValues(group.InvitationTokensColumn, fks...)) })) neighbors, err := query.All(ctx) if err != nil { @@ -849,7 +849,7 @@ func (gq *GroupQuery) loadInvitationTokens(ctx context.Context, query *GroupInvi } node, ok := nodeids[*fk] if !ok { - return fmt.Errorf(`unexpected referenced foreign-key "group_invitation_tokens" returned %v for node %v`, *fk, n.ID) + return fmt.Errorf(`unexpected foreign-key "group_invitation_tokens" returned %v for node %v`, *fk, n.ID) } assign(node, n) } @@ -865,11 +865,8 @@ func (gq *GroupQuery) loadNotifiers(ctx context.Context, query *NotifierQuery, n init(nodes[i]) } } - if len(query.ctx.Fields) > 0 { - query.ctx.AppendFieldOnce(notifier.FieldGroupID) - } query.Where(predicate.Notifier(func(s *sql.Selector) { - s.Where(sql.InValues(s.C(group.NotifiersColumn), fks...)) + s.Where(sql.InValues(group.NotifiersColumn, fks...)) })) neighbors, err := query.All(ctx) if err != nil { @@ -879,7 +876,7 @@ func (gq *GroupQuery) loadNotifiers(ctx context.Context, query *NotifierQuery, n fk := n.GroupID node, ok := nodeids[fk] if !ok { - return fmt.Errorf(`unexpected referenced foreign-key "group_id" returned %v for node %v`, fk, n.ID) + return fmt.Errorf(`unexpected foreign-key "group_id" returned %v for node %v`, fk, n.ID) } assign(node, n) } diff --git a/backend/internal/data/ent/group_update.go b/backend/internal/data/ent/group_update.go index fdb11a3..7e22cb2 100644 --- a/backend/internal/data/ent/group_update.go +++ b/backend/internal/data/ent/group_update.go @@ -48,24 +48,16 @@ func (gu *GroupUpdate) SetName(s string) *GroupUpdate { return gu } -// SetNillableName sets the "name" field if the given value is not nil. -func (gu *GroupUpdate) SetNillableName(s *string) *GroupUpdate { - if s != nil { - gu.SetName(*s) - } - return gu -} - // SetCurrency sets the "currency" field. -func (gu *GroupUpdate) SetCurrency(s string) *GroupUpdate { - gu.mutation.SetCurrency(s) +func (gu *GroupUpdate) SetCurrency(gr group.Currency) *GroupUpdate { + gu.mutation.SetCurrency(gr) return gu } // SetNillableCurrency sets the "currency" field if the given value is not nil. -func (gu *GroupUpdate) SetNillableCurrency(s *string) *GroupUpdate { - if s != nil { - gu.SetCurrency(*s) +func (gu *GroupUpdate) SetNillableCurrency(gr *group.Currency) *GroupUpdate { + if gr != nil { + gu.SetCurrency(*gr) } return gu } @@ -330,7 +322,7 @@ func (gu *GroupUpdate) RemoveNotifiers(n ...*Notifier) *GroupUpdate { // Save executes the query and returns the number of nodes affected by the update operation. func (gu *GroupUpdate) Save(ctx context.Context) (int, error) { gu.defaults() - return withHooks(ctx, gu.sqlSave, gu.mutation, gu.hooks) + return withHooks[int, GroupMutation](ctx, gu.sqlSave, gu.mutation, gu.hooks) } // SaveX is like Save, but panics if an error occurs. @@ -370,6 +362,11 @@ func (gu *GroupUpdate) check() error { return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "Group.name": %w`, err)} } } + if v, ok := gu.mutation.Currency(); ok { + if err := group.CurrencyValidator(v); err != nil { + return &ValidationError{Name: "currency", err: fmt.Errorf(`ent: validator failed for field "Group.currency": %w`, err)} + } + } return nil } @@ -392,7 +389,7 @@ func (gu *GroupUpdate) sqlSave(ctx context.Context) (n int, err error) { _spec.SetField(group.FieldName, field.TypeString, value) } if value, ok := gu.mutation.Currency(); ok { - _spec.SetField(group.FieldCurrency, field.TypeString, value) + _spec.SetField(group.FieldCurrency, field.TypeEnum, value) } if gu.mutation.UsersCleared() { edge := &sqlgraph.EdgeSpec{ @@ -741,24 +738,16 @@ func (guo *GroupUpdateOne) SetName(s string) *GroupUpdateOne { return guo } -// SetNillableName sets the "name" field if the given value is not nil. -func (guo *GroupUpdateOne) SetNillableName(s *string) *GroupUpdateOne { - if s != nil { - guo.SetName(*s) - } - return guo -} - // SetCurrency sets the "currency" field. -func (guo *GroupUpdateOne) SetCurrency(s string) *GroupUpdateOne { - guo.mutation.SetCurrency(s) +func (guo *GroupUpdateOne) SetCurrency(gr group.Currency) *GroupUpdateOne { + guo.mutation.SetCurrency(gr) return guo } // SetNillableCurrency sets the "currency" field if the given value is not nil. -func (guo *GroupUpdateOne) SetNillableCurrency(s *string) *GroupUpdateOne { - if s != nil { - guo.SetCurrency(*s) +func (guo *GroupUpdateOne) SetNillableCurrency(gr *group.Currency) *GroupUpdateOne { + if gr != nil { + guo.SetCurrency(*gr) } return guo } @@ -1036,7 +1025,7 @@ func (guo *GroupUpdateOne) Select(field string, fields ...string) *GroupUpdateOn // Save executes the query and returns the updated Group entity. func (guo *GroupUpdateOne) Save(ctx context.Context) (*Group, error) { guo.defaults() - return withHooks(ctx, guo.sqlSave, guo.mutation, guo.hooks) + return withHooks[*Group, GroupMutation](ctx, guo.sqlSave, guo.mutation, guo.hooks) } // SaveX is like Save, but panics if an error occurs. @@ -1076,6 +1065,11 @@ func (guo *GroupUpdateOne) check() error { return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "Group.name": %w`, err)} } } + if v, ok := guo.mutation.Currency(); ok { + if err := group.CurrencyValidator(v); err != nil { + return &ValidationError{Name: "currency", err: fmt.Errorf(`ent: validator failed for field "Group.currency": %w`, err)} + } + } return nil } @@ -1115,7 +1109,7 @@ func (guo *GroupUpdateOne) sqlSave(ctx context.Context) (_node *Group, err error _spec.SetField(group.FieldName, field.TypeString, value) } if value, ok := guo.mutation.Currency(); ok { - _spec.SetField(group.FieldCurrency, field.TypeString, value) + _spec.SetField(group.FieldCurrency, field.TypeEnum, value) } if guo.mutation.UsersCleared() { edge := &sqlgraph.EdgeSpec{ diff --git a/backend/internal/data/ent/groupinvitationtoken.go b/backend/internal/data/ent/groupinvitationtoken.go index d715cc6..f8c2bb3 100644 --- a/backend/internal/data/ent/groupinvitationtoken.go +++ b/backend/internal/data/ent/groupinvitationtoken.go @@ -7,7 +7,6 @@ import ( "strings" "time" - "entgo.io/ent" "entgo.io/ent/dialect/sql" "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/data/ent/group" @@ -33,7 +32,6 @@ type GroupInvitationToken struct { // The values are being populated by the GroupInvitationTokenQuery when eager-loading is set. Edges GroupInvitationTokenEdges `json:"edges"` group_invitation_tokens *uuid.UUID - selectValues sql.SelectValues } // GroupInvitationTokenEdges holds the relations/edges for other nodes in the graph. @@ -74,7 +72,7 @@ func (*GroupInvitationToken) scanValues(columns []string) ([]any, error) { case groupinvitationtoken.ForeignKeys[0]: // group_invitation_tokens values[i] = &sql.NullScanner{S: new(uuid.UUID)} default: - values[i] = new(sql.UnknownType) + return nil, fmt.Errorf("unexpected column %q for type GroupInvitationToken", columns[i]) } } return values, nil @@ -131,19 +129,11 @@ func (git *GroupInvitationToken) assignValues(columns []string, values []any) er git.group_invitation_tokens = new(uuid.UUID) *git.group_invitation_tokens = *value.S.(*uuid.UUID) } - default: - git.selectValues.Set(columns[i], values[i]) } } return nil } -// Value returns the ent.Value that was dynamically selected and assigned to the GroupInvitationToken. -// This includes values selected through modifiers, order, etc. -func (git *GroupInvitationToken) Value(name string) (ent.Value, error) { - return git.selectValues.Get(name) -} - // QueryGroup queries the "group" edge of the GroupInvitationToken entity. func (git *GroupInvitationToken) QueryGroup() *GroupQuery { return NewGroupInvitationTokenClient(git.config).QueryGroup(git) diff --git a/backend/internal/data/ent/groupinvitationtoken/groupinvitationtoken.go b/backend/internal/data/ent/groupinvitationtoken/groupinvitationtoken.go index 748d739..1daea17 100644 --- a/backend/internal/data/ent/groupinvitationtoken/groupinvitationtoken.go +++ b/backend/internal/data/ent/groupinvitationtoken/groupinvitationtoken.go @@ -5,8 +5,6 @@ package groupinvitationtoken import ( "time" - "entgo.io/ent/dialect/sql" - "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" ) @@ -83,45 +81,3 @@ var ( // DefaultID holds the default value on creation for the "id" field. DefaultID func() uuid.UUID ) - -// OrderOption defines the ordering options for the GroupInvitationToken queries. -type OrderOption func(*sql.Selector) - -// ByID orders the results by the id field. -func ByID(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldID, opts...).ToFunc() -} - -// ByCreatedAt orders the results by the created_at field. -func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() -} - -// ByUpdatedAt orders the results by the updated_at field. -func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc() -} - -// ByExpiresAt orders the results by the expires_at field. -func ByExpiresAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldExpiresAt, opts...).ToFunc() -} - -// ByUses orders the results by the uses field. -func ByUses(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldUses, opts...).ToFunc() -} - -// ByGroupField orders the results by group field. -func ByGroupField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newGroupStep(), sql.OrderByField(field, opts...)) - } -} -func newGroupStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(GroupInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn), - ) -} diff --git a/backend/internal/data/ent/groupinvitationtoken/where.go b/backend/internal/data/ent/groupinvitationtoken/where.go index d462df0..2d81adc 100644 --- a/backend/internal/data/ent/groupinvitationtoken/where.go +++ b/backend/internal/data/ent/groupinvitationtoken/where.go @@ -295,7 +295,11 @@ func HasGroup() predicate.GroupInvitationToken { // HasGroupWith applies the HasEdge predicate on the "group" edge with a given conditions (other predicates). func HasGroupWith(preds ...predicate.Group) predicate.GroupInvitationToken { return predicate.GroupInvitationToken(func(s *sql.Selector) { - step := newGroupStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(GroupInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -306,15 +310,32 @@ func HasGroupWith(preds ...predicate.Group) predicate.GroupInvitationToken { // And groups predicates with the AND operator between them. func And(predicates ...predicate.GroupInvitationToken) predicate.GroupInvitationToken { - return predicate.GroupInvitationToken(sql.AndPredicates(predicates...)) + return predicate.GroupInvitationToken(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for _, p := range predicates { + p(s1) + } + s.Where(s1.P()) + }) } // Or groups predicates with the OR operator between them. func Or(predicates ...predicate.GroupInvitationToken) predicate.GroupInvitationToken { - return predicate.GroupInvitationToken(sql.OrPredicates(predicates...)) + return predicate.GroupInvitationToken(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for i, p := range predicates { + if i > 0 { + s1.Or() + } + p(s1) + } + s.Where(s1.P()) + }) } // Not applies the not operator on the given predicate. func Not(p predicate.GroupInvitationToken) predicate.GroupInvitationToken { - return predicate.GroupInvitationToken(sql.NotPredicates(p)) + return predicate.GroupInvitationToken(func(s *sql.Selector) { + p(s.Not()) + }) } diff --git a/backend/internal/data/ent/groupinvitationtoken_create.go b/backend/internal/data/ent/groupinvitationtoken_create.go index 1d5859f..e478ace 100644 --- a/backend/internal/data/ent/groupinvitationtoken_create.go +++ b/backend/internal/data/ent/groupinvitationtoken_create.go @@ -125,7 +125,7 @@ func (gitc *GroupInvitationTokenCreate) Mutation() *GroupInvitationTokenMutation // Save creates the GroupInvitationToken in the database. func (gitc *GroupInvitationTokenCreate) Save(ctx context.Context) (*GroupInvitationToken, error) { gitc.defaults() - return withHooks(ctx, gitc.sqlSave, gitc.mutation, gitc.hooks) + return withHooks[*GroupInvitationToken, GroupInvitationTokenMutation](ctx, gitc.sqlSave, gitc.mutation, gitc.hooks) } // SaveX calls Save and panics if Save returns an error. @@ -269,15 +269,11 @@ func (gitc *GroupInvitationTokenCreate) createSpec() (*GroupInvitationToken, *sq // GroupInvitationTokenCreateBulk is the builder for creating many GroupInvitationToken entities in bulk. type GroupInvitationTokenCreateBulk struct { config - err error builders []*GroupInvitationTokenCreate } // Save creates the GroupInvitationToken entities in the database. func (gitcb *GroupInvitationTokenCreateBulk) Save(ctx context.Context) ([]*GroupInvitationToken, error) { - if gitcb.err != nil { - return nil, gitcb.err - } specs := make([]*sqlgraph.CreateSpec, len(gitcb.builders)) nodes := make([]*GroupInvitationToken, len(gitcb.builders)) mutators := make([]Mutator, len(gitcb.builders)) @@ -294,8 +290,8 @@ func (gitcb *GroupInvitationTokenCreateBulk) Save(ctx context.Context) ([]*Group return nil, err } builder.mutation = mutation - var err error nodes[i], specs[i] = builder.createSpec() + var err error if i < len(mutators)-1 { _, err = mutators[i+1].Mutate(root, gitcb.builders[i+1].mutation) } else { diff --git a/backend/internal/data/ent/groupinvitationtoken_delete.go b/backend/internal/data/ent/groupinvitationtoken_delete.go index 5878fdf..1720383 100644 --- a/backend/internal/data/ent/groupinvitationtoken_delete.go +++ b/backend/internal/data/ent/groupinvitationtoken_delete.go @@ -27,7 +27,7 @@ func (gitd *GroupInvitationTokenDelete) Where(ps ...predicate.GroupInvitationTok // Exec executes the deletion query and returns how many vertices were deleted. func (gitd *GroupInvitationTokenDelete) Exec(ctx context.Context) (int, error) { - return withHooks(ctx, gitd.sqlExec, gitd.mutation, gitd.hooks) + return withHooks[int, GroupInvitationTokenMutation](ctx, gitd.sqlExec, gitd.mutation, gitd.hooks) } // ExecX is like Exec, but panics if an error occurs. diff --git a/backend/internal/data/ent/groupinvitationtoken_query.go b/backend/internal/data/ent/groupinvitationtoken_query.go index 89de054..287b509 100644 --- a/backend/internal/data/ent/groupinvitationtoken_query.go +++ b/backend/internal/data/ent/groupinvitationtoken_query.go @@ -20,7 +20,7 @@ import ( type GroupInvitationTokenQuery struct { config ctx *QueryContext - order []groupinvitationtoken.OrderOption + order []OrderFunc inters []Interceptor predicates []predicate.GroupInvitationToken withGroup *GroupQuery @@ -56,7 +56,7 @@ func (gitq *GroupInvitationTokenQuery) Unique(unique bool) *GroupInvitationToken } // Order specifies how the records should be ordered. -func (gitq *GroupInvitationTokenQuery) Order(o ...groupinvitationtoken.OrderOption) *GroupInvitationTokenQuery { +func (gitq *GroupInvitationTokenQuery) Order(o ...OrderFunc) *GroupInvitationTokenQuery { gitq.order = append(gitq.order, o...) return gitq } @@ -272,7 +272,7 @@ func (gitq *GroupInvitationTokenQuery) Clone() *GroupInvitationTokenQuery { return &GroupInvitationTokenQuery{ config: gitq.config, ctx: gitq.ctx.Clone(), - order: append([]groupinvitationtoken.OrderOption{}, gitq.order...), + order: append([]OrderFunc{}, gitq.order...), inters: append([]Interceptor{}, gitq.inters...), predicates: append([]predicate.GroupInvitationToken{}, gitq.predicates...), withGroup: gitq.withGroup.Clone(), diff --git a/backend/internal/data/ent/groupinvitationtoken_update.go b/backend/internal/data/ent/groupinvitationtoken_update.go index 3e0db91..73d6b5c 100644 --- a/backend/internal/data/ent/groupinvitationtoken_update.go +++ b/backend/internal/data/ent/groupinvitationtoken_update.go @@ -110,7 +110,7 @@ func (gitu *GroupInvitationTokenUpdate) ClearGroup() *GroupInvitationTokenUpdate // Save executes the query and returns the number of nodes affected by the update operation. func (gitu *GroupInvitationTokenUpdate) Save(ctx context.Context) (int, error) { gitu.defaults() - return withHooks(ctx, gitu.sqlSave, gitu.mutation, gitu.hooks) + return withHooks[int, GroupInvitationTokenMutation](ctx, gitu.sqlSave, gitu.mutation, gitu.hooks) } // SaveX is like Save, but panics if an error occurs. @@ -309,7 +309,7 @@ func (gituo *GroupInvitationTokenUpdateOne) Select(field string, fields ...strin // Save executes the query and returns the updated GroupInvitationToken entity. func (gituo *GroupInvitationTokenUpdateOne) Save(ctx context.Context) (*GroupInvitationToken, error) { gituo.defaults() - return withHooks(ctx, gituo.sqlSave, gituo.mutation, gituo.hooks) + return withHooks[*GroupInvitationToken, GroupInvitationTokenMutation](ctx, gituo.sqlSave, gituo.mutation, gituo.hooks) } // SaveX is like Save, but panics if an error occurs. diff --git a/backend/internal/data/ent/item.go b/backend/internal/data/ent/item.go index 7b2be8a..2890000 100644 --- a/backend/internal/data/ent/item.go +++ b/backend/internal/data/ent/item.go @@ -7,7 +7,6 @@ import ( "strings" "time" - "entgo.io/ent" "entgo.io/ent/dialect/sql" "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/data/ent/group" @@ -72,7 +71,6 @@ type Item struct { group_items *uuid.UUID item_children *uuid.UUID location_items *uuid.UUID - selectValues sql.SelectValues } // ItemEdges holds the relations/edges for other nodes in the graph. @@ -206,7 +204,7 @@ func (*Item) scanValues(columns []string) ([]any, error) { case item.ForeignKeys[2]: // location_items values[i] = &sql.NullScanner{S: new(uuid.UUID)} default: - values[i] = new(sql.UnknownType) + return nil, fmt.Errorf("unexpected column %q for type Item", columns[i]) } } return values, nil @@ -385,19 +383,11 @@ func (i *Item) assignValues(columns []string, values []any) error { i.location_items = new(uuid.UUID) *i.location_items = *value.S.(*uuid.UUID) } - default: - i.selectValues.Set(columns[j], values[j]) } } return nil } -// Value returns the ent.Value that was dynamically selected and assigned to the Item. -// This includes values selected through modifiers, order, etc. -func (i *Item) Value(name string) (ent.Value, error) { - return i.selectValues.Get(name) -} - // QueryGroup queries the "group" edge of the Item entity. func (i *Item) QueryGroup() *GroupQuery { return NewItemClient(i.config).QueryGroup(i) diff --git a/backend/internal/data/ent/item/item.go b/backend/internal/data/ent/item/item.go index bd04679..b5e2bb6 100644 --- a/backend/internal/data/ent/item/item.go +++ b/backend/internal/data/ent/item/item.go @@ -5,8 +5,6 @@ package item import ( "time" - "entgo.io/ent/dialect/sql" - "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" ) @@ -228,273 +226,3 @@ var ( // DefaultID holds the default value on creation for the "id" field. DefaultID func() uuid.UUID ) - -// OrderOption defines the ordering options for the Item queries. -type OrderOption func(*sql.Selector) - -// ByID orders the results by the id field. -func ByID(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldID, opts...).ToFunc() -} - -// ByCreatedAt orders the results by the created_at field. -func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() -} - -// ByUpdatedAt orders the results by the updated_at field. -func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc() -} - -// ByName orders the results by the name field. -func ByName(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldName, opts...).ToFunc() -} - -// ByDescription orders the results by the description field. -func ByDescription(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldDescription, opts...).ToFunc() -} - -// ByImportRef orders the results by the import_ref field. -func ByImportRef(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldImportRef, opts...).ToFunc() -} - -// ByNotes orders the results by the notes field. -func ByNotes(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldNotes, opts...).ToFunc() -} - -// ByQuantity orders the results by the quantity field. -func ByQuantity(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldQuantity, opts...).ToFunc() -} - -// ByInsured orders the results by the insured field. -func ByInsured(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldInsured, opts...).ToFunc() -} - -// ByArchived orders the results by the archived field. -func ByArchived(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldArchived, opts...).ToFunc() -} - -// ByAssetID orders the results by the asset_id field. -func ByAssetID(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldAssetID, opts...).ToFunc() -} - -// BySerialNumber orders the results by the serial_number field. -func BySerialNumber(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldSerialNumber, opts...).ToFunc() -} - -// ByModelNumber orders the results by the model_number field. -func ByModelNumber(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldModelNumber, opts...).ToFunc() -} - -// ByManufacturer orders the results by the manufacturer field. -func ByManufacturer(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldManufacturer, opts...).ToFunc() -} - -// ByLifetimeWarranty orders the results by the lifetime_warranty field. -func ByLifetimeWarranty(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldLifetimeWarranty, opts...).ToFunc() -} - -// ByWarrantyExpires orders the results by the warranty_expires field. -func ByWarrantyExpires(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldWarrantyExpires, opts...).ToFunc() -} - -// ByWarrantyDetails orders the results by the warranty_details field. -func ByWarrantyDetails(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldWarrantyDetails, opts...).ToFunc() -} - -// ByPurchaseTime orders the results by the purchase_time field. -func ByPurchaseTime(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldPurchaseTime, opts...).ToFunc() -} - -// ByPurchaseFrom orders the results by the purchase_from field. -func ByPurchaseFrom(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldPurchaseFrom, opts...).ToFunc() -} - -// ByPurchasePrice orders the results by the purchase_price field. -func ByPurchasePrice(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldPurchasePrice, opts...).ToFunc() -} - -// BySoldTime orders the results by the sold_time field. -func BySoldTime(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldSoldTime, opts...).ToFunc() -} - -// BySoldTo orders the results by the sold_to field. -func BySoldTo(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldSoldTo, opts...).ToFunc() -} - -// BySoldPrice orders the results by the sold_price field. -func BySoldPrice(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldSoldPrice, opts...).ToFunc() -} - -// BySoldNotes orders the results by the sold_notes field. -func BySoldNotes(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldSoldNotes, opts...).ToFunc() -} - -// ByGroupField orders the results by group field. -func ByGroupField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newGroupStep(), sql.OrderByField(field, opts...)) - } -} - -// ByParentField orders the results by parent field. -func ByParentField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newParentStep(), sql.OrderByField(field, opts...)) - } -} - -// ByChildrenCount orders the results by children count. -func ByChildrenCount(opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborsCount(s, newChildrenStep(), opts...) - } -} - -// ByChildren orders the results by children terms. -func ByChildren(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newChildrenStep(), append([]sql.OrderTerm{term}, terms...)...) - } -} - -// ByLabelCount orders the results by label count. -func ByLabelCount(opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborsCount(s, newLabelStep(), opts...) - } -} - -// ByLabel orders the results by label terms. -func ByLabel(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newLabelStep(), append([]sql.OrderTerm{term}, terms...)...) - } -} - -// ByLocationField orders the results by location field. -func ByLocationField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newLocationStep(), sql.OrderByField(field, opts...)) - } -} - -// ByFieldsCount orders the results by fields count. -func ByFieldsCount(opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborsCount(s, newFieldsStep(), opts...) - } -} - -// ByFields orders the results by fields terms. -func ByFields(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newFieldsStep(), append([]sql.OrderTerm{term}, terms...)...) - } -} - -// ByMaintenanceEntriesCount orders the results by maintenance_entries count. -func ByMaintenanceEntriesCount(opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborsCount(s, newMaintenanceEntriesStep(), opts...) - } -} - -// ByMaintenanceEntries orders the results by maintenance_entries terms. -func ByMaintenanceEntries(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newMaintenanceEntriesStep(), append([]sql.OrderTerm{term}, terms...)...) - } -} - -// ByAttachmentsCount orders the results by attachments count. -func ByAttachmentsCount(opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborsCount(s, newAttachmentsStep(), opts...) - } -} - -// ByAttachments orders the results by attachments terms. -func ByAttachments(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newAttachmentsStep(), append([]sql.OrderTerm{term}, terms...)...) - } -} -func newGroupStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(GroupInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn), - ) -} -func newParentStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(Table, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, ParentTable, ParentColumn), - ) -} -func newChildrenStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(Table, FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, ChildrenTable, ChildrenColumn), - ) -} -func newLabelStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(LabelInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.M2M, true, LabelTable, LabelPrimaryKey...), - ) -} -func newLocationStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(LocationInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, LocationTable, LocationColumn), - ) -} -func newFieldsStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(FieldsInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, FieldsTable, FieldsColumn), - ) -} -func newMaintenanceEntriesStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(MaintenanceEntriesInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, MaintenanceEntriesTable, MaintenanceEntriesColumn), - ) -} -func newAttachmentsStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(AttachmentsInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, AttachmentsTable, AttachmentsColumn), - ) -} diff --git a/backend/internal/data/ent/item/where.go b/backend/internal/data/ent/item/where.go index 7504e6a..883a33a 100644 --- a/backend/internal/data/ent/item/where.go +++ b/backend/internal/data/ent/item/where.go @@ -1420,7 +1420,11 @@ func HasGroup() predicate.Item { // HasGroupWith applies the HasEdge predicate on the "group" edge with a given conditions (other predicates). func HasGroupWith(preds ...predicate.Group) predicate.Item { return predicate.Item(func(s *sql.Selector) { - step := newGroupStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(GroupInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -1443,7 +1447,11 @@ func HasParent() predicate.Item { // HasParentWith applies the HasEdge predicate on the "parent" edge with a given conditions (other predicates). func HasParentWith(preds ...predicate.Item) predicate.Item { return predicate.Item(func(s *sql.Selector) { - step := newParentStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(Table, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, ParentTable, ParentColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -1466,7 +1474,11 @@ func HasChildren() predicate.Item { // HasChildrenWith applies the HasEdge predicate on the "children" edge with a given conditions (other predicates). func HasChildrenWith(preds ...predicate.Item) predicate.Item { return predicate.Item(func(s *sql.Selector) { - step := newChildrenStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(Table, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, ChildrenTable, ChildrenColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -1489,7 +1501,11 @@ func HasLabel() predicate.Item { // HasLabelWith applies the HasEdge predicate on the "label" edge with a given conditions (other predicates). func HasLabelWith(preds ...predicate.Label) predicate.Item { return predicate.Item(func(s *sql.Selector) { - step := newLabelStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(LabelInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2M, true, LabelTable, LabelPrimaryKey...), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -1512,7 +1528,11 @@ func HasLocation() predicate.Item { // HasLocationWith applies the HasEdge predicate on the "location" edge with a given conditions (other predicates). func HasLocationWith(preds ...predicate.Location) predicate.Item { return predicate.Item(func(s *sql.Selector) { - step := newLocationStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(LocationInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, LocationTable, LocationColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -1535,7 +1555,11 @@ func HasFields() predicate.Item { // HasFieldsWith applies the HasEdge predicate on the "fields" edge with a given conditions (other predicates). func HasFieldsWith(preds ...predicate.ItemField) predicate.Item { return predicate.Item(func(s *sql.Selector) { - step := newFieldsStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(FieldsInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, FieldsTable, FieldsColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -1558,7 +1582,11 @@ func HasMaintenanceEntries() predicate.Item { // HasMaintenanceEntriesWith applies the HasEdge predicate on the "maintenance_entries" edge with a given conditions (other predicates). func HasMaintenanceEntriesWith(preds ...predicate.MaintenanceEntry) predicate.Item { return predicate.Item(func(s *sql.Selector) { - step := newMaintenanceEntriesStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(MaintenanceEntriesInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, MaintenanceEntriesTable, MaintenanceEntriesColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -1581,7 +1609,11 @@ func HasAttachments() predicate.Item { // HasAttachmentsWith applies the HasEdge predicate on the "attachments" edge with a given conditions (other predicates). func HasAttachmentsWith(preds ...predicate.Attachment) predicate.Item { return predicate.Item(func(s *sql.Selector) { - step := newAttachmentsStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(AttachmentsInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, AttachmentsTable, AttachmentsColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -1592,15 +1624,32 @@ func HasAttachmentsWith(preds ...predicate.Attachment) predicate.Item { // And groups predicates with the AND operator between them. func And(predicates ...predicate.Item) predicate.Item { - return predicate.Item(sql.AndPredicates(predicates...)) + return predicate.Item(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for _, p := range predicates { + p(s1) + } + s.Where(s1.P()) + }) } // Or groups predicates with the OR operator between them. func Or(predicates ...predicate.Item) predicate.Item { - return predicate.Item(sql.OrPredicates(predicates...)) + return predicate.Item(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for i, p := range predicates { + if i > 0 { + s1.Or() + } + p(s1) + } + s.Where(s1.P()) + }) } // Not applies the not operator on the given predicate. func Not(p predicate.Item) predicate.Item { - return predicate.Item(sql.NotPredicates(p)) + return predicate.Item(func(s *sql.Selector) { + p(s.Not()) + }) } diff --git a/backend/internal/data/ent/item_create.go b/backend/internal/data/ent/item_create.go index 9eb1cb6..34dfa58 100644 --- a/backend/internal/data/ent/item_create.go +++ b/backend/internal/data/ent/item_create.go @@ -487,7 +487,7 @@ func (ic *ItemCreate) Mutation() *ItemMutation { // Save creates the Item in the database. func (ic *ItemCreate) Save(ctx context.Context) (*Item, error) { ic.defaults() - return withHooks(ctx, ic.sqlSave, ic.mutation, ic.hooks) + return withHooks[*Item, ItemMutation](ctx, ic.sqlSave, ic.mutation, ic.hooks) } // SaveX calls Save and panics if Save returns an error. @@ -900,15 +900,11 @@ func (ic *ItemCreate) createSpec() (*Item, *sqlgraph.CreateSpec) { // ItemCreateBulk is the builder for creating many Item entities in bulk. type ItemCreateBulk struct { config - err error builders []*ItemCreate } // Save creates the Item entities in the database. func (icb *ItemCreateBulk) Save(ctx context.Context) ([]*Item, error) { - if icb.err != nil { - return nil, icb.err - } specs := make([]*sqlgraph.CreateSpec, len(icb.builders)) nodes := make([]*Item, len(icb.builders)) mutators := make([]Mutator, len(icb.builders)) @@ -925,8 +921,8 @@ func (icb *ItemCreateBulk) Save(ctx context.Context) ([]*Item, error) { return nil, err } builder.mutation = mutation - var err error nodes[i], specs[i] = builder.createSpec() + var err error if i < len(mutators)-1 { _, err = mutators[i+1].Mutate(root, icb.builders[i+1].mutation) } else { diff --git a/backend/internal/data/ent/item_delete.go b/backend/internal/data/ent/item_delete.go index d634d5d..c2d00ff 100644 --- a/backend/internal/data/ent/item_delete.go +++ b/backend/internal/data/ent/item_delete.go @@ -27,7 +27,7 @@ func (id *ItemDelete) Where(ps ...predicate.Item) *ItemDelete { // Exec executes the deletion query and returns how many vertices were deleted. func (id *ItemDelete) Exec(ctx context.Context) (int, error) { - return withHooks(ctx, id.sqlExec, id.mutation, id.hooks) + return withHooks[int, ItemMutation](ctx, id.sqlExec, id.mutation, id.hooks) } // ExecX is like Exec, but panics if an error occurs. diff --git a/backend/internal/data/ent/item_query.go b/backend/internal/data/ent/item_query.go index 12fc331..c66b6c6 100644 --- a/backend/internal/data/ent/item_query.go +++ b/backend/internal/data/ent/item_query.go @@ -26,7 +26,7 @@ import ( type ItemQuery struct { config ctx *QueryContext - order []item.OrderOption + order []OrderFunc inters []Interceptor predicates []predicate.Item withGroup *GroupQuery @@ -69,7 +69,7 @@ func (iq *ItemQuery) Unique(unique bool) *ItemQuery { } // Order specifies how the records should be ordered. -func (iq *ItemQuery) Order(o ...item.OrderOption) *ItemQuery { +func (iq *ItemQuery) Order(o ...OrderFunc) *ItemQuery { iq.order = append(iq.order, o...) return iq } @@ -439,7 +439,7 @@ func (iq *ItemQuery) Clone() *ItemQuery { return &ItemQuery{ config: iq.config, ctx: iq.ctx.Clone(), - order: append([]item.OrderOption{}, iq.order...), + order: append([]OrderFunc{}, iq.order...), inters: append([]Interceptor{}, iq.inters...), predicates: append([]predicate.Item{}, iq.predicates...), withGroup: iq.withGroup.Clone(), @@ -790,7 +790,7 @@ func (iq *ItemQuery) loadChildren(ctx context.Context, query *ItemQuery, nodes [ } query.withFKs = true query.Where(predicate.Item(func(s *sql.Selector) { - s.Where(sql.InValues(s.C(item.ChildrenColumn), fks...)) + s.Where(sql.InValues(item.ChildrenColumn, fks...)) })) neighbors, err := query.All(ctx) if err != nil { @@ -803,7 +803,7 @@ func (iq *ItemQuery) loadChildren(ctx context.Context, query *ItemQuery, nodes [ } node, ok := nodeids[*fk] if !ok { - return fmt.Errorf(`unexpected referenced foreign-key "item_children" returned %v for node %v`, *fk, n.ID) + return fmt.Errorf(`unexpected foreign-key "item_children" returned %v for node %v`, *fk, n.ID) } assign(node, n) } @@ -914,7 +914,7 @@ func (iq *ItemQuery) loadFields(ctx context.Context, query *ItemFieldQuery, node } query.withFKs = true query.Where(predicate.ItemField(func(s *sql.Selector) { - s.Where(sql.InValues(s.C(item.FieldsColumn), fks...)) + s.Where(sql.InValues(item.FieldsColumn, fks...)) })) neighbors, err := query.All(ctx) if err != nil { @@ -927,7 +927,7 @@ func (iq *ItemQuery) loadFields(ctx context.Context, query *ItemFieldQuery, node } node, ok := nodeids[*fk] if !ok { - return fmt.Errorf(`unexpected referenced foreign-key "item_fields" returned %v for node %v`, *fk, n.ID) + return fmt.Errorf(`unexpected foreign-key "item_fields" returned %v for node %v`, *fk, n.ID) } assign(node, n) } @@ -943,11 +943,8 @@ func (iq *ItemQuery) loadMaintenanceEntries(ctx context.Context, query *Maintena init(nodes[i]) } } - if len(query.ctx.Fields) > 0 { - query.ctx.AppendFieldOnce(maintenanceentry.FieldItemID) - } query.Where(predicate.MaintenanceEntry(func(s *sql.Selector) { - s.Where(sql.InValues(s.C(item.MaintenanceEntriesColumn), fks...)) + s.Where(sql.InValues(item.MaintenanceEntriesColumn, fks...)) })) neighbors, err := query.All(ctx) if err != nil { @@ -957,7 +954,7 @@ func (iq *ItemQuery) loadMaintenanceEntries(ctx context.Context, query *Maintena fk := n.ItemID node, ok := nodeids[fk] if !ok { - return fmt.Errorf(`unexpected referenced foreign-key "item_id" returned %v for node %v`, fk, n.ID) + return fmt.Errorf(`unexpected foreign-key "item_id" returned %v for node %v`, fk, n.ID) } assign(node, n) } @@ -975,7 +972,7 @@ func (iq *ItemQuery) loadAttachments(ctx context.Context, query *AttachmentQuery } query.withFKs = true query.Where(predicate.Attachment(func(s *sql.Selector) { - s.Where(sql.InValues(s.C(item.AttachmentsColumn), fks...)) + s.Where(sql.InValues(item.AttachmentsColumn, fks...)) })) neighbors, err := query.All(ctx) if err != nil { @@ -988,7 +985,7 @@ func (iq *ItemQuery) loadAttachments(ctx context.Context, query *AttachmentQuery } node, ok := nodeids[*fk] if !ok { - return fmt.Errorf(`unexpected referenced foreign-key "item_attachments" returned %v for node %v`, *fk, n.ID) + return fmt.Errorf(`unexpected foreign-key "item_attachments" returned %v for node %v`, *fk, n.ID) } assign(node, n) } diff --git a/backend/internal/data/ent/item_update.go b/backend/internal/data/ent/item_update.go index 8cd4722..03932bf 100644 --- a/backend/internal/data/ent/item_update.go +++ b/backend/internal/data/ent/item_update.go @@ -47,14 +47,6 @@ func (iu *ItemUpdate) SetName(s string) *ItemUpdate { return iu } -// SetNillableName sets the "name" field if the given value is not nil. -func (iu *ItemUpdate) SetNillableName(s *string) *ItemUpdate { - if s != nil { - iu.SetName(*s) - } - return iu -} - // SetDescription sets the "description" field. func (iu *ItemUpdate) SetDescription(s string) *ItemUpdate { iu.mutation.SetDescription(s) @@ -696,7 +688,7 @@ func (iu *ItemUpdate) RemoveAttachments(a ...*Attachment) *ItemUpdate { // Save executes the query and returns the number of nodes affected by the update operation. func (iu *ItemUpdate) Save(ctx context.Context) (int, error) { iu.defaults() - return withHooks(ctx, iu.sqlSave, iu.mutation, iu.hooks) + return withHooks[int, ItemMutation](ctx, iu.sqlSave, iu.mutation, iu.hooks) } // SaveX is like Save, but panics if an error occurs. @@ -1255,14 +1247,6 @@ func (iuo *ItemUpdateOne) SetName(s string) *ItemUpdateOne { return iuo } -// SetNillableName sets the "name" field if the given value is not nil. -func (iuo *ItemUpdateOne) SetNillableName(s *string) *ItemUpdateOne { - if s != nil { - iuo.SetName(*s) - } - return iuo -} - // SetDescription sets the "description" field. func (iuo *ItemUpdateOne) SetDescription(s string) *ItemUpdateOne { iuo.mutation.SetDescription(s) @@ -1917,7 +1901,7 @@ func (iuo *ItemUpdateOne) Select(field string, fields ...string) *ItemUpdateOne // Save executes the query and returns the updated Item entity. func (iuo *ItemUpdateOne) Save(ctx context.Context) (*Item, error) { iuo.defaults() - return withHooks(ctx, iuo.sqlSave, iuo.mutation, iuo.hooks) + return withHooks[*Item, ItemMutation](ctx, iuo.sqlSave, iuo.mutation, iuo.hooks) } // SaveX is like Save, but panics if an error occurs. diff --git a/backend/internal/data/ent/itemfield.go b/backend/internal/data/ent/itemfield.go index b2b8b8d..cff6751 100644 --- a/backend/internal/data/ent/itemfield.go +++ b/backend/internal/data/ent/itemfield.go @@ -7,7 +7,6 @@ import ( "strings" "time" - "entgo.io/ent" "entgo.io/ent/dialect/sql" "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/data/ent/item" @@ -39,9 +38,8 @@ type ItemField struct { TimeValue time.Time `json:"time_value,omitempty"` // Edges holds the relations/edges for other nodes in the graph. // The values are being populated by the ItemFieldQuery when eager-loading is set. - Edges ItemFieldEdges `json:"edges"` - item_fields *uuid.UUID - selectValues sql.SelectValues + Edges ItemFieldEdges `json:"edges"` + item_fields *uuid.UUID } // ItemFieldEdges holds the relations/edges for other nodes in the graph. @@ -84,7 +82,7 @@ func (*ItemField) scanValues(columns []string) ([]any, error) { case itemfield.ForeignKeys[0]: // item_fields values[i] = &sql.NullScanner{S: new(uuid.UUID)} default: - values[i] = new(sql.UnknownType) + return nil, fmt.Errorf("unexpected column %q for type ItemField", columns[i]) } } return values, nil @@ -165,19 +163,11 @@ func (_if *ItemField) assignValues(columns []string, values []any) error { _if.item_fields = new(uuid.UUID) *_if.item_fields = *value.S.(*uuid.UUID) } - default: - _if.selectValues.Set(columns[i], values[i]) } } return nil } -// Value returns the ent.Value that was dynamically selected and assigned to the ItemField. -// This includes values selected through modifiers, order, etc. -func (_if *ItemField) Value(name string) (ent.Value, error) { - return _if.selectValues.Get(name) -} - // QueryItem queries the "item" edge of the ItemField entity. func (_if *ItemField) QueryItem() *ItemQuery { return NewItemFieldClient(_if.config).QueryItem(_if) diff --git a/backend/internal/data/ent/itemfield/itemfield.go b/backend/internal/data/ent/itemfield/itemfield.go index dfbf378..ccad0fe 100644 --- a/backend/internal/data/ent/itemfield/itemfield.go +++ b/backend/internal/data/ent/itemfield/itemfield.go @@ -6,8 +6,6 @@ import ( "fmt" "time" - "entgo.io/ent/dialect/sql" - "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" ) @@ -127,70 +125,3 @@ func TypeValidator(_type Type) error { return fmt.Errorf("itemfield: invalid enum value for type field: %q", _type) } } - -// OrderOption defines the ordering options for the ItemField queries. -type OrderOption func(*sql.Selector) - -// ByID orders the results by the id field. -func ByID(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldID, opts...).ToFunc() -} - -// ByCreatedAt orders the results by the created_at field. -func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() -} - -// ByUpdatedAt orders the results by the updated_at field. -func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc() -} - -// ByName orders the results by the name field. -func ByName(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldName, opts...).ToFunc() -} - -// ByDescription orders the results by the description field. -func ByDescription(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldDescription, opts...).ToFunc() -} - -// ByType orders the results by the type field. -func ByType(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldType, opts...).ToFunc() -} - -// ByTextValue orders the results by the text_value field. -func ByTextValue(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldTextValue, opts...).ToFunc() -} - -// ByNumberValue orders the results by the number_value field. -func ByNumberValue(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldNumberValue, opts...).ToFunc() -} - -// ByBooleanValue orders the results by the boolean_value field. -func ByBooleanValue(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldBooleanValue, opts...).ToFunc() -} - -// ByTimeValue orders the results by the time_value field. -func ByTimeValue(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldTimeValue, opts...).ToFunc() -} - -// ByItemField orders the results by item field. -func ByItemField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newItemStep(), sql.OrderByField(field, opts...)) - } -} -func newItemStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(ItemInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, ItemTable, ItemColumn), - ) -} diff --git a/backend/internal/data/ent/itemfield/where.go b/backend/internal/data/ent/itemfield/where.go index 8a2d4aa..94805ea 100644 --- a/backend/internal/data/ent/itemfield/where.go +++ b/backend/internal/data/ent/itemfield/where.go @@ -525,7 +525,11 @@ func HasItem() predicate.ItemField { // HasItemWith applies the HasEdge predicate on the "item" edge with a given conditions (other predicates). func HasItemWith(preds ...predicate.Item) predicate.ItemField { return predicate.ItemField(func(s *sql.Selector) { - step := newItemStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(ItemInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, ItemTable, ItemColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -536,15 +540,32 @@ func HasItemWith(preds ...predicate.Item) predicate.ItemField { // And groups predicates with the AND operator between them. func And(predicates ...predicate.ItemField) predicate.ItemField { - return predicate.ItemField(sql.AndPredicates(predicates...)) + return predicate.ItemField(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for _, p := range predicates { + p(s1) + } + s.Where(s1.P()) + }) } // Or groups predicates with the OR operator between them. func Or(predicates ...predicate.ItemField) predicate.ItemField { - return predicate.ItemField(sql.OrPredicates(predicates...)) + return predicate.ItemField(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for i, p := range predicates { + if i > 0 { + s1.Or() + } + p(s1) + } + s.Where(s1.P()) + }) } // Not applies the not operator on the given predicate. func Not(p predicate.ItemField) predicate.ItemField { - return predicate.ItemField(sql.NotPredicates(p)) + return predicate.ItemField(func(s *sql.Selector) { + p(s.Not()) + }) } diff --git a/backend/internal/data/ent/itemfield_create.go b/backend/internal/data/ent/itemfield_create.go index 65a22fb..19e49a2 100644 --- a/backend/internal/data/ent/itemfield_create.go +++ b/backend/internal/data/ent/itemfield_create.go @@ -173,7 +173,7 @@ func (ifc *ItemFieldCreate) Mutation() *ItemFieldMutation { // Save creates the ItemField in the database. func (ifc *ItemFieldCreate) Save(ctx context.Context) (*ItemField, error) { ifc.defaults() - return withHooks(ctx, ifc.sqlSave, ifc.mutation, ifc.hooks) + return withHooks[*ItemField, ItemFieldMutation](ctx, ifc.sqlSave, ifc.mutation, ifc.hooks) } // SaveX calls Save and panics if Save returns an error. @@ -356,15 +356,11 @@ func (ifc *ItemFieldCreate) createSpec() (*ItemField, *sqlgraph.CreateSpec) { // ItemFieldCreateBulk is the builder for creating many ItemField entities in bulk. type ItemFieldCreateBulk struct { config - err error builders []*ItemFieldCreate } // Save creates the ItemField entities in the database. func (ifcb *ItemFieldCreateBulk) Save(ctx context.Context) ([]*ItemField, error) { - if ifcb.err != nil { - return nil, ifcb.err - } specs := make([]*sqlgraph.CreateSpec, len(ifcb.builders)) nodes := make([]*ItemField, len(ifcb.builders)) mutators := make([]Mutator, len(ifcb.builders)) @@ -381,8 +377,8 @@ func (ifcb *ItemFieldCreateBulk) Save(ctx context.Context) ([]*ItemField, error) return nil, err } builder.mutation = mutation - var err error nodes[i], specs[i] = builder.createSpec() + var err error if i < len(mutators)-1 { _, err = mutators[i+1].Mutate(root, ifcb.builders[i+1].mutation) } else { diff --git a/backend/internal/data/ent/itemfield_delete.go b/backend/internal/data/ent/itemfield_delete.go index ba85cbc..181b736 100644 --- a/backend/internal/data/ent/itemfield_delete.go +++ b/backend/internal/data/ent/itemfield_delete.go @@ -27,7 +27,7 @@ func (ifd *ItemFieldDelete) Where(ps ...predicate.ItemField) *ItemFieldDelete { // Exec executes the deletion query and returns how many vertices were deleted. func (ifd *ItemFieldDelete) Exec(ctx context.Context) (int, error) { - return withHooks(ctx, ifd.sqlExec, ifd.mutation, ifd.hooks) + return withHooks[int, ItemFieldMutation](ctx, ifd.sqlExec, ifd.mutation, ifd.hooks) } // ExecX is like Exec, but panics if an error occurs. diff --git a/backend/internal/data/ent/itemfield_query.go b/backend/internal/data/ent/itemfield_query.go index 21bffb8..c00e422 100644 --- a/backend/internal/data/ent/itemfield_query.go +++ b/backend/internal/data/ent/itemfield_query.go @@ -20,7 +20,7 @@ import ( type ItemFieldQuery struct { config ctx *QueryContext - order []itemfield.OrderOption + order []OrderFunc inters []Interceptor predicates []predicate.ItemField withItem *ItemQuery @@ -56,7 +56,7 @@ func (ifq *ItemFieldQuery) Unique(unique bool) *ItemFieldQuery { } // Order specifies how the records should be ordered. -func (ifq *ItemFieldQuery) Order(o ...itemfield.OrderOption) *ItemFieldQuery { +func (ifq *ItemFieldQuery) Order(o ...OrderFunc) *ItemFieldQuery { ifq.order = append(ifq.order, o...) return ifq } @@ -272,7 +272,7 @@ func (ifq *ItemFieldQuery) Clone() *ItemFieldQuery { return &ItemFieldQuery{ config: ifq.config, ctx: ifq.ctx.Clone(), - order: append([]itemfield.OrderOption{}, ifq.order...), + order: append([]OrderFunc{}, ifq.order...), inters: append([]Interceptor{}, ifq.inters...), predicates: append([]predicate.ItemField{}, ifq.predicates...), withItem: ifq.withItem.Clone(), diff --git a/backend/internal/data/ent/itemfield_update.go b/backend/internal/data/ent/itemfield_update.go index 3f44dc1..83e956f 100644 --- a/backend/internal/data/ent/itemfield_update.go +++ b/backend/internal/data/ent/itemfield_update.go @@ -42,14 +42,6 @@ func (ifu *ItemFieldUpdate) SetName(s string) *ItemFieldUpdate { return ifu } -// SetNillableName sets the "name" field if the given value is not nil. -func (ifu *ItemFieldUpdate) SetNillableName(s *string) *ItemFieldUpdate { - if s != nil { - ifu.SetName(*s) - } - return ifu -} - // SetDescription sets the "description" field. func (ifu *ItemFieldUpdate) SetDescription(s string) *ItemFieldUpdate { ifu.mutation.SetDescription(s) @@ -76,14 +68,6 @@ func (ifu *ItemFieldUpdate) SetType(i itemfield.Type) *ItemFieldUpdate { return ifu } -// SetNillableType sets the "type" field if the given value is not nil. -func (ifu *ItemFieldUpdate) SetNillableType(i *itemfield.Type) *ItemFieldUpdate { - if i != nil { - ifu.SetType(*i) - } - return ifu -} - // SetTextValue sets the "text_value" field. func (ifu *ItemFieldUpdate) SetTextValue(s string) *ItemFieldUpdate { ifu.mutation.SetTextValue(s) @@ -192,7 +176,7 @@ func (ifu *ItemFieldUpdate) ClearItem() *ItemFieldUpdate { // Save executes the query and returns the number of nodes affected by the update operation. func (ifu *ItemFieldUpdate) Save(ctx context.Context) (int, error) { ifu.defaults() - return withHooks(ctx, ifu.sqlSave, ifu.mutation, ifu.hooks) + return withHooks[int, ItemFieldMutation](ctx, ifu.sqlSave, ifu.mutation, ifu.hooks) } // SaveX is like Save, but panics if an error occurs. @@ -359,14 +343,6 @@ func (ifuo *ItemFieldUpdateOne) SetName(s string) *ItemFieldUpdateOne { return ifuo } -// SetNillableName sets the "name" field if the given value is not nil. -func (ifuo *ItemFieldUpdateOne) SetNillableName(s *string) *ItemFieldUpdateOne { - if s != nil { - ifuo.SetName(*s) - } - return ifuo -} - // SetDescription sets the "description" field. func (ifuo *ItemFieldUpdateOne) SetDescription(s string) *ItemFieldUpdateOne { ifuo.mutation.SetDescription(s) @@ -393,14 +369,6 @@ func (ifuo *ItemFieldUpdateOne) SetType(i itemfield.Type) *ItemFieldUpdateOne { return ifuo } -// SetNillableType sets the "type" field if the given value is not nil. -func (ifuo *ItemFieldUpdateOne) SetNillableType(i *itemfield.Type) *ItemFieldUpdateOne { - if i != nil { - ifuo.SetType(*i) - } - return ifuo -} - // SetTextValue sets the "text_value" field. func (ifuo *ItemFieldUpdateOne) SetTextValue(s string) *ItemFieldUpdateOne { ifuo.mutation.SetTextValue(s) @@ -522,7 +490,7 @@ func (ifuo *ItemFieldUpdateOne) Select(field string, fields ...string) *ItemFiel // Save executes the query and returns the updated ItemField entity. func (ifuo *ItemFieldUpdateOne) Save(ctx context.Context) (*ItemField, error) { ifuo.defaults() - return withHooks(ctx, ifuo.sqlSave, ifuo.mutation, ifuo.hooks) + return withHooks[*ItemField, ItemFieldMutation](ctx, ifuo.sqlSave, ifuo.mutation, ifuo.hooks) } // SaveX is like Save, but panics if an error occurs. diff --git a/backend/internal/data/ent/label.go b/backend/internal/data/ent/label.go index fdd6f8d..945b597 100644 --- a/backend/internal/data/ent/label.go +++ b/backend/internal/data/ent/label.go @@ -7,7 +7,6 @@ import ( "strings" "time" - "entgo.io/ent" "entgo.io/ent/dialect/sql" "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/data/ent/group" @@ -33,7 +32,6 @@ type Label struct { // The values are being populated by the LabelQuery when eager-loading is set. Edges LabelEdges `json:"edges"` group_labels *uuid.UUID - selectValues sql.SelectValues } // LabelEdges holds the relations/edges for other nodes in the graph. @@ -83,7 +81,7 @@ func (*Label) scanValues(columns []string) ([]any, error) { case label.ForeignKeys[0]: // group_labels values[i] = &sql.NullScanner{S: new(uuid.UUID)} default: - values[i] = new(sql.UnknownType) + return nil, fmt.Errorf("unexpected column %q for type Label", columns[i]) } } return values, nil @@ -140,19 +138,11 @@ func (l *Label) assignValues(columns []string, values []any) error { l.group_labels = new(uuid.UUID) *l.group_labels = *value.S.(*uuid.UUID) } - default: - l.selectValues.Set(columns[i], values[i]) } } return nil } -// Value returns the ent.Value that was dynamically selected and assigned to the Label. -// This includes values selected through modifiers, order, etc. -func (l *Label) Value(name string) (ent.Value, error) { - return l.selectValues.Get(name) -} - // QueryGroup queries the "group" edge of the Label entity. func (l *Label) QueryGroup() *GroupQuery { return NewLabelClient(l.config).QueryGroup(l) diff --git a/backend/internal/data/ent/label/label.go b/backend/internal/data/ent/label/label.go index df34c87..82bcdbd 100644 --- a/backend/internal/data/ent/label/label.go +++ b/backend/internal/data/ent/label/label.go @@ -5,8 +5,6 @@ package label import ( "time" - "entgo.io/ent/dialect/sql" - "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" ) @@ -98,71 +96,3 @@ var ( // DefaultID holds the default value on creation for the "id" field. DefaultID func() uuid.UUID ) - -// OrderOption defines the ordering options for the Label queries. -type OrderOption func(*sql.Selector) - -// ByID orders the results by the id field. -func ByID(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldID, opts...).ToFunc() -} - -// ByCreatedAt orders the results by the created_at field. -func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() -} - -// ByUpdatedAt orders the results by the updated_at field. -func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc() -} - -// ByName orders the results by the name field. -func ByName(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldName, opts...).ToFunc() -} - -// ByDescription orders the results by the description field. -func ByDescription(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldDescription, opts...).ToFunc() -} - -// ByColor orders the results by the color field. -func ByColor(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldColor, opts...).ToFunc() -} - -// ByGroupField orders the results by group field. -func ByGroupField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newGroupStep(), sql.OrderByField(field, opts...)) - } -} - -// ByItemsCount orders the results by items count. -func ByItemsCount(opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborsCount(s, newItemsStep(), opts...) - } -} - -// ByItems orders the results by items terms. -func ByItems(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newItemsStep(), append([]sql.OrderTerm{term}, terms...)...) - } -} -func newGroupStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(GroupInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn), - ) -} -func newItemsStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(ItemsInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.M2M, false, ItemsTable, ItemsPrimaryKey...), - ) -} diff --git a/backend/internal/data/ent/label/where.go b/backend/internal/data/ent/label/where.go index 3754ac7..fd321e1 100644 --- a/backend/internal/data/ent/label/where.go +++ b/backend/internal/data/ent/label/where.go @@ -390,7 +390,11 @@ func HasGroup() predicate.Label { // HasGroupWith applies the HasEdge predicate on the "group" edge with a given conditions (other predicates). func HasGroupWith(preds ...predicate.Group) predicate.Label { return predicate.Label(func(s *sql.Selector) { - step := newGroupStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(GroupInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -413,7 +417,11 @@ func HasItems() predicate.Label { // HasItemsWith applies the HasEdge predicate on the "items" edge with a given conditions (other predicates). func HasItemsWith(preds ...predicate.Item) predicate.Label { return predicate.Label(func(s *sql.Selector) { - step := newItemsStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(ItemsInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2M, false, ItemsTable, ItemsPrimaryKey...), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -424,15 +432,32 @@ func HasItemsWith(preds ...predicate.Item) predicate.Label { // And groups predicates with the AND operator between them. func And(predicates ...predicate.Label) predicate.Label { - return predicate.Label(sql.AndPredicates(predicates...)) + return predicate.Label(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for _, p := range predicates { + p(s1) + } + s.Where(s1.P()) + }) } // Or groups predicates with the OR operator between them. func Or(predicates ...predicate.Label) predicate.Label { - return predicate.Label(sql.OrPredicates(predicates...)) + return predicate.Label(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for i, p := range predicates { + if i > 0 { + s1.Or() + } + p(s1) + } + s.Where(s1.P()) + }) } // Not applies the not operator on the given predicate. func Not(p predicate.Label) predicate.Label { - return predicate.Label(sql.NotPredicates(p)) + return predicate.Label(func(s *sql.Selector) { + p(s.Not()) + }) } diff --git a/backend/internal/data/ent/label_create.go b/backend/internal/data/ent/label_create.go index 0ad6469..9a2c85f 100644 --- a/backend/internal/data/ent/label_create.go +++ b/backend/internal/data/ent/label_create.go @@ -133,7 +133,7 @@ func (lc *LabelCreate) Mutation() *LabelMutation { // Save creates the Label in the database. func (lc *LabelCreate) Save(ctx context.Context) (*Label, error) { lc.defaults() - return withHooks(ctx, lc.sqlSave, lc.mutation, lc.hooks) + return withHooks[*Label, LabelMutation](ctx, lc.sqlSave, lc.mutation, lc.hooks) } // SaveX calls Save and panics if Save returns an error. @@ -297,15 +297,11 @@ func (lc *LabelCreate) createSpec() (*Label, *sqlgraph.CreateSpec) { // LabelCreateBulk is the builder for creating many Label entities in bulk. type LabelCreateBulk struct { config - err error builders []*LabelCreate } // Save creates the Label entities in the database. func (lcb *LabelCreateBulk) Save(ctx context.Context) ([]*Label, error) { - if lcb.err != nil { - return nil, lcb.err - } specs := make([]*sqlgraph.CreateSpec, len(lcb.builders)) nodes := make([]*Label, len(lcb.builders)) mutators := make([]Mutator, len(lcb.builders)) @@ -322,8 +318,8 @@ func (lcb *LabelCreateBulk) Save(ctx context.Context) ([]*Label, error) { return nil, err } builder.mutation = mutation - var err error nodes[i], specs[i] = builder.createSpec() + var err error if i < len(mutators)-1 { _, err = mutators[i+1].Mutate(root, lcb.builders[i+1].mutation) } else { diff --git a/backend/internal/data/ent/label_delete.go b/backend/internal/data/ent/label_delete.go index f3b514a..2f6e251 100644 --- a/backend/internal/data/ent/label_delete.go +++ b/backend/internal/data/ent/label_delete.go @@ -27,7 +27,7 @@ func (ld *LabelDelete) Where(ps ...predicate.Label) *LabelDelete { // Exec executes the deletion query and returns how many vertices were deleted. func (ld *LabelDelete) Exec(ctx context.Context) (int, error) { - return withHooks(ctx, ld.sqlExec, ld.mutation, ld.hooks) + return withHooks[int, LabelMutation](ctx, ld.sqlExec, ld.mutation, ld.hooks) } // ExecX is like Exec, but panics if an error occurs. diff --git a/backend/internal/data/ent/label_query.go b/backend/internal/data/ent/label_query.go index e3bb6d1..925641b 100644 --- a/backend/internal/data/ent/label_query.go +++ b/backend/internal/data/ent/label_query.go @@ -22,7 +22,7 @@ import ( type LabelQuery struct { config ctx *QueryContext - order []label.OrderOption + order []OrderFunc inters []Interceptor predicates []predicate.Label withGroup *GroupQuery @@ -59,7 +59,7 @@ func (lq *LabelQuery) Unique(unique bool) *LabelQuery { } // Order specifies how the records should be ordered. -func (lq *LabelQuery) Order(o ...label.OrderOption) *LabelQuery { +func (lq *LabelQuery) Order(o ...OrderFunc) *LabelQuery { lq.order = append(lq.order, o...) return lq } @@ -297,7 +297,7 @@ func (lq *LabelQuery) Clone() *LabelQuery { return &LabelQuery{ config: lq.config, ctx: lq.ctx.Clone(), - order: append([]label.OrderOption{}, lq.order...), + order: append([]OrderFunc{}, lq.order...), inters: append([]Interceptor{}, lq.inters...), predicates: append([]predicate.Label{}, lq.predicates...), withGroup: lq.withGroup.Clone(), diff --git a/backend/internal/data/ent/label_update.go b/backend/internal/data/ent/label_update.go index 0862d22..303e2e8 100644 --- a/backend/internal/data/ent/label_update.go +++ b/backend/internal/data/ent/label_update.go @@ -43,14 +43,6 @@ func (lu *LabelUpdate) SetName(s string) *LabelUpdate { return lu } -// SetNillableName sets the "name" field if the given value is not nil. -func (lu *LabelUpdate) SetNillableName(s *string) *LabelUpdate { - if s != nil { - lu.SetName(*s) - } - return lu -} - // SetDescription sets the "description" field. func (lu *LabelUpdate) SetDescription(s string) *LabelUpdate { lu.mutation.SetDescription(s) @@ -152,7 +144,7 @@ func (lu *LabelUpdate) RemoveItems(i ...*Item) *LabelUpdate { // Save executes the query and returns the number of nodes affected by the update operation. func (lu *LabelUpdate) Save(ctx context.Context) (int, error) { lu.defaults() - return withHooks(ctx, lu.sqlSave, lu.mutation, lu.hooks) + return withHooks[int, LabelMutation](ctx, lu.sqlSave, lu.mutation, lu.hooks) } // SaveX is like Save, but panics if an error occurs. @@ -344,14 +336,6 @@ func (luo *LabelUpdateOne) SetName(s string) *LabelUpdateOne { return luo } -// SetNillableName sets the "name" field if the given value is not nil. -func (luo *LabelUpdateOne) SetNillableName(s *string) *LabelUpdateOne { - if s != nil { - luo.SetName(*s) - } - return luo -} - // SetDescription sets the "description" field. func (luo *LabelUpdateOne) SetDescription(s string) *LabelUpdateOne { luo.mutation.SetDescription(s) @@ -466,7 +450,7 @@ func (luo *LabelUpdateOne) Select(field string, fields ...string) *LabelUpdateOn // Save executes the query and returns the updated Label entity. func (luo *LabelUpdateOne) Save(ctx context.Context) (*Label, error) { luo.defaults() - return withHooks(ctx, luo.sqlSave, luo.mutation, luo.hooks) + return withHooks[*Label, LabelMutation](ctx, luo.sqlSave, luo.mutation, luo.hooks) } // SaveX is like Save, but panics if an error occurs. diff --git a/backend/internal/data/ent/location.go b/backend/internal/data/ent/location.go index 640f05e..156f8c0 100644 --- a/backend/internal/data/ent/location.go +++ b/backend/internal/data/ent/location.go @@ -7,7 +7,6 @@ import ( "strings" "time" - "entgo.io/ent" "entgo.io/ent/dialect/sql" "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/data/ent/group" @@ -32,7 +31,6 @@ type Location struct { Edges LocationEdges `json:"edges"` group_locations *uuid.UUID location_children *uuid.UUID - selectValues sql.SelectValues } // LocationEdges holds the relations/edges for other nodes in the graph. @@ -110,7 +108,7 @@ func (*Location) scanValues(columns []string) ([]any, error) { case location.ForeignKeys[1]: // location_children values[i] = &sql.NullScanner{S: new(uuid.UUID)} default: - values[i] = new(sql.UnknownType) + return nil, fmt.Errorf("unexpected column %q for type Location", columns[i]) } } return values, nil @@ -168,19 +166,11 @@ func (l *Location) assignValues(columns []string, values []any) error { l.location_children = new(uuid.UUID) *l.location_children = *value.S.(*uuid.UUID) } - default: - l.selectValues.Set(columns[i], values[i]) } } return nil } -// Value returns the ent.Value that was dynamically selected and assigned to the Location. -// This includes values selected through modifiers, order, etc. -func (l *Location) Value(name string) (ent.Value, error) { - return l.selectValues.Get(name) -} - // QueryGroup queries the "group" edge of the Location entity. func (l *Location) QueryGroup() *GroupQuery { return NewLocationClient(l.config).QueryGroup(l) diff --git a/backend/internal/data/ent/location/location.go b/backend/internal/data/ent/location/location.go index 4a7fc16..420e3a3 100644 --- a/backend/internal/data/ent/location/location.go +++ b/backend/internal/data/ent/location/location.go @@ -5,8 +5,6 @@ package location import ( "time" - "entgo.io/ent/dialect/sql" - "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" ) @@ -102,101 +100,3 @@ var ( // DefaultID holds the default value on creation for the "id" field. DefaultID func() uuid.UUID ) - -// OrderOption defines the ordering options for the Location queries. -type OrderOption func(*sql.Selector) - -// ByID orders the results by the id field. -func ByID(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldID, opts...).ToFunc() -} - -// ByCreatedAt orders the results by the created_at field. -func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() -} - -// ByUpdatedAt orders the results by the updated_at field. -func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc() -} - -// ByName orders the results by the name field. -func ByName(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldName, opts...).ToFunc() -} - -// ByDescription orders the results by the description field. -func ByDescription(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldDescription, opts...).ToFunc() -} - -// ByGroupField orders the results by group field. -func ByGroupField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newGroupStep(), sql.OrderByField(field, opts...)) - } -} - -// ByParentField orders the results by parent field. -func ByParentField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newParentStep(), sql.OrderByField(field, opts...)) - } -} - -// ByChildrenCount orders the results by children count. -func ByChildrenCount(opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborsCount(s, newChildrenStep(), opts...) - } -} - -// ByChildren orders the results by children terms. -func ByChildren(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newChildrenStep(), append([]sql.OrderTerm{term}, terms...)...) - } -} - -// ByItemsCount orders the results by items count. -func ByItemsCount(opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborsCount(s, newItemsStep(), opts...) - } -} - -// ByItems orders the results by items terms. -func ByItems(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newItemsStep(), append([]sql.OrderTerm{term}, terms...)...) - } -} -func newGroupStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(GroupInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn), - ) -} -func newParentStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(Table, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, ParentTable, ParentColumn), - ) -} -func newChildrenStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(Table, FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, ChildrenTable, ChildrenColumn), - ) -} -func newItemsStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(ItemsInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, ItemsTable, ItemsColumn), - ) -} diff --git a/backend/internal/data/ent/location/where.go b/backend/internal/data/ent/location/where.go index a89ef4d..2dab72e 100644 --- a/backend/internal/data/ent/location/where.go +++ b/backend/internal/data/ent/location/where.go @@ -310,7 +310,11 @@ func HasGroup() predicate.Location { // HasGroupWith applies the HasEdge predicate on the "group" edge with a given conditions (other predicates). func HasGroupWith(preds ...predicate.Group) predicate.Location { return predicate.Location(func(s *sql.Selector) { - step := newGroupStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(GroupInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -333,7 +337,11 @@ func HasParent() predicate.Location { // HasParentWith applies the HasEdge predicate on the "parent" edge with a given conditions (other predicates). func HasParentWith(preds ...predicate.Location) predicate.Location { return predicate.Location(func(s *sql.Selector) { - step := newParentStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(Table, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, ParentTable, ParentColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -356,7 +364,11 @@ func HasChildren() predicate.Location { // HasChildrenWith applies the HasEdge predicate on the "children" edge with a given conditions (other predicates). func HasChildrenWith(preds ...predicate.Location) predicate.Location { return predicate.Location(func(s *sql.Selector) { - step := newChildrenStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(Table, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, ChildrenTable, ChildrenColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -379,7 +391,11 @@ func HasItems() predicate.Location { // HasItemsWith applies the HasEdge predicate on the "items" edge with a given conditions (other predicates). func HasItemsWith(preds ...predicate.Item) predicate.Location { return predicate.Location(func(s *sql.Selector) { - step := newItemsStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(ItemsInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, ItemsTable, ItemsColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -390,15 +406,32 @@ func HasItemsWith(preds ...predicate.Item) predicate.Location { // And groups predicates with the AND operator between them. func And(predicates ...predicate.Location) predicate.Location { - return predicate.Location(sql.AndPredicates(predicates...)) + return predicate.Location(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for _, p := range predicates { + p(s1) + } + s.Where(s1.P()) + }) } // Or groups predicates with the OR operator between them. func Or(predicates ...predicate.Location) predicate.Location { - return predicate.Location(sql.OrPredicates(predicates...)) + return predicate.Location(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for i, p := range predicates { + if i > 0 { + s1.Or() + } + p(s1) + } + s.Where(s1.P()) + }) } // Not applies the not operator on the given predicate. func Not(p predicate.Location) predicate.Location { - return predicate.Location(sql.NotPredicates(p)) + return predicate.Location(func(s *sql.Selector) { + p(s.Not()) + }) } diff --git a/backend/internal/data/ent/location_create.go b/backend/internal/data/ent/location_create.go index 98f0f7a..5da1e10 100644 --- a/backend/internal/data/ent/location_create.go +++ b/backend/internal/data/ent/location_create.go @@ -153,7 +153,7 @@ func (lc *LocationCreate) Mutation() *LocationMutation { // Save creates the Location in the database. func (lc *LocationCreate) Save(ctx context.Context) (*Location, error) { lc.defaults() - return withHooks(ctx, lc.sqlSave, lc.mutation, lc.hooks) + return withHooks[*Location, LocationMutation](ctx, lc.sqlSave, lc.mutation, lc.hooks) } // SaveX calls Save and panics if Save returns an error. @@ -341,15 +341,11 @@ func (lc *LocationCreate) createSpec() (*Location, *sqlgraph.CreateSpec) { // LocationCreateBulk is the builder for creating many Location entities in bulk. type LocationCreateBulk struct { config - err error builders []*LocationCreate } // Save creates the Location entities in the database. func (lcb *LocationCreateBulk) Save(ctx context.Context) ([]*Location, error) { - if lcb.err != nil { - return nil, lcb.err - } specs := make([]*sqlgraph.CreateSpec, len(lcb.builders)) nodes := make([]*Location, len(lcb.builders)) mutators := make([]Mutator, len(lcb.builders)) @@ -366,8 +362,8 @@ func (lcb *LocationCreateBulk) Save(ctx context.Context) ([]*Location, error) { return nil, err } builder.mutation = mutation - var err error nodes[i], specs[i] = builder.createSpec() + var err error if i < len(mutators)-1 { _, err = mutators[i+1].Mutate(root, lcb.builders[i+1].mutation) } else { diff --git a/backend/internal/data/ent/location_delete.go b/backend/internal/data/ent/location_delete.go index 451b7f1..67a2adc 100644 --- a/backend/internal/data/ent/location_delete.go +++ b/backend/internal/data/ent/location_delete.go @@ -27,7 +27,7 @@ func (ld *LocationDelete) Where(ps ...predicate.Location) *LocationDelete { // Exec executes the deletion query and returns how many vertices were deleted. func (ld *LocationDelete) Exec(ctx context.Context) (int, error) { - return withHooks(ctx, ld.sqlExec, ld.mutation, ld.hooks) + return withHooks[int, LocationMutation](ctx, ld.sqlExec, ld.mutation, ld.hooks) } // ExecX is like Exec, but panics if an error occurs. diff --git a/backend/internal/data/ent/location_query.go b/backend/internal/data/ent/location_query.go index 4aae965..a3d2ae3 100644 --- a/backend/internal/data/ent/location_query.go +++ b/backend/internal/data/ent/location_query.go @@ -22,7 +22,7 @@ import ( type LocationQuery struct { config ctx *QueryContext - order []location.OrderOption + order []OrderFunc inters []Interceptor predicates []predicate.Location withGroup *GroupQuery @@ -61,7 +61,7 @@ func (lq *LocationQuery) Unique(unique bool) *LocationQuery { } // Order specifies how the records should be ordered. -func (lq *LocationQuery) Order(o ...location.OrderOption) *LocationQuery { +func (lq *LocationQuery) Order(o ...OrderFunc) *LocationQuery { lq.order = append(lq.order, o...) return lq } @@ -343,7 +343,7 @@ func (lq *LocationQuery) Clone() *LocationQuery { return &LocationQuery{ config: lq.config, ctx: lq.ctx.Clone(), - order: append([]location.OrderOption{}, lq.order...), + order: append([]OrderFunc{}, lq.order...), inters: append([]Interceptor{}, lq.inters...), predicates: append([]predicate.Location{}, lq.predicates...), withGroup: lq.withGroup.Clone(), @@ -615,7 +615,7 @@ func (lq *LocationQuery) loadChildren(ctx context.Context, query *LocationQuery, } query.withFKs = true query.Where(predicate.Location(func(s *sql.Selector) { - s.Where(sql.InValues(s.C(location.ChildrenColumn), fks...)) + s.Where(sql.InValues(location.ChildrenColumn, fks...)) })) neighbors, err := query.All(ctx) if err != nil { @@ -628,7 +628,7 @@ func (lq *LocationQuery) loadChildren(ctx context.Context, query *LocationQuery, } node, ok := nodeids[*fk] if !ok { - return fmt.Errorf(`unexpected referenced foreign-key "location_children" returned %v for node %v`, *fk, n.ID) + return fmt.Errorf(`unexpected foreign-key "location_children" returned %v for node %v`, *fk, n.ID) } assign(node, n) } @@ -646,7 +646,7 @@ func (lq *LocationQuery) loadItems(ctx context.Context, query *ItemQuery, nodes } query.withFKs = true query.Where(predicate.Item(func(s *sql.Selector) { - s.Where(sql.InValues(s.C(location.ItemsColumn), fks...)) + s.Where(sql.InValues(location.ItemsColumn, fks...)) })) neighbors, err := query.All(ctx) if err != nil { @@ -659,7 +659,7 @@ func (lq *LocationQuery) loadItems(ctx context.Context, query *ItemQuery, nodes } node, ok := nodeids[*fk] if !ok { - return fmt.Errorf(`unexpected referenced foreign-key "location_items" returned %v for node %v`, *fk, n.ID) + return fmt.Errorf(`unexpected foreign-key "location_items" returned %v for node %v`, *fk, n.ID) } assign(node, n) } diff --git a/backend/internal/data/ent/location_update.go b/backend/internal/data/ent/location_update.go index d569b21..d5de7f7 100644 --- a/backend/internal/data/ent/location_update.go +++ b/backend/internal/data/ent/location_update.go @@ -43,14 +43,6 @@ func (lu *LocationUpdate) SetName(s string) *LocationUpdate { return lu } -// SetNillableName sets the "name" field if the given value is not nil. -func (lu *LocationUpdate) SetNillableName(s *string) *LocationUpdate { - if s != nil { - lu.SetName(*s) - } - return lu -} - // SetDescription sets the "description" field. func (lu *LocationUpdate) SetDescription(s string) *LocationUpdate { lu.mutation.SetDescription(s) @@ -193,7 +185,7 @@ func (lu *LocationUpdate) RemoveItems(i ...*Item) *LocationUpdate { // Save executes the query and returns the number of nodes affected by the update operation. func (lu *LocationUpdate) Save(ctx context.Context) (int, error) { lu.defaults() - return withHooks(ctx, lu.sqlSave, lu.mutation, lu.hooks) + return withHooks[int, LocationMutation](ctx, lu.sqlSave, lu.mutation, lu.hooks) } // SaveX is like Save, but panics if an error occurs. @@ -448,14 +440,6 @@ func (luo *LocationUpdateOne) SetName(s string) *LocationUpdateOne { return luo } -// SetNillableName sets the "name" field if the given value is not nil. -func (luo *LocationUpdateOne) SetNillableName(s *string) *LocationUpdateOne { - if s != nil { - luo.SetName(*s) - } - return luo -} - // SetDescription sets the "description" field. func (luo *LocationUpdateOne) SetDescription(s string) *LocationUpdateOne { luo.mutation.SetDescription(s) @@ -611,7 +595,7 @@ func (luo *LocationUpdateOne) Select(field string, fields ...string) *LocationUp // Save executes the query and returns the updated Location entity. func (luo *LocationUpdateOne) Save(ctx context.Context) (*Location, error) { luo.defaults() - return withHooks(ctx, luo.sqlSave, luo.mutation, luo.hooks) + return withHooks[*Location, LocationMutation](ctx, luo.sqlSave, luo.mutation, luo.hooks) } // SaveX is like Save, but panics if an error occurs. diff --git a/backend/internal/data/ent/maintenanceentry.go b/backend/internal/data/ent/maintenanceentry.go index af35e0b..98301c8 100644 --- a/backend/internal/data/ent/maintenanceentry.go +++ b/backend/internal/data/ent/maintenanceentry.go @@ -7,7 +7,6 @@ import ( "strings" "time" - "entgo.io/ent" "entgo.io/ent/dialect/sql" "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/data/ent/item" @@ -37,8 +36,7 @@ type MaintenanceEntry struct { Cost float64 `json:"cost,omitempty"` // Edges holds the relations/edges for other nodes in the graph. // The values are being populated by the MaintenanceEntryQuery when eager-loading is set. - Edges MaintenanceEntryEdges `json:"edges"` - selectValues sql.SelectValues + Edges MaintenanceEntryEdges `json:"edges"` } // MaintenanceEntryEdges holds the relations/edges for other nodes in the graph. @@ -77,7 +75,7 @@ func (*MaintenanceEntry) scanValues(columns []string) ([]any, error) { case maintenanceentry.FieldID, maintenanceentry.FieldItemID: values[i] = new(uuid.UUID) default: - values[i] = new(sql.UnknownType) + return nil, fmt.Errorf("unexpected column %q for type MaintenanceEntry", columns[i]) } } return values, nil @@ -145,19 +143,11 @@ func (me *MaintenanceEntry) assignValues(columns []string, values []any) error { } else if value.Valid { me.Cost = value.Float64 } - default: - me.selectValues.Set(columns[i], values[i]) } } return nil } -// Value returns the ent.Value that was dynamically selected and assigned to the MaintenanceEntry. -// This includes values selected through modifiers, order, etc. -func (me *MaintenanceEntry) Value(name string) (ent.Value, error) { - return me.selectValues.Get(name) -} - // QueryItem queries the "item" edge of the MaintenanceEntry entity. func (me *MaintenanceEntry) QueryItem() *ItemQuery { return NewMaintenanceEntryClient(me.config).QueryItem(me) diff --git a/backend/internal/data/ent/maintenanceentry/maintenanceentry.go b/backend/internal/data/ent/maintenanceentry/maintenanceentry.go index b4b8142..690a696 100644 --- a/backend/internal/data/ent/maintenanceentry/maintenanceentry.go +++ b/backend/internal/data/ent/maintenanceentry/maintenanceentry.go @@ -5,8 +5,6 @@ package maintenanceentry import ( "time" - "entgo.io/ent/dialect/sql" - "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" ) @@ -83,65 +81,3 @@ var ( // DefaultID holds the default value on creation for the "id" field. DefaultID func() uuid.UUID ) - -// OrderOption defines the ordering options for the MaintenanceEntry queries. -type OrderOption func(*sql.Selector) - -// ByID orders the results by the id field. -func ByID(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldID, opts...).ToFunc() -} - -// ByCreatedAt orders the results by the created_at field. -func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() -} - -// ByUpdatedAt orders the results by the updated_at field. -func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc() -} - -// ByItemID orders the results by the item_id field. -func ByItemID(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldItemID, opts...).ToFunc() -} - -// ByDate orders the results by the date field. -func ByDate(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldDate, opts...).ToFunc() -} - -// ByScheduledDate orders the results by the scheduled_date field. -func ByScheduledDate(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldScheduledDate, opts...).ToFunc() -} - -// ByName orders the results by the name field. -func ByName(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldName, opts...).ToFunc() -} - -// ByDescription orders the results by the description field. -func ByDescription(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldDescription, opts...).ToFunc() -} - -// ByCost orders the results by the cost field. -func ByCost(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldCost, opts...).ToFunc() -} - -// ByItemField orders the results by item field. -func ByItemField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newItemStep(), sql.OrderByField(field, opts...)) - } -} -func newItemStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(ItemInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, ItemTable, ItemColumn), - ) -} diff --git a/backend/internal/data/ent/maintenanceentry/where.go b/backend/internal/data/ent/maintenanceentry/where.go index 85e736d..798ce63 100644 --- a/backend/internal/data/ent/maintenanceentry/where.go +++ b/backend/internal/data/ent/maintenanceentry/where.go @@ -490,7 +490,11 @@ func HasItem() predicate.MaintenanceEntry { // HasItemWith applies the HasEdge predicate on the "item" edge with a given conditions (other predicates). func HasItemWith(preds ...predicate.Item) predicate.MaintenanceEntry { return predicate.MaintenanceEntry(func(s *sql.Selector) { - step := newItemStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(ItemInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, ItemTable, ItemColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -501,15 +505,32 @@ func HasItemWith(preds ...predicate.Item) predicate.MaintenanceEntry { // And groups predicates with the AND operator between them. func And(predicates ...predicate.MaintenanceEntry) predicate.MaintenanceEntry { - return predicate.MaintenanceEntry(sql.AndPredicates(predicates...)) + return predicate.MaintenanceEntry(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for _, p := range predicates { + p(s1) + } + s.Where(s1.P()) + }) } // Or groups predicates with the OR operator between them. func Or(predicates ...predicate.MaintenanceEntry) predicate.MaintenanceEntry { - return predicate.MaintenanceEntry(sql.OrPredicates(predicates...)) + return predicate.MaintenanceEntry(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for i, p := range predicates { + if i > 0 { + s1.Or() + } + p(s1) + } + s.Where(s1.P()) + }) } // Not applies the not operator on the given predicate. func Not(p predicate.MaintenanceEntry) predicate.MaintenanceEntry { - return predicate.MaintenanceEntry(sql.NotPredicates(p)) + return predicate.MaintenanceEntry(func(s *sql.Selector) { + p(s.Not()) + }) } diff --git a/backend/internal/data/ent/maintenanceentry_create.go b/backend/internal/data/ent/maintenanceentry_create.go index ea71a4d..da81f9f 100644 --- a/backend/internal/data/ent/maintenanceentry_create.go +++ b/backend/internal/data/ent/maintenanceentry_create.go @@ -145,7 +145,7 @@ func (mec *MaintenanceEntryCreate) Mutation() *MaintenanceEntryMutation { // Save creates the MaintenanceEntry in the database. func (mec *MaintenanceEntryCreate) Save(ctx context.Context) (*MaintenanceEntry, error) { mec.defaults() - return withHooks(ctx, mec.sqlSave, mec.mutation, mec.hooks) + return withHooks[*MaintenanceEntry, MaintenanceEntryMutation](ctx, mec.sqlSave, mec.mutation, mec.hooks) } // SaveX calls Save and panics if Save returns an error. @@ -306,15 +306,11 @@ func (mec *MaintenanceEntryCreate) createSpec() (*MaintenanceEntry, *sqlgraph.Cr // MaintenanceEntryCreateBulk is the builder for creating many MaintenanceEntry entities in bulk. type MaintenanceEntryCreateBulk struct { config - err error builders []*MaintenanceEntryCreate } // Save creates the MaintenanceEntry entities in the database. func (mecb *MaintenanceEntryCreateBulk) Save(ctx context.Context) ([]*MaintenanceEntry, error) { - if mecb.err != nil { - return nil, mecb.err - } specs := make([]*sqlgraph.CreateSpec, len(mecb.builders)) nodes := make([]*MaintenanceEntry, len(mecb.builders)) mutators := make([]Mutator, len(mecb.builders)) @@ -331,8 +327,8 @@ func (mecb *MaintenanceEntryCreateBulk) Save(ctx context.Context) ([]*Maintenanc return nil, err } builder.mutation = mutation - var err error nodes[i], specs[i] = builder.createSpec() + var err error if i < len(mutators)-1 { _, err = mutators[i+1].Mutate(root, mecb.builders[i+1].mutation) } else { diff --git a/backend/internal/data/ent/maintenanceentry_delete.go b/backend/internal/data/ent/maintenanceentry_delete.go index 0323ae9..d65ed8b 100644 --- a/backend/internal/data/ent/maintenanceentry_delete.go +++ b/backend/internal/data/ent/maintenanceentry_delete.go @@ -27,7 +27,7 @@ func (med *MaintenanceEntryDelete) Where(ps ...predicate.MaintenanceEntry) *Main // Exec executes the deletion query and returns how many vertices were deleted. func (med *MaintenanceEntryDelete) Exec(ctx context.Context) (int, error) { - return withHooks(ctx, med.sqlExec, med.mutation, med.hooks) + return withHooks[int, MaintenanceEntryMutation](ctx, med.sqlExec, med.mutation, med.hooks) } // ExecX is like Exec, but panics if an error occurs. diff --git a/backend/internal/data/ent/maintenanceentry_query.go b/backend/internal/data/ent/maintenanceentry_query.go index 8d41f75..52c8504 100644 --- a/backend/internal/data/ent/maintenanceentry_query.go +++ b/backend/internal/data/ent/maintenanceentry_query.go @@ -20,7 +20,7 @@ import ( type MaintenanceEntryQuery struct { config ctx *QueryContext - order []maintenanceentry.OrderOption + order []OrderFunc inters []Interceptor predicates []predicate.MaintenanceEntry withItem *ItemQuery @@ -55,7 +55,7 @@ func (meq *MaintenanceEntryQuery) Unique(unique bool) *MaintenanceEntryQuery { } // Order specifies how the records should be ordered. -func (meq *MaintenanceEntryQuery) Order(o ...maintenanceentry.OrderOption) *MaintenanceEntryQuery { +func (meq *MaintenanceEntryQuery) Order(o ...OrderFunc) *MaintenanceEntryQuery { meq.order = append(meq.order, o...) return meq } @@ -271,7 +271,7 @@ func (meq *MaintenanceEntryQuery) Clone() *MaintenanceEntryQuery { return &MaintenanceEntryQuery{ config: meq.config, ctx: meq.ctx.Clone(), - order: append([]maintenanceentry.OrderOption{}, meq.order...), + order: append([]OrderFunc{}, meq.order...), inters: append([]Interceptor{}, meq.inters...), predicates: append([]predicate.MaintenanceEntry{}, meq.predicates...), withItem: meq.withItem.Clone(), @@ -456,9 +456,6 @@ func (meq *MaintenanceEntryQuery) querySpec() *sqlgraph.QuerySpec { _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) } } - if meq.withItem != nil { - _spec.Node.AddColumnOnce(maintenanceentry.FieldItemID) - } } if ps := meq.predicates; len(ps) > 0 { _spec.Predicate = func(selector *sql.Selector) { diff --git a/backend/internal/data/ent/maintenanceentry_update.go b/backend/internal/data/ent/maintenanceentry_update.go index 3616d32..e9ed740 100644 --- a/backend/internal/data/ent/maintenanceentry_update.go +++ b/backend/internal/data/ent/maintenanceentry_update.go @@ -42,14 +42,6 @@ func (meu *MaintenanceEntryUpdate) SetItemID(u uuid.UUID) *MaintenanceEntryUpdat return meu } -// SetNillableItemID sets the "item_id" field if the given value is not nil. -func (meu *MaintenanceEntryUpdate) SetNillableItemID(u *uuid.UUID) *MaintenanceEntryUpdate { - if u != nil { - meu.SetItemID(*u) - } - return meu -} - // SetDate sets the "date" field. func (meu *MaintenanceEntryUpdate) SetDate(t time.Time) *MaintenanceEntryUpdate { meu.mutation.SetDate(t) @@ -96,14 +88,6 @@ func (meu *MaintenanceEntryUpdate) SetName(s string) *MaintenanceEntryUpdate { return meu } -// SetNillableName sets the "name" field if the given value is not nil. -func (meu *MaintenanceEntryUpdate) SetNillableName(s *string) *MaintenanceEntryUpdate { - if s != nil { - meu.SetName(*s) - } - return meu -} - // SetDescription sets the "description" field. func (meu *MaintenanceEntryUpdate) SetDescription(s string) *MaintenanceEntryUpdate { meu.mutation.SetDescription(s) @@ -164,7 +148,7 @@ func (meu *MaintenanceEntryUpdate) ClearItem() *MaintenanceEntryUpdate { // Save executes the query and returns the number of nodes affected by the update operation. func (meu *MaintenanceEntryUpdate) Save(ctx context.Context) (int, error) { meu.defaults() - return withHooks(ctx, meu.sqlSave, meu.mutation, meu.hooks) + return withHooks[int, MaintenanceEntryMutation](ctx, meu.sqlSave, meu.mutation, meu.hooks) } // SaveX is like Save, but panics if an error occurs. @@ -318,14 +302,6 @@ func (meuo *MaintenanceEntryUpdateOne) SetItemID(u uuid.UUID) *MaintenanceEntryU return meuo } -// SetNillableItemID sets the "item_id" field if the given value is not nil. -func (meuo *MaintenanceEntryUpdateOne) SetNillableItemID(u *uuid.UUID) *MaintenanceEntryUpdateOne { - if u != nil { - meuo.SetItemID(*u) - } - return meuo -} - // SetDate sets the "date" field. func (meuo *MaintenanceEntryUpdateOne) SetDate(t time.Time) *MaintenanceEntryUpdateOne { meuo.mutation.SetDate(t) @@ -372,14 +348,6 @@ func (meuo *MaintenanceEntryUpdateOne) SetName(s string) *MaintenanceEntryUpdate return meuo } -// SetNillableName sets the "name" field if the given value is not nil. -func (meuo *MaintenanceEntryUpdateOne) SetNillableName(s *string) *MaintenanceEntryUpdateOne { - if s != nil { - meuo.SetName(*s) - } - return meuo -} - // SetDescription sets the "description" field. func (meuo *MaintenanceEntryUpdateOne) SetDescription(s string) *MaintenanceEntryUpdateOne { meuo.mutation.SetDescription(s) @@ -453,7 +421,7 @@ func (meuo *MaintenanceEntryUpdateOne) Select(field string, fields ...string) *M // Save executes the query and returns the updated MaintenanceEntry entity. func (meuo *MaintenanceEntryUpdateOne) Save(ctx context.Context) (*MaintenanceEntry, error) { meuo.defaults() - return withHooks(ctx, meuo.sqlSave, meuo.mutation, meuo.hooks) + return withHooks[*MaintenanceEntry, MaintenanceEntryMutation](ctx, meuo.sqlSave, meuo.mutation, meuo.hooks) } // SaveX is like Save, but panics if an error occurs. diff --git a/backend/internal/data/ent/migrate/schema.go b/backend/internal/data/ent/migrate/schema.go index 2b58838..0d11507 100644 --- a/backend/internal/data/ent/migrate/schema.go +++ b/backend/internal/data/ent/migrate/schema.go @@ -14,7 +14,6 @@ var ( {Name: "created_at", Type: field.TypeTime}, {Name: "updated_at", Type: field.TypeTime}, {Name: "type", Type: field.TypeEnum, Enums: []string{"photo", "manual", "warranty", "attachment", "receipt"}, Default: "attachment"}, - {Name: "primary", Type: field.TypeBool, Default: false}, {Name: "document_attachments", Type: field.TypeUUID}, {Name: "item_attachments", Type: field.TypeUUID}, } @@ -26,13 +25,13 @@ var ( ForeignKeys: []*schema.ForeignKey{ { Symbol: "attachments_documents_attachments", - Columns: []*schema.Column{AttachmentsColumns[5]}, + Columns: []*schema.Column{AttachmentsColumns[4]}, RefColumns: []*schema.Column{DocumentsColumns[0]}, OnDelete: schema.Cascade, }, { Symbol: "attachments_items_attachments", - Columns: []*schema.Column{AttachmentsColumns[6]}, + Columns: []*schema.Column{AttachmentsColumns[5]}, RefColumns: []*schema.Column{ItemsColumns[0]}, OnDelete: schema.Cascade, }, @@ -117,7 +116,7 @@ var ( {Name: "created_at", Type: field.TypeTime}, {Name: "updated_at", Type: field.TypeTime}, {Name: "name", Type: field.TypeString, Size: 255}, - {Name: "currency", Type: field.TypeString, Default: "usd"}, + {Name: "currency", Type: field.TypeEnum, Enums: []string{"usd", "eur", "gbp", "jpy", "zar", "aud", "nok", "nzd", "sek", "dkk", "inr", "rmb", "bgn", "chf", "pln", "try", "ron", "czk"}, Default: "usd"}, } // GroupsTable holds the schema information for the "groups" table. GroupsTable = &schema.Table{ diff --git a/backend/internal/data/ent/mutation.go b/backend/internal/data/ent/mutation.go index 6fa15d3..bc38aeb 100644 --- a/backend/internal/data/ent/mutation.go +++ b/backend/internal/data/ent/mutation.go @@ -61,7 +61,6 @@ type AttachmentMutation struct { created_at *time.Time updated_at *time.Time _type *attachment.Type - primary *bool clearedFields map[string]struct{} item *uuid.UUID cleareditem bool @@ -284,42 +283,6 @@ func (m *AttachmentMutation) ResetType() { m._type = nil } -// SetPrimary sets the "primary" field. -func (m *AttachmentMutation) SetPrimary(b bool) { - m.primary = &b -} - -// Primary returns the value of the "primary" field in the mutation. -func (m *AttachmentMutation) Primary() (r bool, exists bool) { - v := m.primary - if v == nil { - return - } - return *v, true -} - -// OldPrimary returns the old "primary" field's value of the Attachment entity. -// If the Attachment object wasn't provided to the builder, the object is fetched from the database. -// An error is returned if the mutation operation is not UpdateOne, or the database query fails. -func (m *AttachmentMutation) OldPrimary(ctx context.Context) (v bool, err error) { - if !m.op.Is(OpUpdateOne) { - return v, errors.New("OldPrimary is only allowed on UpdateOne operations") - } - if m.id == nil || m.oldValue == nil { - return v, errors.New("OldPrimary requires an ID field in the mutation") - } - oldValue, err := m.oldValue(ctx) - if err != nil { - return v, fmt.Errorf("querying old value for OldPrimary: %w", err) - } - return oldValue.Primary, nil -} - -// ResetPrimary resets all changes to the "primary" field. -func (m *AttachmentMutation) ResetPrimary() { - m.primary = nil -} - // SetItemID sets the "item" edge to the Item entity by id. func (m *AttachmentMutation) SetItemID(id uuid.UUID) { m.item = &id @@ -432,7 +395,7 @@ func (m *AttachmentMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *AttachmentMutation) Fields() []string { - fields := make([]string, 0, 4) + fields := make([]string, 0, 3) if m.created_at != nil { fields = append(fields, attachment.FieldCreatedAt) } @@ -442,9 +405,6 @@ func (m *AttachmentMutation) Fields() []string { if m._type != nil { fields = append(fields, attachment.FieldType) } - if m.primary != nil { - fields = append(fields, attachment.FieldPrimary) - } return fields } @@ -459,8 +419,6 @@ func (m *AttachmentMutation) Field(name string) (ent.Value, bool) { return m.UpdatedAt() case attachment.FieldType: return m.GetType() - case attachment.FieldPrimary: - return m.Primary() } return nil, false } @@ -476,8 +434,6 @@ func (m *AttachmentMutation) OldField(ctx context.Context, name string) (ent.Val return m.OldUpdatedAt(ctx) case attachment.FieldType: return m.OldType(ctx) - case attachment.FieldPrimary: - return m.OldPrimary(ctx) } return nil, fmt.Errorf("unknown Attachment field %s", name) } @@ -508,13 +464,6 @@ func (m *AttachmentMutation) SetField(name string, value ent.Value) error { } m.SetType(v) return nil - case attachment.FieldPrimary: - v, ok := value.(bool) - if !ok { - return fmt.Errorf("unexpected type %T for field %s", value, name) - } - m.SetPrimary(v) - return nil } return fmt.Errorf("unknown Attachment field %s", name) } @@ -573,9 +522,6 @@ func (m *AttachmentMutation) ResetField(name string) error { case attachment.FieldType: m.ResetType() return nil - case attachment.FieldPrimary: - m.ResetPrimary() - return nil } return fmt.Errorf("unknown Attachment field %s", name) } @@ -2340,7 +2286,7 @@ type GroupMutation struct { created_at *time.Time updated_at *time.Time name *string - currency *string + currency *group.Currency clearedFields map[string]struct{} users map[uuid.UUID]struct{} removedusers map[uuid.UUID]struct{} @@ -2581,12 +2527,12 @@ func (m *GroupMutation) ResetName() { } // SetCurrency sets the "currency" field. -func (m *GroupMutation) SetCurrency(s string) { - m.currency = &s +func (m *GroupMutation) SetCurrency(gr group.Currency) { + m.currency = &gr } // Currency returns the value of the "currency" field in the mutation. -func (m *GroupMutation) Currency() (r string, exists bool) { +func (m *GroupMutation) Currency() (r group.Currency, exists bool) { v := m.currency if v == nil { return @@ -2597,7 +2543,7 @@ func (m *GroupMutation) Currency() (r string, exists bool) { // OldCurrency returns the old "currency" field's value of the Group entity. // If the Group object wasn't provided to the builder, the object is fetched from the database. // An error is returned if the mutation operation is not UpdateOne, or the database query fails. -func (m *GroupMutation) OldCurrency(ctx context.Context) (v string, err error) { +func (m *GroupMutation) OldCurrency(ctx context.Context) (v group.Currency, err error) { if !m.op.Is(OpUpdateOne) { return v, errors.New("OldCurrency is only allowed on UpdateOne operations") } @@ -3105,7 +3051,7 @@ func (m *GroupMutation) SetField(name string, value ent.Value) error { m.SetName(v) return nil case group.FieldCurrency: - v, ok := value.(string) + v, ok := value.(group.Currency) if !ok { return fmt.Errorf("unexpected type %T for field %s", value, name) } @@ -9529,7 +9475,6 @@ func (m *MaintenanceEntryMutation) ResetCost() { // ClearItem clears the "item" edge to the Item entity. func (m *MaintenanceEntryMutation) ClearItem() { m.cleareditem = true - m.clearedFields[maintenanceentry.FieldItemID] = struct{}{} } // ItemCleared reports if the "item" edge to the Item entity was cleared. @@ -10293,7 +10238,6 @@ func (m *NotifierMutation) ResetIsActive() { // ClearGroup clears the "group" edge to the Group entity. func (m *NotifierMutation) ClearGroup() { m.clearedgroup = true - m.clearedFields[notifier.FieldGroupID] = struct{}{} } // GroupCleared reports if the "group" edge to the Group entity was cleared. @@ -10320,7 +10264,6 @@ func (m *NotifierMutation) ResetGroup() { // ClearUser clears the "user" edge to the User entity. func (m *NotifierMutation) ClearUser() { m.cleareduser = true - m.clearedFields[notifier.FieldUserID] = struct{}{} } // UserCleared reports if the "user" edge to the User entity was cleared. diff --git a/backend/internal/data/ent/notifier.go b/backend/internal/data/ent/notifier.go index 05a267b..4664c49 100644 --- a/backend/internal/data/ent/notifier.go +++ b/backend/internal/data/ent/notifier.go @@ -7,7 +7,6 @@ import ( "strings" "time" - "entgo.io/ent" "entgo.io/ent/dialect/sql" "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/data/ent/group" @@ -36,8 +35,7 @@ type Notifier struct { IsActive bool `json:"is_active,omitempty"` // Edges holds the relations/edges for other nodes in the graph. // The values are being populated by the NotifierQuery when eager-loading is set. - Edges NotifierEdges `json:"edges"` - selectValues sql.SelectValues + Edges NotifierEdges `json:"edges"` } // NotifierEdges holds the relations/edges for other nodes in the graph. @@ -91,7 +89,7 @@ func (*Notifier) scanValues(columns []string) ([]any, error) { case notifier.FieldID, notifier.FieldGroupID, notifier.FieldUserID: values[i] = new(uuid.UUID) default: - values[i] = new(sql.UnknownType) + return nil, fmt.Errorf("unexpected column %q for type Notifier", columns[i]) } } return values, nil @@ -153,19 +151,11 @@ func (n *Notifier) assignValues(columns []string, values []any) error { } else if value.Valid { n.IsActive = value.Bool } - default: - n.selectValues.Set(columns[i], values[i]) } } return nil } -// Value returns the ent.Value that was dynamically selected and assigned to the Notifier. -// This includes values selected through modifiers, order, etc. -func (n *Notifier) Value(name string) (ent.Value, error) { - return n.selectValues.Get(name) -} - // QueryGroup queries the "group" edge of the Notifier entity. func (n *Notifier) QueryGroup() *GroupQuery { return NewNotifierClient(n.config).QueryGroup(n) diff --git a/backend/internal/data/ent/notifier/notifier.go b/backend/internal/data/ent/notifier/notifier.go index d24b6bc..ead4c2a 100644 --- a/backend/internal/data/ent/notifier/notifier.go +++ b/backend/internal/data/ent/notifier/notifier.go @@ -5,8 +5,6 @@ package notifier import ( "time" - "entgo.io/ent/dialect/sql" - "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" ) @@ -89,74 +87,3 @@ var ( // DefaultID holds the default value on creation for the "id" field. DefaultID func() uuid.UUID ) - -// OrderOption defines the ordering options for the Notifier queries. -type OrderOption func(*sql.Selector) - -// ByID orders the results by the id field. -func ByID(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldID, opts...).ToFunc() -} - -// ByCreatedAt orders the results by the created_at field. -func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() -} - -// ByUpdatedAt orders the results by the updated_at field. -func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc() -} - -// ByGroupID orders the results by the group_id field. -func ByGroupID(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldGroupID, opts...).ToFunc() -} - -// ByUserID orders the results by the user_id field. -func ByUserID(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldUserID, opts...).ToFunc() -} - -// ByName orders the results by the name field. -func ByName(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldName, opts...).ToFunc() -} - -// ByURL orders the results by the url field. -func ByURL(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldURL, opts...).ToFunc() -} - -// ByIsActive orders the results by the is_active field. -func ByIsActive(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldIsActive, opts...).ToFunc() -} - -// ByGroupField orders the results by group field. -func ByGroupField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newGroupStep(), sql.OrderByField(field, opts...)) - } -} - -// ByUserField orders the results by user field. -func ByUserField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newUserStep(), sql.OrderByField(field, opts...)) - } -} -func newGroupStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(GroupInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn), - ) -} -func newUserStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(UserInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, UserTable, UserColumn), - ) -} diff --git a/backend/internal/data/ent/notifier/where.go b/backend/internal/data/ent/notifier/where.go index fa9b3bc..35ca73c 100644 --- a/backend/internal/data/ent/notifier/where.go +++ b/backend/internal/data/ent/notifier/where.go @@ -365,7 +365,11 @@ func HasGroup() predicate.Notifier { // HasGroupWith applies the HasEdge predicate on the "group" edge with a given conditions (other predicates). func HasGroupWith(preds ...predicate.Group) predicate.Notifier { return predicate.Notifier(func(s *sql.Selector) { - step := newGroupStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(GroupInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -388,7 +392,11 @@ func HasUser() predicate.Notifier { // HasUserWith applies the HasEdge predicate on the "user" edge with a given conditions (other predicates). func HasUserWith(preds ...predicate.User) predicate.Notifier { return predicate.Notifier(func(s *sql.Selector) { - step := newUserStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(UserInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, UserTable, UserColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -399,15 +407,32 @@ func HasUserWith(preds ...predicate.User) predicate.Notifier { // And groups predicates with the AND operator between them. func And(predicates ...predicate.Notifier) predicate.Notifier { - return predicate.Notifier(sql.AndPredicates(predicates...)) + return predicate.Notifier(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for _, p := range predicates { + p(s1) + } + s.Where(s1.P()) + }) } // Or groups predicates with the OR operator between them. func Or(predicates ...predicate.Notifier) predicate.Notifier { - return predicate.Notifier(sql.OrPredicates(predicates...)) + return predicate.Notifier(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for i, p := range predicates { + if i > 0 { + s1.Or() + } + p(s1) + } + s.Where(s1.P()) + }) } // Not applies the not operator on the given predicate. func Not(p predicate.Notifier) predicate.Notifier { - return predicate.Notifier(sql.NotPredicates(p)) + return predicate.Notifier(func(s *sql.Selector) { + p(s.Not()) + }) } diff --git a/backend/internal/data/ent/notifier_create.go b/backend/internal/data/ent/notifier_create.go index 42265e2..ed16da8 100644 --- a/backend/internal/data/ent/notifier_create.go +++ b/backend/internal/data/ent/notifier_create.go @@ -121,7 +121,7 @@ func (nc *NotifierCreate) Mutation() *NotifierMutation { // Save creates the Notifier in the database. func (nc *NotifierCreate) Save(ctx context.Context) (*Notifier, error) { nc.defaults() - return withHooks(ctx, nc.sqlSave, nc.mutation, nc.hooks) + return withHooks[*Notifier, NotifierMutation](ctx, nc.sqlSave, nc.mutation, nc.hooks) } // SaveX calls Save and panics if Save returns an error. @@ -300,15 +300,11 @@ func (nc *NotifierCreate) createSpec() (*Notifier, *sqlgraph.CreateSpec) { // NotifierCreateBulk is the builder for creating many Notifier entities in bulk. type NotifierCreateBulk struct { config - err error builders []*NotifierCreate } // Save creates the Notifier entities in the database. func (ncb *NotifierCreateBulk) Save(ctx context.Context) ([]*Notifier, error) { - if ncb.err != nil { - return nil, ncb.err - } specs := make([]*sqlgraph.CreateSpec, len(ncb.builders)) nodes := make([]*Notifier, len(ncb.builders)) mutators := make([]Mutator, len(ncb.builders)) @@ -325,8 +321,8 @@ func (ncb *NotifierCreateBulk) Save(ctx context.Context) ([]*Notifier, error) { return nil, err } builder.mutation = mutation - var err error nodes[i], specs[i] = builder.createSpec() + var err error if i < len(mutators)-1 { _, err = mutators[i+1].Mutate(root, ncb.builders[i+1].mutation) } else { diff --git a/backend/internal/data/ent/notifier_delete.go b/backend/internal/data/ent/notifier_delete.go index 586b093..c4f0d45 100644 --- a/backend/internal/data/ent/notifier_delete.go +++ b/backend/internal/data/ent/notifier_delete.go @@ -27,7 +27,7 @@ func (nd *NotifierDelete) Where(ps ...predicate.Notifier) *NotifierDelete { // Exec executes the deletion query and returns how many vertices were deleted. func (nd *NotifierDelete) Exec(ctx context.Context) (int, error) { - return withHooks(ctx, nd.sqlExec, nd.mutation, nd.hooks) + return withHooks[int, NotifierMutation](ctx, nd.sqlExec, nd.mutation, nd.hooks) } // ExecX is like Exec, but panics if an error occurs. diff --git a/backend/internal/data/ent/notifier_query.go b/backend/internal/data/ent/notifier_query.go index c88b4ef..1283eb1 100644 --- a/backend/internal/data/ent/notifier_query.go +++ b/backend/internal/data/ent/notifier_query.go @@ -21,7 +21,7 @@ import ( type NotifierQuery struct { config ctx *QueryContext - order []notifier.OrderOption + order []OrderFunc inters []Interceptor predicates []predicate.Notifier withGroup *GroupQuery @@ -57,7 +57,7 @@ func (nq *NotifierQuery) Unique(unique bool) *NotifierQuery { } // Order specifies how the records should be ordered. -func (nq *NotifierQuery) Order(o ...notifier.OrderOption) *NotifierQuery { +func (nq *NotifierQuery) Order(o ...OrderFunc) *NotifierQuery { nq.order = append(nq.order, o...) return nq } @@ -295,7 +295,7 @@ func (nq *NotifierQuery) Clone() *NotifierQuery { return &NotifierQuery{ config: nq.config, ctx: nq.ctx.Clone(), - order: append([]notifier.OrderOption{}, nq.order...), + order: append([]OrderFunc{}, nq.order...), inters: append([]Interceptor{}, nq.inters...), predicates: append([]predicate.Notifier{}, nq.predicates...), withGroup: nq.withGroup.Clone(), @@ -528,12 +528,6 @@ func (nq *NotifierQuery) querySpec() *sqlgraph.QuerySpec { _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) } } - if nq.withGroup != nil { - _spec.Node.AddColumnOnce(notifier.FieldGroupID) - } - if nq.withUser != nil { - _spec.Node.AddColumnOnce(notifier.FieldUserID) - } } if ps := nq.predicates; len(ps) > 0 { _spec.Predicate = func(selector *sql.Selector) { diff --git a/backend/internal/data/ent/notifier_update.go b/backend/internal/data/ent/notifier_update.go index ea28f32..5d75028 100644 --- a/backend/internal/data/ent/notifier_update.go +++ b/backend/internal/data/ent/notifier_update.go @@ -43,56 +43,24 @@ func (nu *NotifierUpdate) SetGroupID(u uuid.UUID) *NotifierUpdate { return nu } -// SetNillableGroupID sets the "group_id" field if the given value is not nil. -func (nu *NotifierUpdate) SetNillableGroupID(u *uuid.UUID) *NotifierUpdate { - if u != nil { - nu.SetGroupID(*u) - } - return nu -} - // SetUserID sets the "user_id" field. func (nu *NotifierUpdate) SetUserID(u uuid.UUID) *NotifierUpdate { nu.mutation.SetUserID(u) return nu } -// SetNillableUserID sets the "user_id" field if the given value is not nil. -func (nu *NotifierUpdate) SetNillableUserID(u *uuid.UUID) *NotifierUpdate { - if u != nil { - nu.SetUserID(*u) - } - return nu -} - // SetName sets the "name" field. func (nu *NotifierUpdate) SetName(s string) *NotifierUpdate { nu.mutation.SetName(s) return nu } -// SetNillableName sets the "name" field if the given value is not nil. -func (nu *NotifierUpdate) SetNillableName(s *string) *NotifierUpdate { - if s != nil { - nu.SetName(*s) - } - return nu -} - // SetURL sets the "url" field. func (nu *NotifierUpdate) SetURL(s string) *NotifierUpdate { nu.mutation.SetURL(s) return nu } -// SetNillableURL sets the "url" field if the given value is not nil. -func (nu *NotifierUpdate) SetNillableURL(s *string) *NotifierUpdate { - if s != nil { - nu.SetURL(*s) - } - return nu -} - // SetIsActive sets the "is_active" field. func (nu *NotifierUpdate) SetIsActive(b bool) *NotifierUpdate { nu.mutation.SetIsActive(b) @@ -137,7 +105,7 @@ func (nu *NotifierUpdate) ClearUser() *NotifierUpdate { // Save executes the query and returns the number of nodes affected by the update operation. func (nu *NotifierUpdate) Save(ctx context.Context) (int, error) { nu.defaults() - return withHooks(ctx, nu.sqlSave, nu.mutation, nu.hooks) + return withHooks[int, NotifierMutation](ctx, nu.sqlSave, nu.mutation, nu.hooks) } // SaveX is like Save, but panics if an error occurs. @@ -305,56 +273,24 @@ func (nuo *NotifierUpdateOne) SetGroupID(u uuid.UUID) *NotifierUpdateOne { return nuo } -// SetNillableGroupID sets the "group_id" field if the given value is not nil. -func (nuo *NotifierUpdateOne) SetNillableGroupID(u *uuid.UUID) *NotifierUpdateOne { - if u != nil { - nuo.SetGroupID(*u) - } - return nuo -} - // SetUserID sets the "user_id" field. func (nuo *NotifierUpdateOne) SetUserID(u uuid.UUID) *NotifierUpdateOne { nuo.mutation.SetUserID(u) return nuo } -// SetNillableUserID sets the "user_id" field if the given value is not nil. -func (nuo *NotifierUpdateOne) SetNillableUserID(u *uuid.UUID) *NotifierUpdateOne { - if u != nil { - nuo.SetUserID(*u) - } - return nuo -} - // SetName sets the "name" field. func (nuo *NotifierUpdateOne) SetName(s string) *NotifierUpdateOne { nuo.mutation.SetName(s) return nuo } -// SetNillableName sets the "name" field if the given value is not nil. -func (nuo *NotifierUpdateOne) SetNillableName(s *string) *NotifierUpdateOne { - if s != nil { - nuo.SetName(*s) - } - return nuo -} - // SetURL sets the "url" field. func (nuo *NotifierUpdateOne) SetURL(s string) *NotifierUpdateOne { nuo.mutation.SetURL(s) return nuo } -// SetNillableURL sets the "url" field if the given value is not nil. -func (nuo *NotifierUpdateOne) SetNillableURL(s *string) *NotifierUpdateOne { - if s != nil { - nuo.SetURL(*s) - } - return nuo -} - // SetIsActive sets the "is_active" field. func (nuo *NotifierUpdateOne) SetIsActive(b bool) *NotifierUpdateOne { nuo.mutation.SetIsActive(b) @@ -412,7 +348,7 @@ func (nuo *NotifierUpdateOne) Select(field string, fields ...string) *NotifierUp // Save executes the query and returns the updated Notifier entity. func (nuo *NotifierUpdateOne) Save(ctx context.Context) (*Notifier, error) { nuo.defaults() - return withHooks(ctx, nuo.sqlSave, nuo.mutation, nuo.hooks) + return withHooks[*Notifier, NotifierMutation](ctx, nuo.sqlSave, nuo.mutation, nuo.hooks) } // SaveX is like Save, but panics if an error occurs. diff --git a/backend/internal/data/ent/runtime.go b/backend/internal/data/ent/runtime.go index c3aff00..9edc90b 100644 --- a/backend/internal/data/ent/runtime.go +++ b/backend/internal/data/ent/runtime.go @@ -40,10 +40,6 @@ func init() { attachment.DefaultUpdatedAt = attachmentDescUpdatedAt.Default.(func() time.Time) // attachment.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field. attachment.UpdateDefaultUpdatedAt = attachmentDescUpdatedAt.UpdateDefault.(func() time.Time) - // attachmentDescPrimary is the schema descriptor for primary field. - attachmentDescPrimary := attachmentFields[1].Descriptor() - // attachment.DefaultPrimary holds the default value on creation for the primary field. - attachment.DefaultPrimary = attachmentDescPrimary.Default.(bool) // attachmentDescID is the schema descriptor for id field. attachmentDescID := attachmentMixinFields0[0].Descriptor() // attachment.DefaultID holds the default value on creation for the id field. @@ -161,10 +157,6 @@ func init() { return nil } }() - // groupDescCurrency is the schema descriptor for currency field. - groupDescCurrency := groupFields[1].Descriptor() - // group.DefaultCurrency holds the default value on creation for the currency field. - group.DefaultCurrency = groupDescCurrency.Default.(string) // groupDescID is the schema descriptor for id field. groupDescID := groupMixinFields0[0].Descriptor() // group.DefaultID holds the default value on creation for the id field. diff --git a/backend/internal/data/ent/runtime/runtime.go b/backend/internal/data/ent/runtime/runtime.go index b5773b1..c198804 100644 --- a/backend/internal/data/ent/runtime/runtime.go +++ b/backend/internal/data/ent/runtime/runtime.go @@ -5,6 +5,6 @@ package runtime // The schema-stitching logic is generated in github.com/hay-kot/homebox/backend/internal/data/ent/runtime.go const ( - Version = "v0.12.5" // Version of ent codegen. - Sum = "h1:KREM5E4CSoej4zeGa88Ou/gfturAnpUv0mzAjch1sj4=" // Sum of ent codegen. + Version = "v0.11.10" // Version of ent codegen. + Sum = "h1:iqn32ybY5HRW3xSAyMNdNKpZhKgMf1Zunsej9yPKUI8=" // Sum of ent codegen. ) diff --git a/backend/internal/data/ent/schema/attachment.go b/backend/internal/data/ent/schema/attachment.go index 589b684..7f4673a 100644 --- a/backend/internal/data/ent/schema/attachment.go +++ b/backend/internal/data/ent/schema/attachment.go @@ -24,8 +24,6 @@ func (Attachment) Fields() []ent.Field { field.Enum("type"). Values("photo", "manual", "warranty", "attachment", "receipt"). Default("attachment"), - field.Bool("primary"). - Default(false), } } diff --git a/backend/internal/data/ent/schema/group.go b/backend/internal/data/ent/schema/group.go index 352ac0b..0d143a3 100644 --- a/backend/internal/data/ent/schema/group.go +++ b/backend/internal/data/ent/schema/group.go @@ -27,8 +27,9 @@ func (Group) Fields() []ent.Field { field.String("name"). MaxLen(255). NotEmpty(), - field.String("currency"). - Default("usd"), + field.Enum("currency"). + Default("usd"). + Values("usd", "eur", "gbp", "jpy", "zar", "aud", "nok", "nzd", "sek", "dkk", "inr", "rmb", "bgn", "chf", "pln", "try", "ron", "czk"), } } @@ -69,6 +70,7 @@ func (g GroupMixin) Fields() []ent.Field { } return nil + } func (g GroupMixin) Edges() []ent.Edge { diff --git a/backend/internal/data/ent/schema/templates/has_id.tmpl b/backend/internal/data/ent/schema/templates/has_id.tmpl index d9134e9..cc6e30a 100644 --- a/backend/internal/data/ent/schema/templates/has_id.tmpl +++ b/backend/internal/data/ent/schema/templates/has_id.tmpl @@ -20,4 +20,4 @@ import "github.com/google/uuid" } {{ end }} -{{ end }} +{{ end }} \ No newline at end of file diff --git a/backend/internal/data/ent/schema/user.go b/backend/internal/data/ent/schema/user.go index 10b0a8a..39eb38c 100644 --- a/backend/internal/data/ent/schema/user.go +++ b/backend/internal/data/ent/schema/user.go @@ -78,6 +78,7 @@ func (g UserMixin) Fields() []ent.Field { } return nil + } func (g UserMixin) Edges() []ent.Edge { diff --git a/backend/internal/data/ent/user.go b/backend/internal/data/ent/user.go index 3331de7..5acfa9b 100644 --- a/backend/internal/data/ent/user.go +++ b/backend/internal/data/ent/user.go @@ -7,7 +7,6 @@ import ( "strings" "time" - "entgo.io/ent" "entgo.io/ent/dialect/sql" "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/data/ent/group" @@ -39,9 +38,8 @@ type User struct { ActivatedOn time.Time `json:"activated_on,omitempty"` // Edges holds the relations/edges for other nodes in the graph. // The values are being populated by the UserQuery when eager-loading is set. - Edges UserEdges `json:"edges"` - group_users *uuid.UUID - selectValues sql.SelectValues + Edges UserEdges `json:"edges"` + group_users *uuid.UUID } // UserEdges holds the relations/edges for other nodes in the graph. @@ -104,7 +102,7 @@ func (*User) scanValues(columns []string) ([]any, error) { case user.ForeignKeys[0]: // group_users values[i] = &sql.NullScanner{S: new(uuid.UUID)} default: - values[i] = new(sql.UnknownType) + return nil, fmt.Errorf("unexpected column %q for type User", columns[i]) } } return values, nil @@ -185,19 +183,11 @@ func (u *User) assignValues(columns []string, values []any) error { u.group_users = new(uuid.UUID) *u.group_users = *value.S.(*uuid.UUID) } - default: - u.selectValues.Set(columns[i], values[i]) } } return nil } -// Value returns the ent.Value that was dynamically selected and assigned to the User. -// This includes values selected through modifiers, order, etc. -func (u *User) Value(name string) (ent.Value, error) { - return u.selectValues.Get(name) -} - // QueryGroup queries the "group" edge of the User entity. func (u *User) QueryGroup() *GroupQuery { return NewUserClient(u.config).QueryGroup(u) diff --git a/backend/internal/data/ent/user/user.go b/backend/internal/data/ent/user/user.go index 33b657b..93c0c03 100644 --- a/backend/internal/data/ent/user/user.go +++ b/backend/internal/data/ent/user/user.go @@ -6,8 +6,6 @@ import ( "fmt" "time" - "entgo.io/ent/dialect/sql" - "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" ) @@ -146,112 +144,3 @@ func RoleValidator(r Role) error { return fmt.Errorf("user: invalid enum value for role field: %q", r) } } - -// OrderOption defines the ordering options for the User queries. -type OrderOption func(*sql.Selector) - -// ByID orders the results by the id field. -func ByID(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldID, opts...).ToFunc() -} - -// ByCreatedAt orders the results by the created_at field. -func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() -} - -// ByUpdatedAt orders the results by the updated_at field. -func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc() -} - -// ByName orders the results by the name field. -func ByName(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldName, opts...).ToFunc() -} - -// ByEmail orders the results by the email field. -func ByEmail(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldEmail, opts...).ToFunc() -} - -// ByPassword orders the results by the password field. -func ByPassword(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldPassword, opts...).ToFunc() -} - -// ByIsSuperuser orders the results by the is_superuser field. -func ByIsSuperuser(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldIsSuperuser, opts...).ToFunc() -} - -// BySuperuser orders the results by the superuser field. -func BySuperuser(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldSuperuser, opts...).ToFunc() -} - -// ByRole orders the results by the role field. -func ByRole(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldRole, opts...).ToFunc() -} - -// ByActivatedOn orders the results by the activated_on field. -func ByActivatedOn(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldActivatedOn, opts...).ToFunc() -} - -// ByGroupField orders the results by group field. -func ByGroupField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newGroupStep(), sql.OrderByField(field, opts...)) - } -} - -// ByAuthTokensCount orders the results by auth_tokens count. -func ByAuthTokensCount(opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborsCount(s, newAuthTokensStep(), opts...) - } -} - -// ByAuthTokens orders the results by auth_tokens terms. -func ByAuthTokens(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newAuthTokensStep(), append([]sql.OrderTerm{term}, terms...)...) - } -} - -// ByNotifiersCount orders the results by notifiers count. -func ByNotifiersCount(opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborsCount(s, newNotifiersStep(), opts...) - } -} - -// ByNotifiers orders the results by notifiers terms. -func ByNotifiers(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newNotifiersStep(), append([]sql.OrderTerm{term}, terms...)...) - } -} -func newGroupStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(GroupInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn), - ) -} -func newAuthTokensStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(AuthTokensInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, AuthTokensTable, AuthTokensColumn), - ) -} -func newNotifiersStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(NotifiersInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, NotifiersTable, NotifiersColumn), - ) -} diff --git a/backend/internal/data/ent/user/where.go b/backend/internal/data/ent/user/where.go index 8686e73..2ad23bb 100644 --- a/backend/internal/data/ent/user/where.go +++ b/backend/internal/data/ent/user/where.go @@ -475,7 +475,11 @@ func HasGroup() predicate.User { // HasGroupWith applies the HasEdge predicate on the "group" edge with a given conditions (other predicates). func HasGroupWith(preds ...predicate.Group) predicate.User { return predicate.User(func(s *sql.Selector) { - step := newGroupStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(GroupInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -498,7 +502,11 @@ func HasAuthTokens() predicate.User { // HasAuthTokensWith applies the HasEdge predicate on the "auth_tokens" edge with a given conditions (other predicates). func HasAuthTokensWith(preds ...predicate.AuthTokens) predicate.User { return predicate.User(func(s *sql.Selector) { - step := newAuthTokensStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(AuthTokensInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, AuthTokensTable, AuthTokensColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -521,7 +529,11 @@ func HasNotifiers() predicate.User { // HasNotifiersWith applies the HasEdge predicate on the "notifiers" edge with a given conditions (other predicates). func HasNotifiersWith(preds ...predicate.Notifier) predicate.User { return predicate.User(func(s *sql.Selector) { - step := newNotifiersStep() + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(NotifiersInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, false, NotifiersTable, NotifiersColumn), + ) sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { for _, p := range preds { p(s) @@ -532,15 +544,32 @@ func HasNotifiersWith(preds ...predicate.Notifier) predicate.User { // And groups predicates with the AND operator between them. func And(predicates ...predicate.User) predicate.User { - return predicate.User(sql.AndPredicates(predicates...)) + return predicate.User(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for _, p := range predicates { + p(s1) + } + s.Where(s1.P()) + }) } // Or groups predicates with the OR operator between them. func Or(predicates ...predicate.User) predicate.User { - return predicate.User(sql.OrPredicates(predicates...)) + return predicate.User(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for i, p := range predicates { + if i > 0 { + s1.Or() + } + p(s1) + } + s.Where(s1.P()) + }) } // Not applies the not operator on the given predicate. func Not(p predicate.User) predicate.User { - return predicate.User(sql.NotPredicates(p)) + return predicate.User(func(s *sql.Selector) { + p(s.Not()) + }) } diff --git a/backend/internal/data/ent/user_create.go b/backend/internal/data/ent/user_create.go index 2cfe2d1..a53177b 100644 --- a/backend/internal/data/ent/user_create.go +++ b/backend/internal/data/ent/user_create.go @@ -189,7 +189,7 @@ func (uc *UserCreate) Mutation() *UserMutation { // Save creates the User in the database. func (uc *UserCreate) Save(ctx context.Context) (*User, error) { uc.defaults() - return withHooks(ctx, uc.sqlSave, uc.mutation, uc.hooks) + return withHooks[*User, UserMutation](ctx, uc.sqlSave, uc.mutation, uc.hooks) } // SaveX calls Save and panics if Save returns an error. @@ -417,15 +417,11 @@ func (uc *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) { // UserCreateBulk is the builder for creating many User entities in bulk. type UserCreateBulk struct { config - err error builders []*UserCreate } // Save creates the User entities in the database. func (ucb *UserCreateBulk) Save(ctx context.Context) ([]*User, error) { - if ucb.err != nil { - return nil, ucb.err - } specs := make([]*sqlgraph.CreateSpec, len(ucb.builders)) nodes := make([]*User, len(ucb.builders)) mutators := make([]Mutator, len(ucb.builders)) @@ -442,8 +438,8 @@ func (ucb *UserCreateBulk) Save(ctx context.Context) ([]*User, error) { return nil, err } builder.mutation = mutation - var err error nodes[i], specs[i] = builder.createSpec() + var err error if i < len(mutators)-1 { _, err = mutators[i+1].Mutate(root, ucb.builders[i+1].mutation) } else { diff --git a/backend/internal/data/ent/user_delete.go b/backend/internal/data/ent/user_delete.go index 08fd3ef..4e38aab 100644 --- a/backend/internal/data/ent/user_delete.go +++ b/backend/internal/data/ent/user_delete.go @@ -27,7 +27,7 @@ func (ud *UserDelete) Where(ps ...predicate.User) *UserDelete { // Exec executes the deletion query and returns how many vertices were deleted. func (ud *UserDelete) Exec(ctx context.Context) (int, error) { - return withHooks(ctx, ud.sqlExec, ud.mutation, ud.hooks) + return withHooks[int, UserMutation](ctx, ud.sqlExec, ud.mutation, ud.hooks) } // ExecX is like Exec, but panics if an error occurs. diff --git a/backend/internal/data/ent/user_query.go b/backend/internal/data/ent/user_query.go index 7205e9b..aa90822 100644 --- a/backend/internal/data/ent/user_query.go +++ b/backend/internal/data/ent/user_query.go @@ -23,7 +23,7 @@ import ( type UserQuery struct { config ctx *QueryContext - order []user.OrderOption + order []OrderFunc inters []Interceptor predicates []predicate.User withGroup *GroupQuery @@ -61,7 +61,7 @@ func (uq *UserQuery) Unique(unique bool) *UserQuery { } // Order specifies how the records should be ordered. -func (uq *UserQuery) Order(o ...user.OrderOption) *UserQuery { +func (uq *UserQuery) Order(o ...OrderFunc) *UserQuery { uq.order = append(uq.order, o...) return uq } @@ -321,7 +321,7 @@ func (uq *UserQuery) Clone() *UserQuery { return &UserQuery{ config: uq.config, ctx: uq.ctx.Clone(), - order: append([]user.OrderOption{}, uq.order...), + order: append([]OrderFunc{}, uq.order...), inters: append([]Interceptor{}, uq.inters...), predicates: append([]predicate.User{}, uq.predicates...), withGroup: uq.withGroup.Clone(), @@ -542,7 +542,7 @@ func (uq *UserQuery) loadAuthTokens(ctx context.Context, query *AuthTokensQuery, } query.withFKs = true query.Where(predicate.AuthTokens(func(s *sql.Selector) { - s.Where(sql.InValues(s.C(user.AuthTokensColumn), fks...)) + s.Where(sql.InValues(user.AuthTokensColumn, fks...)) })) neighbors, err := query.All(ctx) if err != nil { @@ -555,7 +555,7 @@ func (uq *UserQuery) loadAuthTokens(ctx context.Context, query *AuthTokensQuery, } node, ok := nodeids[*fk] if !ok { - return fmt.Errorf(`unexpected referenced foreign-key "user_auth_tokens" returned %v for node %v`, *fk, n.ID) + return fmt.Errorf(`unexpected foreign-key "user_auth_tokens" returned %v for node %v`, *fk, n.ID) } assign(node, n) } @@ -571,11 +571,8 @@ func (uq *UserQuery) loadNotifiers(ctx context.Context, query *NotifierQuery, no init(nodes[i]) } } - if len(query.ctx.Fields) > 0 { - query.ctx.AppendFieldOnce(notifier.FieldUserID) - } query.Where(predicate.Notifier(func(s *sql.Selector) { - s.Where(sql.InValues(s.C(user.NotifiersColumn), fks...)) + s.Where(sql.InValues(user.NotifiersColumn, fks...)) })) neighbors, err := query.All(ctx) if err != nil { @@ -585,7 +582,7 @@ func (uq *UserQuery) loadNotifiers(ctx context.Context, query *NotifierQuery, no fk := n.UserID node, ok := nodeids[fk] if !ok { - return fmt.Errorf(`unexpected referenced foreign-key "user_id" returned %v for node %v`, fk, n.ID) + return fmt.Errorf(`unexpected foreign-key "user_id" returned %v for node %v`, fk, n.ID) } assign(node, n) } diff --git a/backend/internal/data/ent/user_update.go b/backend/internal/data/ent/user_update.go index 0e4c01a..88fb763 100644 --- a/backend/internal/data/ent/user_update.go +++ b/backend/internal/data/ent/user_update.go @@ -44,42 +44,18 @@ func (uu *UserUpdate) SetName(s string) *UserUpdate { return uu } -// SetNillableName sets the "name" field if the given value is not nil. -func (uu *UserUpdate) SetNillableName(s *string) *UserUpdate { - if s != nil { - uu.SetName(*s) - } - return uu -} - // SetEmail sets the "email" field. func (uu *UserUpdate) SetEmail(s string) *UserUpdate { uu.mutation.SetEmail(s) return uu } -// SetNillableEmail sets the "email" field if the given value is not nil. -func (uu *UserUpdate) SetNillableEmail(s *string) *UserUpdate { - if s != nil { - uu.SetEmail(*s) - } - return uu -} - // SetPassword sets the "password" field. func (uu *UserUpdate) SetPassword(s string) *UserUpdate { uu.mutation.SetPassword(s) return uu } -// SetNillablePassword sets the "password" field if the given value is not nil. -func (uu *UserUpdate) SetNillablePassword(s *string) *UserUpdate { - if s != nil { - uu.SetPassword(*s) - } - return uu -} - // SetIsSuperuser sets the "is_superuser" field. func (uu *UserUpdate) SetIsSuperuser(b bool) *UserUpdate { uu.mutation.SetIsSuperuser(b) @@ -239,7 +215,7 @@ func (uu *UserUpdate) RemoveNotifiers(n ...*Notifier) *UserUpdate { // Save executes the query and returns the number of nodes affected by the update operation. func (uu *UserUpdate) Save(ctx context.Context) (int, error) { uu.defaults() - return withHooks(ctx, uu.sqlSave, uu.mutation, uu.hooks) + return withHooks[int, UserMutation](ctx, uu.sqlSave, uu.mutation, uu.hooks) } // SaveX is like Save, but panics if an error occurs. @@ -490,42 +466,18 @@ func (uuo *UserUpdateOne) SetName(s string) *UserUpdateOne { return uuo } -// SetNillableName sets the "name" field if the given value is not nil. -func (uuo *UserUpdateOne) SetNillableName(s *string) *UserUpdateOne { - if s != nil { - uuo.SetName(*s) - } - return uuo -} - // SetEmail sets the "email" field. func (uuo *UserUpdateOne) SetEmail(s string) *UserUpdateOne { uuo.mutation.SetEmail(s) return uuo } -// SetNillableEmail sets the "email" field if the given value is not nil. -func (uuo *UserUpdateOne) SetNillableEmail(s *string) *UserUpdateOne { - if s != nil { - uuo.SetEmail(*s) - } - return uuo -} - // SetPassword sets the "password" field. func (uuo *UserUpdateOne) SetPassword(s string) *UserUpdateOne { uuo.mutation.SetPassword(s) return uuo } -// SetNillablePassword sets the "password" field if the given value is not nil. -func (uuo *UserUpdateOne) SetNillablePassword(s *string) *UserUpdateOne { - if s != nil { - uuo.SetPassword(*s) - } - return uuo -} - // SetIsSuperuser sets the "is_superuser" field. func (uuo *UserUpdateOne) SetIsSuperuser(b bool) *UserUpdateOne { uuo.mutation.SetIsSuperuser(b) @@ -698,7 +650,7 @@ func (uuo *UserUpdateOne) Select(field string, fields ...string) *UserUpdateOne // Save executes the query and returns the updated User entity. func (uuo *UserUpdateOne) Save(ctx context.Context) (*User, error) { uuo.defaults() - return withHooks(ctx, uuo.sqlSave, uuo.mutation, uuo.hooks) + return withHooks[*User, UserMutation](ctx, uuo.sqlSave, uuo.mutation, uuo.hooks) } // SaveX is like Save, but panics if an error occurs. diff --git a/backend/internal/data/migrations/migrations.go b/backend/internal/data/migrations/migrations.go index a2afdc8..d477df9 100644 --- a/backend/internal/data/migrations/migrations.go +++ b/backend/internal/data/migrations/migrations.go @@ -1,10 +1,9 @@ -// Package migrations provides a way to embed the migrations into the binary. package migrations import ( "embed" "os" - "path" + "path/filepath" ) //go:embed all:migrations @@ -29,12 +28,12 @@ func Write(temp string) error { continue } - b, err := Files.ReadFile(path.Join("migrations", f.Name())) + b, err := Files.ReadFile(filepath.Join("migrations", f.Name())) if err != nil { return err } - err = os.WriteFile(path.Join(temp, f.Name()), b, 0o644) + err = os.WriteFile(filepath.Join(temp, f.Name()), b, 0o644) if err != nil { return err } diff --git a/backend/internal/data/migrations/migrations/20231006213457_add_primary_attachment_flag.sql b/backend/internal/data/migrations/migrations/20231006213457_add_primary_attachment_flag.sql deleted file mode 100644 index b7506c1..0000000 --- a/backend/internal/data/migrations/migrations/20231006213457_add_primary_attachment_flag.sql +++ /dev/null @@ -1,12 +0,0 @@ --- Disable the enforcement of foreign-keys constraints -PRAGMA foreign_keys = off; --- Create "new_attachments" table -CREATE TABLE `new_attachments` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `type` text NOT NULL DEFAULT 'attachment', `primary` bool NOT NULL DEFAULT false, `document_attachments` uuid NOT NULL, `item_attachments` uuid NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `attachments_documents_attachments` FOREIGN KEY (`document_attachments`) REFERENCES `documents` (`id`) ON DELETE CASCADE, CONSTRAINT `attachments_items_attachments` FOREIGN KEY (`item_attachments`) REFERENCES `items` (`id`) ON DELETE CASCADE); --- Copy rows from old table "attachments" to new temporary table "new_attachments" -INSERT INTO `new_attachments` (`id`, `created_at`, `updated_at`, `type`, `document_attachments`, `item_attachments`) SELECT `id`, `created_at`, `updated_at`, `type`, `document_attachments`, `item_attachments` FROM `attachments`; --- Drop "attachments" table after copying rows -DROP TABLE `attachments`; --- Rename temporary table "new_attachments" to "attachments" -ALTER TABLE `new_attachments` RENAME TO `attachments`; --- Enable back the enforcement of foreign-keys constraints -PRAGMA foreign_keys = on; diff --git a/backend/internal/data/migrations/migrations/atlas.sum b/backend/internal/data/migrations/migrations/atlas.sum index e8d99a6..84c48d2 100644 --- a/backend/internal/data/migrations/migrations/atlas.sum +++ b/backend/internal/data/migrations/migrations/atlas.sum @@ -1,4 +1,4 @@ -h1:sjJCTAqc9FG8BKBIzh5ZynYD/Ilz6vnLqM4XX83WQ4M= +h1:VjVLPBHzJ8N1Hiw+Aeitb0alnVn9UFilnajCzc+pie8= 20220929052825_init.sql h1:ZlCqm1wzjDmofeAcSX3jE4h4VcdTNGpRg2eabztDy9Q= 20221001210956_group_invitations.sql h1:YQKJFtE39wFOcRNbZQ/d+ZlHwrcfcsZlcv/pLEYdpjw= 20221009173029_add_user_roles.sql h1:vWmzAfgEWQeGk0Vn70zfVPCcfEZth3E0JcvyKTjpYyU= @@ -12,4 +12,3 @@ h1:sjJCTAqc9FG8BKBIzh5ZynYD/Ilz6vnLqM4XX83WQ4M= 20230227024134_add_scheduled_date.sql h1:8qO5OBZ0AzsfYEQOAQQrYIjyhSwM+v1A+/ylLSoiyoc= 20230305065819_add_notifier_types.sql h1:r5xrgCKYQ2o9byBqYeAX1zdp94BLdaxf4vq9OmGHNl0= 20230305071524_add_group_id_to_notifiers.sql h1:xDShqbyClcFhvJbwclOHdczgXbdffkxXNWjV61hL/t4= -20231006213457_add_primary_attachment_flag.sql h1:J4tMSJQFa7vaj0jpnh8YKTssdyIjRyq6RXDXZIzDDu4= diff --git a/backend/internal/data/repo/asset_id_type.go b/backend/internal/data/repo/asset_id_type.go index 0a53a4a..678a510 100644 --- a/backend/internal/data/repo/asset_id_type.go +++ b/backend/internal/data/repo/asset_id_type.go @@ -47,11 +47,6 @@ func (aid AssetID) MarshalJSON() ([]byte, error) { } func (aid *AssetID) UnmarshalJSON(d []byte) error { - if len(d) == 0 || bytes.Equal(d, []byte(`""`)) { - *aid = -1 - return nil - } - d = bytes.Replace(d, []byte(`"`), []byte(``), -1) d = bytes.Replace(d, []byte(`-`), []byte(``), -1) diff --git a/backend/internal/data/repo/main_test.go b/backend/internal/data/repo/main_test.go index 47e5ec0..cfb1630 100644 --- a/backend/internal/data/repo/main_test.go +++ b/backend/internal/data/repo/main_test.go @@ -6,15 +6,13 @@ import ( "os" "testing" - "github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus" "github.com/hay-kot/homebox/backend/internal/data/ent" "github.com/hay-kot/homebox/backend/pkgs/faker" _ "github.com/mattn/go-sqlite3" ) var ( - fk = faker.NewFaker() - tbus = eventbus.New() + fk = faker.NewFaker() tClient *ent.Client tRepos *AllRepos @@ -45,18 +43,14 @@ func TestMain(m *testing.M) { log.Fatalf("failed opening connection to sqlite: %v", err) } - go func() { - _ = tbus.Run(context.Background()) - }() - err = client.Schema.Create(context.Background()) if err != nil { log.Fatalf("failed creating schema resources: %v", err) } tClient = client - tRepos = New(tClient, tbus, os.TempDir()) - defer func() { _ = client.Close() }() + tRepos = New(tClient, os.TempDir()) + defer client.Close() bootstrap() diff --git a/backend/internal/data/repo/repo_documents_test.go b/backend/internal/data/repo/repo_documents_test.go index 4634235..2a22fac 100644 --- a/backend/internal/data/repo/repo_documents_test.go +++ b/backend/internal/data/repo/repo_documents_test.go @@ -11,7 +11,6 @@ import ( "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/data/ent" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func useDocs(t *testing.T, num int) []DocumentOut { @@ -26,7 +25,7 @@ func useDocs(t *testing.T, num int) []DocumentOut { Content: bytes.NewReader([]byte(fk.Str(10))), }) - require.NoError(t, err) + assert.NoError(t, err) assert.NotNil(t, doc) results = append(results, doc) ids = append(ids, doc.ID) @@ -81,31 +80,31 @@ func TestDocumentRepository_CreateUpdateDelete(t *testing.T) { t.Run(tt.name, func(t *testing.T) { // Create Document got, err := r.Create(tt.args.ctx, tt.args.gid, tt.args.doc) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, tt.title, got.Title) assert.Equal(t, fmt.Sprintf("%s/%s/documents", temp, tt.args.gid), filepath.Dir(got.Path)) ensureRead := func() { // Read Document bts, err := os.ReadFile(got.Path) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, tt.content, string(bts)) } ensureRead() // Update Document got, err = r.Rename(tt.args.ctx, got.ID, "__"+tt.title+"__") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "__"+tt.title+"__", got.Title) ensureRead() // Delete Document err = r.Delete(tt.args.ctx, got.ID) - require.NoError(t, err) + assert.NoError(t, err) _, err = os.Stat(got.Path) - require.Error(t, err) + assert.Error(t, err) }) } } diff --git a/backend/internal/data/repo/repo_group.go b/backend/internal/data/repo/repo_group.go index 8f93c78..fab543c 100644 --- a/backend/internal/data/repo/repo_group.go +++ b/backend/internal/data/repo/repo_group.go @@ -28,7 +28,7 @@ func NewGroupRepository(db *ent.Client) *GroupRepository { Name: g.Name, CreatedAt: g.CreatedAt, UpdatedAt: g.UpdatedAt, - Currency: strings.ToUpper(g.Currency), + Currency: strings.ToUpper(g.Currency.String()), } } @@ -233,7 +233,7 @@ func (r *GroupRepository) StatsGroup(ctx context.Context, GID uuid.UUID) (GroupS (SELECT COUNT(*) FROM items WHERE group_items = ? AND items.archived = false) AS total_items, (SELECT COUNT(*) FROM locations WHERE group_locations = ?) AS total_locations, (SELECT COUNT(*) FROM labels WHERE group_labels = ?) AS total_labels, - (SELECT SUM(purchase_price*quantity) FROM items WHERE group_items = ? AND items.archived = false) AS total_item_price, + (SELECT SUM(purchase_price) FROM items WHERE group_items = ? AND items.archived = false) AS total_item_price, (SELECT COUNT(*) FROM items WHERE group_items = ? @@ -265,9 +265,11 @@ func (r *GroupRepository) GroupCreate(ctx context.Context, name string) (Group, } func (r *GroupRepository) GroupUpdate(ctx context.Context, ID uuid.UUID, data GroupUpdate) (Group, error) { + currency := group.Currency(strings.ToLower(data.Currency)) + entity, err := r.db.Group.UpdateOneID(ID). SetName(data.Name). - SetCurrency(strings.ToLower(data.Currency)). + SetCurrency(currency). Save(ctx) return r.groupMapper.MapErr(entity, err) diff --git a/backend/internal/data/repo/repo_group_test.go b/backend/internal/data/repo/repo_group_test.go index 180d72e..4321fec 100644 --- a/backend/internal/data/repo/repo_group_test.go +++ b/backend/internal/data/repo/repo_group_test.go @@ -5,30 +5,29 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func Test_Group_Create(t *testing.T) { g, err := tRepos.Groups.GroupCreate(context.Background(), "test") - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "test", g.Name) // Get by ID foundGroup, err := tRepos.Groups.GroupByID(context.Background(), g.ID) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, g.ID, foundGroup.ID) } func Test_Group_Update(t *testing.T) { g, err := tRepos.Groups.GroupCreate(context.Background(), "test") - require.NoError(t, err) + assert.NoError(t, err) g, err = tRepos.Groups.GroupUpdate(context.Background(), g.ID, GroupUpdate{ Name: "test2", Currency: "eur", }) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, "test2", g.Name) assert.Equal(t, "EUR", g.Currency) } @@ -39,7 +38,7 @@ func Test_Group_GroupStatistics(t *testing.T) { stats, err := tRepos.Groups.StatsGroup(context.Background(), tGroup.ID) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, 20, stats.TotalItems) assert.Equal(t, 20, stats.TotalLabels) assert.Equal(t, 1, stats.TotalUsers) diff --git a/backend/internal/data/repo/repo_item_attachments.go b/backend/internal/data/repo/repo_item_attachments.go index da57b31..a034369 100644 --- a/backend/internal/data/repo/repo_item_attachments.go +++ b/backend/internal/data/repo/repo_item_attachments.go @@ -7,7 +7,6 @@ import ( "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/data/ent" "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" - "github.com/hay-kot/homebox/backend/internal/data/ent/item" ) // AttachmentRepo is a repository for Attachments table that links Items to Documents @@ -25,14 +24,12 @@ type ( UpdatedAt time.Time `json:"updatedAt"` Type string `json:"type"` Document DocumentOut `json:"document"` - Primary bool `json:"primary"` } ItemAttachmentUpdate struct { - ID uuid.UUID `json:"-"` - Type string `json:"type"` - Title string `json:"title"` - Primary bool `json:"primary"` + ID uuid.UUID `json:"-"` + Type string `json:"type"` + Title string `json:"title"` } ) @@ -42,7 +39,6 @@ func ToItemAttachment(attachment *ent.Attachment) ItemAttachment { CreatedAt: attachment.CreatedAt, UpdatedAt: attachment.UpdatedAt, Type: attachment.Type.String(), - Primary: attachment.Primary, Document: DocumentOut{ ID: attachment.Edges.Document.ID, Title: attachment.Edges.Document.Title, @@ -51,31 +47,12 @@ func ToItemAttachment(attachment *ent.Attachment) ItemAttachment { } } -func (r *AttachmentRepo) Create(ctx context.Context, itemID, docID uuid.UUID, typ attachment.Type) (*ent.Attachment, error) { - bldr := r.db.Attachment.Create(). +func (r *AttachmentRepo) Create(ctx context.Context, itemId, docId uuid.UUID, typ attachment.Type) (*ent.Attachment, error) { + return r.db.Attachment.Create(). SetType(typ). - SetDocumentID(docID). - SetItemID(itemID) - - // Autoset primary to true if this is the first attachment - // that is of type photo - if typ == attachment.TypePhoto { - cnt, err := r.db.Attachment.Query(). - Where( - attachment.HasItemWith(item.ID(itemID)), - attachment.TypeEQ(typ), - ). - Count(ctx) - if err != nil { - return nil, err - } - - if cnt == 0 { - bldr = bldr.SetPrimary(true) - } - } - - return bldr.Save(ctx) + SetDocumentID(docId). + SetItemID(itemId). + Save(ctx) } func (r *AttachmentRepo) Get(ctx context.Context, id uuid.UUID) (*ent.Attachment, error) { @@ -87,33 +64,10 @@ func (r *AttachmentRepo) Get(ctx context.Context, id uuid.UUID) (*ent.Attachment Only(ctx) } -func (r *AttachmentRepo) Update(ctx context.Context, itemID uuid.UUID, data *ItemAttachmentUpdate) (*ent.Attachment, error) { - // TODO: execute within Tx - typ := attachment.Type(data.Type) - - bldr := r.db.Attachment.UpdateOneID(itemID). - SetType(typ) - - // Primary only applies to photos - if typ == attachment.TypePhoto { - bldr = bldr.SetPrimary(data.Primary) - } else { - bldr = bldr.SetPrimary(false) - } - - itm, err := bldr.Save(ctx) - if err != nil { - return nil, err - } - - // Ensure all other attachments are not primary - err = r.db.Attachment.Update(). - Where( - attachment.HasItemWith(item.ID(itemID)), - attachment.IDNEQ(itm.ID), - ). - SetPrimary(false). - Exec(ctx) +func (r *AttachmentRepo) Update(ctx context.Context, itemId uuid.UUID, typ attachment.Type) (*ent.Attachment, error) { + itm, err := r.db.Attachment.UpdateOneID(itemId). + SetType(typ). + Save(ctx) if err != nil { return nil, err } diff --git a/backend/internal/data/repo/repo_item_attachments_test.go b/backend/internal/data/repo/repo_item_attachments_test.go index 9007b2e..4c9d77d 100644 --- a/backend/internal/data/repo/repo_item_attachments_test.go +++ b/backend/internal/data/repo/repo_item_attachments_test.go @@ -8,7 +8,6 @@ import ( "github.com/hay-kot/homebox/backend/internal/data/ent" "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestAttachmentRepo_Create(t *testing.T) { @@ -24,8 +23,8 @@ func TestAttachmentRepo_Create(t *testing.T) { type args struct { ctx context.Context - itemID uuid.UUID - docID uuid.UUID + itemId uuid.UUID + docId uuid.UUID typ attachment.Type } tests := []struct { @@ -38,8 +37,8 @@ func TestAttachmentRepo_Create(t *testing.T) { name: "create attachment", args: args{ ctx: context.Background(), - itemID: item.ID, - docID: doc.ID, + itemId: item.ID, + docId: doc.ID, typ: attachment.TypePhoto, }, want: &ent.Attachment{ @@ -50,8 +49,8 @@ func TestAttachmentRepo_Create(t *testing.T) { name: "create attachment with invalid item id", args: args{ ctx: context.Background(), - itemID: uuid.New(), - docID: doc.ID, + itemId: uuid.New(), + docId: doc.ID, typ: "blarg", }, wantErr: true, @@ -59,7 +58,7 @@ func TestAttachmentRepo_Create(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := tRepos.Attachments.Create(tt.args.ctx, tt.args.itemID, tt.args.docID, tt.args.typ) + got, err := tRepos.Attachments.Create(tt.args.ctx, tt.args.itemId, tt.args.docId, tt.args.typ) if (err != nil) != tt.wantErr { t.Errorf("AttachmentRepo.Create() error = %v, wantErr %v", err, tt.wantErr) return @@ -72,9 +71,9 @@ func TestAttachmentRepo_Create(t *testing.T) { assert.Equal(t, tt.want.Type, got.Type) withItems, err := tRepos.Attachments.Get(tt.args.ctx, got.ID) - require.NoError(t, err) - assert.Equal(t, tt.args.itemID, withItems.Edges.Item.ID) - assert.Equal(t, tt.args.docID, withItems.Edges.Document.ID) + assert.NoError(t, err) + assert.Equal(t, tt.args.itemId, withItems.Edges.Item.ID) + assert.Equal(t, tt.args.docId, withItems.Edges.Document.ID) ids = append(ids, got.ID) }) @@ -97,7 +96,7 @@ func useAttachments(t *testing.T, n int) []*ent.Attachment { attachments := make([]*ent.Attachment, n) for i := 0; i < n; i++ { attachment, err := tRepos.Attachments.Create(context.Background(), item.ID, doc.ID, attachment.TypePhoto) - require.NoError(t, err) + assert.NoError(t, err) attachments[i] = attachment ids = append(ids, attachment.ID) @@ -111,14 +110,11 @@ func TestAttachmentRepo_Update(t *testing.T) { for _, typ := range []attachment.Type{"photo", "manual", "warranty", "attachment"} { t.Run(string(typ), func(t *testing.T) { - _, err := tRepos.Attachments.Update(context.Background(), entity.ID, &ItemAttachmentUpdate{ - Type: string(typ), - }) - - require.NoError(t, err) + _, err := tRepos.Attachments.Update(context.Background(), entity.ID, typ) + assert.NoError(t, err) updated, err := tRepos.Attachments.Get(context.Background(), entity.ID) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, typ, updated.Type) }) } @@ -128,8 +124,8 @@ func TestAttachmentRepo_Delete(t *testing.T) { entity := useAttachments(t, 1)[0] err := tRepos.Attachments.Delete(context.Background(), entity.ID) - require.NoError(t, err) + assert.NoError(t, err) _, err = tRepos.Attachments.Get(context.Background(), entity.ID) - require.Error(t, err) + assert.Error(t, err) } diff --git a/backend/internal/data/repo/repo_items.go b/backend/internal/data/repo/repo_items.go index 72ba904..103c3e9 100644 --- a/backend/internal/data/repo/repo_items.go +++ b/backend/internal/data/repo/repo_items.go @@ -6,9 +6,7 @@ import ( "time" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus" "github.com/hay-kot/homebox/backend/internal/data/ent" - "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" "github.com/hay-kot/homebox/backend/internal/data/ent/group" "github.com/hay-kot/homebox/backend/internal/data/ent/item" "github.com/hay-kot/homebox/backend/internal/data/ent/itemfield" @@ -19,8 +17,7 @@ import ( ) type ItemsRepository struct { - db *ent.Client - bus *eventbus.EventBus + db *ent.Client } type ( @@ -32,15 +29,13 @@ type ( ItemQuery struct { Page int PageSize int - Search string `json:"search"` - AssetID AssetID `json:"assetId"` - LocationIDs []uuid.UUID `json:"locationIds"` - LabelIDs []uuid.UUID `json:"labelIds"` - ParentItemIDs []uuid.UUID `json:"parentIds"` - SortBy string `json:"sortBy"` - IncludeArchived bool `json:"includeArchived"` - Fields []FieldQuery `json:"fields"` - OrderBy string `json:"orderBy"` + Search string `json:"search"` + AssetID AssetID `json:"assetId"` + LocationIDs []uuid.UUID `json:"locationIds"` + LabelIDs []uuid.UUID `json:"labelIds"` + SortBy string `json:"sortBy"` + IncludeArchived bool `json:"includeArchived"` + Fields []FieldQuery } ItemField struct { @@ -55,8 +50,8 @@ type ( ItemCreate struct { ImportRef string `json:"-"` - ParentID uuid.UUID `json:"parentId" extensions:"x-nullable"` - Name string `json:"name" validate:"required,min=1,max=255"` + ParentID uuid.UUID `json:"parentId" extensions:"x-nullable"` + Name string `json:"name" validate:"required,min=1,max=255"` Description string `json:"description" validate:"max=1000"` AssetID AssetID `json:"-"` @@ -66,9 +61,9 @@ type ( } ItemUpdate struct { - ParentID uuid.UUID `json:"parentId" extensions:"x-nullable,x-omitempty"` + ParentID uuid.UUID `json:"parentId" extensions:"x-nullable,x-omitempty"` ID uuid.UUID `json:"id"` - AssetID AssetID `json:"assetId" swaggertype:"string"` + AssetID AssetID `json:"assetId"` Name string `json:"name"` Description string `json:"description"` Quantity int `json:"quantity"` @@ -108,7 +103,7 @@ type ( ItemPatch struct { ID uuid.UUID `json:"id"` Quantity *int `json:"quantity,omitempty" extensions:"x-nullable,x-omitempty"` - ImportRef *string `json:"-,omitempty" extensions:"x-nullable,x-omitempty"` + ImportRef *string `json:"importRef,omitempty" extensions:"x-nullable,x-omitempty"` } ItemSummary struct { @@ -127,8 +122,6 @@ type ( // Edges Location *LocationSummary `json:"location,omitempty" extensions:"x-nullable,x-omitempty"` Labels []LabelSummary `json:"labels"` - - ImageID *uuid.UUID `json:"imageId,omitempty"` } ItemOut struct { @@ -160,6 +153,7 @@ type ( Attachments []ItemAttachment `json:"attachments"` Fields []ItemField `json:"fields"` + Children []ItemSummary `json:"children"` } ) @@ -177,16 +171,6 @@ func mapItemSummary(item *ent.Item) ItemSummary { labels = mapEach(item.Edges.Label, mapLabelSummary) } - var imageID *uuid.UUID - if item.Edges.Attachments != nil { - for _, a := range item.Edges.Attachments { - if a.Primary && a.Edges.Document != nil { - imageID = &a.ID - break - } - } - } - return ItemSummary{ ID: item.ID, Name: item.Name, @@ -204,7 +188,6 @@ func mapItemSummary(item *ent.Item) ItemSummary { // Warranty Insured: item.Insured, - ImageID: imageID, } } @@ -240,6 +223,11 @@ func mapItemOut(item *ent.Item) ItemOut { fields = mapFields(item.Edges.Fields) } + var children []ItemSummary + if item.Edges.Children != nil { + children = mapEach(item.Edges.Children, mapItemSummary) + } + var parent *ItemSummary if item.Edges.Parent != nil { v := mapItemSummary(item.Edges.Parent) @@ -273,12 +261,7 @@ func mapItemOut(item *ent.Item) ItemOut { Notes: item.Notes, Attachments: attachments, Fields: fields, - } -} - -func (e *ItemsRepository) publishMutationEvent(GID uuid.UUID) { - if e.bus != nil { - e.bus.Publish(eventbus.EventItemMutation, eventbus.GroupMutationEvent{GID: GID}) + Children: children, } } @@ -290,6 +273,7 @@ func (e *ItemsRepository) getOne(ctx context.Context, where ...predicate.Item) ( WithLabel(). WithLocation(). WithGroup(). + WithChildren(). WithParent(). WithAttachments(func(aq *ent.AttachmentQuery) { aq.WithDocument() @@ -341,9 +325,6 @@ func (e *ItemsRepository) QueryByGroup(ctx context.Context, gid uuid.UUID, q Ite item.Or( item.NameContainsFold(q.Search), item.DescriptionContainsFold(q.Search), - item.SerialNumberContainsFold(q.Search), - item.ModelNumberContainsFold(q.Search), - item.ManufacturerContainsFold(q.Search), item.NotesContainsFold(q.Search), ), ) @@ -393,10 +374,6 @@ func (e *ItemsRepository) QueryByGroup(ctx context.Context, gid uuid.UUID, q Ite andPredicates = append(andPredicates, item.Or(fieldPredicates...)) } - - if len(q.ParentItemIDs) > 0 { - andPredicates = append(andPredicates, item.HasParentWith(item.IDIn(q.ParentItemIDs...))) - } } if len(andPredicates) > 0 { @@ -408,25 +385,9 @@ func (e *ItemsRepository) QueryByGroup(ctx context.Context, gid uuid.UUID, q Ite return PaginationResult[ItemSummary]{}, err } - // Order - switch q.OrderBy { - case "createdAt": - qb = qb.Order(ent.Desc(item.FieldCreatedAt)) - case "updatedAt": - qb = qb.Order(ent.Desc(item.FieldUpdatedAt)) - default: // "name" - qb = qb.Order(ent.Asc(item.FieldName)) - } - - qb = qb. + qb = qb.Order(ent.Asc(item.FieldName)). WithLabel(). - WithLocation(). - WithAttachments(func(aq *ent.AttachmentQuery) { - aq.Where( - attachment.Primary(true), - ). - WithDocument() - }) + WithLocation() if q.Page != -1 || q.PageSize != -1 { qb = qb. @@ -547,18 +508,11 @@ func (e *ItemsRepository) Create(ctx context.Context, gid uuid.UUID, data ItemCr return ItemOut{}, err } - e.publishMutationEvent(gid) return e.GetOne(ctx, result.ID) } func (e *ItemsRepository) Delete(ctx context.Context, id uuid.UUID) error { - err := e.db.Item.DeleteOneID(id).Exec(ctx) - if err != nil { - return err - } - - e.publishMutationEvent(id) - return nil + return e.db.Item.DeleteOneID(id).Exec(ctx) } func (e *ItemsRepository) DeleteByGroup(ctx context.Context, gid, id uuid.UUID) error { @@ -568,11 +522,6 @@ func (e *ItemsRepository) DeleteByGroup(ctx context.Context, gid, id uuid.UUID) item.ID(id), item.HasGroupWith(group.ID(gid)), ).Exec(ctx) - if err != nil { - return err - } - - e.publishMutationEvent(gid) return err } @@ -688,7 +637,6 @@ func (e *ItemsRepository) UpdateByGroup(ctx context.Context, GID uuid.UUID, data } } - e.publishMutationEvent(GID) return e.GetOne(ctx, data.ID) } @@ -727,7 +675,6 @@ func (e *ItemsRepository) Patch(ctx context.Context, GID, ID uuid.UUID, data Ite q.SetQuantity(*data.Quantity) } - e.publishMutationEvent(GID) return q.Exec(ctx) } @@ -799,11 +746,8 @@ func (e *ItemsRepository) ZeroOutTimeFields(ctx context.Context, GID uuid.UUID) item.HasGroupWith(group.ID(GID)), item.Or( item.PurchaseTimeNotNil(), - item.PurchaseFromLT("0002-01-01"), item.SoldTimeNotNil(), - item.SoldToLT("0002-01-01"), item.WarrantyExpiresNotNil(), - item.WarrantyDetailsLT("0002-01-01"), ), ) @@ -822,36 +766,15 @@ func (e *ItemsRepository) ZeroOutTimeFields(ctx context.Context, GID uuid.UUID) updateQ := e.db.Item.Update().Where(item.ID(i.ID)) if !i.PurchaseTime.IsZero() { - switch { - case i.PurchaseTime.Year() < 100: - updateQ.ClearPurchaseTime() - default: - updateQ.SetPurchaseTime(toDateOnly(i.PurchaseTime)) - } - } else { - updateQ.ClearPurchaseTime() + updateQ.SetPurchaseTime(toDateOnly(i.PurchaseTime)) } if !i.SoldTime.IsZero() { - switch { - case i.SoldTime.Year() < 100: - updateQ.ClearSoldTime() - default: - updateQ.SetSoldTime(toDateOnly(i.SoldTime)) - } - } else { - updateQ.ClearSoldTime() + updateQ.SetSoldTime(toDateOnly(i.SoldTime)) } if !i.WarrantyExpires.IsZero() { - switch { - case i.WarrantyExpires.Year() < 100: - updateQ.ClearWarrantyExpires() - default: - updateQ.SetWarrantyExpires(toDateOnly(i.WarrantyExpires)) - } - } else { - updateQ.ClearWarrantyExpires() + updateQ.SetWarrantyExpires(toDateOnly(i.WarrantyExpires)) } _, err = updateQ.Save(ctx) @@ -864,51 +787,3 @@ func (e *ItemsRepository) ZeroOutTimeFields(ctx context.Context, GID uuid.UUID) return updated, nil } - -func (e *ItemsRepository) SetPrimaryPhotos(ctx context.Context, GID uuid.UUID) (int, error) { - // All items where there is no primary photo - itemIDs, err := e.db.Item.Query(). - Where( - item.HasGroupWith(group.ID(GID)), - item.HasAttachmentsWith( - attachment.TypeEQ(attachment.TypePhoto), - attachment.Not( - attachment.And( - attachment.Primary(true), - attachment.TypeEQ(attachment.TypePhoto), - ), - ), - ), - ). - IDs(ctx) - if err != nil { - return -1, err - } - - updated := 0 - for _, id := range itemIDs { - // Find the first photo attachment - a, err := e.db.Attachment.Query(). - Where( - attachment.HasItemWith(item.ID(id)), - attachment.TypeEQ(attachment.TypePhoto), - attachment.Primary(false), - ). - First(ctx) - if err != nil { - return updated, err - } - - // Set it as primary - _, err = e.db.Attachment.UpdateOne(a). - SetPrimary(true). - Save(ctx) - if err != nil { - return updated, err - } - - updated++ - } - - return updated, nil -} diff --git a/backend/internal/data/repo/repo_items_test.go b/backend/internal/data/repo/repo_items_test.go index 9d60596..ac2814d 100644 --- a/backend/internal/data/repo/repo_items_test.go +++ b/backend/internal/data/repo/repo_items_test.go @@ -22,7 +22,7 @@ func useItems(t *testing.T, len int) []ItemOut { t.Helper() location, err := tRepos.Locations.Create(context.Background(), tGroup.ID, locationFactory()) - require.NoError(t, err) + assert.NoError(t, err) items := make([]ItemOut, len) for i := 0; i < len; i++ { @@ -30,7 +30,7 @@ func useItems(t *testing.T, len int) []ItemOut { itm.LocationID = location.ID item, err := tRepos.Items.Create(context.Background(), tGroup.ID, itm) - require.NoError(t, err) + assert.NoError(t, err) items[i] = item } @@ -39,7 +39,7 @@ func useItems(t *testing.T, len int) []ItemOut { _ = tRepos.Items.Delete(context.Background(), item.ID) } - _ = tRepos.Locations.delete(context.Background(), location.ID) + _ = tRepos.Locations.Delete(context.Background(), location.ID) }) return items @@ -61,22 +61,23 @@ func TestItemsRepository_RecursiveRelationships(t *testing.T) { // Append Parent ID _, err := tRepos.Items.UpdateByGroup(context.Background(), tGroup.ID, update) - require.NoError(t, err) + assert.NoError(t, err) // Check Parent ID updated, err := tRepos.Items.GetOne(context.Background(), child.ID) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, parent.ID, updated.Parent.ID) // Remove Parent ID update.ParentID = uuid.Nil _, err = tRepos.Items.UpdateByGroup(context.Background(), tGroup.ID, update) - require.NoError(t, err) + assert.NoError(t, err) // Check Parent ID updated, err = tRepos.Items.GetOne(context.Background(), child.ID) - require.NoError(t, err) + assert.NoError(t, err) assert.Nil(t, updated.Parent) + } } @@ -85,7 +86,7 @@ func TestItemsRepository_GetOne(t *testing.T) { for _, item := range entity { result, err := tRepos.Items.GetOne(context.Background(), item.ID) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, item.ID, result.ID) } } @@ -95,9 +96,9 @@ func TestItemsRepository_GetAll(t *testing.T) { expected := useItems(t, length) results, err := tRepos.Items.GetAll(context.Background(), tGroup.ID) - require.NoError(t, err) + assert.NoError(t, err) - assert.Len(t, results, length) + assert.Equal(t, length, len(results)) for _, item := range results { for _, expectedItem := range expected { @@ -112,23 +113,23 @@ func TestItemsRepository_GetAll(t *testing.T) { func TestItemsRepository_Create(t *testing.T) { location, err := tRepos.Locations.Create(context.Background(), tGroup.ID, locationFactory()) - require.NoError(t, err) + assert.NoError(t, err) itm := itemFactory() itm.LocationID = location.ID result, err := tRepos.Items.Create(context.Background(), tGroup.ID, itm) - require.NoError(t, err) + assert.NoError(t, err) assert.NotEmpty(t, result.ID) // Cleanup - Also deletes item - err = tRepos.Locations.delete(context.Background(), location.ID) - require.NoError(t, err) + err = tRepos.Locations.Delete(context.Background(), location.ID) + assert.NoError(t, err) } func TestItemsRepository_Create_Location(t *testing.T) { location, err := tRepos.Locations.Create(context.Background(), tGroup.ID, locationFactory()) - require.NoError(t, err) + assert.NoError(t, err) assert.NotEmpty(t, location.ID) item := itemFactory() @@ -136,18 +137,18 @@ func TestItemsRepository_Create_Location(t *testing.T) { // Create Resource result, err := tRepos.Items.Create(context.Background(), tGroup.ID, item) - require.NoError(t, err) + assert.NoError(t, err) assert.NotEmpty(t, result.ID) // Get Resource foundItem, err := tRepos.Items.GetOne(context.Background(), result.ID) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, result.ID, foundItem.ID) assert.Equal(t, location.ID, foundItem.Location.ID) // Cleanup - Also deletes item - err = tRepos.Locations.delete(context.Background(), location.ID) - require.NoError(t, err) + err = tRepos.Locations.Delete(context.Background(), location.ID) + assert.NoError(t, err) } func TestItemsRepository_Delete(t *testing.T) { @@ -155,11 +156,11 @@ func TestItemsRepository_Delete(t *testing.T) { for _, item := range entities { err := tRepos.Items.Delete(context.Background(), item.ID) - require.NoError(t, err) + assert.NoError(t, err) } results, err := tRepos.Items.GetAll(context.Background(), tGroup.ID) - require.NoError(t, err) + assert.NoError(t, err) assert.Empty(t, results) } @@ -212,7 +213,7 @@ func TestItemsRepository_Update_Labels(t *testing.T) { } updated, err := tRepos.Items.UpdateByGroup(context.Background(), tGroup.ID, updateData) - require.NoError(t, err) + assert.NoError(t, err) assert.Len(t, tt.want, len(updated.Labels)) for _, label := range updated.Labels { @@ -249,10 +250,10 @@ func TestItemsRepository_Update(t *testing.T) { } updatedEntity, err := tRepos.Items.UpdateByGroup(context.Background(), tGroup.ID, updateData) - require.NoError(t, err) + assert.NoError(t, err) got, err := tRepos.Items.GetOne(context.Background(), updatedEntity.ID) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, updateData.ID, got.ID) assert.Equal(t, updateData.Name, got.Name) @@ -262,10 +263,10 @@ func TestItemsRepository_Update(t *testing.T) { assert.Equal(t, updateData.Manufacturer, got.Manufacturer) // assert.Equal(t, updateData.PurchaseTime, got.PurchaseTime) assert.Equal(t, updateData.PurchaseFrom, got.PurchaseFrom) - assert.InDelta(t, updateData.PurchasePrice, got.PurchasePrice, 0.01) + assert.Equal(t, updateData.PurchasePrice, got.PurchasePrice) // assert.Equal(t, updateData.SoldTime, got.SoldTime) assert.Equal(t, updateData.SoldTo, got.SoldTo) - assert.InDelta(t, updateData.SoldPrice, got.SoldPrice, 0.01) + assert.Equal(t, updateData.SoldPrice, got.SoldPrice) assert.Equal(t, updateData.SoldNotes, got.SoldNotes) assert.Equal(t, updateData.Notes, got.Notes) // assert.Equal(t, updateData.WarrantyExpires, got.WarrantyExpires) @@ -274,15 +275,15 @@ func TestItemsRepository_Update(t *testing.T) { } func TestItemRepository_GetAllCustomFields(t *testing.T) { - const FieldsCount = 5 + const FIELDS_COUNT = 5 entity := useItems(t, 1)[0] - fields := make([]ItemField, FieldsCount) - names := make([]string, FieldsCount) - values := make([]string, FieldsCount) + fields := make([]ItemField, FIELDS_COUNT) + names := make([]string, FIELDS_COUNT) + values := make([]string, FIELDS_COUNT) - for i := 0; i < FieldsCount; i++ { + for i := 0; i < FIELDS_COUNT; i++ { name := fk.Str(10) fields[i] = ItemField{ Name: name, @@ -305,7 +306,7 @@ func TestItemRepository_GetAllCustomFields(t *testing.T) { // Test getting all fields { results, err := tRepos.Items.GetAllCustomFieldNames(context.Background(), tGroup.ID) - require.NoError(t, err) + assert.NoError(t, err) assert.ElementsMatch(t, names, results) } @@ -313,7 +314,7 @@ func TestItemRepository_GetAllCustomFields(t *testing.T) { { results, err := tRepos.Items.GetAllCustomFieldValues(context.Background(), tUser.GroupID, names[0]) - require.NoError(t, err) + assert.NoError(t, err) assert.ElementsMatch(t, values[:1], results) } } diff --git a/backend/internal/data/repo/repo_labels.go b/backend/internal/data/repo/repo_labels.go index 2358f9c..ee62fd8 100644 --- a/backend/internal/data/repo/repo_labels.go +++ b/backend/internal/data/repo/repo_labels.go @@ -5,28 +5,26 @@ import ( "time" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus" "github.com/hay-kot/homebox/backend/internal/data/ent" "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" "github.com/hay-kot/homebox/backend/internal/data/ent/label" "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) type LabelRepository struct { - db *ent.Client - bus *eventbus.EventBus + db *ent.Client } - type ( LabelCreate struct { - Name string `json:"name" validate:"required,min=1,max=255"` + Name string `json:"name" validate:"required,min=1,max=255"` Description string `json:"description" validate:"max=255"` Color string `json:"color"` } LabelUpdate struct { ID uuid.UUID `json:"id"` - Name string `json:"name" validate:"required,min=1,max=255"` + Name string `json:"name" validate:"required,min=1,max=255"` Description string `json:"description" validate:"max=255"` Color string `json:"color"` } @@ -41,6 +39,7 @@ type ( LabelOut struct { LabelSummary + Items []ItemSummary `json:"items"` } ) @@ -62,12 +61,7 @@ var ( func mapLabelOut(label *ent.Label) LabelOut { return LabelOut{ LabelSummary: mapLabelSummary(label), - } -} - -func (r *LabelRepository) publishMutationEvent(GID uuid.UUID) { - if r.bus != nil { - r.bus.Publish(eventbus.EventLabelMutation, eventbus.GroupMutationEvent{GID: GID}) + Items: mapEach(label.Edges.Items, mapItemSummary), } } @@ -75,6 +69,9 @@ func (r *LabelRepository) getOne(ctx context.Context, where ...predicate.Label) return mapLabelOutErr(r.db.Label.Query(). Where(where...). WithGroup(). + WithItems(func(iq *ent.ItemQuery) { + iq.Where(item.Archived(false)) + }). Only(ctx), ) } @@ -87,28 +84,27 @@ func (r *LabelRepository) GetOneByGroup(ctx context.Context, gid, ld uuid.UUID) return r.getOne(ctx, label.ID(ld), label.HasGroupWith(group.ID(gid))) } -func (r *LabelRepository) GetAll(ctx context.Context, groupID uuid.UUID) ([]LabelSummary, error) { +func (r *LabelRepository) GetAll(ctx context.Context, groupId uuid.UUID) ([]LabelSummary, error) { return mapLabelsOut(r.db.Label.Query(). - Where(label.HasGroupWith(group.ID(groupID))). + Where(label.HasGroupWith(group.ID(groupId))). Order(ent.Asc(label.FieldName)). WithGroup(). All(ctx), ) } -func (r *LabelRepository) Create(ctx context.Context, groupID uuid.UUID, data LabelCreate) (LabelOut, error) { +func (r *LabelRepository) Create(ctx context.Context, groupdId uuid.UUID, data LabelCreate) (LabelOut, error) { label, err := r.db.Label.Create(). SetName(data.Name). SetDescription(data.Description). SetColor(data.Color). - SetGroupID(groupID). + SetGroupID(groupdId). Save(ctx) if err != nil { return LabelOut{}, err } - label.Edges.Group = &ent.Group{ID: groupID} // bootstrap group ID - r.publishMutationEvent(groupID) + label.Edges.Group = &ent.Group{ID: groupdId} // bootstrap group ID return mapLabelOut(label), err } @@ -125,19 +121,25 @@ func (r *LabelRepository) update(ctx context.Context, data LabelUpdate, where .. Save(ctx) } +func (r *LabelRepository) Update(ctx context.Context, data LabelUpdate) (LabelOut, error) { + _, err := r.update(ctx, data, label.ID(data.ID)) + if err != nil { + return LabelOut{}, err + } + + return r.GetOne(ctx, data.ID) +} + func (r *LabelRepository) UpdateByGroup(ctx context.Context, GID uuid.UUID, data LabelUpdate) (LabelOut, error) { _, err := r.update(ctx, data, label.ID(data.ID), label.HasGroupWith(group.ID(GID))) if err != nil { return LabelOut{}, err } - r.publishMutationEvent(GID) return r.GetOne(ctx, data.ID) } -// delete removes the label from the database. This should only be used when -// the label's ownership is already confirmed/validated. -func (r *LabelRepository) delete(ctx context.Context, id uuid.UUID) error { +func (r *LabelRepository) Delete(ctx context.Context, id uuid.UUID) error { return r.db.Label.DeleteOneID(id).Exec(ctx) } @@ -147,11 +149,6 @@ func (r *LabelRepository) DeleteByGroup(ctx context.Context, gid, id uuid.UUID) label.ID(id), label.HasGroupWith(group.ID(gid)), ).Exec(ctx) - if err != nil { - return err - } - r.publishMutationEvent(gid) - - return nil + return err } diff --git a/backend/internal/data/repo/repo_labels_test.go b/backend/internal/data/repo/repo_labels_test.go index 8b1d66f..691b915 100644 --- a/backend/internal/data/repo/repo_labels_test.go +++ b/backend/internal/data/repo/repo_labels_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func labelFactory() LabelCreate { @@ -23,13 +22,13 @@ func useLabels(t *testing.T, len int) []LabelOut { itm := labelFactory() item, err := tRepos.Labels.Create(context.Background(), tGroup.ID, itm) - require.NoError(t, err) + assert.NoError(t, err) labels[i] = item } t.Cleanup(func() { for _, item := range labels { - _ = tRepos.Labels.delete(context.Background(), item.ID) + _ = tRepos.Labels.Delete(context.Background(), item.ID) } }) @@ -42,7 +41,7 @@ func TestLabelRepository_Get(t *testing.T) { // Get by ID foundLoc, err := tRepos.Labels.GetOne(context.Background(), label.ID) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, label.ID, foundLoc.ID) } @@ -50,26 +49,26 @@ func TestLabelRepositoryGetAll(t *testing.T) { useLabels(t, 10) all, err := tRepos.Labels.GetAll(context.Background(), tGroup.ID) - require.NoError(t, err) + assert.NoError(t, err) assert.Len(t, all, 10) } func TestLabelRepository_Create(t *testing.T) { loc, err := tRepos.Labels.Create(context.Background(), tGroup.ID, labelFactory()) - require.NoError(t, err) + assert.NoError(t, err) // Get by ID foundLoc, err := tRepos.Labels.GetOne(context.Background(), loc.ID) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, loc.ID, foundLoc.ID) - err = tRepos.Labels.delete(context.Background(), loc.ID) - require.NoError(t, err) + err = tRepos.Labels.Delete(context.Background(), loc.ID) + assert.NoError(t, err) } func TestLabelRepository_Update(t *testing.T) { loc, err := tRepos.Labels.Create(context.Background(), tGroup.ID, labelFactory()) - require.NoError(t, err) + assert.NoError(t, err) updateData := LabelUpdate{ ID: loc.ID, @@ -77,27 +76,27 @@ func TestLabelRepository_Update(t *testing.T) { Description: fk.Str(100), } - update, err := tRepos.Labels.UpdateByGroup(context.Background(), tGroup.ID, updateData) - require.NoError(t, err) + update, err := tRepos.Labels.Update(context.Background(), updateData) + assert.NoError(t, err) foundLoc, err := tRepos.Labels.GetOne(context.Background(), loc.ID) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, update.ID, foundLoc.ID) assert.Equal(t, update.Name, foundLoc.Name) assert.Equal(t, update.Description, foundLoc.Description) - err = tRepos.Labels.delete(context.Background(), loc.ID) - require.NoError(t, err) + err = tRepos.Labels.Delete(context.Background(), loc.ID) + assert.NoError(t, err) } func TestLabelRepository_Delete(t *testing.T) { loc, err := tRepos.Labels.Create(context.Background(), tGroup.ID, labelFactory()) - require.NoError(t, err) + assert.NoError(t, err) - err = tRepos.Labels.delete(context.Background(), loc.ID) - require.NoError(t, err) + err = tRepos.Labels.Delete(context.Background(), loc.ID) + assert.NoError(t, err) _, err = tRepos.Labels.GetOne(context.Background(), loc.ID) - require.Error(t, err) + assert.Error(t, err) } diff --git a/backend/internal/data/repo/repo_locations.go b/backend/internal/data/repo/repo_locations.go index fd98fd7..e65a983 100644 --- a/backend/internal/data/repo/repo_locations.go +++ b/backend/internal/data/repo/repo_locations.go @@ -6,27 +6,26 @@ import ( "time" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus" "github.com/hay-kot/homebox/backend/internal/data/ent" "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" "github.com/hay-kot/homebox/backend/internal/data/ent/location" "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) type LocationRepository struct { - db *ent.Client - bus *eventbus.EventBus + db *ent.Client } type ( LocationCreate struct { Name string `json:"name"` - ParentID uuid.UUID `json:"parentId" extensions:"x-nullable"` + ParentID uuid.UUID `json:"parentId" extensions:"x-nullable"` Description string `json:"description"` } LocationUpdate struct { - ParentID uuid.UUID `json:"parentId" extensions:"x-nullable"` + ParentID uuid.UUID `json:"parentId" extensions:"x-nullable"` ID uuid.UUID `json:"id"` Name string `json:"name"` Description string `json:"description"` @@ -48,6 +47,7 @@ type ( LocationOut struct { Parent *LocationSummary `json:"parent,omitempty"` LocationSummary + Items []ItemSummary `json:"items"` Children []LocationSummary `json:"children"` } ) @@ -86,12 +86,7 @@ func mapLocationOut(location *ent.Location) LocationOut { CreatedAt: location.CreatedAt, UpdatedAt: location.UpdatedAt, }, - } -} - -func (r *LocationRepository) publishMutationEvent(GID uuid.UUID) { - if r.bus != nil { - r.bus.Publish(eventbus.EventLocationMutation, eventbus.GroupMutationEvent{GID: GID}) + Items: mapEach(location.Edges.Items, mapItemSummary), } } @@ -99,7 +94,7 @@ type LocationQuery struct { FilterChildren bool `json:"filterChildren" schema:"filterChildren"` } -// GetAll returns all locations with item count field populated +// GetALlWithCount returns all locations with item count field populated func (r *LocationRepository) GetAll(ctx context.Context, GID uuid.UUID, filter LocationQuery) ([]LocationOutCount, error) { query := `--sql SELECT @@ -135,7 +130,6 @@ func (r *LocationRepository) GetAll(ctx context.Context, GID uuid.UUID, filter L if err != nil { return nil, err } - defer func() { _ = rows.Close() }() list := []LocationOutCount{} for rows.Next() { @@ -162,6 +156,11 @@ func (r *LocationRepository) getOne(ctx context.Context, where ...predicate.Loca return mapLocationOutErr(r.db.Location.Query(). Where(where...). WithGroup(). + WithItems(func(iq *ent.ItemQuery) { + iq.Where(item.Archived(false)). + Order(ent.Asc(item.FieldName)). + WithLabel() + }). WithParent(). WithChildren(). Only(ctx)) @@ -191,7 +190,6 @@ func (r *LocationRepository) Create(ctx context.Context, GID uuid.UUID, data Loc } location.Edges.Group = &ent.Group{ID: GID} // bootstrap group ID - r.publishMutationEvent(GID) return mapLocationOut(location), nil } @@ -215,29 +213,20 @@ func (r *LocationRepository) update(ctx context.Context, data LocationUpdate, wh return r.Get(ctx, data.ID) } -func (r *LocationRepository) UpdateByGroup(ctx context.Context, GID, ID uuid.UUID, data LocationUpdate) (LocationOut, error) { - v, err := r.update(ctx, data, location.ID(ID), location.HasGroupWith(group.ID(GID))) - if err != nil { - return LocationOut{}, err - } - - r.publishMutationEvent(GID) - return v, err +func (r *LocationRepository) Update(ctx context.Context, data LocationUpdate) (LocationOut, error) { + return r.update(ctx, data, location.ID(data.ID)) } -// delete should only be used after checking that the location is owned by the -// group. Otherwise, use DeleteByGroup -func (r *LocationRepository) delete(ctx context.Context, ID uuid.UUID) error { +func (r *LocationRepository) UpdateByGroup(ctx context.Context, GID, ID uuid.UUID, data LocationUpdate) (LocationOut, error) { + return r.update(ctx, data, location.ID(ID), location.HasGroupWith(group.ID(GID))) +} + +func (r *LocationRepository) Delete(ctx context.Context, ID uuid.UUID) error { return r.db.Location.DeleteOneID(ID).Exec(ctx) } func (r *LocationRepository) DeleteByGroup(ctx context.Context, GID, ID uuid.UUID) error { _, err := r.db.Location.Delete().Where(location.ID(ID), location.HasGroupWith(group.ID(GID))).Exec(ctx) - if err != nil { - return err - } - r.publishMutationEvent(GID) - return err } @@ -260,67 +249,7 @@ type TreeQuery struct { WithItems bool `json:"withItems" schema:"withItems"` } -type ItemType string - -const ( - ItemTypeLocation ItemType = "location" - ItemTypeItem ItemType = "item" -) - -type ItemPath struct { - Type ItemType `json:"type"` - ID uuid.UUID `json:"id"` - Name string `json:"name"` -} - -func (r *LocationRepository) PathForLoc(ctx context.Context, GID, locID uuid.UUID) ([]ItemPath, error) { - query := `WITH RECURSIVE location_path AS ( - SELECT id, name, location_children - FROM locations - WHERE id = ? -- Replace ? with the ID of the item's location - AND group_locations = ? -- Replace ? with the ID of the group - - UNION ALL - - SELECT loc.id, loc.name, loc.location_children - FROM locations loc - JOIN location_path lp ON loc.id = lp.location_children - ) - - SELECT id, name - FROM location_path` - - rows, err := r.db.Sql().QueryContext(ctx, query, locID, GID) - if err != nil { - return nil, err - } - defer func() { _ = rows.Close() }() - - var locations []ItemPath - - for rows.Next() { - var location ItemPath - location.Type = ItemTypeLocation - if err := rows.Scan(&location.ID, &location.Name); err != nil { - return nil, err - } - locations = append(locations, location) - } - - if err := rows.Err(); err != nil { - return nil, err - } - - // Reverse the order of the locations so that the root is last - for i := len(locations)/2 - 1; i >= 0; i-- { - opp := len(locations) - 1 - i - locations[i], locations[opp] = locations[opp], locations[i] - } - - return locations, nil -} - -func (r *LocationRepository) Tree(ctx context.Context, GID uuid.UUID, tq TreeQuery) ([]TreeItem, error) { +func (lr *LocationRepository) Tree(ctx context.Context, GID uuid.UUID, tq TreeQuery) ([]TreeItem, error) { query := ` WITH recursive location_tree(id, NAME, parent_id, level, node_type) AS ( @@ -402,11 +331,11 @@ func (r *LocationRepository) Tree(ctx context.Context, GID uuid.UUID, tq TreeQue query = strings.ReplaceAll(query, "{{ WITH_ITEMS_FROM }}", "") } - rows, err := r.db.Sql().QueryContext(ctx, query, GID) + rows, err := lr.db.Sql().QueryContext(ctx, query, GID) if err != nil { return nil, err } - defer func() { _ = rows.Close() }() + defer rows.Close() var locations []FlatTreeItem for rows.Next() { diff --git a/backend/internal/data/repo/repo_locations_test.go b/backend/internal/data/repo/repo_locations_test.go index e8b353c..644828d 100644 --- a/backend/internal/data/repo/repo_locations_test.go +++ b/backend/internal/data/repo/repo_locations_test.go @@ -8,7 +8,6 @@ import ( "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/data/ent" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func locationFactory() LocationCreate { @@ -25,13 +24,13 @@ func useLocations(t *testing.T, len int) []LocationOut { for i := 0; i < len; i++ { loc, err := tRepos.Locations.Create(context.Background(), tGroup.ID, locationFactory()) - require.NoError(t, err) + assert.NoError(t, err) out[i] = loc } t.Cleanup(func() { for _, loc := range out { - err := tRepos.Locations.delete(context.Background(), loc.ID) + err := tRepos.Locations.Delete(context.Background(), loc.ID) if err != nil { assert.True(t, ent.IsNotFound(err)) } @@ -43,15 +42,15 @@ func useLocations(t *testing.T, len int) []LocationOut { func TestLocationRepository_Get(t *testing.T) { loc, err := tRepos.Locations.Create(context.Background(), tGroup.ID, locationFactory()) - require.NoError(t, err) + assert.NoError(t, err) // Get by ID foundLoc, err := tRepos.Locations.Get(context.Background(), loc.ID) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, loc.ID, foundLoc.ID) - err = tRepos.Locations.delete(context.Background(), loc.ID) - require.NoError(t, err) + err = tRepos.Locations.Delete(context.Background(), loc.ID) + assert.NoError(t, err) } func TestLocationRepositoryGetAllWithCount(t *testing.T) { @@ -64,10 +63,10 @@ func TestLocationRepositoryGetAllWithCount(t *testing.T) { LocationID: result.ID, }) - require.NoError(t, err) + assert.NoError(t, err) results, err := tRepos.Locations.GetAll(context.Background(), tGroup.ID, LocationQuery{}) - require.NoError(t, err) + assert.NoError(t, err) for _, loc := range results { if loc.ID == result.ID { @@ -81,11 +80,11 @@ func TestLocationRepository_Create(t *testing.T) { // Get by ID foundLoc, err := tRepos.Locations.Get(context.Background(), loc.ID) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, loc.ID, foundLoc.ID) - err = tRepos.Locations.delete(context.Background(), loc.ID) - require.NoError(t, err) + err = tRepos.Locations.Delete(context.Background(), loc.ID) + assert.NoError(t, err) } func TestLocationRepository_Update(t *testing.T) { @@ -97,28 +96,28 @@ func TestLocationRepository_Update(t *testing.T) { Description: fk.Str(100), } - update, err := tRepos.Locations.UpdateByGroup(context.Background(), tGroup.ID, updateData.ID, updateData) - require.NoError(t, err) + update, err := tRepos.Locations.Update(context.Background(), updateData) + assert.NoError(t, err) foundLoc, err := tRepos.Locations.Get(context.Background(), loc.ID) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, update.ID, foundLoc.ID) assert.Equal(t, update.Name, foundLoc.Name) assert.Equal(t, update.Description, foundLoc.Description) - err = tRepos.Locations.delete(context.Background(), loc.ID) - require.NoError(t, err) + err = tRepos.Locations.Delete(context.Background(), loc.ID) + assert.NoError(t, err) } func TestLocationRepository_Delete(t *testing.T) { loc := useLocations(t, 1)[0] - err := tRepos.Locations.delete(context.Background(), loc.ID) - require.NoError(t, err) + err := tRepos.Locations.Delete(context.Background(), loc.ID) + assert.NoError(t, err) _, err = tRepos.Locations.Get(context.Background(), loc.ID) - require.Error(t, err) + assert.Error(t, err) } func TestItemRepository_TreeQuery(t *testing.T) { @@ -131,50 +130,22 @@ func TestItemRepository_TreeQuery(t *testing.T) { Name: locs[0].Name, Description: locs[0].Description, }) - require.NoError(t, err) + assert.NoError(t, err) locations, err := tRepos.Locations.Tree(context.Background(), tGroup.ID, TreeQuery{WithItems: true}) - require.NoError(t, err) + assert.NoError(t, err) - assert.Len(t, locations, 2) + assert.Equal(t, 2, len(locations)) // Check roots for _, loc := range locations { if loc.ID == locs[1].ID { - assert.Len(t, loc.Children, 1) + assert.Equal(t, 1, len(loc.Children)) } } } -func TestLocationRepository_PathForLoc(t *testing.T) { - locs := useLocations(t, 3) - - // Set relations 3 -> 2 -> 1 - for i := 0; i < 2; i++ { - _, err := tRepos.Locations.UpdateByGroup(context.Background(), tGroup.ID, locs[i].ID, LocationUpdate{ - ID: locs[i].ID, - ParentID: locs[i+1].ID, - Name: locs[i].Name, - Description: locs[i].Description, - }) - require.NoError(t, err) - } - - last := locs[0] - - path, err := tRepos.Locations.PathForLoc(context.Background(), tGroup.ID, last.ID) - - require.NoError(t, err) - assert.Len(t, path, 3) - - // Check path and order - for i, loc := range path { - assert.Equal(t, locs[2-i].ID, loc.ID) - assert.Equal(t, locs[2-i].Name, loc.Name) - } -} - func TestConvertLocationsToTree(t *testing.T) { uuid1, uuid2, uuid3, uuid4 := uuid.New(), uuid.New(), uuid.New(), uuid.New() diff --git a/backend/internal/data/repo/repo_maintenance_entry.go b/backend/internal/data/repo/repo_maintenance_entry.go index 2714bbd..b699d09 100644 --- a/backend/internal/data/repo/repo_maintenance_entry.go +++ b/backend/internal/data/repo/repo_maintenance_entry.go @@ -23,7 +23,7 @@ type MaintenanceEntryRepository struct { type MaintenanceEntryCreate struct { CompletedDate types.Date `json:"completedDate"` ScheduledDate types.Date `json:"scheduledDate"` - Name string `json:"name" validate:"required"` + Name string `json:"name" validate:"required"` Description string `json:"description"` Cost float64 `json:"cost,string"` } @@ -152,6 +152,7 @@ func (r *MaintenanceEntryRepository) GetLog(ctx context.Context, groupID, itemID maintenanceentry.DateNotNil(), maintenanceentry.DateNEQ(time.Time{}), )) + } else if query.Scheduled { q = q.Where(maintenanceentry.And( maintenanceentry.Or( diff --git a/backend/internal/data/repo/repo_maintenance_entry_test.go b/backend/internal/data/repo/repo_maintenance_entry_test.go index 0fa288c..a82768c 100644 --- a/backend/internal/data/repo/repo_maintenance_entry_test.go +++ b/backend/internal/data/repo/repo_maintenance_entry_test.go @@ -7,7 +7,6 @@ import ( "github.com/hay-kot/homebox/backend/internal/data/types" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) // get the previous month from the current month, accounts for errors when run @@ -68,7 +67,7 @@ func TestMaintenanceEntryRepository_GetLog(t *testing.T) { } assert.Equal(t, item.ID, log.ItemID) - assert.Len(t, log.Entries, 10) + assert.Equal(t, 10, len(log.Entries)) // Calculate the average cost var total float64 @@ -77,11 +76,11 @@ func TestMaintenanceEntryRepository_GetLog(t *testing.T) { total += entry.Cost } - assert.InDelta(t, total, log.CostTotal, .001, "total cost should be equal to the sum of all entries") - assert.InDelta(t, total/2, log.CostAverage, 001, "average cost should be the average of the two months") + assert.Equal(t, total, log.CostTotal, "total cost should be equal to the sum of all entries") + assert.Equal(t, total/2, log.CostAverage, "average cost should be the average of the two months") for _, entry := range log.Entries { err := tRepos.MaintEntry.Delete(context.Background(), entry.ID) - require.NoError(t, err) + assert.NoError(t, err) } } diff --git a/backend/internal/data/repo/repo_notifier.go b/backend/internal/data/repo/repo_notifier.go index f31be4b..2ea27eb 100644 --- a/backend/internal/data/repo/repo_notifier.go +++ b/backend/internal/data/repo/repo_notifier.go @@ -35,15 +35,15 @@ func NewNotifierRepository(db *ent.Client) *NotifierRepository { type ( NotifierCreate struct { - Name string `json:"name" validate:"required,min=1,max=255"` + Name string `json:"name" validate:"required,min=1,max=255"` IsActive bool `json:"isActive"` - URL string `json:"url" validate:"required,shoutrrr"` + URL string `json:"url" validate:"required,shoutrrr"` } NotifierUpdate struct { - Name string `json:"name" validate:"required,min=1,max=255"` + Name string `json:"name" validate:"required,min=1,max=255"` IsActive bool `json:"isActive"` - URL *string `json:"url" validate:"omitempty,shoutrrr" extensions:"x-nullable"` + URL *string `json:"url" validate:"omitempty,shoutrrr" extensions:"x-nullable" ` } NotifierOut struct { diff --git a/backend/internal/data/repo/repo_tokens.go b/backend/internal/data/repo/repo_tokens.go index 42843e0..7ba982e 100644 --- a/backend/internal/data/repo/repo_tokens.go +++ b/backend/internal/data/repo/repo_tokens.go @@ -71,7 +71,7 @@ func (r *TokenRepository) GetRoles(ctx context.Context, token string) (*set.Set[ return &roleSet, nil } -// CreateToken Creates a token for a user +// Creates a token for a user func (r *TokenRepository) CreateToken(ctx context.Context, createToken UserAuthTokenCreate, roles ...authroles.Role) (UserAuthToken, error) { dbToken, err := r.db.AuthTokens.Create(). SetToken(createToken.TokenHash). diff --git a/backend/internal/data/repo/repo_tokens_test.go b/backend/internal/data/repo/repo_tokens_test.go index a0b4375..e066911 100644 --- a/backend/internal/data/repo/repo_tokens_test.go +++ b/backend/internal/data/repo/repo_tokens_test.go @@ -7,15 +7,15 @@ import ( "github.com/hay-kot/homebox/backend/pkgs/hasher" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestAuthTokenRepo_CreateToken(t *testing.T) { + asrt := assert.New(t) ctx := context.Background() user := userFactory() userOut, err := tRepos.Users.Create(ctx, user) - require.NoError(t, err) + asrt.NoError(err) expiresAt := time.Now().Add(time.Hour) @@ -27,22 +27,23 @@ func TestAuthTokenRepo_CreateToken(t *testing.T) { UserID: userOut.ID, }) - require.NoError(t, err) - assert.Equal(t, userOut.ID, token.UserID) - assert.Equal(t, expiresAt, token.ExpiresAt) + asrt.NoError(err) + asrt.Equal(userOut.ID, token.UserID) + asrt.Equal(expiresAt, token.ExpiresAt) // Cleanup - require.NoError(t, tRepos.Users.Delete(ctx, userOut.ID)) + asrt.NoError(tRepos.Users.Delete(ctx, userOut.ID)) _, err = tRepos.AuthTokens.DeleteAll(ctx) - require.NoError(t, err) + asrt.NoError(err) } func TestAuthTokenRepo_DeleteToken(t *testing.T) { + asrt := assert.New(t) ctx := context.Background() user := userFactory() userOut, err := tRepos.Users.Create(ctx, user) - require.NoError(t, err) + asrt.NoError(err) expiresAt := time.Now().Add(time.Hour) @@ -53,14 +54,15 @@ func TestAuthTokenRepo_DeleteToken(t *testing.T) { ExpiresAt: expiresAt, UserID: userOut.ID, }) - require.NoError(t, err) + asrt.NoError(err) // Delete token err = tRepos.AuthTokens.DeleteToken(ctx, []byte(generatedToken.Raw)) - require.NoError(t, err) + asrt.NoError(err) } func TestAuthTokenRepo_GetUserByToken(t *testing.T) { + assert := assert.New(t) ctx := context.Background() user := userFactory() @@ -75,23 +77,24 @@ func TestAuthTokenRepo_GetUserByToken(t *testing.T) { UserID: userOut.ID, }) - require.NoError(t, err) + assert.NoError(err) // Get User from token foundUser, err := tRepos.AuthTokens.GetUserFromToken(ctx, token.TokenHash) - require.NoError(t, err) - assert.Equal(t, userOut.ID, foundUser.ID) - assert.Equal(t, userOut.Name, foundUser.Name) - assert.Equal(t, userOut.Email, foundUser.Email) + assert.NoError(err) + assert.Equal(userOut.ID, foundUser.ID) + assert.Equal(userOut.Name, foundUser.Name) + assert.Equal(userOut.Email, foundUser.Email) // Cleanup - require.NoError(t, tRepos.Users.Delete(ctx, userOut.ID)) + assert.NoError(tRepos.Users.Delete(ctx, userOut.ID)) _, err = tRepos.AuthTokens.DeleteAll(ctx) - require.NoError(t, err) + assert.NoError(err) } func TestAuthTokenRepo_PurgeExpiredTokens(t *testing.T) { + assert := assert.New(t) ctx := context.Background() user := userFactory() @@ -109,26 +112,27 @@ func TestAuthTokenRepo_PurgeExpiredTokens(t *testing.T) { UserID: userOut.ID, }) - require.NoError(t, err) - assert.NotNil(t, createdToken) + assert.NoError(err) + assert.NotNil(createdToken) createdTokens = append(createdTokens, createdToken) + } // Purge expired tokens tokensDeleted, err := tRepos.AuthTokens.PurgeExpiredTokens(ctx) - require.NoError(t, err) - assert.Equal(t, 5, tokensDeleted) + assert.NoError(err) + assert.Equal(5, tokensDeleted) // Check if tokens are deleted for _, token := range createdTokens { _, err := tRepos.AuthTokens.GetUserFromToken(ctx, token.TokenHash) - require.Error(t, err) + assert.Error(err) } // Cleanup - require.NoError(t, tRepos.Users.Delete(ctx, userOut.ID)) + assert.NoError(tRepos.Users.Delete(ctx, userOut.ID)) _, err = tRepos.AuthTokens.DeleteAll(ctx) - require.NoError(t, err) + assert.NoError(err) } diff --git a/backend/internal/data/repo/repo_users.go b/backend/internal/data/repo/repo_users.go index 68b1eb5..03850d6 100644 --- a/backend/internal/data/repo/repo_users.go +++ b/backend/internal/data/repo/repo_users.go @@ -60,32 +60,32 @@ func mapUserOut(user *ent.User) UserOut { } } -func (r *UserRepository) GetOneID(ctx context.Context, ID uuid.UUID) (UserOut, error) { - return mapUserOutErr(r.db.User.Query(). - Where(user.ID(ID)). +func (e *UserRepository) GetOneId(ctx context.Context, id uuid.UUID) (UserOut, error) { + return mapUserOutErr(e.db.User.Query(). + Where(user.ID(id)). WithGroup(). Only(ctx)) } -func (r *UserRepository) GetOneEmail(ctx context.Context, email string) (UserOut, error) { - return mapUserOutErr(r.db.User.Query(). +func (e *UserRepository) GetOneEmail(ctx context.Context, email string) (UserOut, error) { + return mapUserOutErr(e.db.User.Query(). Where(user.EmailEqualFold(email)). WithGroup(). Only(ctx), ) } -func (r *UserRepository) GetAll(ctx context.Context) ([]UserOut, error) { - return mapUsersOutErr(r.db.User.Query().WithGroup().All(ctx)) +func (e *UserRepository) GetAll(ctx context.Context) ([]UserOut, error) { + return mapUsersOutErr(e.db.User.Query().WithGroup().All(ctx)) } -func (r *UserRepository) Create(ctx context.Context, usr UserCreate) (UserOut, error) { +func (e *UserRepository) Create(ctx context.Context, usr UserCreate) (UserOut, error) { role := user.RoleUser if usr.IsOwner { role = user.RoleOwner } - entUser, err := r.db.User. + entUser, err := e.db.User. Create(). SetName(usr.Name). SetEmail(usr.Email). @@ -98,11 +98,11 @@ func (r *UserRepository) Create(ctx context.Context, usr UserCreate) (UserOut, e return UserOut{}, err } - return r.GetOneID(ctx, entUser.ID) + return e.GetOneId(ctx, entUser.ID) } -func (r *UserRepository) Update(ctx context.Context, ID uuid.UUID, data UserUpdate) error { - q := r.db.User.Update(). +func (e *UserRepository) Update(ctx context.Context, ID uuid.UUID, data UserUpdate) error { + q := e.db.User.Update(). Where(user.ID(ID)). SetName(data.Name). SetEmail(data.Email) @@ -111,18 +111,18 @@ func (r *UserRepository) Update(ctx context.Context, ID uuid.UUID, data UserUpda return err } -func (r *UserRepository) Delete(ctx context.Context, id uuid.UUID) error { - _, err := r.db.User.Delete().Where(user.ID(id)).Exec(ctx) +func (e *UserRepository) Delete(ctx context.Context, id uuid.UUID) error { + _, err := e.db.User.Delete().Where(user.ID(id)).Exec(ctx) return err } -func (r *UserRepository) DeleteAll(ctx context.Context) error { - _, err := r.db.User.Delete().Exec(ctx) +func (e *UserRepository) DeleteAll(ctx context.Context) error { + _, err := e.db.User.Delete().Exec(ctx) return err } -func (r *UserRepository) GetSuperusers(ctx context.Context) ([]*ent.User, error) { - users, err := r.db.User.Query().Where(user.IsSuperuser(true)).All(ctx) +func (e *UserRepository) GetSuperusers(ctx context.Context) ([]*ent.User, error) { + users, err := e.db.User.Query().Where(user.IsSuperuser(true)).All(ctx) if err != nil { return nil, err } diff --git a/backend/internal/data/repo/repo_users_test.go b/backend/internal/data/repo/repo_users_test.go index ef85f44..d3cd361 100644 --- a/backend/internal/data/repo/repo_users_test.go +++ b/backend/internal/data/repo/repo_users_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func userFactory() UserCreate { @@ -24,18 +23,18 @@ func TestUserRepo_GetOneEmail(t *testing.T) { ctx := context.Background() _, err := tRepos.Users.Create(ctx, user) - require.NoError(t, err) + assert.NoError(err) foundUser, err := tRepos.Users.GetOneEmail(ctx, user.Email) assert.NotNil(foundUser) - require.NoError(t, err) + assert.Nil(err) assert.Equal(user.Email, foundUser.Email) assert.Equal(user.Name, foundUser.Name) // Cleanup err = tRepos.Users.DeleteAll(ctx) - require.NoError(t, err) + assert.NoError(err) } func TestUserRepo_GetOneId(t *testing.T) { @@ -44,16 +43,16 @@ func TestUserRepo_GetOneId(t *testing.T) { ctx := context.Background() userOut, _ := tRepos.Users.Create(ctx, user) - foundUser, err := tRepos.Users.GetOneID(ctx, userOut.ID) + foundUser, err := tRepos.Users.GetOneId(ctx, userOut.ID) assert.NotNil(foundUser) - require.NoError(t, err) + assert.Nil(err) assert.Equal(user.Email, foundUser.Email) assert.Equal(user.Name, foundUser.Name) // Cleanup err = tRepos.Users.DeleteAll(ctx) - require.NoError(t, err) + assert.NoError(err) } func TestUserRepo_GetAll(t *testing.T) { @@ -77,7 +76,7 @@ func TestUserRepo_GetAll(t *testing.T) { // Validate allUsers, err := tRepos.Users.GetAll(ctx) - require.NoError(t, err) + assert.NoError(t, err) assert.Equal(t, len(created), len(allUsers)) for _, usr := range created { @@ -97,12 +96,12 @@ func TestUserRepo_GetAll(t *testing.T) { // Cleanup err = tRepos.Users.DeleteAll(ctx) - require.NoError(t, err) + assert.NoError(t, err) } func TestUserRepo_Update(t *testing.T) { user, err := tRepos.Users.Create(context.Background(), userFactory()) - require.NoError(t, err) + assert.NoError(t, err) updateData := UserUpdate{ Name: fk.Str(10), @@ -111,11 +110,11 @@ func TestUserRepo_Update(t *testing.T) { // Update err = tRepos.Users.Update(context.Background(), user.ID, updateData) - require.NoError(t, err) + assert.NoError(t, err) // Validate - updated, err := tRepos.Users.GetOneID(context.Background(), user.ID) - require.NoError(t, err) + updated, err := tRepos.Users.GetOneId(context.Background(), user.ID) + assert.NoError(t, err) assert.NotEqual(t, user.Name, updated.Name) assert.NotEqual(t, user.Email, updated.Email) } @@ -132,12 +131,12 @@ func TestUserRepo_Delete(t *testing.T) { ctx := context.Background() allUsers, _ := tRepos.Users.GetAll(ctx) - assert.NotEmpty(t, allUsers) + assert.Greater(t, len(allUsers), 0) err := tRepos.Users.DeleteAll(ctx) - require.NoError(t, err) + assert.NoError(t, err) allUsers, _ = tRepos.Users.GetAll(ctx) - assert.Empty(t, allUsers) + assert.Equal(t, len(allUsers), 0) } func TestUserRepo_GetSuperusers(t *testing.T) { @@ -161,7 +160,7 @@ func TestUserRepo_GetSuperusers(t *testing.T) { ctx := context.Background() superUsers, err := tRepos.Users.GetSuperusers(ctx) - require.NoError(t, err) + assert.NoError(t, err) for _, usr := range superUsers { assert.True(t, usr.IsSuperuser) @@ -169,5 +168,5 @@ func TestUserRepo_GetSuperusers(t *testing.T) { // Cleanup err = tRepos.Users.DeleteAll(ctx) - require.NoError(t, err) + assert.NoError(t, err) } diff --git a/backend/internal/data/repo/repos_all.go b/backend/internal/data/repo/repos_all.go index 2ccc022..2a3cf27 100644 --- a/backend/internal/data/repo/repos_all.go +++ b/backend/internal/data/repo/repos_all.go @@ -1,10 +1,6 @@ -// Package repo provides the data access layer for the application. package repo -import ( - "github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus" - "github.com/hay-kot/homebox/backend/internal/data/ent" -) +import "github.com/hay-kot/homebox/backend/internal/data/ent" // AllRepos is a container for all the repository interfaces type AllRepos struct { @@ -20,14 +16,14 @@ type AllRepos struct { Notifiers *NotifierRepository } -func New(db *ent.Client, bus *eventbus.EventBus, root string) *AllRepos { +func New(db *ent.Client, root string) *AllRepos { return &AllRepos{ Users: &UserRepository{db}, AuthTokens: &TokenRepository{db}, Groups: NewGroupRepository(db), - Locations: &LocationRepository{db, bus}, - Labels: &LabelRepository{db, bus}, - Items: &ItemsRepository{db, bus}, + Locations: &LocationRepository{db}, + Labels: &LabelRepository{db}, + Items: &ItemsRepository{db}, Docs: &DocumentRepository{db, root}, Attachments: &AttachmentRepo{db}, MaintEntry: &MaintenanceEntryRepository{db}, diff --git a/backend/internal/data/types/date.go b/backend/internal/data/types/date.go index 9401e06..1c4b5fa 100644 --- a/backend/internal/data/types/date.go +++ b/backend/internal/data/types/date.go @@ -1,4 +1,3 @@ -// Package types provides custom types for the application. package types import ( diff --git a/backend/internal/sys/config/conf.go b/backend/internal/sys/config/conf.go index 8b7b23c..c1655c2 100644 --- a/backend/internal/sys/config/conf.go +++ b/backend/internal/sys/config/conf.go @@ -1,4 +1,3 @@ -// Package config provides the configuration for the application. package config import ( @@ -6,7 +5,6 @@ import ( "errors" "fmt" "os" - "time" "github.com/ardanlabs/conf/v3" ) @@ -17,48 +15,44 @@ const ( ) type Config struct { - conf.Version - Mode string `yaml:"mode" conf:"default:development"` // development or production - Web WebConfig `yaml:"web"` - Storage Storage `yaml:"storage"` - Log LoggerConf `yaml:"logger"` - Mailer MailerConf `yaml:"mailer"` - Demo bool `yaml:"demo"` - Debug DebugConf `yaml:"debug"` - Options Options `yaml:"options"` + Mode string `yaml:"mode" conf:"default:development"` // development or production + Web WebConfig `yaml:"web"` + Storage Storage `yaml:"storage"` + Log LoggerConf `yaml:"logger"` + Mailer MailerConf `yaml:"mailer"` + Swagger SwaggerConf `yaml:"swagger"` + Demo bool `yaml:"demo"` + Debug DebugConf `yaml:"debug"` + Options Options `yaml:"options"` } type Options struct { - AllowRegistration bool `yaml:"disable_registration" conf:"default:true"` - AutoIncrementAssetID bool `yaml:"auto_increment_asset_id" conf:"default:true"` - CurrencyConfig string `yaml:"currencies"` + AllowRegistration bool `yaml:"disable_registration" conf:"default:true"` + AutoIncrementAssetID bool `yaml:"auto_increment_asset_id" conf:"default:true"` } type DebugConf struct { Enabled bool `yaml:"enabled" conf:"default:false"` - Port string `yaml:"port" conf:"default:4000"` + Port string `yaml:"port" conf:"default:4000"` +} + +type SwaggerConf struct { + Host string `yaml:"host" conf:"default:localhost:7745"` + Scheme string `yaml:"scheme" conf:"default:http"` } type WebConfig struct { - Port string `yaml:"port" conf:"default:7745"` - Host string `yaml:"host"` - MaxUploadSize int64 `yaml:"max_file_upload" conf:"default:10"` - ReadTimeout time.Duration `yaml:"read_timeout" conf:"default:10s"` - WriteTimeout time.Duration `yaml:"write_timeout" conf:"default:10s"` - IdleTimeout time.Duration `yaml:"idle_timeout" conf:"default:30s"` + Port string `yaml:"port" conf:"default:7745"` + Host string `yaml:"host"` + MaxUploadSize int64 `yaml:"max_file_upload" conf:"default:10"` } // New parses the CLI/Config file and returns a Config struct. If the file argument is an empty string, the // file is not read. If the file is not empty, the file is read and the Config struct is returned. -func New(buildstr string, description string) (*Config, error) { +func New() (*Config, error) { var cfg Config const prefix = "HBOX" - cfg.Version = conf.Version{ - Build: buildstr, - Desc: description, - } - help, err := conf.Parse(prefix, &cfg) if err != nil { if errors.Is(err, conf.ErrHelpWanted) { diff --git a/backend/internal/sys/config/conf_database.go b/backend/internal/sys/config/conf_database.go index 2c6a761..76d0ba2 100644 --- a/backend/internal/sys/config/conf_database.go +++ b/backend/internal/sys/config/conf_database.go @@ -6,6 +6,6 @@ const ( type Storage struct { // Data is the path to the root directory - Data string `yaml:"data" conf:"default:./.data"` - SqliteURL string `yaml:"sqlite-url" conf:"default:./.data/homebox.db?_pragma=busy_timeout=999&_pragma=journal_mode=WAL&_fk=1"` + Data string `yaml:"data" conf:"default:./.data"` + SqliteUrl string `yaml:"sqlite-url" conf:"default:./.data/homebox.db?_pragma=busy_timeout=1000&_pragma=journal_mode=WAL&_fk=1"` } diff --git a/backend/internal/sys/validate/errors.go b/backend/internal/sys/validate/errors.go index 09fdf2c..2338785 100644 --- a/backend/internal/sys/validate/errors.go +++ b/backend/internal/sys/validate/errors.go @@ -88,7 +88,7 @@ func (fe FieldErrors) Nil() bool { return len(fe) == 0 } -// Error implements the error interface. +// Error implments the error interface. func (fe FieldErrors) Error() string { d, err := json.Marshal(fe) if err != nil { @@ -101,10 +101,6 @@ func NewFieldErrors(errs ...FieldError) FieldErrors { return errs } -func NewFieldError(field, reason string) FieldError { - return FieldError{Field: field, Error: reason} -} - func IsFieldError(err error) bool { v := FieldErrors{} return errors.As(err, &v) diff --git a/backend/internal/sys/validate/validate.go b/backend/internal/sys/validate/validate.go index d9dbe24..3d121de 100644 --- a/backend/internal/sys/validate/validate.go +++ b/backend/internal/sys/validate/validate.go @@ -1,4 +1,3 @@ -// Package validate provides a wrapper around the go-playground/validator package package validate import ( @@ -9,12 +8,11 @@ import ( var validate *validator.Validate -func init() { // nolint +func init() { validate = validator.New() err := validate.RegisterValidation("shoutrrr", func(fl validator.FieldLevel) bool { prefixes := [...]string{ - "bark://", "discord://", "smtp://", "gotify://", @@ -23,7 +21,6 @@ func init() { // nolint "join://", "mattermost://", "matrix://", - "ntfy://", "opsgenie://", "pushbullet://", "pushover://", @@ -32,8 +29,6 @@ func init() { // nolint "teams://", "telegram://", "zulip://", - "generic://", - "generic+", } str := fl.Field().String() @@ -53,16 +48,17 @@ func init() { // nolint if err != nil { panic(err) } + } -// Check a struct for validation errors and returns any errors the occur. This +// Checks a struct for validation errors and returns any errors the occur. This // wraps the validate.Struct() function and provides some error wrapping. When // a validator.ValidationErrors is returned, it is wrapped transformed into a // FieldErrors array and returned. func Check(val any) error { err := validate.Struct(val) if err != nil { - verrors, ok := err.(validator.ValidationErrors) // nolint - we know it's a validator.ValidationErrors + verrors, ok := err.(validator.ValidationErrors) if !ok { return err } diff --git a/backend/internal/web/adapters/actions.go b/backend/internal/web/adapters/actions.go index 3905723..db9a410 100644 --- a/backend/internal/web/adapters/actions.go +++ b/backend/internal/web/adapters/actions.go @@ -3,8 +3,8 @@ package adapters import ( "net/http" - "github.com/hay-kot/httpkit/errchain" - "github.com/hay-kot/httpkit/server" + "github.com/hay-kot/safeserve/errchain" + "github.com/hay-kot/safeserve/server" ) // Action is a function that adapts a function to the server.Handler interface. diff --git a/backend/internal/web/adapters/command.go b/backend/internal/web/adapters/command.go index d3d099b..3d7eb06 100644 --- a/backend/internal/web/adapters/command.go +++ b/backend/internal/web/adapters/command.go @@ -4,8 +4,8 @@ import ( "net/http" "github.com/google/uuid" - "github.com/hay-kot/httpkit/errchain" - "github.com/hay-kot/httpkit/server" + "github.com/hay-kot/safeserve/errchain" + "github.com/hay-kot/safeserve/server" ) type CommandFunc[T any] func(*http.Request) (T, error) diff --git a/backend/internal/web/adapters/decoders.go b/backend/internal/web/adapters/decoders.go index ad5b82b..ef4bf6c 100644 --- a/backend/internal/web/adapters/decoders.go +++ b/backend/internal/web/adapters/decoders.go @@ -9,7 +9,7 @@ import ( "github.com/google/uuid" "github.com/gorilla/schema" "github.com/hay-kot/homebox/backend/internal/sys/validate" - "github.com/hay-kot/httpkit/server" + "github.com/hay-kot/safeserve/server" ) var queryDecoder = schema.NewDecoder() diff --git a/backend/internal/web/adapters/query.go b/backend/internal/web/adapters/query.go index b044475..8f669f0 100644 --- a/backend/internal/web/adapters/query.go +++ b/backend/internal/web/adapters/query.go @@ -3,8 +3,8 @@ package adapters import ( "net/http" - "github.com/hay-kot/httpkit/errchain" - "github.com/hay-kot/httpkit/server" + "github.com/hay-kot/safeserve/errchain" + "github.com/hay-kot/safeserve/server" ) // Query is a server.Handler that decodes a query from the request and calls the provided function. diff --git a/backend/internal/web/mid/doc.go b/backend/internal/web/mid/doc.go deleted file mode 100644 index 4f71563..0000000 --- a/backend/internal/web/mid/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package mid provides web middleware. -package mid diff --git a/backend/internal/web/mid/errors.go b/backend/internal/web/mid/errors.go index c8b04d6..269387c 100644 --- a/backend/internal/web/mid/errors.go +++ b/backend/internal/web/mid/errors.go @@ -6,8 +6,8 @@ import ( "github.com/go-chi/chi/v5/middleware" "github.com/hay-kot/homebox/backend/internal/data/ent" "github.com/hay-kot/homebox/backend/internal/sys/validate" - "github.com/hay-kot/httpkit/errchain" - "github.com/hay-kot/httpkit/server" + "github.com/hay-kot/safeserve/errchain" + "github.com/hay-kot/safeserve/server" "github.com/rs/zerolog" ) @@ -16,7 +16,7 @@ type ErrorResponse struct { Fields map[string]string `json:"fields,omitempty"` } -func Errors(log zerolog.Logger) errchain.ErrorHandler { +func Errors(svr *server.Server, log zerolog.Logger) errchain.ErrorHandler { return func(h errchain.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { err := h.ServeHTTP(w, r) @@ -44,7 +44,7 @@ func Errors(log zerolog.Logger) errchain.ErrorHandler { case validate.IsFieldError(err): code = http.StatusUnprocessableEntity - fieldErrors := err.(validate.FieldErrors) // nolint + fieldErrors := err.(validate.FieldErrors) resp.Error = "Validation Error" resp.Fields = map[string]string{} @@ -52,7 +52,7 @@ func Errors(log zerolog.Logger) errchain.ErrorHandler { resp.Fields[fieldError.Field] = fieldError.Error } case validate.IsRequestError(err): - requestError := err.(*validate.RequestError) // nolint + requestError := err.(*validate.RequestError) resp.Error = requestError.Error() if requestError.Status == 0 { @@ -71,6 +71,14 @@ func Errors(log zerolog.Logger) errchain.ErrorHandler { if err := server.JSON(w, code, resp); err != nil { log.Err(err).Msg("failed to write response") } + + // If Showdown error, return error + if server.IsShutdownError(err) { + err := svr.Shutdown(err.Error()) + if err != nil { + log.Err(err).Msg("failed to shutdown server") + } + } } }) } diff --git a/backend/internal/web/mid/logger.go b/backend/internal/web/mid/logger.go index 0be4722..d087c68 100644 --- a/backend/internal/web/mid/logger.go +++ b/backend/internal/web/mid/logger.go @@ -1,9 +1,6 @@ package mid import ( - "bufio" - "errors" - "net" "net/http" "github.com/go-chi/chi/v5/middleware" @@ -20,14 +17,6 @@ func (s *spy) WriteHeader(status int) { s.ResponseWriter.WriteHeader(status) } -func (s *spy) Hijack() (net.Conn, *bufio.ReadWriter, error) { - hj, ok := s.ResponseWriter.(http.Hijacker) - if !ok { - return nil, nil, errors.New("response writer does not support hijacking") - } - return hj.Hijack() -} - func Logger(l zerolog.Logger) func(http.Handler) http.Handler { return func(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/backend/pkgs/cgofreesqlite/sqlite.go b/backend/pkgs/cgofreesqlite/sqlite.go index c9faf7a..0560d26 100644 --- a/backend/pkgs/cgofreesqlite/sqlite.go +++ b/backend/pkgs/cgofreesqlite/sqlite.go @@ -1,4 +1,4 @@ -// Package cgofreesqlite package provides a CGO free implementation of the sqlite3 driver. This wraps the +// sqlite package provides a CGO free implementation of the sqlite3 driver. This wraps the // modernc.org/sqlite driver and adds the PRAGMA foreign_keys = ON; statement to the connection // initialization as well as registering the driver with the sql package as "sqlite3" for compatibility // with entgo.io @@ -35,6 +35,6 @@ func (d CGOFreeSqliteDriver) Open(name string) (conn driver.Conn, err error) { return conn, err } -func init() { //nolint:gochecknoinits +func init() { sql.Register("sqlite3", CGOFreeSqliteDriver{Driver: &sqlite.Driver{}}) } diff --git a/backend/pkgs/faker/random.go b/backend/pkgs/faker/random.go index 62e4ff2..2cb3b6a 100644 --- a/backend/pkgs/faker/random.go +++ b/backend/pkgs/faker/random.go @@ -1,4 +1,3 @@ -// Package faker provides a simple interface for generating fake data for testing. package faker import ( diff --git a/backend/pkgs/hasher/doc.go b/backend/pkgs/hasher/doc.go deleted file mode 100644 index 4cbdab4..0000000 --- a/backend/pkgs/hasher/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package hasher provides a simple interface for hashing and verifying passwords. -package hasher diff --git a/backend/pkgs/hasher/password.go b/backend/pkgs/hasher/password.go index a68c868..1be8251 100644 --- a/backend/pkgs/hasher/password.go +++ b/backend/pkgs/hasher/password.go @@ -9,7 +9,7 @@ import ( var enabled = true -func init() { // nolint: gochecknoinits +func init() { disableHas := os.Getenv("UNSAFE_DISABLE_PASSWORD_PROJECTION") == "yes_i_am_sure" if disableHas { diff --git a/backend/pkgs/mailer/mailer.go b/backend/pkgs/mailer/mailer.go index 9b593bc..22609aa 100644 --- a/backend/pkgs/mailer/mailer.go +++ b/backend/pkgs/mailer/mailer.go @@ -1,4 +1,3 @@ -// Package mailer provides a simple mailer for sending emails. package mailer import ( diff --git a/backend/pkgs/mailer/mailer_test.go b/backend/pkgs/mailer/mailer_test.go index 89e55ca..3e67a68 100644 --- a/backend/pkgs/mailer/mailer_test.go +++ b/backend/pkgs/mailer/mailer_test.go @@ -5,7 +5,7 @@ import ( "os" "testing" - "github.com/stretchr/testify/require" + "github.com/stretchr/testify/assert" ) const ( @@ -59,5 +59,5 @@ func Test_Mailer(t *testing.T) { err = mailer.Send(msg) - require.NoError(t, err) + assert.Nil(t, err) } diff --git a/backend/pkgs/pathlib/pathlib.go b/backend/pkgs/pathlib/pathlib.go index e59366d..24420aa 100644 --- a/backend/pkgs/pathlib/pathlib.go +++ b/backend/pkgs/pathlib/pathlib.go @@ -1,4 +1,3 @@ -// Package pathlib provides a way to safely create a file path without overwriting any existing files. package pathlib import ( @@ -15,7 +14,7 @@ var dirReader dirReaderFunc = func(directory string) []string { if err != nil { return nil } - defer func() { _ = f.Close() }() + defer f.Close() names, err := f.Readdirnames(-1) if err != nil { diff --git a/backend/pkgs/set/set.go b/backend/pkgs/set/set.go index fca1c98..b0918bb 100644 --- a/backend/pkgs/set/set.go +++ b/backend/pkgs/set/set.go @@ -1,4 +1,3 @@ -// Package set provides a simple set implementation. package set type key interface { diff --git a/docker-compose.yml b/docker-compose.yml index 6b57760..a1108fc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,3 +1,5 @@ +version: "3.4" + services: homebox: image: homebox diff --git a/docs/docs/api/openapi-2.0.json b/docs/docs/api/openapi-2.0.json index b10c93a..d5e71d2 100644 --- a/docs/docs/api/openapi-2.0.json +++ b/docs/docs/api/openapi-2.0.json @@ -6,6 +6,9 @@ "contact": { "name": "Don't" }, + "license": { + "name": "MIT" + }, "version": "1.0" }, "basePath": "/api", @@ -60,31 +63,6 @@ } } }, - "/v1/actions/set-primary-photos": { - "post": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Sets the first photo of each item as the primary photo", - "produces": [ - "application/json" - ], - "tags": [ - "Actions" - ], - "summary": "Set Primary Photos", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/v1.ActionAmountResult" - } - } - } - } - }, "/v1/actions/zero-item-time-fields": { "post": { "security": [ @@ -143,25 +121,6 @@ } } }, - "/v1/currency": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "Base" - ], - "summary": "Currency", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/currencies.Currency" - } - } - } - } - }, "/v1/groups": { "get": { "security": [ @@ -422,16 +381,6 @@ "description": "location Ids", "name": "locations", "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi", - "description": "parent Ids", - "name": "parentIds", - "in": "query" } ], "responses": { @@ -681,46 +630,6 @@ "description": "No Content" } } - }, - "patch": { - "security": [ - { - "Bearer": [] - } - ], - "produces": [ - "application/json" - ], - "tags": [ - "Items" - ], - "summary": "Update Item", - "parameters": [ - { - "type": "string", - "description": "Item ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "Item Data", - "name": "payload", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/repo.ItemPatch" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/repo.ItemOut" - } - } - } } }, "/v1/items/{id}/attachments": { @@ -777,7 +686,7 @@ "422": { "description": "Unprocessable Entity", "schema": { - "$ref": "#/definitions/validate.ErrorResponse" + "$ref": "#/definitions/mid.ErrorResponse" } } } @@ -1010,42 +919,6 @@ } } }, - "/v1/items/{id}/path": { - "get": { - "security": [ - { - "Bearer": [] - } - ], - "produces": [ - "application/json" - ], - "tags": [ - "Items" - ], - "summary": "Get the full path of an item", - "parameters": [ - { - "type": "string", - "description": "Item ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/repo.ItemPath" - } - } - } - } - } - }, "/v1/labels": { "get": { "security": [ @@ -1632,7 +1505,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/v1.APISummary" + "$ref": "#/definitions/v1.ApiSummary" } } } @@ -1703,12 +1576,6 @@ "schema": { "$ref": "#/definitions/v1.LoginForm" } - }, - { - "type": "string", - "description": "auth provider", - "name": "provider", - "in": "query" } ], "responses": { @@ -1887,20 +1754,17 @@ } }, "definitions": { - "currencies.Currency": { + "mid.ErrorResponse": { "type": "object", "properties": { - "code": { + "error": { "type": "string" }, - "local": { - "type": "string" - }, - "name": { - "type": "string" - }, - "symbol": { - "type": "string" + "fields": { + "type": "object", + "additionalProperties": { + "type": "string" + } } } }, @@ -1984,9 +1848,6 @@ "id": { "type": "string" }, - "primary": { - "type": "boolean" - }, "type": { "type": "string" }, @@ -1998,9 +1859,6 @@ "repo.ItemAttachmentUpdate": { "type": "object", "properties": { - "primary": { - "type": "boolean" - }, "title": { "type": "string" }, @@ -2079,6 +1937,12 @@ "$ref": "#/definitions/repo.ItemAttachment" } }, + "children": { + "type": "array", + "items": { + "$ref": "#/definitions/repo.ItemSummary" + } + }, "createdAt": { "type": "string" }, @@ -2094,9 +1958,6 @@ "id": { "type": "string" }, - "imageId": { - "type": "string" - }, "insured": { "type": "boolean" }, @@ -2112,13 +1973,9 @@ }, "location": { "description": "Edges", - "allOf": [ - { - "$ref": "#/definitions/repo.LocationSummary" - } - ], "x-nullable": true, - "x-omitempty": true + "x-omitempty": true, + "$ref": "#/definitions/repo.LocationSummary" }, "manufacturer": { "type": "string" @@ -2134,13 +1991,9 @@ "type": "string" }, "parent": { - "allOf": [ - { - "$ref": "#/definitions/repo.ItemSummary" - } - ], "x-nullable": true, - "x-omitempty": true + "x-omitempty": true, + "$ref": "#/definitions/repo.ItemSummary" }, "purchaseFrom": { "type": "string" @@ -2184,33 +2037,6 @@ } } }, - "repo.ItemPatch": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "quantity": { - "type": "integer", - "x-nullable": true, - "x-omitempty": true - } - } - }, - "repo.ItemPath": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "type": { - "$ref": "#/definitions/repo.ItemType" - } - } - }, "repo.ItemSummary": { "type": "object", "properties": { @@ -2226,9 +2052,6 @@ "id": { "type": "string" }, - "imageId": { - "type": "string" - }, "insured": { "type": "boolean" }, @@ -2240,13 +2063,9 @@ }, "location": { "description": "Edges", - "allOf": [ - { - "$ref": "#/definitions/repo.LocationSummary" - } - ], "x-nullable": true, - "x-omitempty": true + "x-omitempty": true, + "$ref": "#/definitions/repo.LocationSummary" }, "name": { "type": "string" @@ -2263,17 +2082,6 @@ } } }, - "repo.ItemType": { - "type": "string", - "enum": [ - "location", - "item" - ], - "x-enum-varnames": [ - "ItemTypeLocation", - "ItemTypeItem" - ] - }, "repo.ItemUpdate": { "type": "object", "properties": { @@ -2366,6 +2174,7 @@ "type": "string" }, "warrantyExpires": { + "description": "Sold", "type": "string" } } @@ -2402,6 +2211,12 @@ "id": { "type": "string" }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/repo.ItemSummary" + } + }, "name": { "type": "string" }, @@ -2463,6 +2278,12 @@ "id": { "type": "string" }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/repo.ItemSummary" + } + }, "name": { "type": "string" }, @@ -2539,6 +2360,7 @@ "type": "object", "properties": { "completedDate": { + "description": "Sold", "type": "string" }, "cost": { @@ -2555,6 +2377,7 @@ "type": "string" }, "scheduledDate": { + "description": "Sold", "type": "string" } } @@ -2566,6 +2389,7 @@ ], "properties": { "completedDate": { + "description": "Sold", "type": "string" }, "cost": { @@ -2579,6 +2403,7 @@ "type": "string" }, "scheduledDate": { + "description": "Sold", "type": "string" } } @@ -2587,6 +2412,7 @@ "type": "object", "properties": { "completedDate": { + "description": "Sold", "type": "string" }, "cost": { @@ -2600,6 +2426,7 @@ "type": "string" }, "scheduledDate": { + "description": "Sold", "type": "string" } } @@ -2835,7 +2662,15 @@ } } }, - "v1.APISummary": { + "v1.ActionAmountResult": { + "type": "object", + "properties": { + "completed": { + "type": "integer" + } + } + }, + "v1.ApiSummary": { "type": "object", "properties": { "allowRegistration": { @@ -2864,14 +2699,6 @@ } } }, - "v1.ActionAmountResult": { - "type": "object", - "properties": { - "completed": { - "type": "integer" - } - } - }, "v1.Build": { "type": "object", "properties": { @@ -2968,17 +2795,6 @@ "properties": { "item": {} } - }, - "validate.ErrorResponse": { - "type": "object", - "properties": { - "error": { - "type": "string" - }, - "fields": { - "type": "string" - } - } } }, "securityDefinitions": { diff --git a/docs/docs/assets/img/homebox-email-banner.jpg b/docs/docs/assets/img/homebox-email-banner.jpg deleted file mode 100644 index e611c43..0000000 Binary files a/docs/docs/assets/img/homebox-email-banner.jpg and /dev/null differ diff --git a/docs/docs/import-csv.md b/docs/docs/import-csv.md index 6ed4f4b..8d5586f 100644 --- a/docs/docs/import-csv.md +++ b/docs/docs/import-csv.md @@ -2,11 +2,11 @@ ## Quick Start -Using the CSV import is the recommended way for adding items to the database. It is always going to be the fastest way to import any large number of items and provides the most flexibility when it comes to adding items. +Using the CSV import is the recommended way for adding items to the database. It is always going to be the fastest way to import any large amount of items and provides the most flexibility when it comes to adding items. **Current Limitations** - - Imports only support importing items, locations, and labels + - Imports only supports importing items, locations, and labels - Imports and Exports do not support attachments. Attachments must be uploaded after import - CSV Exports do not support nested path exports (e.g. `Home / Office / Desk`) and will only export the Items direct parent, (though imports _do_ support nested paths) - Cannot specify item-to-item relationships (e.g. `Item A` is a child of `Item B`) @@ -16,13 +16,13 @@ Using the CSV import is the recommended way for adding items to the database. It ## CSV Reference -Below are the supported columns. They are case-sensitive, can be in any ordered or can be omitted unless otherwise specified. +Below are the supported columns. They are case sensitive, can be in any ordered or can be omitted unless otherwise specified. ### Special Syntax Columns `HB.import_ref` -: Import Refs are unique strings that can be used to deduplicate imports. Before an item is imported, we check the database for a matching ref. If the ref exists, we skip the creation of that item. +: Import Refs are unique strings that can be used to deduplicate imports. Before an item is imported, we check the database for a matching ref. If the ref exists, we skip creation of that item. * String Type * Max 100 Characters @@ -52,7 +52,7 @@ Below are the supported columns. They are case-sensitive, can be in any ordered ### Standard Columns | Column | Type | Description | -|----------------------|---------------|-----------------------------------------------| +| -------------------- | ------------- | --------------------------------------------- | | HB.quantity | Integer | The quantity of items to create | | HB.name | String | Name of the item | | HB.asset_id | AssetID | Asset ID for the item | @@ -76,7 +76,7 @@ Below are the supported columns. They are case-sensitive, can be in any ordered **Type Key** | Type | Format | -|---------|-----------------------------------------------------| +| ------- | --------------------------------------------------- | | String | Max 255 Characters unless otherwise specified | | Date | YYYY-MM-DD | | Boolean | true or false, yes or no, 1 or 0 - case insensitive | diff --git a/docs/docs/index.md b/docs/docs/index.md index 188dac5..708e33a 100644 --- a/docs/docs/index.md +++ b/docs/docs/index.md @@ -15,19 +15,19 @@ -Homebox is the inventory and organization system built for the Home User! With a focus on simplicity and ease of use, Homebox is the perfect solution for your home inventory, organization, and management needs. While developing this project, I've tried to keep the following principles in mind: +Homebox is the inventory and organization system built for the Home User! With a focus on simplicity and ease of use, Homebox is the perfect solution for your home inventory, organization, and management needs. While developing this project I've tried to keep the following principles in mind: - _Simple_ - Homebox is designed to be simple and easy to use. No complicated setup or configuration required. Use either a single docker container, or deploy yourself by compiling the binary for your platform of choice. -- _Blazingly Fast_ - Homebox is written in Go, which makes it extremely fast and requires minimal resources to deploy. In general idle memory usage is less than 50MB for the whole container. +- _Blazingly Fast_ - Homebox is written in Go which makes it extremely fast and requires minimal resources to deploy. In general idle memory usage is less than 50MB for the whole container. - _Portable_ - Homebox is designed to be portable and run on anywhere. We use SQLite and an embedded Web UI to make it easy to deploy, use, and backup. ## Project Status -Homebox is currently in early active development and is currently in **beta** stage. This means that the project may still be unstable and clunky. Overall, we are striving to not introduce any breaking changes and have checks in place to ensure migrations and upgrades are smooth. However, we do not guarantee that there will be no breaking changes. We will try to keep the documentation up to date as we make changes. +Homebox is currently in early-active development and is currently in **beta** stage. This means that the project may still be unstable and clunky. Overall we are striving to not introduce any breaking changes and have checks in place to ensure migrations and upgrades are smooth. However, we do not guarantee that there will be no breaking changes. We will try to keep the documentation up to date as we make changes. ## Features -- Create and Manage _Items_ by providing a name and a description - That's it! Homebox requires only a few details to be provided to create an item, after that you can specify as much detail as you want, or hide away some of the things you won't ever need. +- Create and Manage _Items_ by provided a name and description - That's it! Homebox requires only a few details to be provided to create an item, after that you can specify as much detail as you want, or hide away some of the things you won't ever need. - Optional Details for Items include - Warranty Information - Sold To Information @@ -40,17 +40,17 @@ Homebox is currently in early active development and is currently in **beta** st - Bill of Materials Export - QR Code Label Generator - Organize _Items_ by creating _Labels_ and _Locations_ and assigning them to items. -- Multi-Tenant Support - All users are placed in a group and can only see items in their group. Invite family members to your group, or share an instance among friends! +- Multi-Tenant Support - All users are placed inside of a group and can only see items that are apart of their group. Invite family members to your group, or share an instance among friends! ## Why Not Use Something Else? -There are a lot of great inventory management systems out there, but none of them _really_ fit my needs as a home user. Snipe-IT is a fantastic product that has so many robust features and management options which makes it easy to become overwhelmed and confused. I wanted something that was simple and easy to use that didn't require a lot of cognitive overhead to manage. I primarily built this to organize my IOT devices and save my warranty and documentation information in a central, searchable location. +There are a lot of great inventory management systems out there, but none of them _really_ fit my needs as a home user. Snipe-IT is a fantastic product that has so many robust features and management options that it's easy to become overwhelmed and confused. I wanted something that was simple and easy to use that didn't require a lot of cognitive overhead to manage. I primarily built this to organize my IOT devices and save my warranty and documentation information in a central, searchable location. ### Spreadsheet -That's a fair point. If your needs can be fulfilled by a Spreadsheet, I'd suggest using that instead. I've found spreadsheets get pretty unwieldy when you have a lot of data, and it's hard to keep track of what's where. I also wanted to be able to search and filter my data in a more robust way than a spreadsheet can provide. I also wanted to leave the door open for more advanced features in the future like maintenance logs, moving label generators, and more. +That's a fair point. If your needs can be fulfilled by a Spreadsheet, I'd suggest using that instead. I've found spreadsheets get pretty unwieldy when you have a lot of data and it's hard to keep track of what's where. I also wanted to be able to search and filter my data in a more robust way than a spreadsheet can provide. I also wanted to leave to door open for more advanced features in the future like maintenance logs, moving label generators, and more. ### Snipe-It? -Snipe-It is the gold standard for IT management. If your use-case is to manage consumables and IT physical infrastructure, I highly suggest you look at Snipe-It over Homebox, it's just more purpose built for that use case. Homebox is, in contrast, purpose built for the home user, which means that we try to focus on keeping things simple and easy to use. Lowering the friction for creating items and managing them is a key goal of Homebox which means you lose out on some of the more advanced features. In most cases, this is a good trade-off. \ No newline at end of file +Snipe-It is the gold standard for IT management. If your use-case is to manage consumables and IT physical infrastructure I highly suggest you look at Snipe-It over Homebox, it's just more purpose built for that use case. Homebox is, in contrast, purpose built for the home user, which means that we try to focus on keeping things simple and easy to use. Lowering the friction for creating items and managing them is a key goal of Homebox which means you lose out on some of the more advanced features. In most cases this is a good trade-off. \ No newline at end of file diff --git a/docs/docs/quick-start.md b/docs/docs/quick-start.md index 278b442..e0ad87b 100644 --- a/docs/docs/quick-start.md +++ b/docs/docs/quick-start.md @@ -4,33 +4,24 @@ Great for testing out the application, but not recommended for stable use. Checkout the docker-compose for the recommended deployment. -For each image there are two tags, respectively the regular tag and $TAG-rootless, which uses a non-root image. - ```sh -# If using the rootless image, ensure data -# folder has correct permissions -$ mkdir -p /path/to/data/folder -$ chown 65532:65532 -R /path/to/data/folder -# --------------------------------------- -# Run the image -$ docker run -d \ +docker run -d \ --name homebox \ --restart unless-stopped \ --publish 3100:7745 \ --env TZ=Europe/Bucharest \ --volume /path/to/data/folder/:/data \ ghcr.io/hay-kot/homebox:latest -# ghcr.io/hay-kot/homebox:latest-rootless - ``` ## Docker-Compose ```yaml +version: "3.4" + services: homebox: image: ghcr.io/hay-kot/homebox:latest -# image: ghcr.io/hay-kot/homebox:latest-rootless container_name: homebox restart: always environment: @@ -47,9 +38,6 @@ volumes: driver: local ``` -!!! note - If you use the `rootless` image, and instead of using named volumes you would prefer using a hostMount directly (e.g., `volumes: [ /path/to/data/folder:/data ]`) you need to `chown` the chosen directory in advance to the `65532` user (as shown in the Docker example above). - ## Env Variables & Configuration | Variable | Default | Description | @@ -59,13 +47,9 @@ volumes: | HBOX_WEB_HOST | | host to run the web server on, if you're using docker do not change this | | HBOX_OPTIONS_ALLOW_REGISTRATION | true | allow users to register themselves | | HBOX_OPTIONS_AUTO_INCREMENT_ASSET_ID | true | auto increments the asset_id field for new items | -| HBOX_OPTIONS_CURRENCY_CONFIG | | json configuration file containing additional currencie | | HBOX_WEB_MAX_UPLOAD_SIZE | 10 | maximum file upload size supported in MB | -| HBOX_WEB_READ_TIMEOUT | 10 | Read timeout of HTTP sever | -| HBOX_WEB_WRITE_TIMEOUT | 10 | Write timeout of HTTP server | -| HBOX_WEB_IDLE_TIMEOUT | 30 | Idle timeout of HTTP server | | HBOX_STORAGE_DATA | /data/ | path to the data directory, do not change this if you're using docker | -| HBOX_STORAGE_SQLITE_URL | /data/homebox.db?_fk=1 | sqlite database url, if you're using docker do not change this | +| HBOX_STORAGE_SQLITE_URL | /data/homebox.db?_fk=1 | sqlite database url, in you're using docker do not change this | | HBOX_LOG_LEVEL | info | log level to use, can be one of: trace, debug, info, warn, error, critical | | HBOX_LOG_FORMAT | text | log format to use, can be one of: text, json | | HBOX_MAILER_HOST | | email host to use, if not set no email provider will be used | @@ -103,7 +87,6 @@ volumes: --debug-port/$HBOX_DEBUG_PORT (default: 4000) --options-allow-registration/$HBOX_OPTIONS_ALLOW_REGISTRATION (default: true) --options-auto-increment-asset-id/$HBOX_OPTIONS_AUTO_INCREMENT_ASSET_ID (default: true) - --options-currency-config/$HBOX_OPTIONS_CURRENCY_CONFIG --help/-h display this help message ``` diff --git a/docs/docs/tips-tricks.md b/docs/docs/tips-tricks.md index a5ed05a..f2200c3 100644 --- a/docs/docs/tips-tricks.md +++ b/docs/docs/tips-tricks.md @@ -12,7 +12,7 @@ Custom fields are a great way to add any extra information to your item. The fol Custom fields are appended to the main details section of your item. !!! tip - Homebox Custom Fields also have special support for URLs. Provide a URL (`https://google.com`) and it will be automatically converted to a clickable link in the UI. Optionally, you can also use Markdown syntax to add a custom text to the button. `[Google](https://google.com)` + Homebox Custom Fields also have special support for URLs. Provide a URL (`https://google.com`) and it will be automatically converted to a clickable link in the UI. Optionally, you can also use markdown syntax to add a custom text to the button. `[Google](https://google.com)` ## Managing Asset IDs @@ -20,26 +20,26 @@ Homebox provides the option to auto-set asset IDs, this is the default behavior. Example ID: `000-001` -Asset IDs are partially managed by Homebox, but have a flexible implementation to allow for unique use cases. IDs are non-unique at the database level, so there is nothing stopping a user from manually setting duplicate IDs for various items. There are two recommended approaches to manage Asset IDs: +Asset IDs are partially managed by Homebox, but have a flexible implementation to allow for unique use cases. ID's are non-unique at the database level so there is nothing stopping a user from manually setting duplicate IDs for various items. There are two recommended approaches to manage Asset IDs ### 1. Auto Incrementing IDs -This is the default behavior likely to experience the most consistency. Whenever creating or importing an item, that item receives the next available ID. This is recommended for most users. +This is the default behavior and likely to one to experience the most consistent behavior. Whenever creating or importing an item, that items receives the next available ID. This is the most consistent approach and is recommended for most users. -### 2. Auto Incrementing IDs with Reset +### 2. Auto Incrementing ID's with Reset -In some cases, you may want to skip some items such as consumables, or items that are loosely tracked. In this case, we recommend that you leave auto-incrementing IDs enabled _however_ when you create a new item that you want to skip, you can go to that item and reset the ID to 0. This will remove it from the auto-incrementing sequence, and the next item will receive the next available ID. +In some cases you may want to skip some items such as consumables, or items that are loosely tracked. In this case, we recommend that you leave auto-incrementing ID's enabled _however_ when you create a new item that you want to skip, you can go to that item and reset the ID to 0. This will remove it from the auto-incrementing sequence and the next item will receive the next available ID. !!! tip - If you're migrating from an older version, there is an action on the user's profile page to assign IDs to all items. This will assign the next available ID to all items in order of their creation. You should __only do this once__ during the migration process. You should be especially cautious with this if you're using the reset feature described in [option number 2](#2-auto-incrementing-ids-with-reset) + If you're migrating from an older version there is a action on the users profile page to assign IDs to all items. This will assign the next available ID to all items in the order of creation. You should _only_ do this once during the migration process. You should be especially cautious of this action if you're using the reset feature described in option number 2 ## QR Codes :octicons-tag-24: 0.7.0 -Homebox has a built-in QR code generator that can be used to generate QR codes for your items. This is useful for tracking items with a mobile device. You can generate a QR code for any item by clicking the QR code icon in the top right of the item details page. The same can be done for the Labels and Locations page. Currently, support is limited to generating one-off QR Codes. +Homebox has a built-in QR code generator that can be used to generate QR codes for your items. This is useful for tracking items with a mobile device. You can generate a QR code for any item by clicking the QR code icon in the top right of the item details page. The same can be done for the Labels and Locations page. Currently support is limited to generating one off QR Codes. -However, the API endpoint is available for generating QR codes on the fly for any item (or any other data) if you provide a valid API key in the query parameters. An example url would look like `/api/v1/qrcode?data=https://homebox.fly.dev/item/{uuid}`. Currently, the easiest way to get an API token is to use one from an existing URL of the QR Code in the API key, but this will be improved in the future. +However, the API endpoint is available for generating QR codes on the fly for any item (or any other data) if you provide a valid API key in the query parameters. An example url would look like `/api/v1/qrcode?data=https://homebox.fly.dev/item/{uuid}`. Currently the easiest way to get an API token is to use one from an existing URL of the QR Code in the API key, but this will be improved in the future. :octicons-tag-24: v0.8.0 @@ -55,26 +55,4 @@ Homebox uses [shoutrrr](https://containrrr.dev/shoutrrr/0.7/) to send notificati **Notifications are sent on the day the maintenance is scheduled at or around 8am.** -As of `v0.9.0` we have limited support for complex scheduling of maintenance events. If you have requests for extended functionality, please open an issue on GitHub or reach out on Discord. We're still gauging the demand for this feature. - - -## Custom Currencies - -:octicons-tag-24: v0.11.0 - -Homebox allows you to add additional currencies to your instance by specify a JSON file containing the currencies you want to add. - -**Environment Variable:** `HBOX_OPTIONS_CURRENCY_CONFIG` - -### Example - -```json -[ - { - "code": "AED", - "local": "United Arab Emirates", - "symbol": "د.إ", - "name": "United Arab Emirates Dirham" - }, -] -``` +As of `v0.9.0` we have limited support for complex scheduling of maintenance events. If you have requests for extended functionality, please open an issue on GitHub or reach out on Discord. We're still gauging the demand for this feature. \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt index d7301ed..68bfe4a 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1 @@ -mkdocs-material==9.5.12 \ No newline at end of file +mkdocs-material==9.1.4 \ No newline at end of file diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js index c567952..fa57669 100644 --- a/frontend/.eslintrc.js +++ b/frontend/.eslintrc.js @@ -25,7 +25,6 @@ module.exports = { "vue/no-setup-props-destructure": 0, "vue/no-multiple-template-root": 0, "vue/no-v-model-argument": 0, - "@typescript-eslint/consistent-type-imports": "error", "@typescript-eslint/ban-ts-comment": 0, "@typescript-eslint/no-unused-vars": [ "error", diff --git a/frontend/components/App/Header.vue b/frontend/components/App/Header.vue index b42da7f..a142f8d 100644 --- a/frontend/components/App/Header.vue +++ b/frontend/components/App/Header.vue @@ -1,6 +1,4 @@ diff --git a/frontend/components/App/Toast.vue b/frontend/components/App/Toast.vue index d713714..06c3944 100644 --- a/frontend/components/App/Toast.vue +++ b/frontend/components/App/Toast.vue @@ -14,14 +14,14 @@ >
{{ notify.message }}
@@ -31,10 +31,6 @@ diff --git a/frontend/components/Base/SectionHeader.vue b/frontend/components/Base/SectionHeader.vue index da25def..43fa8b2 100644 --- a/frontend/components/Base/SectionHeader.vue +++ b/frontend/components/Base/SectionHeader.vue @@ -1,7 +1,7 @@ + + diff --git a/frontend/components/Chart/Line.vue b/frontend/components/Chart/Line.vue new file mode 100644 index 0000000..c36ef93 --- /dev/null +++ b/frontend/components/Chart/Line.vue @@ -0,0 +1,113 @@ + + + + + diff --git a/frontend/components/Form/Autocomplete2.vue b/frontend/components/Form/Autocomplete2.vue index d9fe64a..b71c30e 100644 --- a/frontend/components/Form/Autocomplete2.vue +++ b/frontend/components/Form/Autocomplete2.vue @@ -10,16 +10,8 @@ class="w-full input input-bordered" @change="search = $event.target.value" /> - - + -