Compare commits

..

2 Commits

Author SHA1 Message Date
tonyaellie
53a5ed1f77 feat: proof of concept 2025-04-13 16:43:16 +00:00
tonyaellie
5d5ee8f555 feat: move image upload to its own component 2025-04-13 15:33:23 +00:00
537 changed files with 25456 additions and 95721 deletions

View File

@@ -29,6 +29,6 @@
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "node",
"features": {
"ghcr.io/devcontainers/features/go:1": "1.24"
"ghcr.io/devcontainers/features/go:1": "1.21"
}
}

3
.gitattributes vendored
View File

@@ -1,3 +0,0 @@
backend/internal/data/ent/** linguist-generated=true
backend/internal/data/ent/schema/** linguist-generated=false
frontend/lib/api/types/** linguist-generated=true

40
.github/AGENTS.md vendored
View File

@@ -1,40 +0,0 @@
This is a Go based repository with a VueJS client for the frontend built with Vite and Nuxt, with ShadCN.
To make life easier, the use of a Taskfile is included for the majority of development commands.
Please follow these guidelines when contributing:
## Required Before Each Commit
- Generate Swagger Files: `task swag --force`
- Generate JS API Client: `task typescript-types --force`
- Lint Golang: `task go:lint`
- Lint frontend: `task ui:fix`
## Repository Structure
### Backend
- `backend/`: Contains the backend folders
- `backend/app`: Contains main app code including API endpoints
- `backend/internal/core`: Contains basic services such as currencies
- `backend/data`: Contains all information related to data, including `ent` schemas, repos, migrations, etc.
- `backend/data/migrations`: Contains migration data, the `sqlite3` sub-folder contains sqlite migrations, `postgres` sub-folder the postgres migrations, BOTH are REQUIRED.
- `backend/data/ent/schema`: Contains the actual `ent` data models.
- `backend/data/repo`: Contains the data repositories
- `backend/pkgs`: Contains general helper functions and services
### Frontend
- `frontend/`: Contains initial frontend files
- `frontend/components`: Contains the ShadCN components
- `frontend/locales`: Contains the i18n JSON for languages
- `frontend/pages`: Contains VueJS pages
- `frontend/test`: Contains Playwright setup
- `frontend/test/e2e`: Contains actual Playwright test files
### Docs
- `docs/`: Contains VitePress based documentation
## Key Guidelines
1. Follow best practices for the various programming languages
2. Maintain existing code structure and organization when possible
3. Use dependency injection when reasonable
4. Write tests for new functionality and after fixing bugs to validate they're fixed
5. Document changes to the `docs/` folder when appropriate

1
.github/FUNDING.yml vendored
View File

@@ -1,2 +1 @@
open_collective: homebox
github: [tankerkiller125,katosdev,tonyaellie]

View File

@@ -58,17 +58,6 @@ body:
- Other
validations:
required: true
- type: dropdown
id: database
attributes:
label: Database Type
description: What database backend are you using?
multiple: false
options:
- SQLite
- PostgreSQL
validations:
required: true
- type: dropdown
id: arch
attributes:

View File

@@ -1,11 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: GitHub Community Support
url: https://github.com/sysadminsmedia/homebox/discussions/categories/support
about: Get support for issues here
- name: Feature Requests
url: https://github.com/sysadminsmedia/homebox/discussions/categories/ideas
about: Have an idea for Homebox? Share it in our discussions forum. If we decide to take it on we will create an issue for it.
- name: Translate
url: https://translate.sysadminsmedia.com
about: Help us translate Homebox! All contributions and all languages welcome!

View File

@@ -1,4 +1,9 @@
---
name: "Feature Request"
description: "Submit a feature request for the current release"
labels: ["⬆️ enhancement"]
projects: ["sysadminsmedia/2"]
type: "Enhancement"
body:
- type: textarea
id: problem-statement
@@ -26,5 +31,9 @@ body:
label: Contributions
description: Please confirm the following
options:
- label: I have searched through existing ideas in the discussions to check if this is a duplicate
- label: I have searched through existing issues and feature requests to see if my idea has already been proposed.
required: true
- label: If this feature is accepted, I would be willing to help implement and maintain this feature.
required: false
- label: If this feature is accepted, I'm willing to sponsor the development of this feature.
required: false

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

View File

@@ -1,8 +0,0 @@
# Screenshots
These screenshots are taken from our public [Demo](https://demo.homebox.software) instance.
Note that whilst we will make every effort to ensure that these are maintained and updated, they may be outdated or missing functionality and we would always advise reviewing our demo instances:
- [Demo](https://demo.homebox.software)
- [Nightly](https://nightly.homebox.software)
- [VNext](https://vnext.homebox.software/)

View File

@@ -1,213 +1,64 @@
#!/usr/bin/env python3
import csv
import io
import json
import logging
import os
import sys
from pathlib import Path
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
API_URL = 'https://restcountries.com/v3.1/all?fields=name,common,currencies'
# Default to a pinned commit for supply-chain security
DEFAULT_ISO_4217_URL = 'https://raw.githubusercontent.com/datasets/currency-codes/052b3088938ba32028a14e75040c286c5e142145/data/codes-all.csv'
ISO_4217_URL = os.environ.get('ISO_4217_URL', DEFAULT_ISO_4217_URL)
SAVE_PATH = Path('backend/internal/core/currencies/currencies.json')
TIMEOUT = 10 # seconds
# Known currency decimal overrides
CURRENCY_DECIMAL_OVERRIDES = {
"BTC": 8, # Bitcoin uses 8 decimal places
"JPY": 0, # Japanese Yen has no decimal places
"BHD": 3, # Bahraini Dinar uses 3 decimal places
}
DEFAULT_DECIMALS = 2
MIN_DECIMALS = 0
MAX_DECIMALS = 6
def setup_logging():
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s %(levelname)s: %(message)s'
)
def get_currency_decimals(code, iso_data):
"""
Get the decimal places for a currency code.
Checks overrides first, then ISO data, then uses default.
Clamps result to safe range [MIN_DECIMALS, MAX_DECIMALS].
"""
# Normalize the input code
normalized_code = (code or "").strip().upper()
# First check overrides
if normalized_code in CURRENCY_DECIMAL_OVERRIDES:
decimals = CURRENCY_DECIMAL_OVERRIDES[normalized_code]
# Then check ISO data
elif normalized_code in iso_data:
decimals = iso_data[normalized_code]
# Finally use default
else:
decimals = DEFAULT_DECIMALS
# Ensure it's an integer and clamp to safe range
try:
decimals = int(decimals)
except (ValueError, TypeError):
decimals = DEFAULT_DECIMALS
return max(MIN_DECIMALS, min(MAX_DECIMALS, decimals))
def fetch_iso_4217_data():
"""
Fetch ISO 4217 currency data to get minor units (decimal places).
Returns a dict mapping currency code to minor units.
"""
# Log the resolved URL for transparency
logging.info("Fetching ISO 4217 data from: %s", ISO_4217_URL)
if not ISO_4217_URL.lower().startswith("https://"):
logging.error("Refusing non-HTTPS ISO_4217_URL: %s", ISO_4217_URL)
return {}
session = requests.Session()
retries = Retry(
total=3,
backoff_factor=1,
status_forcelist=[429, 500, 502, 503, 504],
allowed_methods=frozenset(['GET'])
)
session.mount('https://', HTTPAdapter(max_retries=retries))
try:
# Add Accept header for CSV content
headers = {'Accept': 'text/csv'}
resp = session.get(ISO_4217_URL, timeout=TIMEOUT, headers=headers)
resp.raise_for_status()
except requests.exceptions.RequestException as e:
logging.error("Failed to fetch ISO 4217 data: %s", e)
return {}
# Parse CSV data
iso_data = {}
try:
# Decode with utf-8-sig to strip BOM if present
csv_content = resp.content.decode('utf-8-sig')
csv_reader = csv.DictReader(io.StringIO(csv_content))
for row in csv_reader:
code = row.get('AlphabeticCode', '').strip()
minor_unit = row.get('MinorUnit', '').strip()
if code and minor_unit != 'N.A.':
try:
# Convert minor unit to int (decimal places)
iso_data[code] = int(minor_unit) if minor_unit.isdigit() else 2
except (ValueError, TypeError):
iso_data[code] = 2 # Default to 2 if parsing fails
logging.info("Successfully loaded decimal data for %d currencies from ISO 4217", len(iso_data))
return iso_data
except Exception as e:
logging.error("Failed to parse ISO 4217 CSV data: %s", e)
return {}
import json
import os
def fetch_currencies():
# First, fetch ISO 4217 data for decimal places
iso_data = fetch_iso_4217_data()
session = requests.Session()
retries = Retry(
total=3,
backoff_factor=1,
status_forcelist=[429, 500, 502, 503, 504],
allowed_methods=frozenset(['GET'])
)
session.mount('https://', HTTPAdapter(max_retries=retries))
try:
resp = session.get(API_URL, timeout=TIMEOUT)
resp.raise_for_status()
response = requests.get('https://restcountries.com/v3.1/all?fields=name,common,currencies')
response.raise_for_status()
except requests.exceptions.RequestException as e:
logging.error("API request failed: %s", e)
return None # signal fatal
print(f"An error occurred while making the request: {e}")
return []
try:
countries = resp.json()
except ValueError as e:
logging.error("Failed to parse JSON response: %s", e)
return None # signal fatal
countries = response.json()
except json.JSONDecodeError:
print("Failed to decode JSON from the response.")
return []
results = []
currencies_list = []
for country in countries:
country_name = country.get('name', {}).get('common') or "Unknown"
for code, info in country.get('currencies', {}).items():
# Get decimal places using the helper function
decimals = get_currency_decimals(code, iso_data)
results.append({
'code': code,
'local': country_name,
'symbol': info.get('symbol', ''),
'name': info.get('name', ''),
'decimals': decimals
country_name = country.get('name', {}).get('common')
country_currencies = country.get('currencies', {})
for currency_code, currency_info in country_currencies.items():
symbol = currency_info.get('symbol', '')
currencies_list.append({
'code': currency_code,
'local': country_name,
'symbol': symbol,
'name': currency_info.get('name')
})
# sort by country name for consistency
return sorted(results, key=lambda x: x['local'].lower())
return currencies_list
def load_existing(path: Path):
if not path.exists():
return []
def save_currencies(currencies, file_path):
# Sort the list by the "local" field
sorted_currencies = sorted(currencies, key=lambda x: x['local'].lower() if x['local'] else "")
try:
with path.open('r', encoding='utf-8') as f:
os.makedirs(os.path.dirname(file_path), exist_ok=True)
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(sorted_currencies, f, ensure_ascii=False, indent=4)
except IOError as e:
print(f"An error occurred while writing to the file: {e}")
def load_existing_currencies(file_path):
try:
with open(file_path, 'r', encoding='utf-8') as f:
return json.load(f)
except (IOError, ValueError) as e:
logging.warning("Could not load existing file (%s): %s", path, e)
return []
def save_currencies(data, path: Path):
path.parent.mkdir(parents=True, exist_ok=True)
with path.open('w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=4)
logging.info("Wrote %d entries to %s", len(data), path)
except (IOError, json.JSONDecodeError):
return [] # Return an empty list if file doesn't exist or is invalid
def main():
setup_logging()
logging.info("🔄 Starting currency update")
existing = load_existing(SAVE_PATH)
new = fetch_currencies()
# Fatal API / parse error → exit non-zero so the workflow will fail
if new is None:
logging.error("Aborting: failed to fetch or parse API data.")
sys.exit(1)
# Empty array → log & exit zero (no file change)
if not new:
logging.warning("API returned empty list; skipping write.")
sys.exit(0)
# Identical to existing → nothing to do
if new == existing:
logging.info("Up-to-date; skipping write.")
sys.exit(0)
# Otherwise actually overwrite
save_currencies(new, SAVE_PATH)
logging.info("✅ Currency file updated.")
save_path = 'backend/internal/core/currencies/currencies.json'
existing_currencies = load_existing_currencies(save_path)
new_currencies = fetch_currencies()
if new_currencies == existing_currencies:
print("Currencies up-to-date with API, skipping commit.")
else:
save_currencies(new_currencies, save_path)
print("Currencies updated and saved.")
if __name__ == "__main__":
main()

View File

@@ -1,20 +1,21 @@
name: Publish Release Binaries
on:
workflow_dispatch:
push:
tags: [ 'v*.*.*' ]
jobs:
# backend-tests:
# name: "Backend Server Tests"
# uses: sysadminsmedia/homebox/.github/workflows/partial-backend.yaml@main
# frontend-tests:
# name: "Frontend and End-to-End Tests"
# uses: sysadminsmedia/homebox/.github/workflows/partial-frontend.yaml@main
goreleaser:
name: goreleaser
runs-on: ubuntu-latest
outputs:
hashes: ${{ steps.binary.outputs.hashes }}
permissions:
contents: write
packages: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -23,111 +24,24 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.24"
cache-dependency-path: backend/go.mod
- uses: pnpm/action-setup@v2
with:
version: 9.15.3
version: 7.30.1
- name: Build Frontend and Copy to Backend
working-directory: frontend
run: |
pnpm install
pnpm install --shamefully-hoist
pnpm run build
cp -r ./.output/public ../backend/app/api/static/
- name: Install CoSign
working-directory: backend
run: |
go install github.com/sigstore/cosign/cmd/cosign@latest
- name: Install Syft
working-directory: backend
run: |
go install github.com/anchore/syft/cmd/syft@latest
- name: Run GoReleaser
id: releaser
if: startsWith(github.ref, 'refs/tags/')
uses: goreleaser/goreleaser-action@v5
with:
workdir: "backend"
distribution: goreleaser
version: "~> v2"
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COSIGN_PWD: ${{ secrets.COSIGN_PWD }}
COSIGN_YES: "true"
- name: Generate binary hashes
if: startsWith(github.ref, 'refs/tags/')
id: binary
env:
ARTIFACTS: "${{ steps.releaser.outputs.artifacts }}"
run: |
set -euo pipefail
checksum_file=$(echo "$ARTIFACTS" | jq -r '.[] | select (.type=="Checksum") | .path')
echo "hashes=$(cat $checksum_file | base64 -w0)" >> "$GITHUB_OUTPUT"
- name: Run GoReleaser No Release
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
uses: goreleaser/goreleaser-action@v5
with:
workdir: "backend"
distribution: goreleaser
version: "~> v2"
args: release --clean --snapshot --skip=publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COSIGN_PWD: ${{ secrets.COSIGN_PWD }}
COSIGN_YES: "true"
binary-provenance:
if: startsWith(github.ref, 'refs/tags/')
needs: [ goreleaser ]
permissions:
actions: read # To read the workflow path.
id-token: write # To sign the provenance.
contents: write # To add assets to a release.
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.9.0
with:
base64-subjects: "${{ needs.goreleaser.outputs.hashes }}"
upload-assets: true # upload to a new release
verification-with-slsa-verifier:
if: startsWith(github.ref, 'refs/tags/')
needs: [goreleaser, binary-provenance]
runs-on: ubuntu-latest
permissions: read-all
steps:
- name: Install the verifier
uses: slsa-framework/slsa-verifier/actions/installer@v2.4.0
- name: Download assets
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PROVENANCE: "${{ needs.binary-provenance.outputs.provenance-name }}"
run: |
set -euo pipefail
gh -R "$GITHUB_REPOSITORY" release download "$GITHUB_REF_NAME" -p "*.tar.gz"
gh -R "$GITHUB_REPOSITORY" release download "$GITHUB_REF_NAME" -p "*.zip"
gh -R "$GITHUB_REPOSITORY" release download "$GITHUB_REF_NAME" -p "$PROVENANCE"
- name: Verify assets
env:
CHECKSUMS: ${{ needs.goreleaser.outputs.hashes }}
PROVENANCE: "${{ needs.binary-provenance.outputs.provenance-name }}"
run: |
set -euo pipefail
checksums=$(echo "$CHECKSUMS" | base64 -d)
while read -r line; do
fn=$(echo $line | cut -d ' ' -f2)
echo "Verifying $fn"
slsa-verifier verify-artifact --provenance-path "$PROVENANCE" \
--source-uri "github.com/$GITHUB_REPOSITORY" \
--source-tag "$GITHUB_REF_NAME" \
"$fn"
done <<<"$checksums"

View File

@@ -7,35 +7,46 @@ on:
jobs:
delete-old-images-main:
name: Delete Old Images for Main Repo
name: Delete Untagged Images
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- uses: dataaxiom/ghcr-cleanup-action@v1
- name: Fetch multi-platform package version SHAs
id: multi-arch-digests
run: |
package1=$(docker manifest inspect ghcr.io/sysadminsmedia/homebox | jq -r '.manifests.[] | .digest' | paste -s -d ' ' -)
echo "multi-arch-digests=$package1" >> $GITHUB_OUTPUT
- uses: snok/container-retention-policy@v3.0.0
with:
dry-run: true
delete-ghost-images: true
delete-partial-images: true
delete-orphaned-images: true
delete-untagged: true
validate: true
token: '${{ github.token }}'
package: homebox
use-regex: true
exclude-tags: latest,latest-rootless,main,main-rootless,nightly,nightly-rootless,*.*.*,0.*,0,*.*.*-rootless,0.*-rootless,0-rootless
older-than: 180 days
skip-shas: ${{ steps.multi-arch-digests.outputs.multi-arch-digests }}
# The type of account. Can be either 'org' or 'personal'.
account: sysadminsmedia
# Image name to delete. Supports passing several names as a comma-separated list.
image-names: homebox
# The cut-off for which to delete images older than. For example '2 days ago UTC'. Timezone is required.
cut-off: 90d
# Personal access token with read and delete scopes.
token: ${{ secrets.CLEANUP_PAT }}
# Restrict deletions to images without specific tags. Supports Unix-shell style wildcards
skip-tags: "!latest,!latest-rootless,!0.*,!0.*-rootless,!main,!main-rootless,!vnext,!vnext-rootless,!0,!0-rootless" # optional
# Do not actually delete images. Print output showing what would have been deleted.
dry-run: true # optional, default is false
delete-old-images-devcache:
name: Delete Old Devcache Images
name: Delete Cache Old Images
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- uses: dataaxiom/ghcr-cleanup-action@v1
- uses: snok/container-retention-policy@v3.0.0
with:
dry-run: false
delete-untagged: true
token: '${{ github.token }}'
package: devcache
older-than: 90 days
# The type of account. Can be either 'org' or 'personal'.
account: sysadminsmedia
image-names: devcache
# The cut-off for which to delete images older than. For example '2 days ago UTC'. Timezone is required.
cut-off: 90d
# Personal access token with read and delete scopes.
token: ${{ secrets.CLEANUP_PAT }}
# Do not actually delete images. Print output showing what would have been deleted.
dry-run: true # optional, default is false

View File

@@ -1,52 +0,0 @@
name: "Copilot Setup Steps"
# Automatically run the setup steps when they are changed to allow for easy validation, and
# allow manual testing through the repository's "Actions" tab
on:
workflow_dispatch:
push:
paths:
- .github/workflows/copilot-setup-steps.yml
pull_request:
paths:
- .github/workflows/copilot-setup-steps.yml
jobs:
# The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot.
copilot-setup-steps:
runs-on: ubuntu-latest
# Set the permissions to the lowest permissions possible needed for your steps.
# Copilot will be given its own token for its operations.
permissions:
# If you want to clone the repository as part of your setup steps, for example to install dependencies, you'll need the `contents: read` permission. If you don't clone the repository in your setup steps, Copilot will do this for you automatically after the steps complete.
contents: read
# You can define any steps you want, and they will run before the agent starts.
# If you do not check out your code, Copilot will do this for you.
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
- uses: pnpm/action-setup@v3.0.0
with:
version: 9.12.2
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.24"
cache-dependency-path: backend/go.mod
- name: Install Task
uses: arduino/setup-task@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Perform setup
run: task setup

View File

@@ -1,248 +0,0 @@
name: Docker publish hardened
on:
schedule:
- cron: '00 0 * * *'
push:
branches: [ "main" ]
paths:
- 'backend/**'
- 'frontend/**'
- 'Dockerfile.hardened'
- '.dockerignore'
- '.github/workflows/docker-publish-hardened.yaml'
tags: [ 'v*.*.*' ]
pull_request:
branches: [ "main" ]
paths:
- 'backend/**'
- 'frontend/**'
- 'Dockerfile.hardened'
- '.dockerignore'
- '.github/workflows/docker-publish-hardened.yaml'
permissions:
contents: read # Access to repository contents
packages: write # Write access for pushing to GHCR
id-token: write # Required for OIDC authentication (if used)
attestations: write # Required for signing and attestation (if needed)
env:
DOCKERHUB_REPO: sysadminsmedia/homebox
GHCR_REPO: ghcr.io/${{ github.repository }}
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
attestations: write
strategy:
fail-fast: false
matrix:
platform:
- linux/amd64
- linux/arm64
- linux/arm/v7
steps:
- name: Enable Debug Logs
run: echo "##[debug]Enabling debug logging"
env:
ACTIONS_RUNNER_DEBUG: true
ACTIONS_STEP_DEBUG: true
- name: Checkout repository
uses: actions/checkout@v4
- name: Prepare
run: |
echo "BUILD_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> $GITHUB_ENV
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
branch=${{ github.event.pull_request.number || github.ref_name }}
echo "BRANCH=${branch//\//-}" >> $GITHUB_ENV
echo "DOCKERNAMES=${{ env.DOCKERHUB_REPO }},${{ env.GHCR_REPO }}" >> $GITHUB_ENV
if [[ "${{ github.event_name }}" != "schedule" ]] || [[ "${{ github.ref }}" != refs/tags/* ]]; then
echo "DOCKERNAMES=${{ env.GHCR_REPO }}" >> $GITHUB_ENV
fi
- name: Docker meta
id: meta
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f
with:
images: |
name=${{ env.DOCKERHUB_REPO }},enable=${{ github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/') }}
name=${{ env.GHCR_REPO }}
- name: Login to Docker Hub
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1
if: (github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/'))
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GHCR
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392
with:
image: ghcr.io/sysadminsmedia/binfmt:latest
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
with:
driver-opts: |
image=ghcr.io/sysadminsmedia/buildkit:master
- name: Build and push by digest
id: build
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
with:
context: . # Explicitly specify the build context
file: ./Dockerfile.hardened # Explicitly specify the Dockerfile
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,"name=${{ env.DOCKERNAMES }}",push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }}
cache-from: type=registry,ref=ghcr.io/sysadminsmedia/devcache:${{ env.PLATFORM_PAIR }}-${{ env.BRANCH }}-hardened
cache-to: type=registry,ref=ghcr.io/sysadminsmedia/devcache:${{ env.PLATFORM_PAIR }}-${{ env.BRANCH }}-hardened,mode=max,ignore-error=true
build-args: |
VERSION=${{ github.ref_name }}
COMMIT=${{ github.sha }}
BUILD_TIME=${{ env.BUILD_TIME }}
provenance: mode=max
sbom: true
annotations: ${{ steps.meta.outputs.annotations }}
- name: Attest platform-specific images
uses: actions/attest-build-provenance@v1
if: github.event_name != 'pull_request'
with:
subject-name: ${{ env.GHCR_REPO }}
subject-digest: ${{ steps.build.outputs.digest }}
push-to-registry: true
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
merge:
if: github.event_name != 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
attestations: write
needs:
- build
steps:
- name: Download digests
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
path: /tmp/digests
pattern: digests-*
merge-multiple: true
- name: Login to Docker Hub
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1
if: (github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/'))
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GHCR
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
with:
driver-opts: |
image=ghcr.io/sysadminsmedia/buildkit:master
- name: Docker meta
id: meta
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f
with:
images: |
name=${{ env.DOCKERHUB_REPO }},enable=${{ github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/') }}
name=${{ env.GHCR_REPO }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=schedule,pattern=nightly
flavor: |
suffix=-hardened,onlatest=true
- name: Create manifest list and push GHCR
id: push-ghcr
working-directory: /tmp/digests
run: |
set -euo pipefail
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.GHCR_REPO }}@sha256:%s ' *) 2>&1 | tee /tmp/push-ghcr.out
digest=$(grep -oE 'sha256:[a-f0-9]{64}' /tmp/push-ghcr.out | head -n1 || true)
if [ -z "$digest" ]; then
echo "No digest found in imagetools output:"
cat /tmp/push-ghcr.out
exit 1
fi
echo "digest=$digest" >> $GITHUB_OUTPUT
- name: Attest GHCR images
uses: actions/attest-build-provenance@v1
if: github.event_name != 'pull_request'
with:
subject-name: ${{ env.GHCR_REPO }}
subject-digest: ${{ steps.push-ghcr.outputs.digest }}
push-to-registry: true
- name: Create manifest list and push Dockerhub
id: push-dockerhub
working-directory: /tmp/digests
if: (github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/'))
run: |
set -euo pipefail
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.DOCKERHUB_REPO }}@sha256:%s ' *) 2>&1 | tee /tmp/push-dockerhub.out
digest=$(grep -oE 'sha256:[a-f0-9]{64}' /tmp/push-dockerhub.out | head -n1 || true)
if [ -z "$digest" ]; then
echo "No digest found in imagetools output:"
cat /tmp/push-dockerhub.out
exit 1
fi
echo "digest=$digest" >> $GITHUB_OUTPUT
- name: Attest Dockerhub images
uses: actions/attest-build-provenance@v1
if: (github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/'))
with:
subject-name: ${{ env.DOCKERHUB_REPO }}
subject-digest: ${{ steps.push-dockerhub.outputs.digest }}
push-to-registry: true

View File

@@ -8,7 +8,7 @@ on:
paths:
- 'backend/**'
- 'frontend/**'
- 'Dockerfile.rootless'
- 'Dockerfile'
- '.dockerignore'
- '.github/workflows/docker-publish-rootless.yaml'
ignore:
@@ -19,7 +19,7 @@ on:
paths:
- 'backend/**'
- 'frontend/**'
- 'Dockerfile.rootless'
- 'Dockerfile'
- '.dockerignore'
- '.github/workflows/docker-publish-rootless.yaml'
ignore:
@@ -33,7 +33,7 @@ permissions:
env:
DOCKERHUB_REPO: sysadminsmedia/homebox
GHCR_REPO: ghcr.io/${{ github.repository }}
GHCR_REPO: ghcr.io/sysadminsmedia/homebox
jobs:
build:
@@ -83,7 +83,7 @@ jobs:
- name: Login to Docker Hub
uses: docker/login-action@v3
if: (github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/'))
if: github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/')
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
@@ -98,13 +98,13 @@ jobs:
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
image: ghcr.io/sysadminsmedia/binfmt:latest
image: ghcr.io/amitie10g/binfmt:latest
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver-opts: |
image=ghcr.io/sysadminsmedia/buildkit:master
image=ghcr.io/amitie10g/buildkit:master
- name: Build and push by digest
id: build
@@ -120,18 +120,10 @@ jobs:
build-args: |
VERSION=${{ github.ref_name }}
COMMIT=${{ github.sha }}
provenance: mode=max
provenance: true
sbom: true
annotations: ${{ steps.meta.outputs.annotations }}
- name: Attest platform-specific images
uses: actions/attest-build-provenance@v1
if: github.event_name != 'pull_request'
with:
subject-name: ${{ env.GHCR_REPO }}
subject-digest: ${{ steps.build.outputs.digest }}
push-to-registry: true
- name: Export digest
run: |
mkdir -p /tmp/digests
@@ -167,7 +159,7 @@ jobs:
- name: Login to Docker Hub
uses: docker/login-action@v3
if: (github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/'))
if: github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/')
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
@@ -183,7 +175,7 @@ jobs:
uses: docker/setup-buildx-action@v3
with:
driver-opts: |
image=ghcr.io/sysadminsmedia/buildkit:master
image=ghcr.io/amitie10g/buildkit:master
- name: Docker meta
id: meta
@@ -206,45 +198,13 @@ jobs:
id: push-ghcr
working-directory: /tmp/digests
run: |
set -euo pipefail
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.GHCR_REPO }}@sha256:%s ' *) 2>&1 | tee /tmp/push-ghcr.out
digest=$(grep -oE 'sha256:[a-f0-9]{64}' /tmp/push-ghcr.out | head -n1 || true)
if [ -z "$digest" ]; then
echo "No digest found in imagetools output:"
cat /tmp/push-ghcr.out
exit 1
fi
echo "digest=$digest" >> $GITHUB_OUTPUT
- name: Attest GHCR images
uses: actions/attest-build-provenance@v1
if: github.event_name != 'pull_request'
with:
subject-name: ${{ env.GHCR_REPO }}
subject-digest: ${{ steps.push-ghcr.outputs.digest }}
push-to-registry: true
$(printf '${{ env.GHCR_REPO }}@sha256:%s ' *)
- name: Create manifest list and push Dockerhub
id: push-dockerhub
working-directory: /tmp/digests
if: (github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/'))
if: github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/')
run: |
set -euo pipefail
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.DOCKERHUB_REPO }}@sha256:%s ' *) 2>&1 | tee /tmp/push-dockerhub.out
digest=$(grep -oE 'sha256:[a-f0-9]{64}' /tmp/push-dockerhub.out | head -n1 || true)
if [ -z "$digest" ]; then
echo "No digest found in imagetools output:"
cat /tmp/push-dockerhub.out
exit 1
fi
echo "digest=$digest" >> $GITHUB_OUTPUT
- name: Attest Dockerhub images
uses: actions/attest-build-provenance@v1
if: (github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/'))
with:
subject-name: ${{ env.DOCKERHUB_REPO }}
subject-digest: ${{ steps.push-dockerhub.outputs.digest }}
push-to-registry: true
$(printf '${{ env.DOCKERHUB_REPO }}@sha256:%s ' *)

View File

@@ -27,7 +27,7 @@ on:
env:
DOCKERHUB_REPO: sysadminsmedia/homebox
GHCR_REPO: ghcr.io/${{ github.repository }}
GHCR_REPO: ghcr.io/sysadminsmedia/homebox
permissions:
contents: read # Access to repository contents
@@ -78,7 +78,7 @@ jobs:
- name: Login to Docker Hub
uses: docker/login-action@v3
if: (github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/'))
if: github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/')
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
@@ -93,13 +93,13 @@ jobs:
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
image: ghcr.io/sysadminsmedia/binfmt:latest
image: ghcr.io/amitie10g/binfmt:latest
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver-opts: |
image=ghcr.io/sysadminsmedia/buildkit:latest
image=ghcr.io/amitie10g/buildkit:master
- name: Build and push by digest
id: build
@@ -113,18 +113,10 @@ jobs:
build-args: |
VERSION=${{ github.ref_name }}
COMMIT=${{ github.sha }}
provenance: mode=max
provenance: true
sbom: true
annotations: ${{ steps.meta.outputs.annotations }}
- name: Attest platform-specific images
uses: actions/attest-build-provenance@v1
if: github.event_name != 'pull_request'
with:
subject-name: ${{ env.GHCR_REPO }}
subject-digest: ${{ steps.build.outputs.digest }}
push-to-registry: true
- name: Export digest
run: |
mkdir -p /tmp/digests
@@ -160,7 +152,6 @@ jobs:
- name: Login to Docker Hub
uses: docker/login-action@v3
if: (github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/'))
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
@@ -176,7 +167,7 @@ jobs:
uses: docker/setup-buildx-action@v3
with:
driver-opts: |
image=ghcr.io/sysadminsmedia/buildkit:master
image=ghcr.io/amitie10g/buildkit:master
- name: Docker meta
id: meta
@@ -197,45 +188,14 @@ jobs:
id: push-ghcr
working-directory: /tmp/digests
run: |
set -euo pipefail
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.GHCR_REPO }}@sha256:%s ' *) 2>&1 | tee /tmp/push-ghcr.out
digest=$(grep -oE 'sha256:[a-f0-9]{64}' /tmp/push-ghcr.out | head -n1 || true)
if [ -z "$digest" ]; then
echo "No digest found in imagetools output:"
cat /tmp/push-ghcr.out
exit 1
fi
echo "digest=$digest" >> $GITHUB_OUTPUT
- name: Attest GHCR images
uses: actions/attest-build-provenance@v1
if: github.event_name != 'pull_request'
with:
subject-name: ${{ env.GHCR_REPO }}
subject-digest: ${{ steps.push-ghcr.outputs.digest }}
push-to-registry: true
$(printf '${{ env.GHCR_REPO }}@sha256:%s ' *)
- name: Create manifest list and push Dockerhub
id: push-dockerhub
working-directory: /tmp/digests
if: (github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/'))
if: github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/')
run: |
set -euo pipefail
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.DOCKERHUB_REPO }}@sha256:%s ' *) 2>&1 | tee /tmp/push-dockerhub.out
digest=$(grep -oE 'sha256:[a-f0-9]{64}' /tmp/push-dockerhub.out | head -n1 || true)
if [ -z "$digest" ]; then
echo "No digest found in imagetools output:"
cat /tmp/push-dockerhub.out
exit 1
fi
echo "digest=$digest" >> $GITHUB_OUTPUT
- name: Attest Dockerhub images
uses: actions/attest-build-provenance@v1
if: (github.event_name == 'schedule' || startsWith(github.ref, 'refs/tags/'))
with:
subject-name: ${{ env.DOCKERHUB_REPO }}
subject-digest: ${{ steps.push-dockerhub.outputs.digest }}
push-to-registry: true
$(printf '${{ env.DOCKERHUB_REPO }}@sha256:%s ' *)

View File

@@ -1,95 +0,0 @@
name: E2E (Playwright)
on:
workflow_call:
jobs:
playwright-tests:
timeout-minutes: 60
strategy:
matrix:
shardIndex: [1,2,3,4]
shardTotal: [4]
name: E2E Playwright Testing ${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Task
uses: arduino/setup-task@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.23"
cache-dependency-path: backend/go.mod
- uses: actions/setup-node@v4
with:
node-version: lts/*
- uses: pnpm/action-setup@v3.0.0
with:
version: 9.12.2
- name: Install dependencies
run: pnpm install
working-directory: frontend
- name: Install Go Dependencies
run: go mod download
working-directory: backend
- name: Run E2E Tests
run: task test:e2e -- --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
- uses: actions/upload-artifact@v4
name: Upload partial Playwright report
if: ${{ !cancelled() }}
with:
name: blob-report-${{ matrix.shardIndex }}
path: frontend/blob-report/
retention-days: 2
merge-reports:
# Merge reports after playwright-tests, even if some shards have failed
if: ${{ !cancelled() }}
needs: [playwright-tests]
name: Merge Playwright Reports
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: lts/*
- uses: pnpm/action-setup@v3.0.0
with:
version: 9.12.2
- name: Install dependencies
run: pnpm install
working-directory: frontend
- name: Download blob reports from GitHub Actions Artifacts
uses: actions/download-artifact@v4
with:
path: frontend/all-blob-reports
pattern: blob-report-*
merge-multiple: true
- name: Merge into HTML Report
run: pnpm exec playwright merge-reports --reporter html,github ./all-blob-reports
working-directory: frontend
- name: Upload HTML report
uses: actions/upload-artifact@v4
with:
name: html-report--attempt-${{ github.run_attempt }}
path: frontend/playwright-report
retention-days: 30

View File

@@ -12,8 +12,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.24"
cache-dependency-path: backend/go.mod
go-version: "1.21"
- name: Install Task
uses: arduino/setup-task@v1
@@ -21,7 +20,7 @@ jobs:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: golangci-lint
uses: golangci/golangci-lint-action@v7
uses: golangci/golangci-lint-action@v4
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
@@ -35,3 +34,8 @@ jobs:
- name: Test
run: task go:coverage
- name: Validate OpenAPI definition
uses: swaggerexpert/swagger-editor-validate@v1
with:
definition-file: backend/app/api/static/docs/swagger.json

View File

@@ -1,4 +1,4 @@
name: Frontend
name: Frontend / E2E
on:
workflow_call:
@@ -18,7 +18,7 @@ jobs:
version: 9.12.2
- name: Install dependencies
run: pnpm install
run: pnpm install --shamefully-hoist
working-directory: frontend
- name: Run Lint
@@ -60,8 +60,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.23"
cache-dependency-path: backend/go.mod
go-version: "1.21"
- uses: actions/setup-node@v4
with:
@@ -111,12 +110,11 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.23"
cache-dependency-path: backend/go.mod
go-version: "1.21"
- uses: actions/setup-node@v4
with:
node-version: lts/*
node-version: 18
- uses: pnpm/action-setup@v3.0.0
with:

View File

@@ -9,10 +9,7 @@ on:
paths:
- 'backend/**'
- 'frontend/**'
- '.github/workflows/partial-backend.yaml'
- '.github/workflows/partial-frontend.yaml'
- '.github/workflows/e2e-partial.yaml'
- '.github/workflows/pull-requests.yaml'
- '.github/workflows/**'
jobs:
backend-tests:
@@ -20,9 +17,5 @@ jobs:
uses: ./.github/workflows/partial-backend.yaml
frontend-tests:
name: "Frontend Tests"
uses: ./.github/workflows/partial-frontend.yaml
e2e-tests:
name: "End-to-End Playwright Tests"
uses: ./.github/workflows/e2e-partial.yaml
name: "Frontend and End-to-End Tests"
uses: ./.github/workflows/partial-frontend.yaml

View File

@@ -2,12 +2,8 @@ name: Update Currencies
on:
push:
branches: [ main ]
workflow_dispatch:
permissions:
contents: write
pull-requests: write
branches:
- main
jobs:
update-currencies:
@@ -15,46 +11,90 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v2
with:
python-version: '3.8'
cache: 'pip'
cache-dependency-path: .github/workflows/update-currencies/requirements.txt
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r .github/workflows/update-currencies/requirements.txt
pip install requests
- name: Run currency update script
- name: Run currency fetch script
run: python .github/scripts/update_currencies.py
- name: Check for currencies.json changes
- name: Check for changes
id: check_changes
run: |
if git diff --quiet -- backend/internal/core/currencies/currencies.json; then
echo "changed=false" >> $GITHUB_ENV
if [[ $(git status --porcelain) ]]; then
echo "Changes detected."
echo "changes=true" >> $GITHUB_ENV
else
echo "changed=true" >> $GITHUB_ENV
echo "No changes detected."
echo "changes=false" >> $GITHUB_ENV
fi
- name: Create Pull Request
if: env.changed == 'true'
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: update-currencies
base: main
title: "Update currencies.json"
commit-message: "chore: update currencies.json"
path: .
add-paths: |
backend/internal/core/currencies/currencies.json
- name: Delete existing update-currencies branch
run: |
if git show-ref --verify --quiet refs/heads/update-currencies; then
git branch -D update-currencies
echo "Deleted existing update-currencies branch."
else
echo "No existing update-currencies branch to delete."
fi
- name: No updates needed
if: env.changed == 'false'
run: echo "✅ currencies.json is already up-to-date"
- name: Create new update-currencies branch
if: env.changes == 'true'
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
# Create a new branch
git checkout -b update-currencies
git add backend/internal/core/currencies/currencies.json
git commit -m "Update currencies.json"
# Fetch the latest changes from the remote
git fetch origin
# Attempt to rebase with the latest changes
if git show-ref --verify --quiet refs/remotes/origin/update-currencies; then
if ! git rebase origin/update-currencies; then
echo "Rebase conflicts occurred. Please resolve them manually."
echo "To resolve conflicts, check out the 'update-currencies' branch locally."
exit 1
fi
else
echo "No existing remote branch 'update-currencies'. Skipping rebase."
fi
# Push the new branch to the remote
if ! git push --set-upstream origin update-currencies; then
echo "Push failed, trying to fetch and rebase again."
git fetch origin
if git show-ref --verify --quiet refs/remotes/origin/update-currencies; then
if ! git rebase origin/update-currencies; then
echo "Second rebase failed. Please resolve manually."
exit 1
fi
else
echo "No existing remote branch 'update-currencies'. Skipping rebase."
fi
if ! git push --set-upstream origin update-currencies; then
echo "Second push failed. Please resolve manually."
exit 1
fi
fi
# Create a pull request
curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-X POST \
-d '{"title": "Update currencies", "head": "update-currencies", "base": "main"}' \
https://api.github.com/repos/${{ github.repository }}/pulls
- name: Notify no changes
if: env.changes == 'false'
run: echo "Currencies up-to-date with API, skipping commit."

View File

@@ -1 +0,0 @@
requests

8
.gitignore vendored
View File

@@ -60,10 +60,4 @@ backend/app/api/static/public/*
backend/api
docs/.vitepress/cache/
.data/
# Playwright
frontend/test-results/
frontend/playwright-report/
frontend/blob-report/
frontend/playwright/.cache/
/.data/

View File

@@ -1,603 +0,0 @@
include:
- template: Jobs/SAST.gitlab-ci.yml
- component: $CI_SERVER_FQDN/components/code-quality-oss/codequality-os-scanners-integration/codequality-oss@1.1.4
- component: $CI_SERVER_FQDN/components/code-intelligence/golang-code-intel@v0.3.1
- component: $CI_SERVER_FQDN/components/code-intelligence/typescript-code-intel@v0.3.1
inputs:
node_version: 24
- component: $CI_SERVER_FQDN/components/secret-detection/secret-detection@2.1.0
variables:
GITLAB_ADVANCED_SAST_ENABLED: 'true'
ADVANCED_SAST_PARTIAL_SCAN: 'differential'
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: "/certs"
# Registry configuration - adjust as needed
CI_REGISTRY_IMAGE: $CI_REGISTRY/$CI_PROJECT_PATH
stages:
- test
- build-binaries
- build-docker
- release
# ==========================================
# Test Jobs
# ==========================================
# Backend Tests (Go)
test:backend:
stage: test
image: golang:1.24
cache:
key:
files:
- backend/go.sum
paths:
- backend/.go-pkg-cache/
policy: pull-push
before_script:
- export GOMODCACHE=$(pwd)/backend/.go-pkg-cache
# Install Task
- sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin
script:
- cd backend
- task go:lint
- task go:build
- task go:coverage
coverage: '/coverage: \d+.\d+% of statements/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: backend/coverage.out
paths:
- backend/coverage.out
expire_in: 7 days
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
# Frontend Lint and Typecheck
test:frontend:lint:
stage: test
image: node:22-alpine
cache:
key:
files:
- frontend/pnpm-lock.yaml
paths:
- frontend/node_modules/
- .pnpm-store/
policy: pull-push
before_script:
- npm install -g pnpm@9.15.3
- pnpm config set store-dir $(pwd)/.pnpm-store
script:
- cd frontend
- pnpm install --frozen-lockfile
- pnpm run lint:ci
- pnpm run typecheck
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
# Frontend Integration Tests (SQLite)
test:frontend:integration:
stage: test
image: node:22
cache:
- key:
files:
- frontend/pnpm-lock.yaml
paths:
- frontend/node_modules/
- .pnpm-store/
policy: pull-push
- key:
files:
- backend/go.sum
paths:
- backend/.go-pkg-cache/
policy: pull-push
before_script:
- npm install -g pnpm@9.15.3
- pnpm config set store-dir $(pwd)/.pnpm-store
# Install Task
- sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin
# Install Go
- wget -q https://go.dev/dl/go1.24.0.linux-amd64.tar.gz
- tar -C /usr/local -xzf go1.24.0.linux-amd64.tar.gz
- export PATH=$PATH:/usr/local/go/bin
- export GOMODCACHE=$(pwd)/backend/.go-pkg-cache
script:
- cd frontend
- pnpm install --frozen-lockfile
- cd ..
- task test:ci
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
# Frontend Integration Tests (PostgreSQL Matrix)
test:frontend:integration:postgresql:
stage: test
image: node:22
services:
- name: postgres:${POSTGRES_VERSION}
alias: postgres
variables:
POSTGRES_USER: homebox
POSTGRES_PASSWORD: homebox
POSTGRES_DB: homebox
POSTGRES_HOST_AUTH_METHOD: trust
parallel:
matrix:
- POSTGRES_VERSION: ["17", "16", "15"]
cache:
- key:
files:
- frontend/pnpm-lock.yaml
paths:
- frontend/node_modules/
- .pnpm-store/
policy: pull-push
- key:
files:
- backend/go.sum
paths:
- backend/.go-pkg-cache/
policy: pull-push
before_script:
- npm install -g pnpm@9.15.3
- pnpm config set store-dir $(pwd)/.pnpm-store
# Install Task
- sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin
# Install Go
- wget -q https://go.dev/dl/go1.24.0.linux-amd64.tar.gz
- tar -C /usr/local -xzf go1.24.0.linux-amd64.tar.gz
- export PATH=$PATH:/usr/local/go/bin
- export GOMODCACHE=$(pwd)/backend/.go-pkg-cache
script:
- cd frontend
- pnpm install --frozen-lockfile
- cd ..
- task test:ci:postgresql
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
# E2E Tests (Playwright) - Sharded
test:e2e:playwright:
stage: test
image: mcr.microsoft.com/playwright:v1.48.2-jammy
timeout: 1h
parallel:
matrix:
- SHARD_INDEX: ["1", "2", "3", "4"]
SHARD_TOTAL: "4"
cache:
- key:
files:
- frontend/pnpm-lock.yaml
paths:
- frontend/node_modules/
- .pnpm-store/
policy: pull-push
- key:
files:
- backend/go.sum
paths:
- backend/.go-pkg-cache/
policy: pull-push
before_script:
- npm install -g pnpm@9.15.3
- pnpm config set store-dir $(pwd)/.pnpm-store
# Install Task
- sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin
# Install Go
- wget -q https://go.dev/dl/go1.24.0.linux-amd64.tar.gz
- tar -C /usr/local -xzf go1.24.0.linux-amd64.tar.gz
- export PATH=$PATH:/usr/local/go/bin
- export GOMODCACHE=$(pwd)/backend/.go-pkg-cache
script:
- cd frontend
- pnpm install --frozen-lockfile
- cd ..
- cd backend && go mod download
- task test:e2e -- --shard=$SHARD_INDEX/$SHARD_TOTAL
artifacts:
when: always
paths:
- frontend/blob-report/
expire_in: 2 days
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
# E2E Reports Merge
test:e2e:merge-reports:
stage: test
image: mcr.microsoft.com/playwright:v1.48.2-jammy
needs:
- test:e2e:playwright
cache:
key:
files:
- frontend/pnpm-lock.yaml
paths:
- frontend/node_modules/
- .pnpm-store/
policy: pull
before_script:
- npm install -g pnpm@9.15.3
- pnpm config set store-dir $(pwd)/.pnpm-store
script:
- cd frontend
- pnpm install --frozen-lockfile
# Download all blob reports
- mkdir -p all-blob-reports
# GitLab automatically downloads artifacts from dependencies
- cp -r ../frontend/blob-report/* all-blob-reports/ || true
- pnpm exec playwright merge-reports --reporter html,github ./all-blob-reports || true
artifacts:
when: always
paths:
- frontend/playwright-report/
expire_in: 30 days
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
when: always
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: always
# Update Currencies (Scheduled Job)
update:currencies:
stage: test
image: python:3.11
cache:
key: python-currencies
paths:
- .pip-cache/
before_script:
- pip install --cache-dir .pip-cache -r .github/workflows/update-currencies/requirements.txt
script:
- python .github/scripts/update_currencies.py
- |
if git diff --quiet -- backend/internal/core/currencies/currencies.json; then
echo "✅ currencies.json is already up-to-date"
exit 0
else
echo "Changes detected in currencies.json"
git config user.name "GitLab CI"
git config user.email "ci@gitlab.com"
git checkout -b update-currencies-$CI_COMMIT_SHORT_SHA
git add backend/internal/core/currencies/currencies.json
git commit -m "chore: update currencies.json"
git push -o merge_request.create -o merge_request.target=$CI_DEFAULT_BRANCH -o merge_request.title="Update currencies.json" origin update-currencies-$CI_COMMIT_SHORT_SHA
fi
rules:
- if: $CI_PIPELINE_SOURCE == "schedule" && $UPDATE_CURRENCIES == "true"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $UPDATE_CURRENCIES == "true"
# ==========================================
# Binary Build with GoReleaser
# ==========================================
build:binaries:
stage: build-binaries
image: golang:1.24
cache:
- key:
files:
- frontend/pnpm-lock.yaml
paths:
- frontend/node_modules/
- .pnpm-store/
policy: pull-push
- key:
files:
- backend/go.sum
paths:
- backend/.go-pkg-cache/
policy: pull-push
before_script:
# Install Node.js and pnpm for frontend build
- curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
- apt-get install -y nodejs
- npm install -g pnpm@9.15.3
# Configure pnpm store
- pnpm config set store-dir $(pwd)/.pnpm-store
# Install GoReleaser
- curl -sfL https://goreleaser.com/static/run | bash -s -- check
- curl -sfL https://goreleaser.com/static/run | bash -s -- --version
# Configure Go cache
- export GOMODCACHE=$(pwd)/backend/.go-pkg-cache
script:
# Build frontend
- cd frontend
- pnpm install --frozen-lockfile
- pnpm run build
- cp -r ./.output/public ../backend/app/api/static/
- cd ..
# Run GoReleaser
- cd backend
- |
if [ -n "$CI_COMMIT_TAG" ]; then
echo "Building release for tag: $CI_COMMIT_TAG"
curl -sfL https://goreleaser.com/static/run | bash -s -- release --clean --skip=publish
else
echo "Building snapshot"
curl -sfL https://goreleaser.com/static/run | bash -s -- release --clean --snapshot --skip=publish
fi
artifacts:
name: "homebox-binaries-$CI_COMMIT_REF_SLUG"
paths:
- backend/dist/
expire_in: 30 days
rules:
- if: $CI_COMMIT_TAG
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
# ==========================================
# Docker Build Jobs - Regular
# ==========================================
.docker_build_template:
stage: build-docker
image: docker:latest
services:
- docker:dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
variables:
DOCKER_BUILDKIT: 1
DOCKERFILE: Dockerfile
IMAGE_SUFFIX: ""
script:
- export VERSION=${CI_COMMIT_TAG:-$CI_COMMIT_REF_NAME}
- export COMMIT=$CI_COMMIT_SHA
- export BUILD_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)
- export CACHE_TAG=${IMAGE_SUFFIX:-regular}
# Build and push for the specific platform with layer caching
- |
docker buildx create --use --name builder-${CI_JOB_ID} || true
docker buildx build \
--platform $PLATFORM \
--build-arg VERSION=$VERSION \
--build-arg COMMIT=$COMMIT \
--build-arg BUILD_TIME=$BUILD_TIME \
--cache-from type=registry,ref=$CI_REGISTRY_IMAGE/cache:${PLATFORM_PAIR}-${CACHE_TAG}-$CI_COMMIT_REF_SLUG \
--cache-from type=registry,ref=$CI_REGISTRY_IMAGE/cache:${PLATFORM_PAIR}-${CACHE_TAG}-$CI_DEFAULT_BRANCH \
--cache-to type=registry,ref=$CI_REGISTRY_IMAGE/cache:${PLATFORM_PAIR}-${CACHE_TAG}-$CI_COMMIT_REF_SLUG,mode=max \
--file ./$DOCKERFILE \
--tag $CI_REGISTRY_IMAGE${IMAGE_SUFFIX}:${CI_COMMIT_REF_SLUG}-${PLATFORM_PAIR} \
--push \
.
docker buildx rm builder-${CI_JOB_ID} || true
rules:
- if: $CI_COMMIT_TAG
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
docker:build:amd64:
extends: .docker_build_template
variables:
PLATFORM: linux/amd64
PLATFORM_PAIR: linux-amd64
docker:build:arm64:
extends: .docker_build_template
variables:
PLATFORM: linux/arm64
PLATFORM_PAIR: linux-arm64
docker:build:armv7:
extends: .docker_build_template
variables:
PLATFORM: linux/arm/v7
PLATFORM_PAIR: linux-arm-v7
# ==========================================
# Docker Build Jobs - Rootless
# ==========================================
docker:build:rootless:amd64:
extends: .docker_build_template
variables:
PLATFORM: linux/amd64
PLATFORM_PAIR: linux-amd64
DOCKERFILE: Dockerfile.rootless
IMAGE_SUFFIX: -rootless
docker:build:rootless:arm64:
extends: .docker_build_template
variables:
PLATFORM: linux/arm64
PLATFORM_PAIR: linux-arm64
DOCKERFILE: Dockerfile.rootless
IMAGE_SUFFIX: -rootless
docker:build:rootless:armv7:
extends: .docker_build_template
variables:
PLATFORM: linux/arm/v7
PLATFORM_PAIR: linux-arm-v7
DOCKERFILE: Dockerfile.rootless
IMAGE_SUFFIX: -rootless
# ==========================================
# Docker Build Jobs - Hardened
# ==========================================
docker:build:hardened:amd64:
extends: .docker_build_template
variables:
PLATFORM: linux/amd64
PLATFORM_PAIR: linux-amd64
DOCKERFILE: Dockerfile.hardened
IMAGE_SUFFIX: -hardened
docker:build:hardened:arm64:
extends: .docker_build_template
variables:
PLATFORM: linux/arm64
PLATFORM_PAIR: linux-arm64
DOCKERFILE: Dockerfile.hardened
IMAGE_SUFFIX: -hardened
docker:build:hardened:armv7:
extends: .docker_build_template
variables:
PLATFORM: linux/arm/v7
PLATFORM_PAIR: linux-arm-v7
DOCKERFILE: Dockerfile.hardened
IMAGE_SUFFIX: -hardened
# ==========================================
# Docker Manifest Creation - Regular
# ==========================================
docker:manifest:
stage: release
image: docker:latest
services:
- docker:dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- export VERSION=${CI_COMMIT_TAG:-$CI_COMMIT_REF_NAME}
# Create manifest for regular image
- |
docker manifest create $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG \
$CI_REGISTRY_IMAGE:${CI_COMMIT_REF_SLUG}-linux-amd64 \
$CI_REGISTRY_IMAGE:${CI_COMMIT_REF_SLUG}-linux-arm64 \
$CI_REGISTRY_IMAGE:${CI_COMMIT_REF_SLUG}-linux-arm-v7
docker manifest push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
# Tag as latest on main branch or create version tags
- |
if [ "$CI_COMMIT_BRANCH" = "$CI_DEFAULT_BRANCH" ]; then
docker manifest create $CI_REGISTRY_IMAGE:latest \
$CI_REGISTRY_IMAGE:${CI_COMMIT_REF_SLUG}-linux-amd64 \
$CI_REGISTRY_IMAGE:${CI_COMMIT_REF_SLUG}-linux-arm64 \
$CI_REGISTRY_IMAGE:${CI_COMMIT_REF_SLUG}-linux-arm-v7
docker manifest push $CI_REGISTRY_IMAGE:latest
fi
- |
if [ -n "$CI_COMMIT_TAG" ]; then
# Create version tag
docker manifest create $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG \
$CI_REGISTRY_IMAGE:${CI_COMMIT_REF_SLUG}-linux-amd64 \
$CI_REGISTRY_IMAGE:${CI_COMMIT_REF_SLUG}-linux-arm64 \
$CI_REGISTRY_IMAGE:${CI_COMMIT_REF_SLUG}-linux-arm-v7
docker manifest push $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
# Create major.minor tag if semantic version
MAJOR_MINOR=$(echo $CI_COMMIT_TAG | sed -E 's/^v?([0-9]+\.[0-9]+)\..*/\1/')
if [ -n "$MAJOR_MINOR" ]; then
docker manifest create $CI_REGISTRY_IMAGE:$MAJOR_MINOR \
$CI_REGISTRY_IMAGE:${CI_COMMIT_REF_SLUG}-linux-amd64 \
$CI_REGISTRY_IMAGE:${CI_COMMIT_REF_SLUG}-linux-arm64 \
$CI_REGISTRY_IMAGE:${CI_COMMIT_REF_SLUG}-linux-arm-v7
docker manifest push $CI_REGISTRY_IMAGE:$MAJOR_MINOR
fi
fi
needs:
- docker:build:amd64
- docker:build:arm64
- docker:build:armv7
rules:
- if: $CI_COMMIT_TAG
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
# ==========================================
# Docker Manifest Creation - Rootless
# ==========================================
docker:manifest:rootless:
stage: release
image: docker:latest
services:
- docker:dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- export VERSION=${CI_COMMIT_TAG:-$CI_COMMIT_REF_NAME}
# Create manifest for rootless image
- |
docker manifest create $CI_REGISTRY_IMAGE-rootless:$CI_COMMIT_REF_SLUG \
$CI_REGISTRY_IMAGE-rootless:${CI_COMMIT_REF_SLUG}-linux-amd64 \
$CI_REGISTRY_IMAGE-rootless:${CI_COMMIT_REF_SLUG}-linux-arm64
docker manifest push $CI_REGISTRY_IMAGE-rootless:$CI_COMMIT_REF_SLUG
# Tag as latest on main branch or create version tags
- |
if [ "$CI_COMMIT_BRANCH" = "$CI_DEFAULT_BRANCH" ]; then
docker manifest create $CI_REGISTRY_IMAGE-rootless:latest \
$CI_REGISTRY_IMAGE-rootless:${CI_COMMIT_REF_SLUG}-linux-amd64 \
$CI_REGISTRY_IMAGE-rootless:${CI_COMMIT_REF_SLUG}-linux-arm64
docker manifest push $CI_REGISTRY_IMAGE-rootless:latest
fi
- |
if [ -n "$CI_COMMIT_TAG" ]; then
docker manifest create $CI_REGISTRY_IMAGE-rootless:$CI_COMMIT_TAG \
$CI_REGISTRY_IMAGE-rootless:${CI_COMMIT_REF_SLUG}-linux-amd64 \
$CI_REGISTRY_IMAGE-rootless:${CI_COMMIT_REF_SLUG}-linux-arm64
docker manifest push $CI_REGISTRY_IMAGE-rootless:$CI_COMMIT_TAG
MAJOR_MINOR=$(echo $CI_COMMIT_TAG | sed -E 's/^v?([0-9]+\.[0-9]+)\..*/\1/')
if [ -n "$MAJOR_MINOR" ]; then
docker manifest create $CI_REGISTRY_IMAGE-rootless:$MAJOR_MINOR \
$CI_REGISTRY_IMAGE-rootless:${CI_COMMIT_REF_SLUG}-linux-amd64 \
$CI_REGISTRY_IMAGE-rootless:${CI_COMMIT_REF_SLUG}-linux-arm64
docker manifest push $CI_REGISTRY_IMAGE-rootless:$MAJOR_MINOR
fi
fi
needs:
- docker:build:rootless:amd64
- docker:build:rootless:arm64
rules:
- if: $CI_COMMIT_TAG
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
# ==========================================
# Docker Manifest Creation - Hardened
# ==========================================
docker:manifest:hardened:
stage: release
image: docker:latest
services:
- docker:dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- export VERSION=${CI_COMMIT_TAG:-$CI_COMMIT_REF_NAME}
# Create manifest for hardened image
- |
docker manifest create $CI_REGISTRY_IMAGE-hardened:$CI_COMMIT_REF_SLUG \
$CI_REGISTRY_IMAGE-hardened:${CI_COMMIT_REF_SLUG}-linux-amd64 \
$CI_REGISTRY_IMAGE-hardened:${CI_COMMIT_REF_SLUG}-linux-arm64
docker manifest push $CI_REGISTRY_IMAGE-hardened:$CI_COMMIT_REF_SLUG
# Tag as latest on main branch or create version tags
- |
if [ "$CI_COMMIT_BRANCH" = "$CI_DEFAULT_BRANCH" ]; then
docker manifest create $CI_REGISTRY_IMAGE-hardened:latest \
$CI_REGISTRY_IMAGE-hardened:${CI_COMMIT_REF_SLUG}-linux-amd64 \
$CI_REGISTRY_IMAGE-hardened:${CI_COMMIT_REF_SLUG}-linux-arm64
docker manifest push $CI_REGISTRY_IMAGE-hardened:latest
fi
- |
if [ -n "$CI_COMMIT_TAG" ]; then
docker manifest create $CI_REGISTRY_IMAGE-hardened:$CI_COMMIT_TAG \
$CI_REGISTRY_IMAGE-hardened:${CI_COMMIT_REF_SLUG}-linux-amd64 \
$CI_REGISTRY_IMAGE-hardened:${CI_COMMIT_REF_SLUG}-linux-arm64
docker manifest push $CI_REGISTRY_IMAGE-hardened:$CI_COMMIT_TAG
MAJOR_MINOR=$(echo $CI_COMMIT_TAG | sed -E 's/^v?([0-9]+\.[0-9]+)\..*/\1/')
if [ -n "$MAJOR_MINOR" ]; then
docker manifest create $CI_REGISTRY_IMAGE-hardened:$MAJOR_MINOR \
$CI_REGISTRY_IMAGE-hardened:${CI_COMMIT_REF_SLUG}-linux-amd64 \
$CI_REGISTRY_IMAGE-hardened:${CI_COMMIT_REF_SLUG}-linux-arm64
docker manifest push $CI_REGISTRY_IMAGE-hardened:$MAJOR_MINOR
fi
fi
needs:
- docker:build:hardened:amd64
- docker:build:hardened:arm64
rules:
- if: $CI_COMMIT_TAG
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

8
.vscode/launch.json vendored
View File

@@ -16,12 +16,14 @@
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceFolder}/backend/app/api/",
"program": "${workspaceRoot}/backend/app/api/",
"args": [],
"env": {
"HBOX_DEMO": "true",
"HBOX_LOG_LEVEL": "debug",
"HBOX_DEBUG_ENABLED": "true"
"HBOX_DEBUG_ENABLED": "true",
"HBOX_STORAGE_DATA": "${workspaceRoot}/backend/.data",
"HBOX_STORAGE_SQLITE_URL": "${workspaceRoot}/backend/.data/homebox.db?_fk=1&_time_format=sqlite"
},
"console": "integratedTerminal",
},
@@ -44,4 +46,4 @@
"console": "integratedTerminal",
}
]
}
}

View File

@@ -4,7 +4,7 @@
},
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.patterns": {
"package.json": "package-lock.json, yarn.lock, eslint.config.mjs, tsconfig.json, .prettierrc, .editorconfig, pnpm-lock.yaml, postcss.config.js, tailwind.config.js",
"package.json": "package-lock.json, yarn.lock, .eslintrc.js, tsconfig.json, .prettierrc, .editorconfig, pnpm-lock.yaml, postcss.config.js, tailwind.config.js",
"docker-compose.yml": "Dockerfile, .dockerignore, docker-compose.dev.yml, docker-compose.yml",
"README.md": "LICENSE, SECURITY.md"
},
@@ -22,8 +22,6 @@
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"eslint.format.enable": true,
"eslint.validate": ["javascript", "typescript", "vue"],
"eslint.useFlatConfig": true,
"css.validate": false,
"tailwindCSS.includeLanguages": {
"vue": "html",

View File

@@ -33,6 +33,8 @@ If you're using `taskfile` you can run `task --list-all` for a list of all comma
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.
### API Development Notes
start command `task go:run`
@@ -44,7 +46,7 @@ start command `task go:run`
start command `task ui:dev`
1. The frontend is a Vue 3 app with Nuxt.js that uses Tailwind and Shadcn-vue for styling.
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.

View File

@@ -1,5 +1,5 @@
# Node dependencies stage
FROM public.ecr.aws/docker/library/node:22-alpine AS frontend-dependencies
FROM public.ecr.aws/docker/library/node:lts-alpine AS frontend-dependencies
WORKDIR /app
# Install pnpm globally (caching layer)
@@ -7,10 +7,10 @@ RUN npm install -g pnpm
# Copy package.json and lockfile to leverage caching
COPY frontend/package.json frontend/pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
RUN pnpm install --frozen-lockfile --shamefully-hoist
# Build Nuxt (frontend) stage
FROM public.ecr.aws/docker/library/node:22-alpine AS frontend-builder
FROM public.ecr.aws/docker/library/node:lts-alpine AS frontend-builder
WORKDIR /app
# Install pnpm globally again (it can reuse the cache if not changed)
@@ -31,8 +31,6 @@ RUN go mod download
# Build API stage
FROM public.ecr.aws/docker/library/golang:alpine AS builder
ARG TARGETOS
ARG TARGETARCH
ARG BUILD_TIME
ARG COMMIT
ARG VERSION
@@ -40,8 +38,7 @@ ARG VERSION
# Install necessary build tools
RUN apk update && \
apk upgrade && \
apk add --no-cache git build-base gcc g++ && \
if [ "$TARGETARCH" != "arm" ] || [ "$TARGETARCH" != "riscv64" ]; then apk --no-cache add libwebp libavif libheif libjxl; fi
apk add --no-cache git build-base gcc g++
WORKDIR /go/src/app
@@ -55,26 +52,19 @@ COPY --from=frontend-builder /app/.output/public ./app/api/static/public
# Use cache for Go build artifacts
RUN --mount=type=cache,target=/root/.cache/go-build \
if [ "$TARGETARCH" = "arm" ] || [ "$TARGETARCH" = "riscv64" ]; \
then echo "nodynamic" $TARGETOS $TARGETARCH; CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build \
-ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \
-tags nodynamic -o /go/bin/api -v ./app/api/*.go; \
else \
echo $TARGETOS $TARGETARCH; CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH 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; \
fi
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 public.ecr.aws/docker/library/alpine:latest
ENV HBOX_MODE=production
ENV HBOX_STORAGE_CONN_STRING=file:///?no_tmp_dir=true
ENV HBOX_STORAGE_PREFIX_PATH=data
ENV HBOX_STORAGE_DATA=/data/
ENV HBOX_DATABASE_SQLITE_PATH=/data/homebox.db?_pragma=busy_timeout=2000&_pragma=journal_mode=WAL&_fk=1&_time_format=sqlite
# Install necessary runtime dependencies
RUN apk --no-cache add ca-certificates wget && \
if [ "$TARGETARCH" != "arm" ] || [ "$TARGETARCH" != "riscv64" ]; then apk --no-cache add libwebp libavif libheif libjxl; fi
RUN apk --no-cache add ca-certificates wget
# Create application directory and copy over built Go binary
RUN mkdir /app

View File

@@ -1,136 +0,0 @@
# ---------------------------------------
# Node dependencies stage
# ---------------------------------------
FROM public.ecr.aws/docker/library/node:22-alpine AS frontend-dependencies
WORKDIR /app
# Install pnpm globally (caching layer)
RUN npm install -g pnpm
# Copy package.json and lockfile to leverage caching
COPY frontend/package.json frontend/pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
# ---------------------------------------
# Build Nuxt (frontend) stage
# ---------------------------------------
FROM public.ecr.aws/docker/library/node:22-alpine AS frontend-builder
WORKDIR /app
# Install pnpm globally again (it can reuse the cache if not changed)
RUN npm install -g pnpm
# Copy over source files and node_modules from dependencies stage
COPY frontend .
COPY --from=frontend-dependencies /app/node_modules ./node_modules
RUN pnpm build
# ---------------------------------------
# Go dependencies stage
# ---------------------------------------
FROM public.ecr.aws/docker/library/golang:alpine AS builder-dependencies
WORKDIR /go/src/app
# Copy go.mod and go.sum for better caching
COPY ./backend/go.mod ./backend/go.sum ./
RUN go mod download
# ---------------------------------------
# Build API + healthcheck stage
# ---------------------------------------
FROM public.ecr.aws/docker/library/golang:alpine AS builder
ARG TARGETOS
ARG TARGETARCH
ARG BUILD_TIME
ARG COMMIT
ARG VERSION
# Install necessary build tools
RUN apk update && \
apk upgrade && \
apk add --no-cache git build-base gcc g++
WORKDIR /go/src/app
# Copy Go modules (from dependencies stage) and source code
COPY --from=builder-dependencies /go/pkg/mod /go/pkg/mod
COPY ./backend .
# Clear old public files and copy new ones from frontend build
RUN rm -rf ./app/api/public
COPY --from=frontend-builder /app/.output/public ./app/api/static/public
# Use cache for Go build artifacts to build Homebox API
RUN --mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build \
-ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \
-tags nodynamic -o /go/bin/api -v ./app/api/*.go
RUN chmod +x /go/bin/api
RUN mkdir /app
RUN mkdir /data
# ---------- Build static healthcheck helper ----------
# A small Go program that GETs the status URL and exits 0 on 2xx.
RUN cat > /tmp/healthcheck.go <<'EOF'
package main
import (
"fmt"
"net/http"
"os"
"time"
)
func main() {
url := "http://127.0.0.1:7745/api/v1/status"
if len(os.Args) > 1 { url = os.Args[1] }
c := &http.Client{ Timeout: 3 * time.Second }
resp, err := c.Get(url)
if err != nil { fmt.Fprintln(os.Stderr, err); os.Exit(1) }
resp.Body.Close()
if resp.StatusCode/100 != 2 {
fmt.Fprintln(os.Stderr, "unexpected status:", resp.StatusCode)
os.Exit(1)
}
}
EOF
RUN --mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH \
go build -ldflags "-s -w" -o /go/bin/hc /tmp/healthcheck.go
# ---------------------------------------
# Production stage
# ---------------------------------------
FROM gcr.io/distroless/static:nonroot
ENV HBOX_MODE=production
ENV HBOX_STORAGE_CONN_STRING=file:///?no_tmp_dir=true
ENV HBOX_STORAGE_PREFIX_PATH=data
ENV HBOX_DATABASE_SQLITE_PATH=/data/homebox.db?_pragma=busy_timeout=2000&_pragma=journal_mode=WAL&_fk=1&_time_format=sqlite
# Create application directory and copy over built Go binary and assets
COPY --from=builder --chown=65532:65532 /app /app
COPY --from=builder --chown=65532:65532 --chmod=755 /go/bin/api /app
COPY --from=builder --chown=65532:65532 /data /data
# Copy the healthcheck helper
COPY --from=builder --chown=65532:65532 --chmod=755 /go/bin/hc /app/healthcheck
# Labels and configuration for the final image
LABEL Name=homebox Version=0.0.1
LABEL org.opencontainers.image.source="https://github.com/sysadminsmedia/homebox"
# Expose necessary ports for Homebox
EXPOSE 7745
WORKDIR /app
# Persist volume for data
VOLUME [ "/data" ]
# Entrypoint and CMD
USER 65532
ENTRYPOINT [ "/app/api" ]
CMD [ "/data/config.yml" ]
# JSON exec-form healthcheck (no shell, no wget)
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
CMD ["/app/healthcheck", "http://127.0.0.1:7745/api/v1/status"]

View File

@@ -1,5 +1,5 @@
# Node dependencies stage
FROM public.ecr.aws/docker/library/node:22-alpine AS frontend-dependencies
FROM public.ecr.aws/docker/library/node:lts-alpine AS frontend-dependencies
WORKDIR /app
# Install pnpm globally (caching layer)
@@ -7,10 +7,10 @@ RUN npm install -g pnpm
# Copy package.json and lockfile to leverage caching
COPY frontend/package.json frontend/pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
RUN pnpm install --frozen-lockfile --shamefully-hoist
# Build Nuxt (frontend) stage
FROM public.ecr.aws/docker/library/node:22-alpine AS frontend-builder
FROM public.ecr.aws/docker/library/node:lts-alpine AS frontend-builder
WORKDIR /app
# Install pnpm globally again (it can reuse the cache if not changed)
@@ -31,8 +31,6 @@ RUN go mod download
# Build API stage
FROM public.ecr.aws/docker/library/golang:alpine AS builder
ARG TARGETOS
ARG TARGETARCH
ARG BUILD_TIME
ARG COMMIT
ARG VERSION
@@ -40,8 +38,7 @@ ARG VERSION
# Install necessary build tools
RUN apk update && \
apk upgrade && \
apk add --no-cache git build-base gcc g++ && \
if [ "$TARGETARCH" != "arm" ] || [ "$TARGETARCH" != "riscv64" ]; then apk --no-cache add libwebp libavif libheif libjxl; fi
apk add --no-cache git build-base gcc g++
WORKDIR /go/src/app
@@ -55,29 +52,21 @@ COPY --from=frontend-builder /app/.output/public ./app/api/static/public
# Use cache for Go build artifacts
RUN --mount=type=cache,target=/root/.cache/go-build \
if [ "$TARGETARCH" = "arm" ] || [ "$TARGETARCH" = "riscv64" ]; \
then echo "nodynamic" $TARGETOS $TARGETARCH; CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build \
-ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \
-tags nodynamic -o /go/bin/api -v ./app/api/*.go; \
else \
echo $TARGETOS $TARGETARCH; CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH 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; \
fi
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
RUN mkdir /data
# Production stage
FROM public.ecr.aws/docker/library/alpine:latest
ENV HBOX_MODE=production
ENV HBOX_STORAGE_CONN_STRING=file:///?no_tmp_dir=true
ENV HBOX_STORAGE_PREFIX_PATH=data
ENV HBOX_STORAGE_DATA=/data/
ENV HBOX_DATABASE_SQLITE_PATH=/data/homebox.db?_pragma=busy_timeout=2000&_pragma=journal_mode=WAL&_fk=1&_time_format=sqlite
# Install necessary runtime dependencies
RUN apk --no-cache add ca-certificates wget && \
if [ "$TARGETARCH" != "arm" ] || [ "$TARGETARCH" != "riscv64" ]; then apk --no-cache add libwebp libavif libheif libjxl; fi
RUN apk --no-cache add ca-certificates wget
# Create a nonroot user with UID/GID 65532
RUN addgroup -g 65532 nonroot && adduser -u 65532 -G nonroot -S nonroot

View File

@@ -2,59 +2,36 @@
<img src="/docs/public/lilbox.svg" height="200"/>
</div>
<h1 align="center" style="margin-top: -10px;"> HomeBox </h1>
<p align="center" style="width: 100%;">
<h1 align="center" style="margin-top: -10px"> HomeBox </h1>
<p align="center" style="width: 100;">
<a href="https://homebox.software/en/">Docs</a>
|
<a href="https://demo.homebox.software">Demo</a>
|
<a href="https://discord.gg/aY4DCkpNA9">Discord</a>
</p>
<p align="center" style="width: 100%;">
<img src="https://img.shields.io/github/check-runs/sysadminsmedia/homebox/main" alt="Github Checks"/>
<img src="https://img.shields.io/github/license/sysadminsmedia/homebox"/>
<img src="https://img.shields.io/github/v/release/sysadminsmedia/homebox?sort=semver&display_name=release"/>
<img src="https://img.shields.io/weblate/progress/homebox?server=https%3A%2F%2Ftranslate.sysadminsmedia.com"/>
</p>
<p align="center" style="width: 100%;">
<img src="https://img.shields.io/reddit/subreddit-subscribers/homebox"/>
<img src="https://img.shields.io/mastodon/follow/110749314839831923?domain=infosec.exchange"/>
<img src="https://img.shields.io/lemmy/homebox%40lemmy.world?label=lemmy"/>
</p>
## What is HomeBox
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, We'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 but Expandable_ - Homebox is designed to be simple and easy to use. No complicated setup or configuration required. But expandable to whatever level of infrastructure you want to put into it.
- 🚀 _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.
### Key Features
- 📇 Rich Organization - Organize your items into categories, locations, and tags. You can also create custom fields to store additional information about your items.
- 🔍 Powerful Search - Quickly find items in your inventory using the powerful search feature.
- 📸 Image Upload - Upload images of your items to make it easy to identify them.
- 📄 Document and Warranty Tracking - Keep track of important documents and warranties for your items.
- 💰 Purchase & Maintenance Tracking - Track purchase dates, prices, and maintenance schedules for your items.
- 📱 Responsive Design - Homebox is designed to work on any device, including desktops, tablets, and smartphones.
## Screenshots
![Login Screen](.github/screenshots/1.png)
![Dashboard](.github/screenshots/2.png)
![Item View](.github/screenshots/3.png)
![Create Item](.github/screenshots/9.png)
![Search](.github/screenshots/8.png)
- _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.
- _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.
# Screenshots
Check out screenshots of the project [here](https://imgur.com/a/5gLWt2j).
You can also try the demo instances of Homebox:
- [Demo](https://demo.homebox.software)
- [Nightly](https://nightly.homebox.software)
- [VNext](https://vnext.homebox.software/)
## Quick Start
[Configuration & Docker Compose](https://homebox.software/en/quick-start.html)
```bash
# If using the rootless or hardened image, ensure data
# 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
@@ -66,7 +43,6 @@ docker run -d \
--volume /path/to/data/folder/:/data \
ghcr.io/sysadminsmedia/homebox:latest
# ghcr.io/sysadminsmedia/homebox:latest-rootless
# ghcr.io/sysadminsmedia/homebox:latest-hardened
```
<!-- CONTRIBUTING -->
@@ -75,20 +51,14 @@ docker run -d \
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
To get started with code based contributions, please see our [contributing guide](https://homebox.software/en/contribute/get-started.html).
If you are not a coder and can't help translate, you can still contribute financially. Financial contributions help us maintain the project and keep demos running.
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.
## Help us Translate
We want to make sure that Homebox is available in as many languages as possible. If you are interested in helping us translate Homebox, please help us via our [Weblate instance](https://translate.sysadminsmedia.com/projects/homebox/).
[![Translation status](https://translate.sysadminsmedia.com/widget/homebox/multi-auto.svg)](https://translate.sysadminsmedia.com/engage/homebox/)
[![Translation status](http://translate.sysadminsmedia.com/widget/homebox/multi-auto.svg)](http://translate.sysadminsmedia.com/engage/homebox/)
## Credits
- Original project by [@hay-kot](https://github.com/hay-kot)
- Logo by [@lakotelman](https://github.com/lakotelman)
### Contributors
<a href="https://github.com/sysadminsmedia/homebox/graphs/contributors">
<img src="https://contrib.rocks/image?repo=sysadminsmedia/homebox" />
</a>

View File

@@ -11,9 +11,8 @@ tasks:
desc: Install development dependencies
cmds:
- go install github.com/swaggo/swag/cmd/swag@latest
- go install github.com/pressly/goose/v3/cmd/goose@v3.8.0
- cd backend && go mod tidy
- cd frontend && pnpm install
- cd frontend && pnpm install --shamefully-hoist
swag:
desc: Generate swagger docs
@@ -23,13 +22,8 @@ tasks:
INTERNAL: "../../../internal"
PKGS: "../../../pkgs"
cmds:
- swag fmt --dir={{ .API }}
- swag init --dir={{ .API }},{{ .INTERNAL }}/core/services,{{ .INTERNAL }}/data/repo --parseDependency
- npx -y -p swagger2openapi swagger2openapi --outfile ./docs/openapi-3.json ./docs/swagger.json
- npx -y -p swagger2openapi swagger2openapi --yaml --outfile ./docs/openapi-3.yaml ./docs/swagger.json
- cp -r ./docs/swagger.json ../../../../docs/en/api/swagger-2.0.json
- cp -r ./docs/swagger.yaml ../../../../docs/en/api/swagger-2.0.yaml
- cp -r ./docs/openapi-3.json ../../../../docs/en/api/openapi-3.0.json
- cp -r ./docs/openapi-3.yaml ../../../../docs/en/api/openapi-3.0.yaml
sources:
- "./backend/app/api/**/*"
- "./backend/internal/data/**"
@@ -87,30 +81,11 @@ tasks:
- go run ./app/api/ {{ .CLI_ARGS }}
silent: false
go:ci:
env:
HBOX_DEMO: true
desc: Runs all go test and lint related tasks
dir: backend
cmds:
- go run ./app/api/ {{ .CLI_ARGS }} &
silent: true
go:ci:with-frontend:
desc: Run backend with frontend in CI mode
dir: frontend
cmds:
- pnpm install
- pnpm run build
- cp -r ./.output/public ../backend/app/api/static/
- task: go:ci
silent: true
go:test:
desc: Runs all go tests using gotestsum - supports passing gotestsum args
dir: backend
cmds:
- go test {{ .CLI_ARGS }} ./...
- gotestsum {{ .CLI_ARGS }} ./...
go:coverage:
desc: Runs all go tests with -race flag and generates a coverage report
@@ -153,6 +128,28 @@ tasks:
sources:
- "./backend/internal/data/ent/schema/**/*"
db:migration:
desc: Runs the database diff engine to generate a SQL migration files
deps:
- db:generate
cmds:
- cd backend && go run app/tools/migrations/main.go {{ .CLI_ARGS }}
db:migration:postgresql:
env:
HBOX_DATABASE_DRIVER: postgres
HBOX_DATABASE_USERNAME: homebox
HBOX_DATABASE_PASSWORD: homebox
HBOX_DATABASE_DATABASE: homebox
HBOX_DATABASE_HOST: localhost
HBOX_DATABASE_PORT: 5432
HBOX_DATABASE_SSL_MODE: disable
desc: Runs the database diff engine to generate a SQL migration files for postgresql
deps:
- db:generate
cmds:
- cd backend && go run app/tools/migrations/main.go {{ .CLI_ARGS }}
ui:watch:
desc: Starts the vitest test runner in watch mode
dir: frontend
@@ -163,14 +160,7 @@ tasks:
desc: Run frontend development server
dir: frontend
cmds:
- pnpm dev --no-fork
ui:ci:
desc: Run frontend build in CI mode
dir: frontend
cmds:
- pnpm dev &
silent: true
- pnpm dev
ui:fix:
desc: Runs prettier and eslint on the frontend
@@ -189,7 +179,7 @@ tasks:
cmds:
- cd backend && go build ./app/api
- backend/api &
- sleep 15
- sleep 10
- cd frontend && pnpm run test:ci
silent: true
@@ -206,20 +196,10 @@ tasks:
cmds:
- cd backend && go build ./app/api
- backend/api &
- sleep 15
- sleep 10
- cd frontend && pnpm run test:ci
silent: true
test:e2e:
desc: Runs end-to-end test on a live server
dir: frontend
cmds:
- task: go:ci:with-frontend
- pnpm exec playwright install-deps
- pnpm exec playwright install
- sleep 30
- TEST_SHUTDOWN_API_SERVER=true E2E_BASE_URL=http://localhost:7745 pnpm exec playwright test -c ./test/playwright.config.ts {{ .CLI_ARGS }}
pr:
desc: Runs all tasks required for a PR
cmds:

View File

@@ -1,81 +1,74 @@
version: "2"
run:
timeout: 10m
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:
default: none
disable-all: true
enable:
- asciicheck
- bodyclose
- copyloopvar
- depguard
- dogsled
- errcheck
- errorlint
- exhaustive
- copyloopvar
- gochecknoinits
- goconst
- gocritic
- gocyclo
- gofmt
- goprintffuncname
- gosimple
- govet
- ineffassign
- misspell
- nakedret
- revive
- sqlclosecheck
- staticcheck
- stylecheck
- tagalign
- testifylint
- typecheck
- typecheck
- unconvert
- unused
- whitespace
- zerologlint
settings:
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.
exhaustive:
default-signifies-exhaustive: true
goconst:
min-len: 5
min-occurrences: 5
gocritic:
enabled-checks:
- ruleguard
revive:
confidence: 3
severity: warning
tagalign:
order:
- json
- schema
- yaml
- yml
- toml
- validate
testifylint:
enable-all: true
exclusions:
generated: lax
paths:
- internal/data/ent.*
- third_party$
- builtin$
- examples$
- sqlclosecheck
issues:
exclude-use-default: false
exclude-dirs:
- internal/data/ent.*
fix: true
formatters:
enable:
- gofmt
exclusions:
generated: lax
paths:
- internal/data/ent.*
- third_party$
- builtin$
- examples$

View File

@@ -14,47 +14,28 @@ builds:
- linux
- windows
- darwin
- freebsd
goarch:
- amd64
- "386"
- arm
- arm64
- riscv64
flags:
- -trimpath
ldflags:
- -s -w
- -X main.version={{.Version}}
- -X main.commit={{.Commit}}
- -X main.date={{.Date}}
ignore:
- goos: windows
goarch: arm
- goos: windows
goarch: "386"
- goos: freebsd
goarch: arm
- goos: freebsd
goarch: "386"
tags:
- >-
{{- if eq .Arch "riscv64" }}nodynamic
{{- else if eq .Arch "arm" }}nodynamic
{{- else if eq .Arch "386" }}nodynamic
{{- else if eq .Os "freebsd" }}nodynamic
{{ end }}
signs:
- cmd: cosign
signature: "${artifact}.sigstore.json"
stdin: "{{ .Env.COSIGN_PWD }}"
args:
- sign-blob
- "--bundle=${signature}"
- "sign-blob"
- "--key=cosign.key"
- "--output-signature=${signature}"
- "${artifact}"
- "--yes"
artifacts: checksum
output: true
- "--yes" # needed on cosign 2.0.0+
artifacts: all
archives:
- formats: [ 'tar.gz' ]
# this name template makes the OS and Arch compatible with the results of uname.
@@ -69,11 +50,11 @@ archives:
format_overrides:
- goos: windows
formats: [ 'zip' ]
sboms:
- artifacts: archive
release:
extra_files:
- glob: dist/*.sig
checksum:
name_template: 'checksums.txt'
snapshot:

View File

@@ -10,7 +10,6 @@ import (
"github.com/hay-kot/httpkit/errchain"
"github.com/hay-kot/httpkit/server"
"github.com/rs/zerolog/log"
"github.com/sysadminsmedia/homebox/backend/app/api/providers"
"github.com/sysadminsmedia/homebox/backend/internal/core/services"
"github.com/sysadminsmedia/homebox/backend/internal/core/services/reporting/eventbus"
"github.com/sysadminsmedia/homebox/backend/internal/data/repo"
@@ -75,7 +74,6 @@ type V1Controller struct {
bus *eventbus.EventBus
url string
config *config.Config
oidcProvider *providers.OIDCProvider
}
type (
@@ -97,14 +95,6 @@ type (
Demo bool `json:"demo"`
AllowRegistration bool `json:"allowRegistration"`
LabelPrinting bool `json:"labelPrinting"`
OIDC OIDCStatus `json:"oidc"`
}
OIDCStatus struct {
Enabled bool `json:"enabled"`
ButtonText string `json:"buttonText,omitempty"`
AutoRedirect bool `json:"autoRedirect,omitempty"`
AllowLocal bool `json:"allowLocal"`
}
)
@@ -121,23 +111,9 @@ func NewControllerV1(svc *services.AllServices, repos *repo.AllRepos, bus *event
opt(ctrl)
}
ctrl.initOIDCProvider()
return ctrl
}
func (ctrl *V1Controller) initOIDCProvider() {
if ctrl.config.OIDC.Enabled {
oidcProvider, err := providers.NewOIDCProvider(ctrl.svc.User, &ctrl.config.OIDC, &ctrl.config.Options, ctrl.cookieSecure)
if err != nil {
log.Err(err).Msg("failed to initialize OIDC provider at startup")
} else {
ctrl.oidcProvider = oidcProvider
log.Info().Msg("OIDC provider initialized successfully at startup")
}
}
}
// HandleBase godoc
//
// @Summary Application Info
@@ -156,12 +132,6 @@ func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) errchain.Hand
Demo: ctrl.isDemo,
AllowRegistration: ctrl.allowRegistration,
LabelPrinting: ctrl.config.LabelMaker.PrintCommand != nil,
OIDC: OIDCStatus{
Enabled: ctrl.config.OIDC.Enabled,
ButtonText: ctrl.config.OIDC.ButtonText,
AutoRedirect: ctrl.config.OIDC.AutoRedirect,
AllowLocal: ctrl.config.Options.AllowLocalLogin,
},
})
}
}

View File

@@ -81,16 +81,3 @@ func (ctrl *V1Controller) HandleItemDateZeroOut() errchain.HandlerFunc {
func (ctrl *V1Controller) HandleSetPrimaryPhotos() errchain.HandlerFunc {
return actionHandlerFactory("ensure asset IDs", ctrl.repo.Items.SetPrimaryPhotos)
}
// HandleCreateMissingThumbnails godoc
//
// @Summary Create Missing Thumbnails
// @Description Creates thumbnails for items that are missing them
// @Tags Actions
// @Produce json
// @Success 200 {object} ActionAmountResult
// @Router /v1/actions/create-missing-thumbnails [Post]
// @Security Bearer
func (ctrl *V1Controller) HandleCreateMissingThumbnails() errchain.HandlerFunc {
return actionHandlerFactory("create missing thumbnails", ctrl.repo.Attachments.CreateMissingThumbnails)
}

View File

@@ -2,7 +2,6 @@ package v1
import (
"errors"
"fmt"
"net/http"
"strconv"
"strings"
@@ -80,15 +79,15 @@ type AuthProvider interface {
// HandleAuthLogin godoc
//
// @Summary User Login
// @Tags Authentication
// @Accept x-www-form-urlencoded
// @Accept application/json
// @Param payload body LoginForm true "Login Data"
// @Param provider query string false "auth provider"
// @Produce json
// @Success 200 {object} TokenResponse
// @Router /v1/users/login [POST]
// @Summary User Login
// @Tags Authentication
// @Accept x-www-form-urlencoded
// @Accept application/json
// @Param payload body LoginForm true "Login Data"
// @Param provider query string false "auth provider"
// @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")
@@ -107,11 +106,6 @@ func (ctrl *V1Controller) HandleAuthLogin(ps ...AuthProvider) errchain.HandlerFu
provider = "local"
}
// Block local only when disabled
if provider == "local" && !ctrl.config.Options.AllowLocalLogin {
return validate.NewRequestError(fmt.Errorf("local login is not enabled"), http.StatusForbidden)
}
// Get the provider
p, ok := providers[provider]
if !ok {
@@ -120,8 +114,8 @@ func (ctrl *V1Controller) HandleAuthLogin(ps ...AuthProvider) errchain.HandlerFu
newToken, err := p.Authenticate(w, r)
if err != nil {
log.Warn().Err(err).Msg("authentication failed")
return validate.NewUnauthorizedError()
log.Err(err).Msg("failed to authenticate")
return server.JSON(w, http.StatusInternalServerError, err.Error())
}
ctrl.setCookies(w, noPort(r.Host), newToken.Raw, newToken.ExpiresAt, true)
@@ -253,65 +247,3 @@ func (ctrl *V1Controller) unsetCookies(w http.ResponseWriter, domain string) {
Path: "/",
})
}
// HandleOIDCLogin godoc
//
// @Summary OIDC Login Initiation
// @Tags Authentication
// @Produce json
// @Success 302
// @Router /v1/users/login/oidc [GET]
func (ctrl *V1Controller) HandleOIDCLogin() errchain.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
// Forbidden if OIDC is not enabled
if !ctrl.config.OIDC.Enabled {
return validate.NewRequestError(fmt.Errorf("OIDC is not enabled"), http.StatusForbidden)
}
// Check if OIDC provider is available
if ctrl.oidcProvider == nil {
log.Error().Msg("OIDC provider not initialized")
return validate.NewRequestError(errors.New("OIDC provider not available"), http.StatusInternalServerError)
}
// Initiate OIDC flow
_, err := ctrl.oidcProvider.InitiateOIDCFlow(w, r)
return err
}
}
// HandleOIDCCallback godoc
//
// @Summary OIDC Callback Handler
// @Tags Authentication
// @Param code query string true "Authorization code"
// @Param state query string true "State parameter"
// @Success 302
// @Router /v1/users/login/oidc/callback [GET]
func (ctrl *V1Controller) HandleOIDCCallback() errchain.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
// Forbidden if OIDC is not enabled
if !ctrl.config.OIDC.Enabled {
return validate.NewRequestError(fmt.Errorf("OIDC is not enabled"), http.StatusForbidden)
}
// Check if OIDC provider is available
if ctrl.oidcProvider == nil {
log.Error().Msg("OIDC provider not initialized")
return validate.NewRequestError(errors.New("OIDC provider not available"), http.StatusInternalServerError)
}
// Handle callback
newToken, err := ctrl.oidcProvider.HandleCallback(w, r)
if err != nil {
log.Err(err).Msg("OIDC callback failed")
http.Redirect(w, r, "/?oidc_error=oidc_auth_failed", http.StatusFound)
return nil
}
// Set cookies and redirect to home
ctrl.setCookies(w, noPort(r.Host), newToken.Raw, newToken.ExpiresAt, true)
http.Redirect(w, r, "/home", http.StatusFound)
return nil
}
}

View File

@@ -1,164 +0,0 @@
package v1
import (
"net/http"
"github.com/google/uuid"
"github.com/hay-kot/httpkit/errchain"
"github.com/sysadminsmedia/homebox/backend/internal/core/services"
"github.com/sysadminsmedia/homebox/backend/internal/data/repo"
"github.com/sysadminsmedia/homebox/backend/internal/web/adapters"
)
// HandleItemTemplatesGetAll godoc
//
// @Summary Get All Item Templates
// @Tags Item Templates
// @Produce json
// @Success 200 {object} []repo.ItemTemplateSummary
// @Router /v1/templates [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleItemTemplatesGetAll() errchain.HandlerFunc {
fn := func(r *http.Request) ([]repo.ItemTemplateSummary, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.ItemTemplates.GetAll(r.Context(), auth.GID)
}
return adapters.Command(fn, http.StatusOK)
}
// HandleItemTemplatesGet godoc
//
// @Summary Get Item Template
// @Tags Item Templates
// @Produce json
// @Param id path string true "Template ID"
// @Success 200 {object} repo.ItemTemplateOut
// @Router /v1/templates/{id} [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleItemTemplatesGet() errchain.HandlerFunc {
fn := func(r *http.Request, ID uuid.UUID) (repo.ItemTemplateOut, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.ItemTemplates.GetOne(r.Context(), auth.GID, ID)
}
return adapters.CommandID("id", fn, http.StatusOK)
}
// HandleItemTemplatesCreate godoc
//
// @Summary Create Item Template
// @Tags Item Templates
// @Produce json
// @Param payload body repo.ItemTemplateCreate true "Template Data"
// @Success 201 {object} repo.ItemTemplateOut
// @Router /v1/templates [POST]
// @Security Bearer
func (ctrl *V1Controller) HandleItemTemplatesCreate() errchain.HandlerFunc {
fn := func(r *http.Request, body repo.ItemTemplateCreate) (repo.ItemTemplateOut, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.ItemTemplates.Create(r.Context(), auth.GID, body)
}
return adapters.Action(fn, http.StatusCreated)
}
// HandleItemTemplatesUpdate godoc
//
// @Summary Update Item Template
// @Tags Item Templates
// @Produce json
// @Param id path string true "Template ID"
// @Param payload body repo.ItemTemplateUpdate true "Template Data"
// @Success 200 {object} repo.ItemTemplateOut
// @Router /v1/templates/{id} [PUT]
// @Security Bearer
func (ctrl *V1Controller) HandleItemTemplatesUpdate() errchain.HandlerFunc {
fn := func(r *http.Request, ID uuid.UUID, body repo.ItemTemplateUpdate) (repo.ItemTemplateOut, error) {
auth := services.NewContext(r.Context())
body.ID = ID
return ctrl.repo.ItemTemplates.Update(r.Context(), auth.GID, body)
}
return adapters.ActionID("id", fn, http.StatusOK)
}
// HandleItemTemplatesDelete godoc
//
// @Summary Delete Item Template
// @Tags Item Templates
// @Produce json
// @Param id path string true "Template ID"
// @Success 204
// @Router /v1/templates/{id} [DELETE]
// @Security Bearer
func (ctrl *V1Controller) HandleItemTemplatesDelete() errchain.HandlerFunc {
fn := func(r *http.Request, ID uuid.UUID) (any, error) {
auth := services.NewContext(r.Context())
err := ctrl.repo.ItemTemplates.Delete(r.Context(), auth.GID, ID)
return nil, err
}
return adapters.CommandID("id", fn, http.StatusNoContent)
}
type ItemTemplateCreateItemRequest struct {
Name string `json:"name" validate:"required,min=1,max=255"`
Description string `json:"description" validate:"max=1000"`
LocationID uuid.UUID `json:"locationId" validate:"required"`
LabelIDs []uuid.UUID `json:"labelIds"`
Quantity *int `json:"quantity"`
}
// HandleItemTemplatesCreateItem godoc
//
// @Summary Create Item from Template
// @Tags Item Templates
// @Produce json
// @Param id path string true "Template ID"
// @Param payload body ItemTemplateCreateItemRequest true "Item Data"
// @Success 201 {object} repo.ItemOut
// @Router /v1/templates/{id}/create-item [POST]
// @Security Bearer
func (ctrl *V1Controller) HandleItemTemplatesCreateItem() errchain.HandlerFunc {
fn := func(r *http.Request, templateID uuid.UUID, body ItemTemplateCreateItemRequest) (repo.ItemOut, error) {
auth := services.NewContext(r.Context())
template, err := ctrl.repo.ItemTemplates.GetOne(r.Context(), auth.GID, templateID)
if err != nil {
return repo.ItemOut{}, err
}
quantity := template.DefaultQuantity
if body.Quantity != nil {
quantity = *body.Quantity
}
// Build custom fields from template
fields := make([]repo.ItemField, len(template.Fields))
for i, f := range template.Fields {
fields[i] = repo.ItemField{
Type: f.Type,
Name: f.Name,
TextValue: f.TextValue,
}
}
// Create item with all template data in a single transaction
return ctrl.repo.Items.CreateFromTemplate(r.Context(), auth.GID, repo.ItemCreateFromTemplate{
Name: body.Name,
Description: body.Description,
Quantity: quantity,
LocationID: body.LocationID,
LabelIDs: body.LabelIDs,
Insured: template.DefaultInsured,
Manufacturer: template.DefaultManufacturer,
ModelNumber: template.DefaultModelNumber,
LifetimeWarranty: template.DefaultLifetimeWarranty,
WarrantyDetails: template.DefaultWarrantyDetails,
Fields: fields,
})
}
return adapters.ActionID("id", fn, http.StatusCreated)
}

View File

@@ -254,25 +254,6 @@ func (ctrl *V1Controller) HandleItemPatch() errchain.HandlerFunc {
return adapters.ActionID("id", fn, http.StatusOK)
}
// HandleItemDuplicate godocs
//
// @Summary Duplicate Item
// @Tags Items
// @Produce json
// @Param id path string true "Item ID"
// @Param payload body repo.DuplicateOptions true "Duplicate Options"
// @Success 201 {object} repo.ItemOut
// @Router /v1/items/{id}/duplicate [POST]
// @Security Bearer
func (ctrl *V1Controller) HandleItemDuplicate() errchain.HandlerFunc {
fn := func(r *http.Request, ID uuid.UUID, options repo.DuplicateOptions) (repo.ItemOut, error) {
ctx := services.NewContext(r.Context())
return ctrl.svc.Items.Duplicate(ctx, ctx.GID, ID, options)
}
return adapters.ActionID("id", fn, http.StatusCreated)
}
// HandleGetAllCustomFieldNames godocs
//
// @Summary Get All Custom Field Names
@@ -315,14 +296,14 @@ func (ctrl *V1Controller) HandleGetAllCustomFieldValues() errchain.HandlerFunc {
// HandleItemsImport godocs
//
// @Summary Import Items
// @Tags Items
// @Accept multipart/form-data
// @Produce json
// @Success 204
// @Param csv formData file true "Image to upload"
// @Router /v1/items/import [Post]
// @Security Bearer
// @Summary Import Items
// @Tags Items
// @Accept multipart/form-data
// @Produce json
// @Success 204
// @Param csv formData file true "Image to upload"
// @Router /v1/items/import [Post]
// @Security Bearer
func (ctrl *V1Controller) HandleItemsImport() errchain.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
err := r.ParseMultipartForm(ctrl.maxUploadSize << 20)

View File

@@ -3,9 +3,7 @@ package v1
import (
"errors"
"net/http"
"net/url"
"path/filepath"
"strconv"
"strings"
"github.com/hay-kot/httpkit/errchain"
@@ -15,13 +13,6 @@ import (
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/attachment"
"github.com/sysadminsmedia/homebox/backend/internal/data/repo"
"github.com/sysadminsmedia/homebox/backend/internal/sys/validate"
"gocloud.dev/blob"
_ "gocloud.dev/blob/azureblob"
_ "gocloud.dev/blob/fileblob"
_ "gocloud.dev/blob/gcsblob"
_ "gocloud.dev/blob/memblob"
_ "gocloud.dev/blob/s3blob"
)
type (
@@ -32,19 +23,18 @@ type (
// HandleItemAttachmentCreate godocs
//
// @Summary Create Item Attachment
// @Tags Items Attachments
// @Accept multipart/form-data
// @Produce json
// @Param id path string true "Item ID"
// @Param file formData file true "File attachment"
// @Param type formData string false "Type of file"
// @Param primary formData bool false "Is this the primary attachment"
// @Param name formData string true "name of the file including extension"
// @Success 200 {object} repo.ItemOut
// @Failure 422 {object} validate.ErrorResponse
// @Router /v1/items/{id}/attachments [POST]
// @Security Bearer
// @Summary Create Item Attachment
// @Tags Items Attachments
// @Accept multipart/form-data
// @Produce json
// @Param id path string true "Item ID"
// @Param file formData file true "File attachment"
// @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
// @Router /v1/items/{id}/attachments [POST]
// @Security Bearer
func (ctrl *V1Controller) HandleItemAttachmentCreate() errchain.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
err := r.ParseMultipartForm(ctrl.maxUploadSize << 20)
@@ -83,19 +73,13 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() errchain.HandlerFunc {
ext := filepath.Ext(attachmentName)
switch strings.ToLower(ext) {
case ".jpg", ".jpeg", ".png", ".webp", ".gif", ".bmp", ".tiff", ".avif", ".ico", ".heic", ".jxl":
case ".jpg", ".jpeg", ".png", ".webp", ".gif", ".bmp", ".tiff":
attachmentType = attachment.TypePhoto.String()
default:
attachmentType = attachment.TypeAttachment.String()
}
}
primary, err := strconv.ParseBool(r.FormValue("primary"))
if err != nil {
log.Debug().Msg("failed to parse primary from form")
primary = false
}
id, err := ctrl.routeID(r)
if err != nil {
return err
@@ -108,7 +92,6 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() errchain.HandlerFunc {
id,
attachmentName,
attachment.Type(attachmentType),
primary,
file,
)
if err != nil {
@@ -175,39 +158,13 @@ func (ctrl *V1Controller) handleItemAttachmentsHandler(w http.ResponseWriter, r
ctx := services.NewContext(r.Context())
switch r.Method {
case http.MethodGet:
doc, err := ctrl.svc.Items.AttachmentPath(r.Context(), ctx.GID, attachmentID)
doc, err := ctrl.svc.Items.AttachmentPath(r.Context(), attachmentID)
if err != nil {
log.Err(err).Msg("failed to get attachment path")
return validate.NewRequestError(err, http.StatusInternalServerError)
}
bucket, err := blob.OpenBucket(ctx, ctrl.repo.Attachments.GetConnString())
if err != nil {
log.Err(err).Msg("failed to open bucket")
return validate.NewRequestError(err, http.StatusInternalServerError)
}
file, err := bucket.NewReader(ctx, ctrl.repo.Attachments.GetFullPath(doc.Path), nil)
if err != nil {
log.Err(err).Msg("failed to open file")
return validate.NewRequestError(err, http.StatusInternalServerError)
}
defer func(file *blob.Reader) {
err := file.Close()
if err != nil {
log.Err(err).Msg("failed to close file")
}
}(file)
defer func(bucket *blob.Bucket) {
err := bucket.Close()
if err != nil {
log.Err(err).Msg("failed to close bucket")
}
}(bucket)
// Set the Content-Disposition header for RFC6266 compliance
disposition := "inline; filename*=UTF-8''" + url.QueryEscape(doc.Title)
w.Header().Set("Content-Disposition", disposition)
http.ServeContent(w, r, doc.Title, doc.CreatedAt, file)
http.ServeFile(w, r, doc.Path)
return nil
// Delete Attachment Handler
@@ -230,9 +187,9 @@ func (ctrl *V1Controller) handleItemAttachmentsHandler(w http.ResponseWriter, r
}
attachment.ID = attachmentID
val, err := ctrl.svc.Items.AttachmentUpdate(ctx, ctx.GID, ID, &attachment)
val, err := ctrl.svc.Items.AttachmentUpdate(ctx, ID, &attachment)
if err != nil {
log.Err(err).Msg("failed to update attachment")
log.Err(err).Msg("failed to delete attachment")
return validate.NewRequestError(err, http.StatusInternalServerError)
}

View File

@@ -29,20 +29,20 @@ func generateOrPrint(ctrl *V1Controller, w http.ResponseWriter, r *http.Request,
_, err = w.Write([]byte("Printed!"))
return err
} else {
return labelmaker.GenerateLabel(w, &params, ctrl.config)
return labelmaker.GenerateLabel(w, &params)
}
}
// HandleGetLocationLabel godoc
//
// @Summary Get Location label
// @Tags Locations
// @Produce json
// @Param id path string true "Location ID"
// @Param print query bool false "Print this label, defaults to false"
// @Success 200 {string} string "image/png"
// @Router /v1/labelmaker/location/{id} [GET]
// @Security Bearer
// @Summary Get Location label
// @Tags Locations
// @Produce json
// @Param id path string true "Location ID"
// @Param print query bool false "Print this label, defaults to false"
// @Success 200 {string} string "image/png"
// @Router /v1/labelmaker/location/{id} [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleGetLocationLabel() errchain.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
ID, err := adapters.RouteUUID(r, "id")
@@ -63,14 +63,14 @@ func (ctrl *V1Controller) HandleGetLocationLabel() errchain.HandlerFunc {
// HandleGetItemLabel godoc
//
// @Summary Get Item label
// @Tags Items
// @Produce json
// @Param id path string true "Item ID"
// @Param print query bool false "Print this label, defaults to false"
// @Success 200 {string} string "image/png"
// @Router /v1/labelmaker/item/{id} [GET]
// @Security Bearer
// @Summary Get Item label
// @Tags Items
// @Produce json
// @Param id path string true "Item ID"
// @Param print query bool false "Print this label, defaults to false"
// @Success 200 {string} string "image/png"
// @Router /v1/labelmaker/item/{id} [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleGetItemLabel() errchain.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
ID, err := adapters.RouteUUID(r, "id")
@@ -97,14 +97,14 @@ func (ctrl *V1Controller) HandleGetItemLabel() errchain.HandlerFunc {
// HandleGetAssetLabel godoc
//
// @Summary Get Asset label
// @Tags Items
// @Produce json
// @Param id path string true "Asset ID"
// @Param print query bool false "Print this label, defaults to false"
// @Success 200 {string} string "image/png"
// @Router /v1/labelmaker/assets/{id} [GET]
// @Security Bearer
// @Summary Get Asset label
// @Tags Items
// @Produce json
// @Param id path string true "Asset ID"
// @Param print query bool false "Print this label, defaults to false"
// @Success 200 {string} string "image/png"
// @Router /v1/labelmaker/assets/{id} [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleGetAssetLabel() errchain.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
assetIDParam := chi.URLParam(r, "id")

View File

@@ -12,14 +12,14 @@ import (
// HandleMaintenanceLogGet godoc
//
// @Summary Get Maintenance Log
// @Tags Item Maintenance
// @Produce json
// @Param id path string true "Item ID"
// @Param filters query repo.MaintenanceFilters false "which maintenance to retrieve"
// @Success 200 {array} repo.MaintenanceEntryWithDetails[]
// @Router /v1/items/{id}/maintenance [GET]
// @Security Bearer
// @Summary Get Maintenance Log
// @Tags Item Maintenance
// @Produce json
// @Param id path string true "Item ID"
// @Param filters query repo.MaintenanceFilters false "which maintenance to retrieve"
// @Success 200 {array} repo.MaintenanceEntryWithDetails[]
// @Router /v1/items/{id}/maintenance [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleMaintenanceLogGet() errchain.HandlerFunc {
fn := func(r *http.Request, ID uuid.UUID, filters repo.MaintenanceFilters) ([]repo.MaintenanceEntryWithDetails, error) {
auth := services.NewContext(r.Context())
@@ -31,14 +31,14 @@ func (ctrl *V1Controller) HandleMaintenanceLogGet() errchain.HandlerFunc {
// HandleMaintenanceEntryCreate godoc
//
// @Summary Create Maintenance Entry
// @Tags Item Maintenance
// @Produce json
// @Param id path string true "Item ID"
// @Param payload body repo.MaintenanceEntryCreate true "Entry Data"
// @Success 201 {object} repo.MaintenanceEntry
// @Router /v1/items/{id}/maintenance [POST]
// @Security Bearer
// @Summary Create Maintenance Entry
// @Tags Item Maintenance
// @Produce json
// @Param id path string true "Item ID"
// @Param payload body repo.MaintenanceEntryCreate true "Entry Data"
// @Success 201 {object} repo.MaintenanceEntry
// @Router /v1/items/{id}/maintenance [POST]
// @Security Bearer
func (ctrl *V1Controller) HandleMaintenanceEntryCreate() errchain.HandlerFunc {
fn := func(r *http.Request, itemID uuid.UUID, body repo.MaintenanceEntryCreate) (repo.MaintenanceEntry, error) {
auth := services.NewContext(r.Context())

View File

@@ -30,14 +30,14 @@ func (ctrl *V1Controller) HandleMaintenanceGetAll() errchain.HandlerFunc {
// HandleMaintenanceEntryUpdate godoc
//
// @Summary Update Maintenance Entry
// @Tags Maintenance
// @Produce json
// @Param id path string true "Maintenance ID"
// @Param payload body repo.MaintenanceEntryUpdate true "Entry Data"
// @Success 200 {object} repo.MaintenanceEntry
// @Router /v1/maintenance/{id} [PUT]
// @Security Bearer
// @Summary Update Maintenance Entry
// @Tags Maintenance
// @Produce json
// @Param id path string true "Maintenance ID"
// @Param payload body repo.MaintenanceEntryUpdate true "Entry Data"
// @Success 200 {object} repo.MaintenanceEntry
// @Router /v1/maintenance/{id} [PUT]
// @Security Bearer
func (ctrl *V1Controller) HandleMaintenanceEntryUpdate() errchain.HandlerFunc {
fn := func(r *http.Request, entryID uuid.UUID, body repo.MaintenanceEntryUpdate) (repo.MaintenanceEntry, error) {
auth := services.NewContext(r.Context())
@@ -49,13 +49,13 @@ func (ctrl *V1Controller) HandleMaintenanceEntryUpdate() errchain.HandlerFunc {
// HandleMaintenanceEntryDelete godoc
//
// @Summary Delete Maintenance Entry
// @Tags Maintenance
// @Produce json
// @Param id path string true "Maintenance ID"
// @Success 204
// @Router /v1/maintenance/{id} [DELETE]
// @Security Bearer
// @Summary Delete Maintenance Entry
// @Tags Maintenance
// @Produce json
// @Param id path string true "Maintenance ID"
// @Success 204
// @Router /v1/maintenance/{id} [DELETE]
// @Security Bearer
func (ctrl *V1Controller) HandleMaintenanceEntryDelete() errchain.HandlerFunc {
fn := func(r *http.Request, entryID uuid.UUID) (any, error) {
auth := services.NewContext(r.Context())

View File

@@ -83,13 +83,13 @@ func (ctrl *V1Controller) HandleUpdateNotifier() errchain.HandlerFunc {
// HandlerNotifierTest godoc
//
// @Summary Test Notifier
// @Tags Notifiers
// @Produce json
// @Param url query string true "URL"
// @Success 204
// @Router /v1/notifiers/test [POST]
// @Security Bearer
// @Summary Test Notifier
// @Tags Notifiers
// @Produce json
// @Param url query string true "URL"
// @Success 204
// @Router /v1/notifiers/test [POST]
// @Security Bearer
func (ctrl *V1Controller) HandlerNotifierTest() errchain.HandlerFunc {
type body struct {
URL string `json:"url" validate:"required"`

View File

@@ -1,332 +0,0 @@
package v1
import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"time"
"github.com/hay-kot/httpkit/errchain"
"github.com/hay-kot/httpkit/server"
"github.com/rs/zerolog/log"
"github.com/sysadminsmedia/homebox/backend/internal/data/repo"
"github.com/sysadminsmedia/homebox/backend/internal/sys/config"
"github.com/sysadminsmedia/homebox/backend/internal/web/adapters"
)
type UPCITEMDBResponse struct {
Code string `json:"code"`
Total int `json:"total"`
Offset int `json:"offset"`
Items []struct {
Ean string `json:"ean"`
Title string `json:"title"`
Description string `json:"description"`
Upc string `json:"upc"`
Brand string `json:"brand"`
Model string `json:"model"`
Color string `json:"color"`
Size string `json:"size"`
Dimension string `json:"dimension"`
Weight string `json:"weight"`
Category string `json:"category"`
LowestRecordedPrice float64 `json:"lowest_recorded_price"`
HighestRecordedPrice float64 `json:"highest_recorded_price"`
Images []string `json:"images"`
Offers []struct {
Merchant string `json:"merchant"`
Domain string `json:"domain"`
Title string `json:"title"`
Currency string `json:"currency"`
ListPrice string `json:"list_price"`
Price float64 `json:"price"`
Shipping string `json:"shipping"`
Condition string `json:"condition"`
Availability string `json:"availability"`
Link string `json:"link"`
UpdatedT int `json:"updated_t"`
} `json:"offers"`
Asin string `json:"asin"`
Elid string `json:"elid"`
} `json:"items"`
}
type BARCODESPIDER_COMResponse struct {
ItemResponse struct {
Code int `json:"code"`
Status string `json:"status"`
Message string `json:"message"`
} `json:"item_response"`
ItemAttributes struct {
Title string `json:"title"`
Upc string `json:"upc"`
Ean string `json:"ean"`
ParentCategory string `json:"parent_category"`
Category string `json:"category"`
Brand string `json:"brand"`
Model string `json:"model"`
Mpn string `json:"mpn"`
Manufacturer string `json:"manufacturer"`
Publisher string `json:"publisher"`
Asin string `json:"asin"`
Color string `json:"color"`
Size string `json:"size"`
Weight string `json:"weight"`
Image string `json:"image"`
IsAdult string `json:"is_adult"`
Description string `json:"description"`
} `json:"item_attributes"`
Stores []struct {
StoreName string `json:"store_name"`
Title string `json:"title"`
Image string `json:"image"`
Price string `json:"price"`
Currency string `json:"currency"`
Link string `json:"link"`
Updated string `json:"updated"`
} `json:"Stores"`
}
// HandleGenerateQRCode godoc
//
// @Summary Search EAN from Barcode
// @Tags Items
// @Produce json
// @Param data query string false "barcode to be searched"
// @Success 200 {object} []repo.BarcodeProduct
// @Router /v1/products/search-from-barcode [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleProductSearchFromBarcode(conf config.BarcodeAPIConf) errchain.HandlerFunc {
type query struct {
// 80 characters is the longest non-2D barcode length (GS1-128)
EAN string `schema:"productEAN" validate:"required,max=80"`
}
return func(w http.ResponseWriter, r *http.Request) error {
q, err := adapters.DecodeQuery[query](r)
if err != nil {
return err
}
const TIMEOUT_SEC = 10
log.Info().Msg("Processing barcode lookup request on: " + q.EAN)
// Search on UPCITEMDB
var products []repo.BarcodeProduct
// www.ean-search.org/: not free
// Example code: dewalt 5035048748428
upcitemdb := func(iEan string) ([]repo.BarcodeProduct, error) {
client := &http.Client{Timeout: TIMEOUT_SEC * time.Second}
resp, err := client.Get("https://api.upcitemdb.com/prod/trial/lookup?upc=" + iEan)
if err != nil {
return nil, err
}
defer func() {
err = errors.Join(err, resp.Body.Close())
}()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API returned status code: %d", resp.StatusCode)
}
// We Read the response body on the line below.
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
// Uncomment the following string for debug
// sb := string(body)
// log.Debug().Msg("Response: " + sb)
var result UPCITEMDBResponse
if err := json.Unmarshal(body, &result); err != nil { // Parse []byte to go struct pointer
log.Error().Msg("Can not unmarshal JSON")
}
var res []repo.BarcodeProduct
for _, it := range result.Items {
var p repo.BarcodeProduct
p.SearchEngineName = "upcitemdb.com"
p.Barcode = iEan
p.Item.Description = it.Description
p.Item.Name = it.Title
p.Manufacturer = it.Brand
p.ModelNumber = it.Model
if len(it.Images) != 0 {
p.ImageURL = it.Images[0]
}
res = append(res, p)
}
return res, nil
}
ps, err := upcitemdb(q.EAN)
if err != nil {
log.Error().Msg("Can not retrieve product from upcitemdb.com" + err.Error())
}
// Barcode spider implementation
barcodespider := func(tokenAPI string, iEan string) ([]repo.BarcodeProduct, error) {
if len(tokenAPI) == 0 {
return nil, errors.New("no api token configured for barcodespider. " +
"Please define the api token in environment variable HBOX_BARCODE_TOKEN_BARCODESPIDER")
}
req, err := http.NewRequest(
"GET", "https://api.barcodespider.com/v1/lookup?upc="+iEan, nil)
if err != nil {
return nil, err
}
req.Header.Add("token", tokenAPI)
client := &http.Client{Timeout: TIMEOUT_SEC * time.Second}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
// defer the call to Body.Close(). We also check the error code, and merge
// it with the other error in this code to avoid error overiding.
defer func() {
err = errors.Join(err, resp.Body.Close())
}()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("barcodespider API returned status code: %d", resp.StatusCode)
}
// We Read the response body on the line below.
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
// Uncomment the following string for debug
// sb := string(body)
// log.Debug().Msg("Response: " + sb)
var result BARCODESPIDER_COMResponse
if err := json.Unmarshal(body, &result); err != nil { // Parse []byte to go struct pointer
log.Error().Msg("Can not unmarshal JSON")
}
// TODO: check 200 code on HTTP response.
var p repo.BarcodeProduct
p.Barcode = iEan
p.SearchEngineName = "barcodespider.com"
p.Item.Name = result.ItemAttributes.Title
p.Item.Description = result.ItemAttributes.Description
p.Manufacturer = result.ItemAttributes.Brand
p.ModelNumber = result.ItemAttributes.Model
p.ImageURL = result.ItemAttributes.Image
var res []repo.BarcodeProduct
res = append(res, p)
return res, nil
}
ps2, err := barcodespider(conf.TokenBarcodespider, q.EAN)
if err != nil {
log.Error().Msg("Can not retrieve product from barcodespider.com: " + err.Error())
}
// Merge everything.
products = append(products, ps...)
products = append(products, ps2...)
// Retrieve images if possible
for i := range products {
p := &products[i]
if len(p.ImageURL) == 0 {
continue
}
// Validate URL is HTTPS
u, err := url.Parse(p.ImageURL)
if err != nil || u.Scheme != "https" {
log.Warn().Msg("Skipping non-HTTPS image URL: " + p.ImageURL)
continue
}
client := &http.Client{Timeout: TIMEOUT_SEC * time.Second}
res, err := client.Get(p.ImageURL)
if err != nil {
log.Warn().Msg("Cannot fetch image for URL: " + p.ImageURL + ": " + err.Error())
}
defer func() {
err = errors.Join(err, res.Body.Close())
}()
// Validate response
if res.StatusCode != http.StatusOK {
continue
}
// Check content type
contentType := res.Header.Get("Content-Type")
if !strings.HasPrefix(contentType, "image/") {
continue
}
// Limit image size to 8MB
limitedReader := io.LimitReader(res.Body, 8*1024*1024)
// Read data of image
bytes, err := io.ReadAll(limitedReader)
if err != nil {
log.Warn().Msg(err.Error())
continue
}
// Convert to Base64
var base64Encoding string
// Determine the content type of the image file
mimeType := http.DetectContentType(bytes)
// Prepend the appropriate URI scheme header depending
// on the MIME type
switch mimeType {
case "image/jpeg":
base64Encoding += "data:image/jpeg;base64,"
case "image/png":
base64Encoding += "data:image/png;base64,"
default:
continue
}
// Append the base64 encoded output
base64Encoding += base64.StdEncoding.EncodeToString(bytes)
p.ImageBase64 = base64Encoding
}
if len(products) != 0 {
return server.JSON(w, http.StatusOK, products)
}
return server.JSON(w, http.StatusNoContent, nil)
}
}

View File

@@ -20,15 +20,9 @@ import (
// @Produce json
// @Param payload body services.UserRegistration true "User Data"
// @Success 204
// @Failure 403 {string} string "Local login is not enabled"
// @Router /v1/users/register [Post]
func (ctrl *V1Controller) HandleUserRegistration() errchain.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
// Forbidden if local login is not enabled
if !ctrl.config.Options.AllowLocalLogin {
return validate.NewRequestError(fmt.Errorf("local login is not enabled"), http.StatusForbidden)
}
regData := services.UserRegistration{}
if err := server.Decode(r, &regData); err != nil {

View File

@@ -18,10 +18,7 @@ func (a *app) setupLogger() {
}
level, err := zerolog.ParseLevel(a.conf.Log.Level)
if err != nil {
log.Error().Err(err).Str("level", a.conf.Log.Level).Msg("invalid log level, falling back to info")
zerolog.SetGlobalLevel(zerolog.InfoLevel)
} else {
if err == nil {
zerolog.SetGlobalLevel(level)
}
}

View File

@@ -1,17 +1,21 @@
package main
import (
"bytes"
"context"
"errors"
"fmt"
"github.com/google/uuid"
"github.com/sysadminsmedia/homebox/backend/internal/sys/analytics"
"net/http"
"os"
"path/filepath"
"strings"
"time"
atlas "ariga.io/atlas/sql/migrate"
"entgo.io/ent/dialect/sql/schema"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/pressly/goose/v3"
"github.com/sysadminsmedia/homebox/backend/internal/sys/analytics"
"github.com/hay-kot/httpkit/errchain"
"github.com/hay-kot/httpkit/graceful"
@@ -26,20 +30,9 @@ import (
"github.com/sysadminsmedia/homebox/backend/internal/data/repo"
"github.com/sysadminsmedia/homebox/backend/internal/sys/config"
"github.com/sysadminsmedia/homebox/backend/internal/web/mid"
"go.balki.me/anyhttp"
_ "github.com/lib/pq"
_ "github.com/sysadminsmedia/homebox/backend/internal/data/migrations/postgres"
_ "github.com/sysadminsmedia/homebox/backend/internal/data/migrations/sqlite3"
_ "github.com/sysadminsmedia/homebox/backend/pkgs/cgofreesqlite"
_ "gocloud.dev/pubsub/awssnssqs"
_ "gocloud.dev/pubsub/azuresb"
_ "gocloud.dev/pubsub/gcppubsub"
_ "gocloud.dev/pubsub/kafkapubsub"
_ "gocloud.dev/pubsub/mempubsub"
_ "gocloud.dev/pubsub/natspubsub"
_ "gocloud.dev/pubsub/rabbitpubsub"
)
var (
@@ -70,19 +63,19 @@ func validatePostgresSSLMode(sslMode string) bool {
return validModes[strings.ToLower(strings.TrimSpace(sslMode))]
}
// @title Homebox API
// @version 1.0
// @description Track, Manage, and Organize your Things.
// @contact.name Homebox Team
// @contact.url https://discord.homebox.software
// @host demo.homebox.software
// @schemes https http
// @BasePath /api
// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
// @description "Type 'Bearer TOKEN' to correctly set the API Key"
// @externalDocs.url https://homebox.software/en/api
// @title Homebox API
// @version 1.0
// @description Track, Manage, and Organize your Things.
// @contact.name Homebox Team
// @contact.url https://discord.homebox.software
// @host demo.homebox.software
// @schemes https http
// @BasePath /api
// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
// @description "Type 'Bearer TOKEN' to correctly set the API Key"
// @externalDocs.url https://homebox.software/en/api
func main() {
zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack
@@ -101,66 +94,113 @@ func run(cfg *config.Config) error {
app := new(cfg)
app.setupLogger()
if cfg.Options.AllowAnalytics {
analytics.Send(version, build())
}
// =========================================================================
// Initialize Database & Repos
err := setupStorageDir(cfg)
err := os.MkdirAll(cfg.Storage.Data, 0o755)
if err != nil {
return err
log.Fatal().Err(err).Msg("failed to create data directory")
}
if strings.ToLower(cfg.Database.Driver) == "postgres" {
if !validatePostgresSSLMode(cfg.Database.SslMode) {
log.Error().Str("sslmode", cfg.Database.SslMode).Msg("invalid sslmode")
return fmt.Errorf("invalid sslmode: %s", cfg.Database.SslMode)
log.Fatal().Str("sslmode", cfg.Database.SslMode).Msg("invalid sslmode")
}
}
databaseURL, err := setupDatabaseURL(cfg)
if err != nil {
return err
// Set up the database URL based on the driver because for some reason a common URL format is not used
databaseURL := ""
switch strings.ToLower(cfg.Database.Driver) {
case "sqlite3":
databaseURL = cfg.Database.SqlitePath
case "postgres":
databaseURL = fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=%s", cfg.Database.Host, cfg.Database.Port, cfg.Database.Username, cfg.Database.Password, cfg.Database.Database, cfg.Database.SslMode)
default:
log.Fatal().Str("driver", cfg.Database.Driver).Msg("unsupported database driver")
}
c, err := ent.Open(strings.ToLower(cfg.Database.Driver), databaseURL)
if err != nil {
log.Error().
log.Fatal().
Err(err).
Str("driver", strings.ToLower(cfg.Database.Driver)).
Str("host", cfg.Database.Host).
Str("port", cfg.Database.Port).
Str("database", cfg.Database.Database).
Msg("failed opening connection to {driver} database at {host}:{port}/{database}")
return fmt.Errorf("failed opening connection to %s database at %s:%s/%s: %w",
strings.ToLower(cfg.Database.Driver),
cfg.Database.Host,
cfg.Database.Port,
cfg.Database.Database,
err,
)
}
defer func(c *ent.Client) {
err := c.Close()
if err != nil {
log.Fatal().Err(err).Msg("failed to close database connection")
}
}(c)
migrationsFs, err := migrations.Migrations(strings.ToLower(cfg.Database.Driver))
// Always create a random temporary directory for migrations
tempUUID, err := uuid.NewUUID()
if err != nil {
return fmt.Errorf("failed to get migrations for %s: %w", strings.ToLower(cfg.Database.Driver), err)
return err
}
temp := filepath.Join(os.TempDir(), fmt.Sprintf("homebox-%s", tempUUID.String()))
goose.SetBaseFS(migrationsFs)
err = goose.SetDialect(strings.ToLower(cfg.Database.Driver))
err = migrations.Write(temp, cfg.Database.Driver)
if err != nil {
log.Error().Str("driver", cfg.Database.Driver).Msg("unsupported database driver")
return fmt.Errorf("unsupported database driver: %s", cfg.Database.Driver)
}
err = goose.Up(c.Sql(), strings.ToLower(cfg.Database.Driver))
if err != nil {
log.Error().Err(err).Msg("failed to migrate database")
return err
}
collectFuncs, err := loadCurrencies(cfg)
dir, err := atlas.NewLocalDir(temp)
if err != nil {
return err
}
options := []schema.MigrateOption{
schema.WithDir(dir),
schema.WithDropColumn(true),
schema.WithDropIndex(true),
}
err = c.Schema.Create(context.Background(), options...)
if err != nil {
log.Error().
Err(err).
Str("driver", cfg.Database.Driver).
Str("url", databaseURL).
Msg("failed creating schema resources")
return err
}
defer func() {
err := os.RemoveAll(temp)
if err != nil {
log.Error().Err(err).Msg("failed to remove temporary directory for database migrations")
}
}()
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.Error().
Err(err).
Str("path", cfg.Options.CurrencyConfig).
Msg("failed to read currency config file")
return err
}
collectFuncs = append(collectFuncs, currencies.CollectJSON(bytes.NewReader(content)))
}
currencies, err := currencies.CollectionCurrencies(collectFuncs...)
if err != nil {
log.Error().
@@ -171,7 +211,7 @@ func run(cfg *config.Config) error {
app.bus = eventbus.New()
app.db = c
app.repos = repo.New(c, app.bus, cfg.Storage, cfg.Database.PubSubConnString, cfg.Thumbnail)
app.repos = repo.New(c, app.bus, cfg.Storage.Data)
app.services = services.New(
app.repos,
services.WithAutoIncrementAssetID(cfg.Options.AutoIncrementAssetID),
@@ -212,52 +252,90 @@ func run(cfg *config.Config) error {
_ = httpserver.Shutdown(context.Background())
}()
listener, addrType, addrCfg, err := anyhttp.GetListener(cfg.Web.Host)
if err == nil {
switch addrType {
case anyhttp.SystemdFD:
sysdCfg := addrCfg.(*anyhttp.SysdConfig)
if sysdCfg.IdleTimeout != nil {
log.Error().Msg("idle timeout not yet supported. Please remove and try again")
return errors.New("idle timeout not yet supported. Please remove and try again")
}
fallthrough
case anyhttp.UnixSocket:
log.Info().Msgf("Server is running on %s", cfg.Web.Host)
return httpserver.Serve(listener)
}
} else {
log.Debug().Msgf("anyhttp error: %v", err)
}
log.Info().Msgf("Server is running on %s:%s", cfg.Web.Host, cfg.Web.Port)
return httpserver.ListenAndServe()
})
// =========================================================================
// Start Reoccurring Tasks
registerRecurringTasks(app, cfg, runner)
// Send analytics if enabled at around midnight UTC
if cfg.Options.AllowAnalytics {
analyticsTime := time.Second
runner.AddPlugin(NewTask("send-analytics", analyticsTime, func(ctx context.Context) {
for {
now := time.Now().UTC()
nextMidnight := time.Date(now.Year(), now.Month(), now.Day()+1, 0, 0, 0, 0, time.UTC)
dur := time.Until(nextMidnight)
analyticsTime = dur
select {
case <-ctx.Done():
return
case <-time.After(dur):
log.Debug().Msg("running send analytics")
err := analytics.Send(version, build())
if err != nil {
log.Error().Err(err).Msg("failed to send analytics")
}
}
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")
err := app.SetupDemo()
if err != nil {
log.Fatal().Msg(err.Error())
}
}
return nil
})
runner.AddPlugin(NewTask("purge-tokens", time.Duration(24)*time.Hour, func(ctx context.Context) {
_, err := app.repos.AuthTokens.PurgeExpiredTokens(ctx)
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)
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) {
now := time.Now()
if now.Hour() == 8 {
fmt.Println("run notifiers")
err := app.services.BackgroundService.SendNotifiersToday(context.Background())
if err != nil {
log.Error().
Err(err).
Msg("failed to send notifiers")
}
}
}))
if cfg.Options.GithubReleaseCheck {
runner.AddPlugin(NewTask("get-latest-github-release", time.Hour, func(ctx context.Context) {
log.Debug().Msg("running get latest github release")
err := app.services.BackgroundService.GetLatestGithubRelease(context.Background())
if err != nil {
log.Error().
Err(err).
Msg("failed to get latest github release")
}
}))
}
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()
})
}
return runner.Start(context.Background())
}

View File

@@ -1,626 +0,0 @@
package providers
import (
"context"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/rs/zerolog/log"
"github.com/sysadminsmedia/homebox/backend/internal/core/services"
"github.com/sysadminsmedia/homebox/backend/internal/sys/config"
"golang.org/x/oauth2"
)
type OIDCProvider struct {
service *services.UserService
config *config.OIDCConf
options *config.Options
cookieSecure bool
provider *oidc.Provider
verifier *oidc.IDTokenVerifier
endpoint oauth2.Endpoint
}
type OIDCClaims struct {
Email string
Groups []string
Name string
Subject string
Issuer string
EmailVerified *bool
}
func NewOIDCProvider(service *services.UserService, config *config.OIDCConf, options *config.Options, cookieSecure bool) (*OIDCProvider, error) {
if !config.Enabled {
return nil, fmt.Errorf("OIDC is not enabled")
}
// Validate required configuration
if config.ClientID == "" {
return nil, fmt.Errorf("OIDC client ID is required when OIDC is enabled (set HBOX_OIDC_CLIENT_ID)")
}
if config.ClientSecret == "" {
return nil, fmt.Errorf("OIDC client secret is required when OIDC is enabled (set HBOX_OIDC_CLIENT_SECRET)")
}
if config.IssuerURL == "" {
return nil, fmt.Errorf("OIDC issuer URL is required when OIDC is enabled (set HBOX_OIDC_ISSUER_URL)")
}
ctx, cancel := context.WithTimeout(context.Background(), config.RequestTimeout)
defer cancel()
provider, err := oidc.NewProvider(ctx, config.IssuerURL)
if err != nil {
return nil, fmt.Errorf("failed to create OIDC provider from issuer URL: %w", err)
}
// Create ID token verifier
verifier := provider.Verifier(&oidc.Config{
ClientID: config.ClientID,
})
log.Info().
Str("issuer", config.IssuerURL).
Str("client_id", config.ClientID).
Str("scope", config.Scope).
Msg("OIDC provider initialized successfully with discovery")
return &OIDCProvider{
service: service,
config: config,
options: options,
cookieSecure: cookieSecure,
provider: provider,
verifier: verifier,
endpoint: provider.Endpoint(),
}, nil
}
func (p *OIDCProvider) Name() string {
return "oidc"
}
// Authenticate implements the AuthProvider interface but is not used for OIDC
// OIDC uses dedicated endpoints: GET /api/v1/users/login/oidc and GET /api/v1/users/login/oidc/callback
func (p *OIDCProvider) Authenticate(w http.ResponseWriter, r *http.Request) (services.UserAuthTokenDetail, error) {
_ = w
_ = r
return services.UserAuthTokenDetail{}, fmt.Errorf("OIDC authentication uses dedicated endpoints: /api/v1/users/login/oidc")
}
// AuthenticateWithBaseURL is the main authentication method that requires baseURL
// Called from handleCallback after state, nonce, and PKCE verification
func (p *OIDCProvider) AuthenticateWithBaseURL(baseURL, expectedNonce, pkceVerifier string, _ http.ResponseWriter, r *http.Request) (services.UserAuthTokenDetail, error) {
code := r.URL.Query().Get("code")
if code == "" {
return services.UserAuthTokenDetail{}, fmt.Errorf("missing authorization code")
}
// Get OAuth2 config for this request
oauth2Config := p.getOAuth2Config(baseURL)
// Exchange code for token with timeout and PKCE verifier
ctx, cancel := context.WithTimeout(r.Context(), p.config.RequestTimeout)
defer cancel()
token, err := oauth2Config.Exchange(ctx, code, oauth2.SetAuthURLParam("code_verifier", pkceVerifier))
if err != nil {
log.Err(err).Msg("failed to exchange OIDC code for token")
return services.UserAuthTokenDetail{}, fmt.Errorf("failed to exchange code for token")
}
// Extract ID token
idToken, ok := token.Extra("id_token").(string)
if !ok {
return services.UserAuthTokenDetail{}, fmt.Errorf("no id_token in response")
}
// Parse and validate the ID token using the library's verifier with timeout
verifyCtx, verifyCancel := context.WithTimeout(r.Context(), p.config.RequestTimeout)
defer verifyCancel()
idTokenStruct, err := p.verifier.Verify(verifyCtx, idToken)
if err != nil {
log.Err(err).Msg("failed to verify ID token")
return services.UserAuthTokenDetail{}, fmt.Errorf("failed to verify ID token")
}
// Extract claims from the verified token using dynamic parsing
var rawClaims map[string]interface{}
if err := idTokenStruct.Claims(&rawClaims); err != nil {
log.Err(err).Msg("failed to extract claims from ID token")
return services.UserAuthTokenDetail{}, fmt.Errorf("failed to extract claims from ID token")
}
// Attempt to retrieve UserInfo claims; use them as primary, fallback to ID token claims.
finalClaims := rawClaims
userInfoCtx, uiCancel := context.WithTimeout(r.Context(), p.config.RequestTimeout)
defer uiCancel()
userInfo, uiErr := p.provider.UserInfo(userInfoCtx, oauth2.StaticTokenSource(token))
if uiErr != nil {
log.Debug().Err(uiErr).Msg("OIDC UserInfo fetch failed; falling back to ID token claims")
} else {
var uiClaims map[string]interface{}
if err := userInfo.Claims(&uiClaims); err != nil {
log.Debug().Err(err).Msg("failed to decode UserInfo claims; falling back to ID token claims")
} else {
finalClaims = mergeOIDCClaims(uiClaims, rawClaims) // UserInfo first, then fill gaps from ID token
log.Debug().Int("userinfo_claims", len(uiClaims)).Int("id_token_claims", len(rawClaims)).Int("merged_claims", len(finalClaims)).Msg("merged UserInfo and ID token claims")
}
}
// Parse claims using configurable claim names (after merge)
claims, err := p.parseOIDCClaims(finalClaims)
if err != nil {
log.Err(err).Msg("failed to parse OIDC claims")
return services.UserAuthTokenDetail{}, fmt.Errorf("failed to parse OIDC claims: %w", err)
}
// Verify nonce claim matches expected value (nonce only from ID token; ensure preserved in merged map)
tokenNonce, exists := finalClaims["nonce"]
if !exists {
log.Warn().Msg("nonce claim missing from ID token - possible replay attack")
return services.UserAuthTokenDetail{}, fmt.Errorf("nonce claim missing from token")
}
tokenNonceStr, ok := tokenNonce.(string)
if !ok {
log.Warn().Msg("nonce claim is not a string in ID token")
return services.UserAuthTokenDetail{}, fmt.Errorf("invalid nonce claim format")
}
if tokenNonceStr != expectedNonce {
log.Warn().Str("received", tokenNonceStr).Str("expected", expectedNonce).Msg("OIDC nonce mismatch - possible replay attack")
return services.UserAuthTokenDetail{}, fmt.Errorf("nonce parameter mismatch")
}
// Check if email is verified
if p.config.VerifyEmail {
if claims.EmailVerified == nil {
return services.UserAuthTokenDetail{}, fmt.Errorf("email verification status not found in token claims")
}
if !*claims.EmailVerified {
return services.UserAuthTokenDetail{}, fmt.Errorf("email not verified")
}
}
// Check group authorization if configured
if p.config.AllowedGroups != "" {
allowedGroups := strings.Split(p.config.AllowedGroups, ",")
if !p.hasAllowedGroup(claims.Groups, allowedGroups) {
log.Warn().
Strs("user_groups", claims.Groups).
Strs("allowed_groups", allowedGroups).
Str("user", claims.Email).
Msg("user not in allowed groups")
return services.UserAuthTokenDetail{}, fmt.Errorf("user not in allowed groups")
}
}
// Determine username from claims
email := claims.Email
if email == "" {
return services.UserAuthTokenDetail{}, fmt.Errorf("no email found in token claims")
}
if claims.Subject == "" {
return services.UserAuthTokenDetail{}, fmt.Errorf("no subject (sub) claim present")
}
if claims.Issuer == "" {
claims.Issuer = p.config.IssuerURL // fallback to configured issuer, though spec requires 'iss'
}
// Use the dedicated OIDC login method (issuer + subject identity)
sessionToken, err := p.service.LoginOIDC(r.Context(), claims.Issuer, claims.Subject, email, claims.Name)
if err != nil {
log.Err(err).Str("email", email).Str("issuer", claims.Issuer).Str("subject", claims.Subject).Msg("OIDC login failed")
return services.UserAuthTokenDetail{}, fmt.Errorf("OIDC login failed: %w", err)
}
return sessionToken, nil
}
func (p *OIDCProvider) parseOIDCClaims(rawClaims map[string]interface{}) (OIDCClaims, error) {
var claims OIDCClaims
// Parse email claim
key := p.config.EmailClaim
if key == "" {
key = "email"
}
if emailValue, exists := rawClaims[key]; exists {
if email, ok := emailValue.(string); ok {
claims.Email = email
}
}
// Parse email_verified claim
if p.config.VerifyEmail {
key = p.config.EmailVerifiedClaim
if key == "" {
key = "email_verified"
}
if emailVerifiedValue, exists := rawClaims[key]; exists {
switch v := emailVerifiedValue.(type) {
case bool:
claims.EmailVerified = &v
case string:
if b, err := strconv.ParseBool(v); err == nil {
claims.EmailVerified = &b
}
}
}
}
// Parse name claim
key = p.config.NameClaim
if key == "" {
key = "name"
}
if nameValue, exists := rawClaims[key]; exists {
if name, ok := nameValue.(string); ok {
claims.Name = name
}
}
// Parse groups claim
key = p.config.GroupClaim
if key == "" {
key = "groups"
}
if groupsValue, exists := rawClaims[key]; exists {
switch groups := groupsValue.(type) {
case []interface{}:
for _, group := range groups {
if groupStr, ok := group.(string); ok {
claims.Groups = append(claims.Groups, groupStr)
}
}
case []string:
claims.Groups = groups
case string:
// Single group as string
claims.Groups = []string{groups}
}
}
// Parse subject claim (always "sub")
if subValue, exists := rawClaims["sub"]; exists {
if subject, ok := subValue.(string); ok {
claims.Subject = subject
}
}
// Parse issuer claim ("iss")
if issValue, exists := rawClaims["iss"]; exists {
if iss, ok := issValue.(string); ok {
claims.Issuer = iss
}
}
return claims, nil
}
func (p *OIDCProvider) hasAllowedGroup(userGroups, allowedGroups []string) bool {
if len(allowedGroups) == 0 {
return true
}
allowedGroupsMap := make(map[string]bool)
for _, group := range allowedGroups {
allowedGroupsMap[strings.TrimSpace(group)] = true
}
for _, userGroup := range userGroups {
if allowedGroupsMap[userGroup] {
return true
}
}
return false
}
func (p *OIDCProvider) GetAuthURL(baseURL, state, nonce, pkceVerifier string) string {
oauth2Config := p.getOAuth2Config(baseURL)
pkceChallenge := generatePKCEChallenge(pkceVerifier)
return oauth2Config.AuthCodeURL(state,
oidc.Nonce(nonce),
oauth2.SetAuthURLParam("code_challenge", pkceChallenge),
oauth2.SetAuthURLParam("code_challenge_method", "S256"))
}
func (p *OIDCProvider) getOAuth2Config(baseURL string) oauth2.Config {
// Construct full redirect URL with dedicated callback endpoint
redirectURL, err := url.JoinPath(baseURL, "/api/v1/users/login/oidc/callback")
if err != nil {
log.Err(err).Msg("failed to construct redirect URL")
return oauth2.Config{}
}
return oauth2.Config{
ClientID: p.config.ClientID,
ClientSecret: p.config.ClientSecret,
RedirectURL: redirectURL,
Endpoint: p.endpoint,
Scopes: strings.Fields(p.config.Scope),
}
}
// initiateOIDCFlow handles the initial OIDC authentication request by redirecting to the provider
func (p *OIDCProvider) initiateOIDCFlow(w http.ResponseWriter, r *http.Request) (services.UserAuthTokenDetail, error) {
// Generate state parameter for CSRF protection
state, err := generateSecureToken()
if err != nil {
log.Err(err).Msg("failed to generate OIDC state parameter")
return services.UserAuthTokenDetail{}, fmt.Errorf("internal server error")
}
// Generate nonce parameter for replay attack protection
nonce, err := generateSecureToken()
if err != nil {
log.Err(err).Msg("failed to generate OIDC nonce parameter")
return services.UserAuthTokenDetail{}, fmt.Errorf("internal server error")
}
// Generate PKCE verifier for code interception protection
pkceVerifier, err := generatePKCEVerifier()
if err != nil {
log.Err(err).Msg("failed to generate OIDC PKCE verifier")
return services.UserAuthTokenDetail{}, fmt.Errorf("internal server error")
}
// Get base URL from request
baseURL := p.getBaseURL(r)
u, _ := url.Parse(baseURL)
domain := u.Hostname()
if domain == "" {
domain = noPort(r.Host)
}
// Store state in session cookie for validation
http.SetCookie(w, &http.Cookie{
Name: "oidc_state",
Value: state,
Expires: time.Now().Add(p.config.StateExpiry),
Domain: domain,
Secure: p.isSecure(r),
HttpOnly: true,
Path: "/",
SameSite: http.SameSiteLaxMode,
})
// Store nonce in session cookie for validation
http.SetCookie(w, &http.Cookie{
Name: "oidc_nonce",
Value: nonce,
Expires: time.Now().Add(p.config.StateExpiry),
Domain: domain,
Secure: p.isSecure(r),
HttpOnly: true,
Path: "/",
SameSite: http.SameSiteLaxMode,
})
// Store PKCE verifier in session cookie for token exchange
http.SetCookie(w, &http.Cookie{
Name: "oidc_pkce_verifier",
Value: pkceVerifier,
Expires: time.Now().Add(p.config.StateExpiry),
Domain: domain,
Secure: p.isSecure(r),
HttpOnly: true,
Path: "/",
SameSite: http.SameSiteLaxMode,
})
// Generate auth URL and redirect
authURL := p.GetAuthURL(baseURL, state, nonce, pkceVerifier)
http.Redirect(w, r, authURL, http.StatusFound)
// Return empty token since this is a redirect response
return services.UserAuthTokenDetail{}, nil
}
// handleCallback processes the OAuth2 callback from the OIDC provider
func (p *OIDCProvider) handleCallback(w http.ResponseWriter, r *http.Request) (services.UserAuthTokenDetail, error) {
// Helper to clear state cookie using computed domain
baseURL := p.getBaseURL(r)
u, _ := url.Parse(baseURL)
domain := u.Hostname()
if domain == "" {
domain = noPort(r.Host)
}
clearCookies := func() {
http.SetCookie(w, &http.Cookie{
Name: "oidc_state",
Value: "",
Expires: time.Unix(0, 0),
Domain: domain,
MaxAge: -1,
Secure: p.isSecure(r),
HttpOnly: true,
Path: "/",
SameSite: http.SameSiteLaxMode,
})
http.SetCookie(w, &http.Cookie{
Name: "oidc_nonce",
Value: "",
Expires: time.Unix(0, 0),
Domain: domain,
MaxAge: -1,
Secure: p.isSecure(r),
HttpOnly: true,
Path: "/",
SameSite: http.SameSiteLaxMode,
})
http.SetCookie(w, &http.Cookie{
Name: "oidc_pkce_verifier",
Value: "",
Expires: time.Unix(0, 0),
Domain: domain,
MaxAge: -1,
Secure: p.isSecure(r),
HttpOnly: true,
Path: "/",
SameSite: http.SameSiteLaxMode,
})
}
// Check for OAuth error responses first
if errCode := r.URL.Query().Get("error"); errCode != "" {
errDesc := r.URL.Query().Get("error_description")
log.Warn().Str("error", errCode).Str("description", errDesc).Msg("OIDC provider returned error")
clearCookies()
return services.UserAuthTokenDetail{}, fmt.Errorf("OIDC provider error: %s - %s", errCode, errDesc)
}
// Verify state parameter
stateCookie, err := r.Cookie("oidc_state")
if err != nil {
log.Warn().Err(err).Msg("OIDC state cookie not found - possible CSRF attack or expired session")
clearCookies()
return services.UserAuthTokenDetail{}, fmt.Errorf("state cookie not found")
}
stateParam := r.URL.Query().Get("state")
if stateParam == "" {
log.Warn().Msg("OIDC state parameter missing from callback")
clearCookies()
return services.UserAuthTokenDetail{}, fmt.Errorf("state parameter missing")
}
if stateParam != stateCookie.Value {
log.Warn().Str("received", stateParam).Str("expected", stateCookie.Value).Msg("OIDC state mismatch - possible CSRF attack")
clearCookies()
return services.UserAuthTokenDetail{}, fmt.Errorf("state parameter mismatch")
}
// Verify nonce parameter
nonceCookie, err := r.Cookie("oidc_nonce")
if err != nil {
log.Warn().Err(err).Msg("OIDC nonce cookie not found - possible replay attack or expired session")
clearCookies()
return services.UserAuthTokenDetail{}, fmt.Errorf("nonce cookie not found")
}
// Verify PKCE verifier parameter
pkceCookie, err := r.Cookie("oidc_pkce_verifier")
if err != nil {
log.Warn().Err(err).Msg("OIDC PKCE verifier cookie not found - possible code interception attack or expired session")
clearCookies()
return services.UserAuthTokenDetail{}, fmt.Errorf("PKCE verifier cookie not found")
}
// Clear cookies before proceeding to token verification
clearCookies()
// Use the existing callback logic but return the token instead of redirecting
return p.AuthenticateWithBaseURL(baseURL, nonceCookie.Value, pkceCookie.Value, w, r)
}
// Helper functions
func generateSecureToken() (string, error) {
// Generate 32 bytes of cryptographically secure random data
bytes := make([]byte, 32)
_, err := rand.Read(bytes)
if err != nil {
return "", fmt.Errorf("failed to generate secure random token: %w", err)
}
// Use URL-safe base64 encoding without padding for clean URLs
return base64.RawURLEncoding.EncodeToString(bytes), nil
}
// generatePKCEVerifier generates a cryptographically secure code verifier for PKCE
func generatePKCEVerifier() (string, error) {
// PKCE verifier must be 43-128 characters, we'll use 43 for efficiency
// 32 bytes = 43 characters when base64url encoded without padding
bytes := make([]byte, 32)
_, err := rand.Read(bytes)
if err != nil {
return "", fmt.Errorf("failed to generate PKCE verifier: %w", err)
}
return base64.RawURLEncoding.EncodeToString(bytes), nil
}
// generatePKCEChallenge generates a code challenge from a verifier using S256 method
func generatePKCEChallenge(verifier string) string {
hash := sha256.Sum256([]byte(verifier))
return base64.RawURLEncoding.EncodeToString(hash[:])
}
func noPort(host string) string {
return strings.Split(host, ":")[0]
}
func (p *OIDCProvider) getBaseURL(r *http.Request) string {
scheme := "http"
if r.TLS != nil {
scheme = "https"
} else if p.options.TrustProxy && r.Header.Get("X-Forwarded-Proto") == "https" {
scheme = "https"
}
host := r.Host
if p.options.Hostname != "" {
host = p.options.Hostname
} else if p.options.TrustProxy {
if xfHost := r.Header.Get("X-Forwarded-Host"); xfHost != "" {
host = xfHost
}
}
return scheme + "://" + host
}
func (p *OIDCProvider) isSecure(r *http.Request) bool {
_ = r
return p.cookieSecure
}
// InitiateOIDCFlow starts the OIDC authentication flow by redirecting to the provider
func (p *OIDCProvider) InitiateOIDCFlow(w http.ResponseWriter, r *http.Request) (services.UserAuthTokenDetail, error) {
return p.initiateOIDCFlow(w, r)
}
// HandleCallback processes the OIDC callback and returns the authenticated user token
func (p *OIDCProvider) HandleCallback(w http.ResponseWriter, r *http.Request) (services.UserAuthTokenDetail, error) {
return p.handleCallback(w, r)
}
func mergeOIDCClaims(primary, secondary map[string]interface{}) map[string]interface{} {
// primary has precedence; fill missing/empty values from secondary.
merged := make(map[string]interface{}, len(primary)+len(secondary))
for k, v := range primary {
merged[k] = v
}
for k, v := range secondary {
if existing, ok := merged[k]; !ok || isEmptyClaim(existing) {
merged[k] = v
}
}
return merged
}
func isEmptyClaim(v interface{}) bool {
if v == nil {
return true
}
switch val := v.(type) {
case string:
return val == ""
case []interface{}:
return len(val) == 0
case []string:
return len(val) == 0
default:
return false
}
}

View File

@@ -1,151 +0,0 @@
package main
import (
"context"
"fmt"
"net/http"
"time"
"github.com/google/uuid"
"github.com/hay-kot/httpkit/graceful"
"github.com/rs/zerolog/log"
"github.com/sysadminsmedia/homebox/backend/internal/sys/config"
"github.com/sysadminsmedia/homebox/backend/pkgs/utils"
"gocloud.dev/pubsub"
)
func registerRecurringTasks(app *app, cfg *config.Config, runner *graceful.Runner) {
runner.AddFunc("eventbus", app.bus.Run)
runner.AddFunc("seed_database", func(ctx context.Context) error {
if cfg.Demo {
log.Info().Msg("Running in demo mode, creating demo data")
err := app.SetupDemo()
if err != nil {
log.Error().Err(err).Msg("failed to setup demo data")
return fmt.Errorf("failed to setup demo data: %w", err)
}
}
return nil
})
runner.AddPlugin(NewTask("purge-tokens", 24*time.Hour, func(ctx context.Context) {
_, err := app.repos.AuthTokens.PurgeExpiredTokens(ctx)
if err != nil {
log.Error().Err(err).Msg("failed to purge expired tokens")
}
}))
runner.AddPlugin(NewTask("purge-invitations", 24*time.Hour, func(ctx context.Context) {
_, err := app.repos.Groups.InvitationPurge(ctx)
if err != nil {
log.Error().Err(err).Msg("failed to purge expired invitations")
}
}))
runner.AddPlugin(NewTask("send-notifications", time.Hour, func(ctx context.Context) {
now := time.Now()
if now.Hour() == 8 {
fmt.Println("run notifiers")
err := app.services.BackgroundService.SendNotifiersToday(context.Background())
if err != nil {
log.Error().Err(err).Msg("failed to send notifiers")
}
}
}))
if cfg.Thumbnail.Enabled {
runner.AddFunc("create-thumbnails-subscription", func(ctx context.Context) error {
pubsubString, err := utils.GenerateSubPubConn(cfg.Database.PubSubConnString, "thumbnails")
if err != nil {
log.Error().Err(err).Msg("failed to generate pubsub connection string")
return err
}
topic, err := pubsub.OpenTopic(ctx, pubsubString)
if err != nil {
return err
}
defer func(topic *pubsub.Topic, ctx context.Context) {
err := topic.Shutdown(ctx)
if err != nil {
log.Err(err).Msg("fail to shutdown pubsub topic")
}
}(topic, ctx)
subscription, err := pubsub.OpenSubscription(ctx, pubsubString)
if err != nil {
log.Err(err).Msg("failed to open pubsub topic")
return err
}
defer func(topic *pubsub.Subscription, ctx context.Context) {
err := topic.Shutdown(ctx)
if err != nil {
log.Err(err).Msg("fail to shutdown pubsub topic")
}
}(subscription, ctx)
for {
select {
case <-ctx.Done():
return ctx.Err()
default:
msg, err := subscription.Receive(ctx)
log.Debug().Msg("received thumbnail generation request from pubsub topic")
if err != nil {
log.Err(err).Msg("failed to receive message from pubsub topic")
continue
}
if msg == nil {
log.Warn().Msg("received nil message from pubsub topic")
continue
}
groupId, err := uuid.Parse(msg.Metadata["group_id"])
if err != nil {
log.Error().Err(err).Str("group_id", msg.Metadata["group_id"]).Msg("failed to parse group ID from message metadata")
}
attachmentId, err := uuid.Parse(msg.Metadata["attachment_id"])
if err != nil {
log.Error().Err(err).Str("attachment_id", msg.Metadata["attachment_id"]).Msg("failed to parse attachment ID from message metadata")
}
err = app.repos.Attachments.CreateThumbnail(ctx, groupId, attachmentId, msg.Metadata["title"], msg.Metadata["path"])
if err != nil {
log.Err(err).Msg("failed to create thumbnail")
}
msg.Ack()
}
}
})
}
if cfg.Options.GithubReleaseCheck {
runner.AddPlugin(NewTask("get-latest-github-release", time.Hour, func(ctx context.Context) {
log.Debug().Msg("running get latest github release")
err := app.services.BackgroundService.GetLatestGithubRelease(context.Background())
if err != nil {
log.Error().Err(err).Msg("failed to get latest github release")
}
}))
}
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()
})
// Print the configuration to the console
cfg.Print()
}
}

View File

@@ -75,11 +75,6 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
r.Post("/users/register", chain.ToHandlerFunc(v1Ctrl.HandleUserRegistration()))
r.Post("/users/login", chain.ToHandlerFunc(v1Ctrl.HandleAuthLogin(providers...)))
if a.conf.OIDC.Enabled {
r.Get("/users/login/oidc", chain.ToHandlerFunc(v1Ctrl.HandleOIDCLogin()))
r.Get("/users/login/oidc/callback", chain.ToHandlerFunc(v1Ctrl.HandleOIDCCallback()))
}
userMW := []errchain.Middleware{
a.mwAuthToken,
a.mwRoles(RoleModeOr, authroles.RoleUser.String()),
@@ -107,7 +102,6 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
r.Post("/actions/zero-item-time-fields", chain.ToHandlerFunc(v1Ctrl.HandleItemDateZeroOut(), userMW...))
r.Post("/actions/ensure-import-refs", chain.ToHandlerFunc(v1Ctrl.HandleEnsureImportRefs(), userMW...))
r.Post("/actions/set-primary-photos", chain.ToHandlerFunc(v1Ctrl.HandleSetPrimaryPhotos(), userMW...))
r.Post("/actions/create-missing-thumbnails", chain.ToHandlerFunc(v1Ctrl.HandleCreateMissingThumbnails(), userMW...))
r.Get("/locations", chain.ToHandlerFunc(v1Ctrl.HandleLocationGetAll(), userMW...))
r.Post("/locations", chain.ToHandlerFunc(v1Ctrl.HandleLocationCreate(), userMW...))
@@ -134,7 +128,6 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
r.Put("/items/{id}", chain.ToHandlerFunc(v1Ctrl.HandleItemUpdate(), userMW...))
r.Patch("/items/{id}", chain.ToHandlerFunc(v1Ctrl.HandleItemPatch(), userMW...))
r.Delete("/items/{id}", chain.ToHandlerFunc(v1Ctrl.HandleItemDelete(), userMW...))
r.Post("/items/{id}/duplicate", chain.ToHandlerFunc(v1Ctrl.HandleItemDuplicate(), userMW...))
r.Post("/items/{id}/attachments", chain.ToHandlerFunc(v1Ctrl.HandleItemAttachmentCreate(), userMW...))
r.Put("/items/{id}/attachments/{attachment_id}", chain.ToHandlerFunc(v1Ctrl.HandleItemAttachmentUpdate(), userMW...))
@@ -145,14 +138,6 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
r.Get("/assets/{id}", chain.ToHandlerFunc(v1Ctrl.HandleAssetGet(), userMW...))
// Item Templates
r.Get("/templates", chain.ToHandlerFunc(v1Ctrl.HandleItemTemplatesGetAll(), userMW...))
r.Post("/templates", chain.ToHandlerFunc(v1Ctrl.HandleItemTemplatesCreate(), userMW...))
r.Get("/templates/{id}", chain.ToHandlerFunc(v1Ctrl.HandleItemTemplatesGet(), userMW...))
r.Put("/templates/{id}", chain.ToHandlerFunc(v1Ctrl.HandleItemTemplatesUpdate(), userMW...))
r.Delete("/templates/{id}", chain.ToHandlerFunc(v1Ctrl.HandleItemTemplatesDelete(), userMW...))
r.Post("/templates/{id}/create-item", chain.ToHandlerFunc(v1Ctrl.HandleItemTemplatesCreateItem(), userMW...))
// Maintenance
r.Get("/maintenance", chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceGetAll(), userMW...))
r.Put("/maintenance/{id}", chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceEntryUpdate(), userMW...))
@@ -171,8 +156,6 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
a.mwRoles(RoleModeOr, authroles.RoleUser.String(), authroles.RoleAttachments.String()),
}
r.Get("/products/search-from-barcode", chain.ToHandlerFunc(v1Ctrl.HandleProductSearchFromBarcode(a.conf.Barcode), userMW...))
r.Get("/qrcode", chain.ToHandlerFunc(v1Ctrl.HandleGenerateQRCode(), assetMW...))
r.Get(
"/items/{id}/attachments/{attachment_id}",

View File

@@ -1,103 +0,0 @@
package main
import (
"bytes"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/rs/zerolog/log"
"github.com/sysadminsmedia/homebox/backend/internal/core/currencies"
"github.com/sysadminsmedia/homebox/backend/internal/sys/config"
)
// setupStorageDir handles the creation and validation of the storage directory.
func setupStorageDir(cfg *config.Config) error {
if strings.HasPrefix(cfg.Storage.ConnString, "file:///./") {
raw := strings.TrimPrefix(cfg.Storage.ConnString, "file:///./")
clean := filepath.Clean(raw)
absBase, err := filepath.Abs(clean)
if err != nil {
log.Error().Err(err).Msg("failed to get absolute path for storage connection string")
return fmt.Errorf("failed to get absolute path for storage connection string: %w", err)
}
absBase = strings.ReplaceAll(absBase, "\\", "/")
storageDir := filepath.Join(absBase, cfg.Storage.PrefixPath)
storageDir = strings.ReplaceAll(storageDir, "\\", "/")
if !strings.HasPrefix(storageDir, absBase+"/") && storageDir != absBase {
log.Error().Str("path", storageDir).Msg("invalid storage path: you tried to use a prefix that is not a subdirectory of the base path")
return fmt.Errorf("invalid storage path: you tried to use a prefix that is not a subdirectory of the base path")
}
if err := os.MkdirAll(storageDir, 0o750); err != nil {
log.Error().Err(err).Msg("failed to create data directory")
return fmt.Errorf("failed to create data directory: %w", err)
}
}
return nil
}
// setupDatabaseURL returns the database URL and ensures any required directories exist.
func setupDatabaseURL(cfg *config.Config) (string, error) {
databaseURL := ""
switch strings.ToLower(cfg.Database.Driver) {
case "sqlite3":
databaseURL = cfg.Database.SqlitePath
dbFilePath := strings.Split(cfg.Database.SqlitePath, "?")[0]
dbDir := filepath.Dir(dbFilePath)
if err := os.MkdirAll(dbDir, 0o755); err != nil {
log.Error().Err(err).Str("path", dbDir).Msg("failed to create SQLite database directory")
return "", fmt.Errorf("failed to create SQLite database directory: %w", err)
}
case "postgres":
databaseURL = fmt.Sprintf("host=%s port=%s dbname=%s sslmode=%s", cfg.Database.Host, cfg.Database.Port, cfg.Database.Database, cfg.Database.SslMode)
if cfg.Database.Username != "" {
databaseURL += fmt.Sprintf(" user=%s", cfg.Database.Username)
}
if cfg.Database.Password != "" {
databaseURL += fmt.Sprintf(" password=%s", cfg.Database.Password)
}
if cfg.Database.SslRootCert != "" {
if _, err := os.Stat(cfg.Database.SslRootCert); err != nil {
log.Error().Err(err).Str("path", cfg.Database.SslRootCert).Msg("SSL root certificate file is not accessible")
return "", fmt.Errorf("SSL root certificate file is not accessible: %w", err)
}
databaseURL += fmt.Sprintf(" sslrootcert=%s", cfg.Database.SslRootCert)
}
if cfg.Database.SslCert != "" {
if _, err := os.Stat(cfg.Database.SslCert); err != nil {
log.Error().Err(err).Str("path", cfg.Database.SslCert).Msg("SSL certificate file is not accessible")
return "", fmt.Errorf("SSL certificate file is not accessible: %w", err)
}
databaseURL += fmt.Sprintf(" sslcert=%s", cfg.Database.SslCert)
}
if cfg.Database.SslKey != "" {
if _, err := os.Stat(cfg.Database.SslKey); err != nil {
log.Error().Err(err).Str("path", cfg.Database.SslKey).Msg("SSL key file is not accessible")
return "", fmt.Errorf("SSL key file is not accessible: %w", err)
}
databaseURL += fmt.Sprintf(" sslkey=%s", cfg.Database.SslKey)
}
default:
log.Error().Str("driver", cfg.Database.Driver).Msg("unsupported database driver")
return "", fmt.Errorf("unsupported database driver: %s", cfg.Database.Driver)
}
return databaseURL, nil
}
// loadCurrencies loads currency data from config if provided.
func loadCurrencies(cfg *config.Config) ([]currencies.CollectorFunc, error) {
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.Error().Err(err).Str("path", cfg.Options.CurrencyConfig).Msg("failed to read currency config file")
return nil, err
}
collectFuncs = append(collectFuncs, currencies.CollectJSON(bytes.NewReader(content)))
}
return collectFuncs, nil
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,108 @@
package main
import (
"context"
"fmt"
"github.com/sysadminsmedia/homebox/backend/internal/sys/config"
"log"
"os"
"path/filepath"
"strings"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/migrate"
atlas "ariga.io/atlas/sql/migrate"
_ "ariga.io/atlas/sql/sqlite"
"entgo.io/ent/dialect"
"entgo.io/ent/dialect/sql/schema"
_ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3"
)
func main() {
cfg, err := config.New(build(), "Homebox inventory management system")
if err != nil {
panic(err)
}
sqlDialect := ""
switch strings.ToLower(cfg.Database.Driver) {
case "sqlite3":
sqlDialect = dialect.SQLite
case "postgres":
sqlDialect = dialect.Postgres
default:
log.Fatalf("unsupported database driver: %s", cfg.Database.Driver)
}
ctx := context.Background()
// Create a local migration directory able to understand Atlas migration file format for replay.
safePath := filepath.Clean(fmt.Sprintf("internal/data/migrations/%s", sqlDialect))
dir, err := atlas.NewLocalDir(safePath)
if err != nil {
log.Fatalf("failed creating atlas migration directory: %v", err)
}
// Migrate diff options.
opts := []schema.MigrateOption{
schema.WithDir(dir), // provide migration directory
schema.WithMigrationMode(schema.ModeReplay), // provide migration mode
schema.WithDialect(sqlDialect), // Ent dialect to use
schema.WithFormatter(atlas.DefaultFormatter),
schema.WithDropIndex(true),
schema.WithDropColumn(true),
}
if len(os.Args) != 2 {
log.Fatalln("migration name is required. Use: 'go run -mod=mod ent/migrate/main.go <name>'")
}
if sqlDialect == dialect.Postgres {
if !validatePostgresSSLMode(cfg.Database.SslMode) {
log.Fatalf("invalid sslmode: %s", cfg.Database.SslMode)
}
}
databaseURL := ""
switch {
case cfg.Database.Driver == "sqlite3":
databaseURL = fmt.Sprintf("sqlite://%s", cfg.Database.SqlitePath)
case cfg.Database.Driver == "postgres":
databaseURL = fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=%s", cfg.Database.Username, cfg.Database.Password, cfg.Database.Host, cfg.Database.Port, cfg.Database.Database, cfg.Database.SslMode)
default:
log.Fatalf("unsupported database driver: %s", cfg.Database.Driver)
}
// Generate migrations using Atlas support for MySQL (note the Ent dialect option passed above).
err = migrate.NamedDiff(ctx, databaseURL, os.Args[1], opts...)
if err != nil {
log.Fatalf("failed generating migration file: %v", err)
}
fmt.Println("Migration file generated successfully.")
}
var (
version = "nightly"
commit = "HEAD"
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)
}
func validatePostgresSSLMode(sslMode string) bool {
validModes := map[string]bool{
"": true,
"disable": true,
"allow": true,
"prefer": true,
"require": true,
"verify-ca": true,
"verify-full": true,
}
return validModes[strings.ToLower(strings.TrimSpace(sslMode))]
}

View File

@@ -1,209 +1,88 @@
module github.com/sysadminsmedia/homebox/backend
go 1.24.0
toolchain go1.24.3
go 1.23.0
require (
entgo.io/ent v0.14.5
github.com/ardanlabs/conf/v3 v3.9.0
ariga.io/atlas v0.31.1-0.20250212144724-069be8033e83
entgo.io/ent v0.14.3
github.com/ardanlabs/conf/v3 v3.4.0
github.com/containrrr/shoutrrr v0.8.0
github.com/coreos/go-oidc/v3 v3.17.0
github.com/evanoberholster/imagemeta v0.3.1
github.com/gen2brain/avif v0.4.4
github.com/gen2brain/heic v0.4.6
github.com/gen2brain/jpegxl v0.4.5
github.com/gen2brain/webp v0.5.5
github.com/go-chi/chi/v5 v5.2.3
github.com/go-playground/validator/v10 v10.28.0
github.com/go-chi/chi/v5 v5.2.1
github.com/go-playground/validator/v10 v10.25.0
github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
github.com/google/uuid v1.6.0
github.com/gorilla/schema v1.4.1
github.com/hay-kot/httpkit v0.0.11
github.com/lib/pq v1.10.9
github.com/mattn/go-sqlite3 v1.14.32
github.com/olahol/melody v1.4.0
github.com/mattn/go-sqlite3 v1.14.24
github.com/olahol/melody v1.2.1
github.com/pkg/errors v0.9.1
github.com/pressly/goose/v3 v3.26.0
github.com/rs/zerolog v1.34.0
github.com/shirou/gopsutil/v4 v4.25.11
github.com/rs/zerolog v1.33.0
github.com/shirou/gopsutil/v4 v4.24.9
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/stretchr/testify v1.11.1
github.com/stretchr/testify v1.10.0
github.com/swaggo/http-swagger/v2 v2.0.2
github.com/swaggo/swag v1.16.6
github.com/swaggo/swag v1.16.4
github.com/yeqown/go-qrcode/v2 v2.2.5
github.com/yeqown/go-qrcode/writer/standard v1.3.0
github.com/zeebo/blake3 v0.2.4
go.balki.me/anyhttp v0.5.2
gocloud.dev v0.44.0
gocloud.dev/pubsub/kafkapubsub v0.44.0
gocloud.dev/pubsub/natspubsub v0.44.0
gocloud.dev/pubsub/rabbitpubsub v0.44.0
golang.org/x/crypto v0.45.0
golang.org/x/image v0.33.0
golang.org/x/oauth2 v0.33.0
golang.org/x/text v0.31.0
modernc.org/sqlite v1.40.1
github.com/yeqown/go-qrcode/writer/standard v1.2.5
golang.org/x/crypto v0.35.0
modernc.org/sqlite v1.36.0
)
require (
github.com/ebitengine/purego v0.8.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
github.com/zclconf/go-cty-yaml v1.1.0 // indirect
)
require (
ariga.io/atlas v0.32.1-0.20250325101103-175b25e1c1b9 // indirect
cel.dev/expr v0.24.0 // indirect
cloud.google.com/go v0.121.6 // indirect
cloud.google.com/go/auth v0.17.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.9.0 // indirect
cloud.google.com/go/iam v1.5.2 // indirect
cloud.google.com/go/monitoring v1.24.2 // indirect
cloud.google.com/go/pubsub v1.50.0 // indirect
cloud.google.com/go/pubsub/v2 v2.2.1 // indirect
cloud.google.com/go/storage v1.56.0 // indirect
github.com/Azure/azure-amqp-common-go/v3 v3.2.3 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.9.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1 // indirect
github.com/Azure/go-amqp v1.4.0 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest/to v0.4.1 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 // indirect
github.com/IBM/sarama v1.46.3 // indirect
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/aws/aws-sdk-go-v2 v1.39.6 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 // indirect
github.com/aws/aws-sdk-go-v2/config v1.31.17 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.18.21 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 // indirect
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.89.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sns v1.34.7 // indirect
github.com/aws/aws-sdk-go-v2/service/sqs v1.38.8 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 // indirect
github.com/aws/smithy-go v1.23.2 // indirect
github.com/bmatcuk/doublestar v1.3.4 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/eapache/go-resiliency v1.7.0 // indirect
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect
github.com/eapache/queue v1.1.0 // indirect
github.com/ebitengine/purego v0.9.1 // indirect
github.com/envoyproxy/go-control-plane/envoy v1.35.0 // indirect
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fogleman/gg v1.3.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.11 // indirect
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-openapi/inflect v0.19.0 // indirect
github.com/go-openapi/jsonpointer v0.22.3 // indirect
github.com/go-openapi/jsonreference v0.21.3 // indirect
github.com/go-openapi/spec v0.22.1 // indirect
github.com/go-openapi/swag/conv v0.25.4 // indirect
github.com/go-openapi/swag/jsonname v0.25.4 // indirect
github.com/go-openapi/swag/jsonutils v0.25.4 // indirect
github.com/go-openapi/swag/loading v0.25.4 // indirect
github.com/go-openapi/swag/stringutils v0.25.4 // indirect
github.com/go-openapi/swag/typeutils v0.25.4 // indirect
github.com/go-openapi/swag/yamlutils v0.25.4 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/go-openapi/inflect v0.21.0 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // 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.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/golang-jwt/jwt/v5 v5.2.3 // indirect
github.com/golang/snappy v1.0.0 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/google/wire v0.7.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.7 // indirect
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
github.com/google/go-cmp v0.6.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/hcl/v2 v2.18.1 // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
github.com/jcmturner/gofork v1.7.6 // indirect
github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/klauspost/compress v1.18.2 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/hashicorp/hcl/v2 v2.23.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // 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/mfridman/interpolate v0.0.2 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/nats-io/nats.go v1.47.0 // indirect
github.com/nats-io/nkeys v0.4.12 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/philhofer/fwd v1.2.0 // indirect
github.com/pierrec/lz4/v4 v4.1.22 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/rabbitmq/amqp091-go v1.10.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // 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/sethvargo/go-retry v0.3.0 // indirect
github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect
github.com/swaggo/files/v2 v2.0.2 // indirect
github.com/tetratelabs/wazero v1.10.1 // indirect
github.com/tinylib/msgp v1.6.1 // indirect
github.com/tklauser/go-sysconf v0.3.16 // indirect
github.com/tklauser/numcpus v0.11.0 // indirect
github.com/yeqown/reedsolomon v1.0.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
github.com/zclconf/go-cty v1.14.4 // indirect
github.com/zclconf/go-cty-yaml v1.1.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.38.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect
go.opentelemetry.io/otel v1.38.0 // indirect
go.opentelemetry.io/otel/metric v1.38.0 // indirect
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect
go.opentelemetry.io/otel/trace v1.38.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 // indirect
golang.org/x/mod v0.30.0 // indirect
golang.org/x/net v0.47.0 // indirect
golang.org/x/sync v0.18.0 // indirect
golang.org/x/sys v0.38.0 // indirect
golang.org/x/time v0.14.0 // indirect
golang.org/x/tools v0.39.0 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
google.golang.org/api v0.257.0 // indirect
google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
google.golang.org/grpc v1.77.0 // indirect
google.golang.org/protobuf v1.36.10 // indirect
github.com/zclconf/go-cty v1.16.0 // indirect
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
golang.org/x/image v0.23.0
golang.org/x/mod v0.23.0 // indirect
golang.org/x/net v0.36.0 // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.22.0 // indirect
golang.org/x/tools v0.30.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/libc v1.67.1 // indirect
modernc.org/libc v1.61.13 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
modernc.org/memory v1.8.2 // indirect
)

View File

@@ -1,235 +1,58 @@
ariga.io/atlas v0.32.1-0.20250325101103-175b25e1c1b9 h1:E0wvcUXTkgyN4wy4LGtNzMNGMytJN8afmIWXJVMi4cc=
ariga.io/atlas v0.32.1-0.20250325101103-175b25e1c1b9/go.mod h1:Oe1xWPuu5q9LzyrWfbZmEZxFYeu4BHTyzfjeW2aZp/w=
cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
cloud.google.com/go v0.121.6 h1:waZiuajrI28iAf40cWgycWNgaXPO06dupuS+sgibK6c=
cloud.google.com/go v0.121.6/go.mod h1:coChdst4Ea5vUpiALcYKXEpR1S9ZgXbhEzzMcMR66vI=
cloud.google.com/go/auth v0.17.0 h1:74yCm7hCj2rUyyAocqnFzsAYXgJhrG26XCFimrc/Kz4=
cloud.google.com/go/auth v0.17.0/go.mod h1:6wv/t5/6rOPAX4fJiRjKkJCvswLwdet7G8+UGXt7nCQ=
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8=
cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE=
cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc=
cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA=
cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=
cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM=
cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U=
cloud.google.com/go/pubsub v1.50.0 h1:hnYpOIxVlgVD1Z8LN7est4DQZK3K6tvZNurZjIVjUe0=
cloud.google.com/go/pubsub v1.50.0/go.mod h1:Di2Y+nqXBpIS+dXUEJPQzLh8PbIQZMLE9IVUFhf2zmM=
cloud.google.com/go/pubsub/v2 v2.2.1 h1:3brZcshL3fIiD1qOxAE2QW9wxsfjioy014x4yC9XuYI=
cloud.google.com/go/pubsub/v2 v2.2.1/go.mod h1:O5f0KHG9zDheZAd3z5rlCRhxt2JQtB+t/IYLKK3Bpvw=
cloud.google.com/go/storage v1.56.0 h1:iixmq2Fse2tqxMbWhLWC9HfBj1qdxqAmiK8/eqtsLxI=
cloud.google.com/go/storage v1.56.0/go.mod h1:Tpuj6t4NweCLzlNbw9Z9iwxEkrSem20AetIeH/shgVU=
cloud.google.com/go/trace v1.11.6 h1:2O2zjPzqPYAHrn3OKl029qlqG6W8ZdYaOWRyr8NgMT4=
cloud.google.com/go/trace v1.11.6/go.mod h1:GA855OeDEBiBMzcckLPE2kDunIpC72N+Pq8WFieFjnI=
entgo.io/ent v0.14.5 h1:Rj2WOYJtCkWyFo6a+5wB3EfBRP0rnx1fMk6gGA0UUe4=
entgo.io/ent v0.14.5/go.mod h1:zTzLmWtPvGpmSwtkaayM2cm5m819NdM7z7tYPq3vN0U=
github.com/Azure/azure-amqp-common-go/v3 v3.2.3 h1:uDF62mbd9bypXWi19V1bN5NZEO84JqgmI5G73ibAmrk=
github.com/Azure/azure-amqp-common-go/v3 v3.2.3/go.mod h1:7rPmbSfszeovxGfc5fSAXE4ehlXQZHpMja2OtxC2Tas=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 h1:Wc1ml6QlJs2BHQ/9Bqu1jiyggbsSjramq2oUmp5WeIo=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 h1:B+blDbyVIG3WaikNxPnhPiJ1MThR03b3vKGtER95TP4=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1/go.mod h1:JdM5psgjfBf5fo2uWOZhflPWyDBZ/O/CNAH9CtsuZE4=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA=
github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.9.1 h1:CRZwf68N55u7ZZo3Xx2ynuqEA6k5GZfwsEUkU8qsAPk=
github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.9.1/go.mod h1:NydgUaroiShkgOcb+X6OUdS3RalWBrvDNtOyFHJtsZY=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.0 h1:LR0kAX9ykz8G4YgLCaRDVJ3+n43R8MneB5dTy2konZo=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.0/go.mod h1:DWAciXemNf++PQJLeXUB4HHH5OpsAh12HZnu2wXE1jA=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1 h1:lhZdRq7TIx0GJQvSyX2Si406vrYsov2FXGp/RnSEtcs=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1/go.mod h1:8cl44BDmi+effbARHMQjgOKA2AYvcohNm7KEt42mSV8=
github.com/Azure/go-amqp v0.17.0/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fwmw9Zlg=
github.com/Azure/go-amqp v1.4.0 h1:Xj3caqi4comOF/L1Uc5iuBxR/pB6KumejC01YQOqOR4=
github.com/Azure/go-amqp v1.4.0/go.mod h1:vZAogwdrkbyK3Mla8m/CxSc/aKdnTZ4IbPxl51Y5WZE=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA=
github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/autorest/to v0.4.1 h1:CxNHBqdzTr7rLtdrtb5CMjJcDut+WNGCVv7OmS5+lTc=
github.com/Azure/go-autorest/autorest/to v0.4.1/go.mod h1:EtaofgU4zmtvn1zT2ARsjRFdq9vXx0YWtmElwL+GZ9M=
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs=
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
ariga.io/atlas v0.31.1-0.20250212144724-069be8033e83 h1:nX4HXncwIdvQ8/8sIUIf1nyCkK8qdBaHQ7EtzPpuiGE=
ariga.io/atlas v0.31.1-0.20250212144724-069be8033e83/go.mod h1:Oe1xWPuu5q9LzyrWfbZmEZxFYeu4BHTyzfjeW2aZp/w=
entgo.io/ent v0.14.3 h1:wokAV/kIlH9TeklJWGGS7AYJdVckr0DloWjIcO9iIIQ=
entgo.io/ent v0.14.3/go.mod h1:aDPE/OziPEu8+OWbzy4UlvWmD2/kbRuWfK2A40hcxJM=
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/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 h1:owcC2UnmsZycprQ5RfRgjydWhuoxg71LUfyiQdijZuM=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0/go.mod h1:ZPpqegjbE99EPKsu3iUWV22A04wzGPcAY/ziSIQEEgs=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.53.0 h1:4LP6hvB4I5ouTbGgWtixJhgED6xdf67twf9PoY96Tbg=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.53.0/go.mod h1:jUZ5LYlw40WMd07qxcQJD5M40aUxrfwqQX1g7zxYnrQ=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 h1:Ron4zCA/yk6U7WOBXhTJcDpsUBG9npumK6xw2auFltQ=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0/go.mod h1:cSgYe11MCNYunTnRXrKiR/tHc0eoKjICUuWpNZoVCOo=
github.com/IBM/sarama v1.46.3 h1:njRsX6jNlnR+ClJ8XmkO+CM4unbrNr/2vB5KK6UA+IE=
github.com/IBM/sarama v1.46.3/go.mod h1:GTUYiF9DMOZVe3FwyGT+dtSPceGFIgA+sPc5u6CBwko=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
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.9.0 h1:aRBYHeD39/OkuaEXYIEoi4wvF3OnS7jUAPxXyLfEu20=
github.com/ardanlabs/conf/v3 v3.9.0/go.mod h1:XlL9P0quWP4m1weOVFmlezabinbZLI05niDof/+Ochk=
github.com/aws/aws-sdk-go-v2 v1.39.6 h1:2JrPCVgWJm7bm83BDwY5z8ietmeJUbh3O2ACnn+Xsqk=
github.com/aws/aws-sdk-go-v2 v1.39.6/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 h1:DHctwEM8P8iTXFxC/QK0MRjwEpWQeM9yzidCRjldUz0=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3/go.mod h1:xdCzcZEtnSTKVDOmUZs4l/j3pSV6rpo1WXl5ugNsL8Y=
github.com/aws/aws-sdk-go-v2/config v1.31.17 h1:QFl8lL6RgakNK86vusim14P2k8BFSxjvUkcWLDjgz9Y=
github.com/aws/aws-sdk-go-v2/config v1.31.17/go.mod h1:V8P7ILjp/Uef/aX8TjGk6OHZN6IKPM5YW6S78QnRD5c=
github.com/aws/aws-sdk-go-v2/credentials v1.18.21 h1:56HGpsgnmD+2/KpG0ikvvR8+3v3COCwaF4r+oWwOeNA=
github.com/aws/aws-sdk-go-v2/credentials v1.18.21/go.mod h1:3YELwedmQbw7cXNaII2Wywd+YY58AmLPwX4LzARgmmA=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 h1:T1brd5dR3/fzNFAQch/iBKeX07/ffu/cLu+q+RuzEWk=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13/go.mod h1:Peg/GBAQ6JDt+RoBf4meB1wylmAipb7Kg2ZFakZTlwk=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.3 h1:4GNV1lhyELGjMz5ILMRxDvxvOaeo3Ux9Z69S1EgVMMQ=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.3/go.mod h1:br7KA6edAAqDGUYJ+zVVPAyMrPhnN+zdt17yTUT6FPw=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13 h1:a+8/MLcWlIxo1lF9xaGt3J/u3yOZx+CdSveSNwjhD40=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13/go.mod h1:oGnKwIYZ4XttyU2JWxFrwvhF6YKiK/9/wmE3v3Iu9K8=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13 h1:HBSI2kDkMdWz4ZM7FjwE7e/pWDEZ+nR95x8Ztet1ooY=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13/go.mod h1:YE94ZoDArI7awZqJzBAZ3PDD2zSfuP7w6P2knOzIn8M=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13 h1:eg/WYAa12vqTphzIdWMzqYRVKKnCboVPRlvaybNCqPA=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13/go.mod h1:/FDdxWhz1486obGrKKC1HONd7krpk38LBt+dutLcN9k=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/Af8Fi+BH+Hsn9TXGdT+hKbDd5XOTZxTMxDk7o=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.4 h1:NvMjwvv8hpGUILarKw7Z4Q0w1H9anXKsesMxtw++MA4=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.4/go.mod h1:455WPHSwaGj2waRSpQp7TsnpOnBfw8iDfPfbwl7KPJE=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 h1:kDqdFvMY4AtKoACfzIGD8A0+hbT41KTKF//gq7jITfM=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13/go.mod h1:lmKuogqSU3HzQCwZ9ZtcqOc5XGMqtDK7OIc2+DxiUEg=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13 h1:zhBJXdhWIFZ1acfDYIhu4+LCzdUS2Vbcum7D01dXlHQ=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13/go.mod h1:JaaOeCE368qn2Hzi3sEzY6FgAZVCIYcC2nwbro2QCh8=
github.com/aws/aws-sdk-go-v2/service/s3 v1.89.2 h1:xgBWsgaeUESl8A8k80p6yBdexMWDVeiDmJ/pkjohJ7c=
github.com/aws/aws-sdk-go-v2/service/s3 v1.89.2/go.mod h1:+wArOOrcHUevqdto9k1tKOF5++YTe9JEcPSc9Tx2ZSw=
github.com/aws/aws-sdk-go-v2/service/sns v1.34.7 h1:OBuZE9Wt8h2imuRktu+WfjiTGrnYdCIJg8IX92aalHE=
github.com/aws/aws-sdk-go-v2/service/sns v1.34.7/go.mod h1:4WYoZAhHt+dWYpoOQUgkUKfuQbE6Gg/hW4oXE0pKS9U=
github.com/aws/aws-sdk-go-v2/service/sqs v1.38.8 h1:80dpSqWMwx2dAm30Ib7J6ucz1ZHfiv5OCRwN/EnCOXQ=
github.com/aws/aws-sdk-go-v2/service/sqs v1.38.8/go.mod h1:IzNt/udsXlETCdvBOL0nmyMe2t9cGmXmZgsdoZGYYhI=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.1 h1:0JPwLz1J+5lEOfy/g0SURC9cxhbQ1lIMHMa+AHZSzz0=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.1/go.mod h1:fKvyjJcz63iL/ftA6RaM8sRCtN4r4zl4tjL3qw5ec7k=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5 h1:OWs0/j2UYR5LOGi88sD5/lhN6TDLG6SfA7CqsQO9zF0=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5/go.mod h1:klO+ejMvYsB4QATfEOIXk8WAEwN4N0aBfJpvC+5SZBo=
github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 h1:mLlUgHn02ue8whiR4BmxxGJLR2gwU6s6ZzJ5wDamBUs=
github.com/aws/aws-sdk-go-v2/service/sts v1.39.1/go.mod h1:E19xDjpzPZC7LS2knI9E6BaRFDK43Eul7vd6rSq2HWk=
github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM=
github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
github.com/ardanlabs/conf/v3 v3.4.0 h1:Qy7/doJjhsv7Lvzqd9tbvH8fAZ9jzqKtwnwcmZ+sxGs=
github.com/ardanlabs/conf/v3 v3.4.0/go.mod h1:OIi6NK95fj8jKFPdZ/UmcPlY37JBg99hdP9o5XmNK9c=
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/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f h1:Y8xYupdHxryycyPlc9Y+bSQAYZnetRJ70VMVKm5CKI0=
github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f/go.mod h1:HlzOvOjVBOfTGSRXRyY0OiCS/3J1akRGQQpRO/7zyF4=
github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE=
github.com/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
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-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc=
github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
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/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA=
github.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho=
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4ALJ04o5Qqpdz8XLIpNA3WM/iSIXqxtqo7UGVws=
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0=
github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A=
github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329 h1:K+fnvUM0VZ7ZFJf0n4L/BRlnsb9pL/GuDG6FqaH+PwM=
github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329/go.mod h1:Alz8LEClvR7xKsrq3qzoc4N0guvVNSS8KmSChGYr9hs=
github.com/envoyproxy/go-control-plane/envoy v1.35.0 h1:ixjkELDE+ru6idPxcHLj8LBVc2bFP7iBytj353BoHUo=
github.com/envoyproxy/go-control-plane/envoy v1.35.0/go.mod h1:09qwbGVuSWWAyN5t/b3iyVfz5+z8QWGrzkoqm/8SbEs=
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI=
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=
github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
github.com/evanoberholster/imagemeta v0.3.1 h1:E4GUjXcvlVMjP9joN25+bBNf3Al3MTTfMqCrDOCW+LE=
github.com/evanoberholster/imagemeta v0.3.1/go.mod h1:V0vtDJmjTqvwAYO8r+u33NRVIMXQb0qSqEfImoKEiXM=
github.com/ebitengine/purego v0.8.0 h1:JbqvnEzRvPpxhCJzJJ2y0RbiZ8nyjccVUrSM3q+GvvE=
github.com/ebitengine/purego v0.8.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
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/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
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/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik=
github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gen2brain/avif v0.4.4 h1:Ga/ss7qcWWQm2bxFpnjYjhJsNfZrWs5RsyklgFjKRSE=
github.com/gen2brain/avif v0.4.4/go.mod h1:/XCaJcjZraQwKVhpu9aEd9aLOssYOawLvhMBtmHVGqk=
github.com/gen2brain/heic v0.4.6 h1:sNh3mfaEZLmDJnFc5WoLxCzh/wj5GwfJScPfvF5CNJE=
github.com/gen2brain/heic v0.4.6/go.mod h1:ECnpqbqLu0qSje4KSNWUUDK47UPXPzl80T27GWGEL5I=
github.com/gen2brain/jpegxl v0.4.5 h1:TWpVEn5xkIfsswzkjHBArd0Cc9AE0tbjBSoa0jDsrbo=
github.com/gen2brain/jpegxl v0.4.5/go.mod h1:4kWYJ18xCEuO2vzocYdGpeqNJ990/Gjy3uLMg5TBN6I=
github.com/gen2brain/webp v0.5.5 h1:MvQR75yIPU/9nSqYT5h13k4URaJK3gf9tgz/ksRbyEg=
github.com/gen2brain/webp v0.5.5/go.mod h1:xOSMzp4aROt2KFW++9qcK/RBTOVC2S9tJG66ip/9Oc0=
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/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/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-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
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.22.3 h1:dKMwfV4fmt6Ah90zloTbUKWMD+0he+12XYAsPotrkn8=
github.com/go-openapi/jsonpointer v0.22.3/go.mod h1:0lBbqeRsQ5lIanv3LHZBrmRGHLHcQoOXQnf88fHlGWo=
github.com/go-openapi/jsonreference v0.21.3 h1:96Dn+MRPa0nYAR8DR1E03SblB5FJvh7W6krPI0Z7qMc=
github.com/go-openapi/jsonreference v0.21.3/go.mod h1:RqkUP0MrLf37HqxZxrIAtTWW4ZJIK1VzduhXYBEeGc4=
github.com/go-openapi/spec v0.22.1 h1:beZMa5AVQzRspNjvhe5aG1/XyBSMeX1eEOs7dMoXh/k=
github.com/go-openapi/spec v0.22.1/go.mod h1:c7aeIQT175dVowfp7FeCvXXnjN/MrpaONStibD2WtDA=
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4=
github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU=
github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI=
github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag=
github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA=
github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY=
github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo=
github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM=
github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s=
github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE=
github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8=
github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0=
github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw=
github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE=
github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw=
github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc=
github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4=
github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg=
github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls=
github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
github.com/go-openapi/inflect v0.21.0 h1:FoBjBTQEcbg2cJUWX6uwL9OyIW8eqc9k4KhN4lfbeYk=
github.com/go-openapi/inflect v0.21.0/go.mod h1:INezMuUu7SJQc2AyR3WO0DqqYUJSj8Kb4hBd7WtjlAw=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
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.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
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.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688=
github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU=
github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8=
github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
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-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
@@ -237,87 +60,41 @@ github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3a
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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0=
github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
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/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
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.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
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/go-replayers/grpcreplay v1.3.0 h1:1Keyy0m1sIpqstQmgz307zhiJ1pV4uIlFds5weTmxbo=
github.com/google/go-replayers/grpcreplay v1.3.0/go.mod h1:v6NgKtkijC0d3e3RW8il6Sy5sqRVUwoQa4mHOGEy8DI=
github.com/google/go-replayers/httpreplay v1.2.0 h1:VM1wEyyjaoU53BwrOnaf9VhAyQQEEioJvFYxYcLRKzk=
github.com/google/go-replayers/httpreplay v1.2.0/go.mod h1:WahEFFZZ7a1P4VM1qEeHy+tME4bwyqPcwWbNlUI1Mcg=
github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc=
github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=
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/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4=
github.com/google/wire v0.7.0/go.mod h1:n6YbUQD9cPKTnHXEBN2DXlOp/mVADhVErcMFb0v3J18=
github.com/googleapis/enterprise-certificate-proxy v0.3.7 h1:zrn2Ee/nWmHulBx5sAVrGgAa0f2/R35S4DJwfFaUPFQ=
github.com/googleapis/enterprise-certificate-proxy v0.3.7/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=
github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=
github.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E=
github.com/gorilla/schema v1.4.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
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/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hashicorp/hcl/v2 v2.18.1 h1:6nxnOJFku1EuSawSD81fuviYUV8DxFr3fp2dUi3ZYSo=
github.com/hashicorp/hcl/v2 v2.18.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE=
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/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg=
github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo=
github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8=
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
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/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
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/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=
@@ -325,268 +102,114 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
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-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs=
github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY=
github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg=
github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
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/nats-io/jwt/v2 v2.5.0 h1:WQQ40AAlqqfx+f6ku+i0pOVm+ASirD4fUh+oQsiE9Ak=
github.com/nats-io/jwt/v2 v2.5.0/go.mod h1:24BeQtRwxRV8ruvC4CojXlx/WQ/VjuwlYiH+vu/+ibI=
github.com/nats-io/nats-server/v2 v2.9.23 h1:6Wj6H6QpP9FMlpCyWUaNu2yeZ/qGj+mdRkZ1wbikExU=
github.com/nats-io/nats-server/v2 v2.9.23/go.mod h1:wEjrEy9vnqIGE4Pqz4/c75v9Pmaq7My2IgFmnykc4C0=
github.com/nats-io/nats.go v1.47.0 h1:YQdADw6J/UfGUd2Oy6tn4Hq6YHxCaJrVKayxxFqYrgM=
github.com/nats-io/nats.go v1.47.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
github.com/nats-io/nkeys v0.4.12 h1:nssm7JKOG9/x4J8II47VWCL1Ds29avyiQDRn0ckMvDc=
github.com/nats-io/nkeys v0.4.12/go.mod h1:MT59A1HYcjIcyQDJStTfaOY6vhy9XTUjOFo+SVsvpBg=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/olahol/melody v1.4.0 h1:Pa5SdeZL/zXPi1tJuMAPDbl4n3gQOThSL6G1p4qZ4SI=
github.com/olahol/melody v1.4.0/go.mod h1:GgkTl6Y7yWj/HtfD48Q5vLKPVoZOH+Qqgfa7CvJgJM4=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
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/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/pressly/goose/v3 v3.26.0 h1:KJakav68jdH0WDvoAcj8+n61WqOIaPGgH0bJWS6jpmM=
github.com/pressly/goose/v3 v3.26.0/go.mod h1:4hC1KrritdCxtuFsqgs1R4AU5bWtTAf+cnWvfhf2DNY=
github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw=
github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o=
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg=
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI=
github.com/redis/go-redis/v9 v9.8.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
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.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
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/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE=
github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas=
github.com/shirou/gopsutil/v4 v4.25.11 h1:X53gB7muL9Gnwwo2evPSE+SfOrltMoR6V3xJAXZILTY=
github.com/shirou/gopsutil/v4 v4.25.11/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU=
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.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/shirou/gopsutil/v4 v4.24.9 h1:KIV+/HaHD5ka5f570RZq+2SaeFsb/pq+fp2DGNWYoOI=
github.com/shirou/gopsutil/v4 v4.24.9/go.mod h1:3fkaHNeYsUFCGZ8+9vZVWtbyM1k2eRnlL+bWO8Bxa/Q=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
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/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo=
github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
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.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI=
github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg=
github.com/tetratelabs/wazero v1.10.1 h1:2DugeJf6VVk58KTPszlNfeeN8AhhpwcZqkJj2wwFuH8=
github.com/tetratelabs/wazero v1.10.1/go.mod h1:DRm5twOQ5Gr1AoEdSi0CLjDQF1J9ZAuyqFIjl1KKfQU=
github.com/tinylib/msgp v1.6.1 h1:ESRv8eL3u+DNHUoSAAQRE50Hm162zqAnBoGv9PzScPY=
github.com/tinylib/msgp v1.6.1/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA=
github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=
github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=
github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=
github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=
github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A=
github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
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.3.0 h1:chdyhEfRtUPgQtuPeaWVGQ/TQx4rE1PqeoW3U+53t34=
github.com/yeqown/go-qrcode/writer/standard v1.3.0/go.mod h1:O4MbzsotGCvy8upYPCR91j81dr5XLT7heuljcNXW+oQ=
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/yeqown/reedsolomon v1.0.0 h1:x1h/Ej/uJnNu8jaX7GLHBWmZKCAWjEJTetkqaabr4B0=
github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw/Iy6g1WiiM=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=
github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
github.com/zclconf/go-cty v1.16.0 h1:xPKEhst+BW5D0wxebMZkxgapvOE/dw7bFTlgSc9nD6w=
github.com/zclconf/go-cty v1.16.0/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=
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI=
github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE=
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
go.balki.me/anyhttp v0.5.2 h1:et4tCDXLeXpWfMNvRKG7ojfrnlr3du7cEaG966MLSpA=
go.balki.me/anyhttp v0.5.2/go.mod h1:JhfekOIjgVODoVqUCficjpIgmB3wwlB7jhN0eN2EZ/s=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/detectors/gcp v1.38.0 h1:ZoYbqX7OaA/TAikspPl3ozPI6iY6LiIY9I8cUfm+pJs=
go.opentelemetry.io/contrib/detectors/gcp v1.38.0/go.mod h1:SU+iU7nu5ud4oCb3LQOhIZ3nRLj6FNVrKgtflbaf2ts=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 h1:rbRJ8BBoVMsQShESYZ0FkvcITu8X8QNwJogcLUmDNNw=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0/go.mod h1:ru6KHrNtNHxM4nD/vd6QrLVWgKhxPYgblq4VAtNawTQ=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY=
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.37.0 h1:6VjV6Et+1Hd2iLZEPtdV7vie80Yyqf7oikJLjQ/myi0=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.37.0/go.mod h1:u8hcp8ji5gaM/RfcOo8z9NMnf1pVLfVY7lBY2VOGuUU=
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
gocloud.dev v0.44.0 h1:iVyMAqFl2r6xUy7M4mfqwlN+21UpJoEtgHEcfiLMUXs=
gocloud.dev v0.44.0/go.mod h1:ZmjROXGdC/eKZLF1N+RujDlFRx3D+4Av2thREKDMVxY=
gocloud.dev/pubsub/kafkapubsub v0.44.0 h1:nQvzfnEN6lCh4j2p+1t0OLS4nmC2U/Ji5aWHVwgkifg=
gocloud.dev/pubsub/kafkapubsub v0.44.0/go.mod h1:/gcNz6OG4HgcY+w2LXwwY4qaRMgtq+SXoPSQU2jOlcw=
gocloud.dev/pubsub/natspubsub v0.44.0 h1:1Us76ckkdgtiE1p1rJZ+38b9TQP051bmjAiQlFQzYrM=
gocloud.dev/pubsub/natspubsub v0.44.0/go.mod h1:PvVAGIhL14PWGwWIXX/zAK42ixr2/PKP4Q4yMiAUraQ=
gocloud.dev/pubsub/rabbitpubsub v0.44.0 h1:MpRIO6XJ/JTqrlUWt3CxwDe1LvaiXUVu4sS5cv4f/AM=
gocloud.dev/pubsub/rabbitpubsub v0.44.0/go.mod h1:BB9+qT3r6g4M5+4asiXaEeqw4QAOzsWusO5krYaqkdA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 h1:DHNhtq3sNNzrvduZZIiFyXWOL9IWaDPHqTnLJp+rCBY=
golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0=
golang.org/x/image v0.33.0 h1:LXRZRnv1+zGd5XBUVRFmYEphyyKJjQjCRiOuAP3sZfQ=
golang.org/x/image v0.33.0/go.mod h1:DD3OsTYT9chzuzTQt+zMcOlBHgfoKQb1gry8p76Y1sc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo=
golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
golang.org/x/image v0.23.0 h1:HseQ7c2OpPKTPVzNjG5fwJsOTCiiwS4QdsYi5XU6H68=
golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY=
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA=
golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/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-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/api v0.257.0 h1:8Y0lzvHlZps53PEaw+G29SsQIkuKrumGWs9puiexNAA=
google.golang.org/api v0.257.0/go.mod h1:4eJrr+vbVaZSqs7vovFd1Jb/A6ml6iw2e6FBYf3GAO4=
google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 h1:Nt6z9UHqSlIdIGJdz6KhTIs2VRx/iOsA5iE8bmQNcxs=
google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79/go.mod h1:kTmlBHMPqR5uCZPBvwa2B18mvubkjyY3CRLI0c6fj0s=
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4=
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM=
google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig=
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis=
modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v4 v4.30.1 h1:4r4U1J6Fhj98NKfSjnPUN7Ze2c6MnAdL0hWw6+LrJpc=
modernc.org/ccgo/v4 v4.30.1/go.mod h1:bIOeI1JL54Utlxn+LwrFyjCx2n2RDiYEaJVSrgdrRfM=
modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA=
modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/gc/v3 v3.1.1 h1:k8T3gkXWY9sEiytKhcgyiZ2L0DTyCQ/nvX+LoCljoRE=
modernc.org/gc/v3 v3.1.1/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
modernc.org/libc v1.67.1 h1:bFaqOaa5/zbWYJo8aW0tXPX21hXsngG2M7mckCnFSVk=
modernc.org/libc v1.67.1/go.mod h1:QvvnnJ5P7aitu0ReNpVIEyesuhmDLQ8kaEoyMjIFZJA=
modernc.org/cc/v4 v4.24.4 h1:TFkx1s6dCkQpd6dKurBNmpo+G8Zl4Sq/ztJ+2+DEsh0=
modernc.org/cc/v4 v4.24.4/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v4 v4.23.16 h1:Z2N+kk38b7SfySC1ZkpGLN2vthNJP1+ZzGZIlH7uBxo=
modernc.org/ccgo/v4 v4.23.16/go.mod h1:nNma8goMTY7aQZQNTyN9AIoJfxav4nvTnvKThAeMDdo=
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.3 h1:aJVhcqAte49LF+mGveZ5KPlsp4tdGdAOT4sipJXADjw=
modernc.org/gc/v2 v2.6.3/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/libc v1.61.13 h1:3LRd6ZO1ezsFiX1y+bHd1ipyEHIJKvuprv0sLTBwLW8=
modernc.org/libc v1.61.13/go.mod h1:8F/uJWL/3nNil0Lgt1Dpz+GgkApWh04N3el3hxJcA6E=
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.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
modernc.org/memory v1.8.2 h1:cL9L4bcoAObu4NkxOlKWBWtNHIsnnACGF/TbqQ6sbcI=
modernc.org/memory v1.8.2/go.mod h1:ZbjSvMO5NQ1A2i3bWeDiVMxIorXwdClKE/0SZ+BMotU=
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.40.1 h1:VfuXcxcUWWKRBuP8+BR9L7VnmusMgBNNnBYGEe9w/iY=
modernc.org/sqlite v1.40.1/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE=
modernc.org/sqlite v1.36.0 h1:EQXNRn4nIS+gfsKeUTymHIz1waxuv5BzU7558dHSfH8=
modernc.org/sqlite v1.36.0/go.mod h1:7MPwH7Z6bREicF9ZVUR78P1IKuxfZ8mRIDHD0iD+8TU=
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=

View File

@@ -7,7 +7,6 @@ import (
_ "embed"
"encoding/json"
"io"
"log"
"slices"
"strings"
"sync"
@@ -16,24 +15,6 @@ import (
//go:embed currencies.json
var defaults []byte
const (
MinDecimals = 0
MaxDecimals = 18
)
// clampDecimals ensures the decimals value is within a safe range [0, 18]
func clampDecimals(decimals int, code string) int {
original := decimals
if decimals < MinDecimals {
decimals = MinDecimals
log.Printf("WARNING: Currency %s had negative decimals (%d), normalized to %d", code, original, decimals)
} else if decimals > MaxDecimals {
decimals = MaxDecimals
log.Printf("WARNING: Currency %s had excessive decimals (%d), normalized to %d", code, original, decimals)
}
return decimals
}
type CollectorFunc func() ([]Currency, error)
func CollectJSON(reader io.Reader) CollectorFunc {
@@ -44,11 +25,6 @@ func CollectJSON(reader io.Reader) CollectorFunc {
return nil, err
}
// Clamp decimals during collection to ensure early normalization
for i := range currencies {
currencies[i].Decimals = clampDecimals(currencies[i].Decimals, currencies[i].Code)
}
return currencies, nil
}
}
@@ -72,11 +48,10 @@ func CollectionCurrencies(collectors ...CollectorFunc) ([]Currency, error) {
}
type Currency struct {
Name string `json:"name"`
Code string `json:"code"`
Local string `json:"local"`
Symbol string `json:"symbol"`
Decimals int `json:"decimals"`
Name string `json:"name"`
Code string `json:"code"`
Local string `json:"local"`
Symbol string `json:"symbol"`
}
type CurrencyRegistry struct {
@@ -87,10 +62,7 @@ type CurrencyRegistry struct {
func NewCurrencyService(currencies []Currency) *CurrencyRegistry {
registry := make(map[string]Currency, len(currencies))
for i := range currencies {
// Clamp decimals to safe range before adding to registry
currency := currencies[i]
currency.Decimals = clampDecimals(currency.Decimals, currency.Code)
registry[currency.Code] = currency
registry[currencies[i].Code] = currencies[i]
}
return &CurrencyRegistry{

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,6 @@ package services
import (
"context"
"github.com/sysadminsmedia/homebox/backend/internal/sys/config"
"log"
"os"
"testing"
@@ -38,11 +37,10 @@ func bootstrap() {
log.Fatal(err)
}
password := fk.Str(10)
tUser, err = tRepos.Users.Create(ctx, repo.UserCreate{
Name: fk.Str(10),
Email: fk.Email(),
Password: &password,
Password: fk.Str(10),
IsSuperuser: fk.Bool(),
GroupID: tGroup.ID,
})
@@ -63,19 +61,7 @@ func MainNoExit(m *testing.M) int {
}
tClient = client
tRepos = repo.New(tClient, tbus, config.Storage{
PrefixPath: "/",
ConnString: "file://" + os.TempDir(),
}, "mem://{{ .Topic }}", config.Thumbnail{
Enabled: false,
Width: 0,
Height: 0,
})
err = os.MkdirAll(os.TempDir()+"/homebox", 0o755)
if err != nil {
return 0
}
tRepos = repo.New(tClient, tbus, os.TempDir()+"/homebox")
defaults, _ := currencies.CollectionCurrencies(
currencies.CollectDefaults(),

View File

@@ -38,10 +38,6 @@ func (svc *ItemService) Create(ctx Context, item repo.ItemCreate) (repo.ItemOut,
return svc.repo.Items.Create(ctx, ctx.GID, item)
}
func (svc *ItemService) Duplicate(ctx Context, gid, id uuid.UUID, options repo.DuplicateOptions) (repo.ItemOut, error) {
return svc.repo.Items.Duplicate(ctx, gid, id, options)
}
func (svc *ItemService) EnsureAssetID(ctx context.Context, gid uuid.UUID) (int, error) {
items, err := svc.repo.Items.GetAllZeroAssetID(ctx, gid)
if err != nil {

View File

@@ -10,25 +10,25 @@ import (
"io"
)
func (svc *ItemService) AttachmentPath(ctx context.Context, gid uuid.UUID, attachmentID uuid.UUID) (*ent.Attachment, error) {
attachment, err := svc.repo.Attachments.Get(ctx, gid, 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
}
return attachment, nil
return attachment.Edges.Document, nil
}
func (svc *ItemService) AttachmentUpdate(ctx Context, gid uuid.UUID, 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, gid, data.ID, data)
attachment, err := svc.repo.Attachments.Update(ctx, data.ID, data)
if err != nil {
return repo.ItemOut{}, err
}
// Update Document
attDoc := attachment
_, err = svc.repo.Attachments.Rename(ctx, gid, attDoc.ID, data.Title)
attDoc := attachment.Edges.Document
_, err = svc.repo.Docs.Rename(ctx, attDoc.ID, data.Title)
if err != nil {
return repo.ItemOut{}, err
}
@@ -39,15 +39,22 @@ func (svc *ItemService) AttachmentUpdate(ctx Context, gid uuid.UUID, itemID uuid
// 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, primary bool, 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)
if err != nil {
return repo.ItemOut{}, err
}
// Create the document
doc, err := svc.repo.Docs.Create(ctx, ctx.GID, repo.DocumentCreate{Title: filename, Content: file})
if err != nil {
log.Err(err).Msg("failed to create document")
return repo.ItemOut{}, err
}
// Create the attachment
_, err = svc.repo.Attachments.Create(ctx, itemID, repo.ItemCreateAttachment{Title: filename, Content: file}, attachmentType, primary)
_, 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
@@ -56,9 +63,28 @@ func (svc *ItemService) AttachmentAdd(ctx Context, itemID uuid.UUID, filename st
return svc.repo.Items.GetOneByGroup(ctx, ctx.GID, itemID)
}
func (svc *ItemService) AttachmentDelete(ctx context.Context, gid uuid.UUID, id uuid.UUID, 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)
if err != nil {
return err
}
attachment, err := svc.repo.Attachments.Get(ctx, attachmentID)
if err != nil {
return err
}
documentID := attachment.Edges.Document.GetID()
// Delete the attachment
err := svc.repo.Attachments.Delete(ctx, gid, id, attachmentID)
err = svc.repo.Attachments.Delete(ctx, attachmentID)
if err != nil {
return err
}
// Delete the document, this function also removes the file
err = svc.repo.Docs.Delete(ctx, documentID)
if err != nil {
return err
}

View File

@@ -10,7 +10,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/sysadminsmedia/homebox/backend/internal/data/repo"
"github.com/sysadminsmedia/homebox/backend/internal/sys/config"
)
func TestItemService_AddAttachment(t *testing.T) {
@@ -46,68 +45,18 @@ func TestItemService_AddAttachment(t *testing.T) {
reader := strings.NewReader(contents)
// Setup
afterAttachment, err := svc.AttachmentAdd(tCtx, itm.ID, "testfile.txt", "attachment", false, reader)
afterAttachment, err := svc.AttachmentAdd(tCtx, itm.ID, "testfile.txt", "attachment", reader)
require.NoError(t, err)
assert.NotNil(t, afterAttachment)
// Check that the file exists
storedPath := afterAttachment.Attachments[0].Path
storedPath := afterAttachment.Attachments[0].Document.Path
// path should now be relative: {group}/{documents}
assert.Equal(t, path.Join(tGroup.ID.String(), "documents"), path.Dir(storedPath))
// {root}/{group}/{item}/{attachment}
assert.Equal(t, path.Join(temp, "homebox", tGroup.ID.String(), "documents"), path.Dir(storedPath))
// Check that the file contents are correct
bts, err := os.ReadFile(path.Join(os.TempDir(), storedPath))
bts, err := os.ReadFile(storedPath)
require.NoError(t, err)
assert.Equal(t, contents, string(bts))
}
func TestItemService_AddAttachment_InvalidStorage(t *testing.T) {
// Create a service with an invalid storage path to simulate the issue
svc := &ItemService{
repo: tRepos,
filepath: "/nonexistent/path/that/should/not/exist",
}
// Create a temporary repo with invalid storage config
invalidRepos := repo.New(tClient, tbus, config.Storage{
PrefixPath: "/",
ConnString: "file:///nonexistent/directory/that/does/not/exist",
}, "mem://{{ .Topic }}", config.Thumbnail{
Enabled: false,
Width: 0,
Height: 0,
})
svc.repo = invalidRepos
loc, err := invalidRepos.Locations.Create(context.Background(), tGroup.ID, repo.LocationCreate{
Description: "test",
Name: "test-invalid",
})
require.NoError(t, err)
assert.NotNil(t, loc)
itmC := repo.ItemCreate{
Name: fk.Str(10),
Description: fk.Str(10),
LocationID: loc.ID,
}
itm, err := invalidRepos.Items.Create(context.Background(), tGroup.ID, itmC)
require.NoError(t, err)
assert.NotNil(t, itm)
t.Cleanup(func() {
err := invalidRepos.Items.Delete(context.Background(), itm.ID)
require.NoError(t, err)
})
contents := fk.Str(1000)
reader := strings.NewReader(contents)
// Attempt to add attachment with invalid storage - should return an error
_, err = svc.AttachmentAdd(tCtx, itm.ID, "testfile.txt", "attachment", false, reader)
// This should return an error now (after the fix)
assert.Error(t, err, "AttachmentAdd should return an error when storage is invalid")
}

View File

@@ -3,21 +3,20 @@ package services
import (
"context"
"errors"
"strings"
"time"
"github.com/google/uuid"
"github.com/rs/zerolog/log"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/authroles"
"github.com/sysadminsmedia/homebox/backend/internal/data/repo"
"github.com/sysadminsmedia/homebox/backend/pkgs/hasher"
)
var (
oneWeek = time.Hour * 24 * 7
ErrorInvalidLogin = errors.New("invalid username or password")
ErrorInvalidToken = errors.New("invalid token")
oneWeek = time.Hour * 24 * 7
ErrorInvalidLogin = errors.New("invalid username or password")
ErrorInvalidToken = errors.New("invalid token")
ErrorTokenIDMismatch = errors.New("token id mismatch")
)
type UserService struct {
@@ -83,7 +82,7 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
usrCreate := repo.UserCreate{
Name: data.Name,
Email: data.Email,
Password: &hashed,
Password: hashed,
IsSuperuser: false,
GroupID: group.ID,
IsOwner: creatingGroup,
@@ -191,134 +190,13 @@ func (svc *UserService) Login(ctx context.Context, username, password string, ex
return UserAuthTokenDetail{}, ErrorInvalidLogin
}
// SECURITY: Deny login for users with null or empty password (OIDC users)
if usr.PasswordHash == "" {
log.Warn().Str("email", username).Msg("Login attempt blocked for user with null password (likely OIDC user)")
// SECURITY: Perform hash to ensure response times are the same
hasher.CheckPasswordHash("not-a-real-password", "not-a-real-password")
if !hasher.CheckPasswordHash(password, usr.PasswordHash) {
return UserAuthTokenDetail{}, ErrorInvalidLogin
}
check, rehash := hasher.CheckPasswordHash(password, usr.PasswordHash)
if !check {
return UserAuthTokenDetail{}, ErrorInvalidLogin
}
if rehash {
hash, err := hasher.HashPassword(password)
if err != nil {
log.Err(err).Msg("Failed to hash password")
return UserAuthTokenDetail{}, err
}
err = svc.repos.Users.ChangePassword(ctx, usr.ID, hash)
if err != nil {
return UserAuthTokenDetail{}, err
}
}
return svc.createSessionToken(ctx, usr.ID, extendedSession)
}
// LoginOIDC creates a session token for a user authenticated via OIDC.
// It now uses issuer + subject for identity association (OIDC spec compliance).
// If the user doesn't exist, it will create one.
func (svc *UserService) LoginOIDC(ctx context.Context, issuer, subject, email, name string) (UserAuthTokenDetail, error) {
issuer = strings.TrimSpace(issuer)
subject = strings.TrimSpace(subject)
email = strings.ToLower(strings.TrimSpace(email))
name = strings.TrimSpace(name)
if issuer == "" || subject == "" {
log.Warn().Str("issuer", issuer).Str("subject", subject).Msg("OIDC login missing issuer or subject")
return UserAuthTokenDetail{}, ErrorInvalidLogin
}
// Try to get existing user by OIDC identity
usr, err := svc.repos.Users.GetOneOIDC(ctx, issuer, subject)
if err != nil {
if !ent.IsNotFound(err) {
log.Err(err).Str("issuer", issuer).Str("subject", subject).Msg("failed to lookup user by OIDC identity")
return UserAuthTokenDetail{}, err
}
// Not found: attempt migration path by email (legacy) if email provided
if email != "" {
legacyUsr, lerr := svc.repos.Users.GetOneEmail(ctx, email)
if lerr == nil {
log.Info().Str("email", email).Str("issuer", issuer).Str("subject", subject).Msg("migrating legacy email-based OIDC user to issuer+subject")
// Update user with OIDC identity fields
if uerr := svc.repos.Users.SetOIDCIdentity(ctx, legacyUsr.ID, issuer, subject); uerr == nil {
usr = legacyUsr
} else {
log.Err(uerr).Str("email", email).Msg("failed to set OIDC identity on legacy user")
}
}
}
}
// Create user if still not resolved
if usr.ID == uuid.Nil {
log.Debug().Str("issuer", issuer).Str("subject", subject).Msg("OIDC user not found, creating new user")
usr, err = svc.registerOIDCUser(ctx, issuer, subject, email, name)
if err != nil {
if ent.IsConstraintError(err) {
if usr2, gerr := svc.repos.Users.GetOneOIDC(ctx, issuer, subject); gerr == nil {
log.Info().Str("issuer", issuer).Str("subject", subject).Msg("OIDC user created concurrently; proceeding")
usr = usr2
} else {
log.Err(gerr).Str("issuer", issuer).Str("subject", subject).Msg("failed to fetch user after constraint error")
return UserAuthTokenDetail{}, gerr
}
} else {
log.Err(err).Str("issuer", issuer).Str("subject", subject).Msg("failed to create OIDC user")
return UserAuthTokenDetail{}, err
}
}
}
return svc.createSessionToken(ctx, usr.ID, true)
}
// registerOIDCUser creates a new user for OIDC authentication with issuer+subject identity.
func (svc *UserService) registerOIDCUser(ctx context.Context, issuer, subject, email, name string) (repo.UserOut, error) {
group, err := svc.repos.Groups.GroupCreate(ctx, "Home")
if err != nil {
log.Err(err).Msg("Failed to create group for OIDC user")
return repo.UserOut{}, err
}
usrCreate := repo.UserCreate{
Name: name,
Email: email,
Password: nil,
IsSuperuser: false,
GroupID: group.ID,
IsOwner: true,
}
entUser, err := svc.repos.Users.CreateWithOIDC(ctx, usrCreate, issuer, subject)
if err != nil {
return repo.UserOut{}, err
}
log.Debug().Str("issuer", issuer).Str("subject", subject).Msg("creating default labels for OIDC user")
for _, label := range defaultLabels() {
_, err := svc.repos.Labels.Create(ctx, group.ID, label)
if err != nil {
log.Err(err).Msg("Failed to create default label")
}
}
log.Debug().Str("issuer", issuer).Str("subject", subject).Msg("creating default locations for OIDC user")
for _, location := range defaultLocations() {
_, err := svc.repos.Locations.Create(ctx, group.ID, location)
if err != nil {
log.Err(err).Msg("Failed to create default location")
}
}
return entUser, nil
}
func (svc *UserService) Logout(ctx context.Context, token string) error {
hash := hasher.HashToken(token)
err := svc.repos.AuthTokens.DeleteToken(ctx, hash)
@@ -349,8 +227,7 @@ func (svc *UserService) ChangePassword(ctx Context, current string, new string)
return false
}
match, _ := hasher.CheckPasswordHash(current, usr.PasswordHash)
if !match {
if !hasher.CheckPasswordHash(current, usr.PasswordHash) {
log.Err(errors.New("current password is incorrect")).Msg("Failed to change password")
return false
}

View File

@@ -11,6 +11,7 @@ import (
"entgo.io/ent/dialect/sql"
"github.com/google/uuid"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/attachment"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/document"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/item"
)
@@ -27,16 +28,10 @@ type Attachment struct {
Type attachment.Type `json:"type,omitempty"`
// Primary holds the value of the "primary" field.
Primary bool `json:"primary,omitempty"`
// Title holds the value of the "title" field.
Title string `json:"title,omitempty"`
// Path holds the value of the "path" field.
Path string `json:"path,omitempty"`
// MimeType holds the value of the "mime_type" field.
MimeType string `json:"mime_type,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"`
attachment_thumbnail *uuid.UUID
document_attachments *uuid.UUID
item_attachments *uuid.UUID
selectValues sql.SelectValues
}
@@ -45,8 +40,8 @@ type Attachment struct {
type AttachmentEdges struct {
// Item holds the value of the item edge.
Item *Item `json:"item,omitempty"`
// Thumbnail holds the value of the thumbnail edge.
Thumbnail *Attachment `json:"thumbnail,omitempty"`
// Document holds the value of the document edge.
Document *Document `json:"document,omitempty"`
// loadedTypes holds the information for reporting if a
// type was loaded (or requested) in eager-loading or not.
loadedTypes [2]bool
@@ -63,15 +58,15 @@ func (e AttachmentEdges) ItemOrErr() (*Item, error) {
return nil, &NotLoadedError{edge: "item"}
}
// ThumbnailOrErr returns the Thumbnail value or an error if the edge
// DocumentOrErr returns the Document value or an error if the edge
// was not loaded in eager-loading, or loaded but was not found.
func (e AttachmentEdges) ThumbnailOrErr() (*Attachment, error) {
if e.Thumbnail != nil {
return e.Thumbnail, nil
func (e AttachmentEdges) DocumentOrErr() (*Document, error) {
if e.Document != nil {
return e.Document, nil
} else if e.loadedTypes[1] {
return nil, &NotFoundError{label: attachment.Label}
return nil, &NotFoundError{label: document.Label}
}
return nil, &NotLoadedError{edge: "thumbnail"}
return nil, &NotLoadedError{edge: "document"}
}
// scanValues returns the types for scanning values from sql.Rows.
@@ -81,13 +76,13 @@ func (*Attachment) scanValues(columns []string) ([]any, error) {
switch columns[i] {
case attachment.FieldPrimary:
values[i] = new(sql.NullBool)
case attachment.FieldType, attachment.FieldTitle, attachment.FieldPath, attachment.FieldMimeType:
case attachment.FieldType:
values[i] = new(sql.NullString)
case attachment.FieldCreatedAt, attachment.FieldUpdatedAt:
values[i] = new(sql.NullTime)
case attachment.FieldID:
values[i] = new(uuid.UUID)
case attachment.ForeignKeys[0]: // attachment_thumbnail
case attachment.ForeignKeys[0]: // document_attachments
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
case attachment.ForeignKeys[1]: // item_attachments
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
@@ -100,7 +95,7 @@ func (*Attachment) scanValues(columns []string) ([]any, error) {
// assignValues assigns the values that were returned from sql.Rows (after scanning)
// to the Attachment fields.
func (_m *Attachment) assignValues(columns []string, values []any) error {
func (a *Attachment) assignValues(columns []string, values []any) error {
if m, n := len(values), len(columns); m < n {
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
}
@@ -110,66 +105,48 @@ func (_m *Attachment) assignValues(columns []string, values []any) error {
if value, ok := values[i].(*uuid.UUID); !ok {
return fmt.Errorf("unexpected type %T for field id", values[i])
} else if value != nil {
_m.ID = *value
a.ID = *value
}
case attachment.FieldCreatedAt:
if value, ok := values[i].(*sql.NullTime); !ok {
return fmt.Errorf("unexpected type %T for field created_at", values[i])
} else if value.Valid {
_m.CreatedAt = value.Time
a.CreatedAt = value.Time
}
case attachment.FieldUpdatedAt:
if value, ok := values[i].(*sql.NullTime); !ok {
return fmt.Errorf("unexpected type %T for field updated_at", values[i])
} else if value.Valid {
_m.UpdatedAt = value.Time
a.UpdatedAt = value.Time
}
case attachment.FieldType:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field type", values[i])
} else if value.Valid {
_m.Type = attachment.Type(value.String)
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 {
_m.Primary = value.Bool
}
case attachment.FieldTitle:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field title", values[i])
} else if value.Valid {
_m.Title = value.String
}
case attachment.FieldPath:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field path", values[i])
} else if value.Valid {
_m.Path = value.String
}
case attachment.FieldMimeType:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field mime_type", values[i])
} else if value.Valid {
_m.MimeType = value.String
a.Primary = value.Bool
}
case attachment.ForeignKeys[0]:
if value, ok := values[i].(*sql.NullScanner); !ok {
return fmt.Errorf("unexpected type %T for field attachment_thumbnail", values[i])
return fmt.Errorf("unexpected type %T for field document_attachments", values[i])
} else if value.Valid {
_m.attachment_thumbnail = new(uuid.UUID)
*_m.attachment_thumbnail = *value.S.(*uuid.UUID)
a.document_attachments = new(uuid.UUID)
*a.document_attachments = *value.S.(*uuid.UUID)
}
case attachment.ForeignKeys[1]:
if value, ok := values[i].(*sql.NullScanner); !ok {
return fmt.Errorf("unexpected type %T for field item_attachments", values[i])
} else if value.Valid {
_m.item_attachments = new(uuid.UUID)
*_m.item_attachments = *value.S.(*uuid.UUID)
a.item_attachments = new(uuid.UUID)
*a.item_attachments = *value.S.(*uuid.UUID)
}
default:
_m.selectValues.Set(columns[i], values[i])
a.selectValues.Set(columns[i], values[i])
}
}
return nil
@@ -177,63 +154,54 @@ func (_m *Attachment) assignValues(columns []string, values []any) error {
// Value returns the ent.Value that was dynamically selected and assigned to the Attachment.
// This includes values selected through modifiers, order, etc.
func (_m *Attachment) Value(name string) (ent.Value, error) {
return _m.selectValues.Get(name)
func (a *Attachment) Value(name string) (ent.Value, error) {
return a.selectValues.Get(name)
}
// QueryItem queries the "item" edge of the Attachment entity.
func (_m *Attachment) QueryItem() *ItemQuery {
return NewAttachmentClient(_m.config).QueryItem(_m)
func (a *Attachment) QueryItem() *ItemQuery {
return NewAttachmentClient(a.config).QueryItem(a)
}
// QueryThumbnail queries the "thumbnail" edge of the Attachment entity.
func (_m *Attachment) QueryThumbnail() *AttachmentQuery {
return NewAttachmentClient(_m.config).QueryThumbnail(_m)
// QueryDocument queries the "document" edge of the Attachment entity.
func (a *Attachment) QueryDocument() *DocumentQuery {
return NewAttachmentClient(a.config).QueryDocument(a)
}
// Update returns a builder for updating this Attachment.
// Note that you need to call Attachment.Unwrap() before calling this method if this Attachment
// was returned from a transaction, and the transaction was committed or rolled back.
func (_m *Attachment) Update() *AttachmentUpdateOne {
return NewAttachmentClient(_m.config).UpdateOne(_m)
func (a *Attachment) Update() *AttachmentUpdateOne {
return NewAttachmentClient(a.config).UpdateOne(a)
}
// Unwrap unwraps the Attachment entity that was returned from a transaction after it was closed,
// so that all future queries will be executed through the driver which created the transaction.
func (_m *Attachment) Unwrap() *Attachment {
_tx, ok := _m.config.driver.(*txDriver)
func (a *Attachment) Unwrap() *Attachment {
_tx, ok := a.config.driver.(*txDriver)
if !ok {
panic("ent: Attachment is not a transactional entity")
}
_m.config.driver = _tx.drv
return _m
a.config.driver = _tx.drv
return a
}
// String implements the fmt.Stringer.
func (_m *Attachment) String() string {
func (a *Attachment) String() string {
var builder strings.Builder
builder.WriteString("Attachment(")
builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID))
builder.WriteString(fmt.Sprintf("id=%v, ", a.ID))
builder.WriteString("created_at=")
builder.WriteString(_m.CreatedAt.Format(time.ANSIC))
builder.WriteString(a.CreatedAt.Format(time.ANSIC))
builder.WriteString(", ")
builder.WriteString("updated_at=")
builder.WriteString(_m.UpdatedAt.Format(time.ANSIC))
builder.WriteString(a.UpdatedAt.Format(time.ANSIC))
builder.WriteString(", ")
builder.WriteString("type=")
builder.WriteString(fmt.Sprintf("%v", _m.Type))
builder.WriteString(fmt.Sprintf("%v", a.Type))
builder.WriteString(", ")
builder.WriteString("primary=")
builder.WriteString(fmt.Sprintf("%v", _m.Primary))
builder.WriteString(", ")
builder.WriteString("title=")
builder.WriteString(_m.Title)
builder.WriteString(", ")
builder.WriteString("path=")
builder.WriteString(_m.Path)
builder.WriteString(", ")
builder.WriteString("mime_type=")
builder.WriteString(_m.MimeType)
builder.WriteString(fmt.Sprintf("%v", a.Primary))
builder.WriteByte(')')
return builder.String()
}

View File

@@ -24,16 +24,10 @@ const (
FieldType = "type"
// FieldPrimary holds the string denoting the primary field in the database.
FieldPrimary = "primary"
// FieldTitle holds the string denoting the title field in the database.
FieldTitle = "title"
// FieldPath holds the string denoting the path field in the database.
FieldPath = "path"
// FieldMimeType holds the string denoting the mime_type field in the database.
FieldMimeType = "mime_type"
// EdgeItem holds the string denoting the item edge name in mutations.
EdgeItem = "item"
// EdgeThumbnail holds the string denoting the thumbnail edge name in mutations.
EdgeThumbnail = "thumbnail"
// EdgeDocument holds the string denoting the document edge name in mutations.
EdgeDocument = "document"
// Table holds the table name of the attachment in the database.
Table = "attachments"
// ItemTable is the table that holds the item relation/edge.
@@ -43,10 +37,13 @@ const (
ItemInverseTable = "items"
// ItemColumn is the table column denoting the item relation/edge.
ItemColumn = "item_attachments"
// ThumbnailTable is the table that holds the thumbnail relation/edge.
ThumbnailTable = "attachments"
// ThumbnailColumn is the table column denoting the thumbnail relation/edge.
ThumbnailColumn = "attachment_thumbnail"
// DocumentTable is the table that holds the document relation/edge.
DocumentTable = "attachments"
// DocumentInverseTable is the table name for the Document entity.
// It exists in this package in order to avoid circular dependency with the "document" package.
DocumentInverseTable = "documents"
// DocumentColumn is the table column denoting the document relation/edge.
DocumentColumn = "document_attachments"
)
// Columns holds all SQL columns for attachment fields.
@@ -56,15 +53,12 @@ var Columns = []string{
FieldUpdatedAt,
FieldType,
FieldPrimary,
FieldTitle,
FieldPath,
FieldMimeType,
}
// ForeignKeys holds the SQL foreign-keys that are owned by the "attachments"
// table and are not defined as standalone fields in the schema.
var ForeignKeys = []string{
"attachment_thumbnail",
"document_attachments",
"item_attachments",
}
@@ -92,12 +86,6 @@ var (
UpdateDefaultUpdatedAt func() time.Time
// DefaultPrimary holds the default value on creation for the "primary" field.
DefaultPrimary bool
// DefaultTitle holds the default value on creation for the "title" field.
DefaultTitle string
// DefaultPath holds the default value on creation for the "path" field.
DefaultPath string
// DefaultMimeType holds the default value on creation for the "mime_type" field.
DefaultMimeType string
// DefaultID holds the default value on creation for the "id" field.
DefaultID func() uuid.UUID
)
@@ -115,7 +103,6 @@ const (
TypeWarranty Type = "warranty"
TypeAttachment Type = "attachment"
TypeReceipt Type = "receipt"
TypeThumbnail Type = "thumbnail"
)
func (_type Type) String() string {
@@ -125,7 +112,7 @@ func (_type Type) String() string {
// TypeValidator is a validator for the "type" field enum values. It is called by the builders before save.
func TypeValidator(_type Type) error {
switch _type {
case TypePhoto, TypeManual, TypeWarranty, TypeAttachment, TypeReceipt, TypeThumbnail:
case TypePhoto, TypeManual, TypeWarranty, TypeAttachment, TypeReceipt:
return nil
default:
return fmt.Errorf("attachment: invalid enum value for type field: %q", _type)
@@ -160,21 +147,6 @@ func ByPrimary(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldPrimary, 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()
}
// ByMimeType orders the results by the mime_type field.
func ByMimeType(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldMimeType, opts...).ToFunc()
}
// ByItemField orders the results by item field.
func ByItemField(field string, opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) {
@@ -182,10 +154,10 @@ func ByItemField(field string, opts ...sql.OrderTermOption) OrderOption {
}
}
// ByThumbnailField orders the results by thumbnail field.
func ByThumbnailField(field string, opts ...sql.OrderTermOption) OrderOption {
// ByDocumentField orders the results by document field.
func ByDocumentField(field string, opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborTerms(s, newThumbnailStep(), sql.OrderByField(field, opts...))
sqlgraph.OrderByNeighborTerms(s, newDocumentStep(), sql.OrderByField(field, opts...))
}
}
func newItemStep() *sqlgraph.Step {
@@ -195,10 +167,10 @@ func newItemStep() *sqlgraph.Step {
sqlgraph.Edge(sqlgraph.M2O, true, ItemTable, ItemColumn),
)
}
func newThumbnailStep() *sqlgraph.Step {
func newDocumentStep() *sqlgraph.Step {
return sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(Table, FieldID),
sqlgraph.Edge(sqlgraph.O2O, false, ThumbnailTable, ThumbnailColumn),
sqlgraph.To(DocumentInverseTable, FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, DocumentTable, DocumentColumn),
)
}

View File

@@ -71,21 +71,6 @@ func Primary(v bool) predicate.Attachment {
return predicate.Attachment(sql.FieldEQ(FieldPrimary, v))
}
// Title applies equality check predicate on the "title" field. It's identical to TitleEQ.
func Title(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldEQ(FieldTitle, v))
}
// Path applies equality check predicate on the "path" field. It's identical to PathEQ.
func Path(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldEQ(FieldPath, v))
}
// MimeType applies equality check predicate on the "mime_type" field. It's identical to MimeTypeEQ.
func MimeType(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldEQ(FieldMimeType, 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))
@@ -196,201 +181,6 @@ func PrimaryNEQ(v bool) predicate.Attachment {
return predicate.Attachment(sql.FieldNEQ(FieldPrimary, v))
}
// TitleEQ applies the EQ predicate on the "title" field.
func TitleEQ(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldEQ(FieldTitle, v))
}
// TitleNEQ applies the NEQ predicate on the "title" field.
func TitleNEQ(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldNEQ(FieldTitle, v))
}
// TitleIn applies the In predicate on the "title" field.
func TitleIn(vs ...string) predicate.Attachment {
return predicate.Attachment(sql.FieldIn(FieldTitle, vs...))
}
// TitleNotIn applies the NotIn predicate on the "title" field.
func TitleNotIn(vs ...string) predicate.Attachment {
return predicate.Attachment(sql.FieldNotIn(FieldTitle, vs...))
}
// TitleGT applies the GT predicate on the "title" field.
func TitleGT(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldGT(FieldTitle, v))
}
// TitleGTE applies the GTE predicate on the "title" field.
func TitleGTE(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldGTE(FieldTitle, v))
}
// TitleLT applies the LT predicate on the "title" field.
func TitleLT(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldLT(FieldTitle, v))
}
// TitleLTE applies the LTE predicate on the "title" field.
func TitleLTE(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldLTE(FieldTitle, v))
}
// TitleContains applies the Contains predicate on the "title" field.
func TitleContains(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldContains(FieldTitle, v))
}
// TitleHasPrefix applies the HasPrefix predicate on the "title" field.
func TitleHasPrefix(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldHasPrefix(FieldTitle, v))
}
// TitleHasSuffix applies the HasSuffix predicate on the "title" field.
func TitleHasSuffix(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldHasSuffix(FieldTitle, v))
}
// TitleEqualFold applies the EqualFold predicate on the "title" field.
func TitleEqualFold(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldEqualFold(FieldTitle, v))
}
// TitleContainsFold applies the ContainsFold predicate on the "title" field.
func TitleContainsFold(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldContainsFold(FieldTitle, v))
}
// PathEQ applies the EQ predicate on the "path" field.
func PathEQ(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldEQ(FieldPath, v))
}
// PathNEQ applies the NEQ predicate on the "path" field.
func PathNEQ(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldNEQ(FieldPath, v))
}
// PathIn applies the In predicate on the "path" field.
func PathIn(vs ...string) predicate.Attachment {
return predicate.Attachment(sql.FieldIn(FieldPath, vs...))
}
// PathNotIn applies the NotIn predicate on the "path" field.
func PathNotIn(vs ...string) predicate.Attachment {
return predicate.Attachment(sql.FieldNotIn(FieldPath, vs...))
}
// PathGT applies the GT predicate on the "path" field.
func PathGT(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldGT(FieldPath, v))
}
// PathGTE applies the GTE predicate on the "path" field.
func PathGTE(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldGTE(FieldPath, v))
}
// PathLT applies the LT predicate on the "path" field.
func PathLT(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldLT(FieldPath, v))
}
// PathLTE applies the LTE predicate on the "path" field.
func PathLTE(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldLTE(FieldPath, v))
}
// PathContains applies the Contains predicate on the "path" field.
func PathContains(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldContains(FieldPath, v))
}
// PathHasPrefix applies the HasPrefix predicate on the "path" field.
func PathHasPrefix(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldHasPrefix(FieldPath, v))
}
// PathHasSuffix applies the HasSuffix predicate on the "path" field.
func PathHasSuffix(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldHasSuffix(FieldPath, v))
}
// PathEqualFold applies the EqualFold predicate on the "path" field.
func PathEqualFold(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldEqualFold(FieldPath, v))
}
// PathContainsFold applies the ContainsFold predicate on the "path" field.
func PathContainsFold(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldContainsFold(FieldPath, v))
}
// MimeTypeEQ applies the EQ predicate on the "mime_type" field.
func MimeTypeEQ(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldEQ(FieldMimeType, v))
}
// MimeTypeNEQ applies the NEQ predicate on the "mime_type" field.
func MimeTypeNEQ(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldNEQ(FieldMimeType, v))
}
// MimeTypeIn applies the In predicate on the "mime_type" field.
func MimeTypeIn(vs ...string) predicate.Attachment {
return predicate.Attachment(sql.FieldIn(FieldMimeType, vs...))
}
// MimeTypeNotIn applies the NotIn predicate on the "mime_type" field.
func MimeTypeNotIn(vs ...string) predicate.Attachment {
return predicate.Attachment(sql.FieldNotIn(FieldMimeType, vs...))
}
// MimeTypeGT applies the GT predicate on the "mime_type" field.
func MimeTypeGT(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldGT(FieldMimeType, v))
}
// MimeTypeGTE applies the GTE predicate on the "mime_type" field.
func MimeTypeGTE(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldGTE(FieldMimeType, v))
}
// MimeTypeLT applies the LT predicate on the "mime_type" field.
func MimeTypeLT(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldLT(FieldMimeType, v))
}
// MimeTypeLTE applies the LTE predicate on the "mime_type" field.
func MimeTypeLTE(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldLTE(FieldMimeType, v))
}
// MimeTypeContains applies the Contains predicate on the "mime_type" field.
func MimeTypeContains(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldContains(FieldMimeType, v))
}
// MimeTypeHasPrefix applies the HasPrefix predicate on the "mime_type" field.
func MimeTypeHasPrefix(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldHasPrefix(FieldMimeType, v))
}
// MimeTypeHasSuffix applies the HasSuffix predicate on the "mime_type" field.
func MimeTypeHasSuffix(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldHasSuffix(FieldMimeType, v))
}
// MimeTypeEqualFold applies the EqualFold predicate on the "mime_type" field.
func MimeTypeEqualFold(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldEqualFold(FieldMimeType, v))
}
// MimeTypeContainsFold applies the ContainsFold predicate on the "mime_type" field.
func MimeTypeContainsFold(v string) predicate.Attachment {
return predicate.Attachment(sql.FieldContainsFold(FieldMimeType, v))
}
// HasItem applies the HasEdge predicate on the "item" edge.
func HasItem() predicate.Attachment {
return predicate.Attachment(func(s *sql.Selector) {
@@ -414,21 +204,21 @@ func HasItemWith(preds ...predicate.Item) predicate.Attachment {
})
}
// HasThumbnail applies the HasEdge predicate on the "thumbnail" edge.
func HasThumbnail() predicate.Attachment {
// HasDocument applies the HasEdge predicate on the "document" edge.
func HasDocument() predicate.Attachment {
return predicate.Attachment(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.Edge(sqlgraph.O2O, false, ThumbnailTable, ThumbnailColumn),
sqlgraph.Edge(sqlgraph.M2O, true, DocumentTable, DocumentColumn),
)
sqlgraph.HasNeighbors(s, step)
})
}
// HasThumbnailWith applies the HasEdge predicate on the "thumbnail" edge with a given conditions (other predicates).
func HasThumbnailWith(preds ...predicate.Attachment) 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 := newThumbnailStep()
step := newDocumentStep()
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds {
p(s)

View File

@@ -12,6 +12,7 @@ import (
"entgo.io/ent/schema/field"
"github.com/google/uuid"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/attachment"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/document"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/item"
)
@@ -23,169 +24,111 @@ type AttachmentCreate struct {
}
// SetCreatedAt sets the "created_at" field.
func (_c *AttachmentCreate) SetCreatedAt(v time.Time) *AttachmentCreate {
_c.mutation.SetCreatedAt(v)
return _c
func (ac *AttachmentCreate) SetCreatedAt(t time.Time) *AttachmentCreate {
ac.mutation.SetCreatedAt(t)
return ac
}
// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
func (_c *AttachmentCreate) SetNillableCreatedAt(v *time.Time) *AttachmentCreate {
if v != nil {
_c.SetCreatedAt(*v)
func (ac *AttachmentCreate) SetNillableCreatedAt(t *time.Time) *AttachmentCreate {
if t != nil {
ac.SetCreatedAt(*t)
}
return _c
return ac
}
// SetUpdatedAt sets the "updated_at" field.
func (_c *AttachmentCreate) SetUpdatedAt(v time.Time) *AttachmentCreate {
_c.mutation.SetUpdatedAt(v)
return _c
func (ac *AttachmentCreate) SetUpdatedAt(t time.Time) *AttachmentCreate {
ac.mutation.SetUpdatedAt(t)
return ac
}
// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil.
func (_c *AttachmentCreate) SetNillableUpdatedAt(v *time.Time) *AttachmentCreate {
if v != nil {
_c.SetUpdatedAt(*v)
func (ac *AttachmentCreate) SetNillableUpdatedAt(t *time.Time) *AttachmentCreate {
if t != nil {
ac.SetUpdatedAt(*t)
}
return _c
return ac
}
// SetType sets the "type" field.
func (_c *AttachmentCreate) SetType(v attachment.Type) *AttachmentCreate {
_c.mutation.SetType(v)
return _c
func (ac *AttachmentCreate) SetType(a attachment.Type) *AttachmentCreate {
ac.mutation.SetType(a)
return ac
}
// SetNillableType sets the "type" field if the given value is not nil.
func (_c *AttachmentCreate) SetNillableType(v *attachment.Type) *AttachmentCreate {
if v != nil {
_c.SetType(*v)
func (ac *AttachmentCreate) SetNillableType(a *attachment.Type) *AttachmentCreate {
if a != nil {
ac.SetType(*a)
}
return _c
return ac
}
// SetPrimary sets the "primary" field.
func (_c *AttachmentCreate) SetPrimary(v bool) *AttachmentCreate {
_c.mutation.SetPrimary(v)
return _c
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 (_c *AttachmentCreate) SetNillablePrimary(v *bool) *AttachmentCreate {
if v != nil {
_c.SetPrimary(*v)
func (ac *AttachmentCreate) SetNillablePrimary(b *bool) *AttachmentCreate {
if b != nil {
ac.SetPrimary(*b)
}
return _c
}
// SetTitle sets the "title" field.
func (_c *AttachmentCreate) SetTitle(v string) *AttachmentCreate {
_c.mutation.SetTitle(v)
return _c
}
// SetNillableTitle sets the "title" field if the given value is not nil.
func (_c *AttachmentCreate) SetNillableTitle(v *string) *AttachmentCreate {
if v != nil {
_c.SetTitle(*v)
}
return _c
}
// SetPath sets the "path" field.
func (_c *AttachmentCreate) SetPath(v string) *AttachmentCreate {
_c.mutation.SetPath(v)
return _c
}
// SetNillablePath sets the "path" field if the given value is not nil.
func (_c *AttachmentCreate) SetNillablePath(v *string) *AttachmentCreate {
if v != nil {
_c.SetPath(*v)
}
return _c
}
// SetMimeType sets the "mime_type" field.
func (_c *AttachmentCreate) SetMimeType(v string) *AttachmentCreate {
_c.mutation.SetMimeType(v)
return _c
}
// SetNillableMimeType sets the "mime_type" field if the given value is not nil.
func (_c *AttachmentCreate) SetNillableMimeType(v *string) *AttachmentCreate {
if v != nil {
_c.SetMimeType(*v)
}
return _c
return ac
}
// SetID sets the "id" field.
func (_c *AttachmentCreate) SetID(v uuid.UUID) *AttachmentCreate {
_c.mutation.SetID(v)
return _c
func (ac *AttachmentCreate) SetID(u uuid.UUID) *AttachmentCreate {
ac.mutation.SetID(u)
return ac
}
// SetNillableID sets the "id" field if the given value is not nil.
func (_c *AttachmentCreate) SetNillableID(v *uuid.UUID) *AttachmentCreate {
if v != nil {
_c.SetID(*v)
func (ac *AttachmentCreate) SetNillableID(u *uuid.UUID) *AttachmentCreate {
if u != nil {
ac.SetID(*u)
}
return _c
return ac
}
// SetItemID sets the "item" edge to the Item entity by ID.
func (_c *AttachmentCreate) SetItemID(id uuid.UUID) *AttachmentCreate {
_c.mutation.SetItemID(id)
return _c
}
// SetNillableItemID sets the "item" edge to the Item entity by ID if the given value is not nil.
func (_c *AttachmentCreate) SetNillableItemID(id *uuid.UUID) *AttachmentCreate {
if id != nil {
_c = _c.SetItemID(*id)
}
return _c
func (ac *AttachmentCreate) SetItemID(id uuid.UUID) *AttachmentCreate {
ac.mutation.SetItemID(id)
return ac
}
// SetItem sets the "item" edge to the Item entity.
func (_c *AttachmentCreate) SetItem(v *Item) *AttachmentCreate {
return _c.SetItemID(v.ID)
func (ac *AttachmentCreate) SetItem(i *Item) *AttachmentCreate {
return ac.SetItemID(i.ID)
}
// SetThumbnailID sets the "thumbnail" edge to the Attachment entity by ID.
func (_c *AttachmentCreate) SetThumbnailID(id uuid.UUID) *AttachmentCreate {
_c.mutation.SetThumbnailID(id)
return _c
// SetDocumentID sets the "document" edge to the Document entity by ID.
func (ac *AttachmentCreate) SetDocumentID(id uuid.UUID) *AttachmentCreate {
ac.mutation.SetDocumentID(id)
return ac
}
// SetNillableThumbnailID sets the "thumbnail" edge to the Attachment entity by ID if the given value is not nil.
func (_c *AttachmentCreate) SetNillableThumbnailID(id *uuid.UUID) *AttachmentCreate {
if id != nil {
_c = _c.SetThumbnailID(*id)
}
return _c
}
// SetThumbnail sets the "thumbnail" edge to the Attachment entity.
func (_c *AttachmentCreate) SetThumbnail(v *Attachment) *AttachmentCreate {
return _c.SetThumbnailID(v.ID)
// SetDocument sets the "document" edge to the Document entity.
func (ac *AttachmentCreate) SetDocument(d *Document) *AttachmentCreate {
return ac.SetDocumentID(d.ID)
}
// Mutation returns the AttachmentMutation object of the builder.
func (_c *AttachmentCreate) Mutation() *AttachmentMutation {
return _c.mutation
func (ac *AttachmentCreate) Mutation() *AttachmentMutation {
return ac.mutation
}
// Save creates the Attachment in the database.
func (_c *AttachmentCreate) Save(ctx context.Context) (*Attachment, error) {
_c.defaults()
return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks)
func (ac *AttachmentCreate) Save(ctx context.Context) (*Attachment, error) {
ac.defaults()
return withHooks(ctx, ac.sqlSave, ac.mutation, ac.hooks)
}
// SaveX calls Save and panics if Save returns an error.
func (_c *AttachmentCreate) SaveX(ctx context.Context) *Attachment {
v, err := _c.Save(ctx)
func (ac *AttachmentCreate) SaveX(ctx context.Context) *Attachment {
v, err := ac.Save(ctx)
if err != nil {
panic(err)
}
@@ -193,91 +136,76 @@ func (_c *AttachmentCreate) SaveX(ctx context.Context) *Attachment {
}
// Exec executes the query.
func (_c *AttachmentCreate) Exec(ctx context.Context) error {
_, err := _c.Save(ctx)
func (ac *AttachmentCreate) Exec(ctx context.Context) error {
_, err := ac.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (_c *AttachmentCreate) ExecX(ctx context.Context) {
if err := _c.Exec(ctx); err != nil {
func (ac *AttachmentCreate) ExecX(ctx context.Context) {
if err := ac.Exec(ctx); err != nil {
panic(err)
}
}
// defaults sets the default values of the builder before save.
func (_c *AttachmentCreate) defaults() {
if _, ok := _c.mutation.CreatedAt(); !ok {
func (ac *AttachmentCreate) defaults() {
if _, ok := ac.mutation.CreatedAt(); !ok {
v := attachment.DefaultCreatedAt()
_c.mutation.SetCreatedAt(v)
ac.mutation.SetCreatedAt(v)
}
if _, ok := _c.mutation.UpdatedAt(); !ok {
if _, ok := ac.mutation.UpdatedAt(); !ok {
v := attachment.DefaultUpdatedAt()
_c.mutation.SetUpdatedAt(v)
ac.mutation.SetUpdatedAt(v)
}
if _, ok := _c.mutation.GetType(); !ok {
if _, ok := ac.mutation.GetType(); !ok {
v := attachment.DefaultType
_c.mutation.SetType(v)
ac.mutation.SetType(v)
}
if _, ok := _c.mutation.Primary(); !ok {
if _, ok := ac.mutation.Primary(); !ok {
v := attachment.DefaultPrimary
_c.mutation.SetPrimary(v)
ac.mutation.SetPrimary(v)
}
if _, ok := _c.mutation.Title(); !ok {
v := attachment.DefaultTitle
_c.mutation.SetTitle(v)
}
if _, ok := _c.mutation.Path(); !ok {
v := attachment.DefaultPath
_c.mutation.SetPath(v)
}
if _, ok := _c.mutation.MimeType(); !ok {
v := attachment.DefaultMimeType
_c.mutation.SetMimeType(v)
}
if _, ok := _c.mutation.ID(); !ok {
if _, ok := ac.mutation.ID(); !ok {
v := attachment.DefaultID()
_c.mutation.SetID(v)
ac.mutation.SetID(v)
}
}
// check runs all checks and user-defined validators on the builder.
func (_c *AttachmentCreate) check() error {
if _, ok := _c.mutation.CreatedAt(); !ok {
func (ac *AttachmentCreate) check() error {
if _, ok := ac.mutation.CreatedAt(); !ok {
return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "Attachment.created_at"`)}
}
if _, ok := _c.mutation.UpdatedAt(); !ok {
if _, ok := ac.mutation.UpdatedAt(); !ok {
return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "Attachment.updated_at"`)}
}
if _, ok := _c.mutation.GetType(); !ok {
if _, ok := ac.mutation.GetType(); !ok {
return &ValidationError{Name: "type", err: errors.New(`ent: missing required field "Attachment.type"`)}
}
if v, ok := _c.mutation.GetType(); ok {
if v, ok := ac.mutation.GetType(); ok {
if err := attachment.TypeValidator(v); err != nil {
return &ValidationError{Name: "type", err: fmt.Errorf(`ent: validator failed for field "Attachment.type": %w`, err)}
}
}
if _, ok := _c.mutation.Primary(); !ok {
if _, ok := ac.mutation.Primary(); !ok {
return &ValidationError{Name: "primary", err: errors.New(`ent: missing required field "Attachment.primary"`)}
}
if _, ok := _c.mutation.Title(); !ok {
return &ValidationError{Name: "title", err: errors.New(`ent: missing required field "Attachment.title"`)}
if len(ac.mutation.ItemIDs()) == 0 {
return &ValidationError{Name: "item", err: errors.New(`ent: missing required edge "Attachment.item"`)}
}
if _, ok := _c.mutation.Path(); !ok {
return &ValidationError{Name: "path", err: errors.New(`ent: missing required field "Attachment.path"`)}
}
if _, ok := _c.mutation.MimeType(); !ok {
return &ValidationError{Name: "mime_type", err: errors.New(`ent: missing required field "Attachment.mime_type"`)}
if len(ac.mutation.DocumentIDs()) == 0 {
return &ValidationError{Name: "document", err: errors.New(`ent: missing required edge "Attachment.document"`)}
}
return nil
}
func (_c *AttachmentCreate) sqlSave(ctx context.Context) (*Attachment, error) {
if err := _c.check(); err != nil {
func (ac *AttachmentCreate) sqlSave(ctx context.Context) (*Attachment, error) {
if err := ac.check(); err != nil {
return nil, err
}
_node, _spec := _c.createSpec()
if err := sqlgraph.CreateNode(ctx, _c.driver, _spec); err != nil {
_node, _spec := ac.createSpec()
if err := sqlgraph.CreateNode(ctx, ac.driver, _spec); err != nil {
if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
@@ -290,49 +218,37 @@ func (_c *AttachmentCreate) sqlSave(ctx context.Context) (*Attachment, error) {
return nil, err
}
}
_c.mutation.id = &_node.ID
_c.mutation.done = true
ac.mutation.id = &_node.ID
ac.mutation.done = true
return _node, nil
}
func (_c *AttachmentCreate) createSpec() (*Attachment, *sqlgraph.CreateSpec) {
func (ac *AttachmentCreate) createSpec() (*Attachment, *sqlgraph.CreateSpec) {
var (
_node = &Attachment{config: _c.config}
_node = &Attachment{config: ac.config}
_spec = sqlgraph.NewCreateSpec(attachment.Table, sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID))
)
if id, ok := _c.mutation.ID(); ok {
if id, ok := ac.mutation.ID(); ok {
_node.ID = id
_spec.ID.Value = &id
}
if value, ok := _c.mutation.CreatedAt(); ok {
if value, ok := ac.mutation.CreatedAt(); ok {
_spec.SetField(attachment.FieldCreatedAt, field.TypeTime, value)
_node.CreatedAt = value
}
if value, ok := _c.mutation.UpdatedAt(); ok {
if value, ok := ac.mutation.UpdatedAt(); ok {
_spec.SetField(attachment.FieldUpdatedAt, field.TypeTime, value)
_node.UpdatedAt = value
}
if value, ok := _c.mutation.GetType(); ok {
if value, ok := ac.mutation.GetType(); ok {
_spec.SetField(attachment.FieldType, field.TypeEnum, value)
_node.Type = value
}
if value, ok := _c.mutation.Primary(); ok {
if value, ok := ac.mutation.Primary(); ok {
_spec.SetField(attachment.FieldPrimary, field.TypeBool, value)
_node.Primary = value
}
if value, ok := _c.mutation.Title(); ok {
_spec.SetField(attachment.FieldTitle, field.TypeString, value)
_node.Title = value
}
if value, ok := _c.mutation.Path(); ok {
_spec.SetField(attachment.FieldPath, field.TypeString, value)
_node.Path = value
}
if value, ok := _c.mutation.MimeType(); ok {
_spec.SetField(attachment.FieldMimeType, field.TypeString, value)
_node.MimeType = value
}
if nodes := _c.mutation.ItemIDs(); len(nodes) > 0 {
if nodes := ac.mutation.ItemIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
@@ -349,21 +265,21 @@ func (_c *AttachmentCreate) createSpec() (*Attachment, *sqlgraph.CreateSpec) {
_node.item_attachments = &nodes[0]
_spec.Edges = append(_spec.Edges, edge)
}
if nodes := _c.mutation.ThumbnailIDs(); len(nodes) > 0 {
if nodes := ac.mutation.DocumentIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2O,
Inverse: false,
Table: attachment.ThumbnailTable,
Columns: []string{attachment.ThumbnailColumn},
Bidi: true,
Rel: sqlgraph.M2O,
Inverse: true,
Table: attachment.DocumentTable,
Columns: []string{attachment.DocumentColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID),
IDSpec: sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_node.attachment_thumbnail = &nodes[0]
_node.document_attachments = &nodes[0]
_spec.Edges = append(_spec.Edges, edge)
}
return _node, _spec
@@ -377,16 +293,16 @@ type AttachmentCreateBulk struct {
}
// Save creates the Attachment entities in the database.
func (_c *AttachmentCreateBulk) Save(ctx context.Context) ([]*Attachment, error) {
if _c.err != nil {
return nil, _c.err
func (acb *AttachmentCreateBulk) Save(ctx context.Context) ([]*Attachment, error) {
if acb.err != nil {
return nil, acb.err
}
specs := make([]*sqlgraph.CreateSpec, len(_c.builders))
nodes := make([]*Attachment, len(_c.builders))
mutators := make([]Mutator, len(_c.builders))
for i := range _c.builders {
specs := make([]*sqlgraph.CreateSpec, len(acb.builders))
nodes := make([]*Attachment, len(acb.builders))
mutators := make([]Mutator, len(acb.builders))
for i := range acb.builders {
func(i int, root context.Context) {
builder := _c.builders[i]
builder := acb.builders[i]
builder.defaults()
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
mutation, ok := m.(*AttachmentMutation)
@@ -400,11 +316,11 @@ func (_c *AttachmentCreateBulk) Save(ctx context.Context) ([]*Attachment, error)
var err error
nodes[i], specs[i] = builder.createSpec()
if i < len(mutators)-1 {
_, err = mutators[i+1].Mutate(root, _c.builders[i+1].mutation)
_, err = mutators[i+1].Mutate(root, acb.builders[i+1].mutation)
} else {
spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
// Invoke the actual operation on the latest mutation in the chain.
if err = sqlgraph.BatchCreate(ctx, _c.driver, spec); err != nil {
if err = sqlgraph.BatchCreate(ctx, acb.driver, spec); err != nil {
if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
@@ -424,7 +340,7 @@ func (_c *AttachmentCreateBulk) Save(ctx context.Context) ([]*Attachment, error)
}(i, ctx)
}
if len(mutators) > 0 {
if _, err := mutators[0].Mutate(ctx, _c.builders[0].mutation); err != nil {
if _, err := mutators[0].Mutate(ctx, acb.builders[0].mutation); err != nil {
return nil, err
}
}
@@ -432,8 +348,8 @@ func (_c *AttachmentCreateBulk) Save(ctx context.Context) ([]*Attachment, error)
}
// SaveX is like Save, but panics if an error occurs.
func (_c *AttachmentCreateBulk) SaveX(ctx context.Context) []*Attachment {
v, err := _c.Save(ctx)
func (acb *AttachmentCreateBulk) SaveX(ctx context.Context) []*Attachment {
v, err := acb.Save(ctx)
if err != nil {
panic(err)
}
@@ -441,14 +357,14 @@ func (_c *AttachmentCreateBulk) SaveX(ctx context.Context) []*Attachment {
}
// Exec executes the query.
func (_c *AttachmentCreateBulk) Exec(ctx context.Context) error {
_, err := _c.Save(ctx)
func (acb *AttachmentCreateBulk) Exec(ctx context.Context) error {
_, err := acb.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (_c *AttachmentCreateBulk) ExecX(ctx context.Context) {
if err := _c.Exec(ctx); err != nil {
func (acb *AttachmentCreateBulk) ExecX(ctx context.Context) {
if err := acb.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -20,56 +20,56 @@ type AttachmentDelete struct {
}
// Where appends a list predicates to the AttachmentDelete builder.
func (_d *AttachmentDelete) Where(ps ...predicate.Attachment) *AttachmentDelete {
_d.mutation.Where(ps...)
return _d
func (ad *AttachmentDelete) Where(ps ...predicate.Attachment) *AttachmentDelete {
ad.mutation.Where(ps...)
return ad
}
// Exec executes the deletion query and returns how many vertices were deleted.
func (_d *AttachmentDelete) Exec(ctx context.Context) (int, error) {
return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks)
func (ad *AttachmentDelete) Exec(ctx context.Context) (int, error) {
return withHooks(ctx, ad.sqlExec, ad.mutation, ad.hooks)
}
// ExecX is like Exec, but panics if an error occurs.
func (_d *AttachmentDelete) ExecX(ctx context.Context) int {
n, err := _d.Exec(ctx)
func (ad *AttachmentDelete) ExecX(ctx context.Context) int {
n, err := ad.Exec(ctx)
if err != nil {
panic(err)
}
return n
}
func (_d *AttachmentDelete) sqlExec(ctx context.Context) (int, error) {
func (ad *AttachmentDelete) sqlExec(ctx context.Context) (int, error) {
_spec := sqlgraph.NewDeleteSpec(attachment.Table, sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID))
if ps := _d.mutation.predicates; len(ps) > 0 {
if ps := ad.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
affected, err := sqlgraph.DeleteNodes(ctx, _d.driver, _spec)
affected, err := sqlgraph.DeleteNodes(ctx, ad.driver, _spec)
if err != nil && sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
_d.mutation.done = true
ad.mutation.done = true
return affected, err
}
// AttachmentDeleteOne is the builder for deleting a single Attachment entity.
type AttachmentDeleteOne struct {
_d *AttachmentDelete
ad *AttachmentDelete
}
// Where appends a list predicates to the AttachmentDelete builder.
func (_d *AttachmentDeleteOne) Where(ps ...predicate.Attachment) *AttachmentDeleteOne {
_d._d.mutation.Where(ps...)
return _d
func (ado *AttachmentDeleteOne) Where(ps ...predicate.Attachment) *AttachmentDeleteOne {
ado.ad.mutation.Where(ps...)
return ado
}
// Exec executes the deletion query.
func (_d *AttachmentDeleteOne) Exec(ctx context.Context) error {
n, err := _d._d.Exec(ctx)
func (ado *AttachmentDeleteOne) Exec(ctx context.Context) error {
n, err := ado.ad.Exec(ctx)
switch {
case err != nil:
return err
@@ -81,8 +81,8 @@ func (_d *AttachmentDeleteOne) Exec(ctx context.Context) error {
}
// ExecX is like Exec, but panics if an error occurs.
func (_d *AttachmentDeleteOne) ExecX(ctx context.Context) {
if err := _d.Exec(ctx); err != nil {
func (ado *AttachmentDeleteOne) ExecX(ctx context.Context) {
if err := ado.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -13,6 +13,7 @@ import (
"entgo.io/ent/schema/field"
"github.com/google/uuid"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/attachment"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/document"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/item"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/predicate"
)
@@ -20,57 +21,57 @@ import (
// AttachmentQuery is the builder for querying Attachment entities.
type AttachmentQuery struct {
config
ctx *QueryContext
order []attachment.OrderOption
inters []Interceptor
predicates []predicate.Attachment
withItem *ItemQuery
withThumbnail *AttachmentQuery
withFKs bool
ctx *QueryContext
order []attachment.OrderOption
inters []Interceptor
predicates []predicate.Attachment
withItem *ItemQuery
withDocument *DocumentQuery
withFKs bool
// intermediate query (i.e. traversal path).
sql *sql.Selector
path func(context.Context) (*sql.Selector, error)
}
// Where adds a new predicate for the AttachmentQuery builder.
func (_q *AttachmentQuery) Where(ps ...predicate.Attachment) *AttachmentQuery {
_q.predicates = append(_q.predicates, ps...)
return _q
func (aq *AttachmentQuery) Where(ps ...predicate.Attachment) *AttachmentQuery {
aq.predicates = append(aq.predicates, ps...)
return aq
}
// Limit the number of records to be returned by this query.
func (_q *AttachmentQuery) Limit(limit int) *AttachmentQuery {
_q.ctx.Limit = &limit
return _q
func (aq *AttachmentQuery) Limit(limit int) *AttachmentQuery {
aq.ctx.Limit = &limit
return aq
}
// Offset to start from.
func (_q *AttachmentQuery) Offset(offset int) *AttachmentQuery {
_q.ctx.Offset = &offset
return _q
func (aq *AttachmentQuery) Offset(offset int) *AttachmentQuery {
aq.ctx.Offset = &offset
return aq
}
// Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method.
func (_q *AttachmentQuery) Unique(unique bool) *AttachmentQuery {
_q.ctx.Unique = &unique
return _q
func (aq *AttachmentQuery) Unique(unique bool) *AttachmentQuery {
aq.ctx.Unique = &unique
return aq
}
// Order specifies how the records should be ordered.
func (_q *AttachmentQuery) Order(o ...attachment.OrderOption) *AttachmentQuery {
_q.order = append(_q.order, o...)
return _q
func (aq *AttachmentQuery) Order(o ...attachment.OrderOption) *AttachmentQuery {
aq.order = append(aq.order, o...)
return aq
}
// QueryItem chains the current query on the "item" edge.
func (_q *AttachmentQuery) QueryItem() *ItemQuery {
query := (&ItemClient{config: _q.config}).Query()
func (aq *AttachmentQuery) QueryItem() *ItemQuery {
query := (&ItemClient{config: aq.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := _q.prepareQuery(ctx); err != nil {
if err := aq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := _q.sqlQuery(ctx)
selector := aq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
@@ -79,29 +80,29 @@ func (_q *AttachmentQuery) QueryItem() *ItemQuery {
sqlgraph.To(item.Table, item.FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, attachment.ItemTable, attachment.ItemColumn),
)
fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step)
fromU = sqlgraph.SetNeighbors(aq.driver.Dialect(), step)
return fromU, nil
}
return query
}
// QueryThumbnail chains the current query on the "thumbnail" edge.
func (_q *AttachmentQuery) QueryThumbnail() *AttachmentQuery {
query := (&AttachmentClient{config: _q.config}).Query()
// QueryDocument chains the current query on the "document" edge.
func (aq *AttachmentQuery) QueryDocument() *DocumentQuery {
query := (&DocumentClient{config: aq.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := _q.prepareQuery(ctx); err != nil {
if err := aq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := _q.sqlQuery(ctx)
selector := aq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(attachment.Table, attachment.FieldID, selector),
sqlgraph.To(attachment.Table, attachment.FieldID),
sqlgraph.Edge(sqlgraph.O2O, false, attachment.ThumbnailTable, attachment.ThumbnailColumn),
sqlgraph.To(document.Table, document.FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, attachment.DocumentTable, attachment.DocumentColumn),
)
fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step)
fromU = sqlgraph.SetNeighbors(aq.driver.Dialect(), step)
return fromU, nil
}
return query
@@ -109,8 +110,8 @@ func (_q *AttachmentQuery) QueryThumbnail() *AttachmentQuery {
// First returns the first Attachment entity from the query.
// Returns a *NotFoundError when no Attachment was found.
func (_q *AttachmentQuery) First(ctx context.Context) (*Attachment, error) {
nodes, err := _q.Limit(1).All(setContextOp(ctx, _q.ctx, ent.OpQueryFirst))
func (aq *AttachmentQuery) First(ctx context.Context) (*Attachment, error) {
nodes, err := aq.Limit(1).All(setContextOp(ctx, aq.ctx, ent.OpQueryFirst))
if err != nil {
return nil, err
}
@@ -121,8 +122,8 @@ func (_q *AttachmentQuery) First(ctx context.Context) (*Attachment, error) {
}
// FirstX is like First, but panics if an error occurs.
func (_q *AttachmentQuery) FirstX(ctx context.Context) *Attachment {
node, err := _q.First(ctx)
func (aq *AttachmentQuery) FirstX(ctx context.Context) *Attachment {
node, err := aq.First(ctx)
if err != nil && !IsNotFound(err) {
panic(err)
}
@@ -131,9 +132,9 @@ func (_q *AttachmentQuery) FirstX(ctx context.Context) *Attachment {
// FirstID returns the first Attachment ID from the query.
// Returns a *NotFoundError when no Attachment ID was found.
func (_q *AttachmentQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) {
func (aq *AttachmentQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = _q.Limit(1).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryFirstID)); err != nil {
if ids, err = aq.Limit(1).IDs(setContextOp(ctx, aq.ctx, ent.OpQueryFirstID)); err != nil {
return
}
if len(ids) == 0 {
@@ -144,8 +145,8 @@ func (_q *AttachmentQuery) FirstID(ctx context.Context) (id uuid.UUID, err error
}
// FirstIDX is like FirstID, but panics if an error occurs.
func (_q *AttachmentQuery) FirstIDX(ctx context.Context) uuid.UUID {
id, err := _q.FirstID(ctx)
func (aq *AttachmentQuery) FirstIDX(ctx context.Context) uuid.UUID {
id, err := aq.FirstID(ctx)
if err != nil && !IsNotFound(err) {
panic(err)
}
@@ -155,8 +156,8 @@ func (_q *AttachmentQuery) FirstIDX(ctx context.Context) uuid.UUID {
// Only returns a single Attachment entity found by the query, ensuring it only returns one.
// Returns a *NotSingularError when more than one Attachment entity is found.
// Returns a *NotFoundError when no Attachment entities are found.
func (_q *AttachmentQuery) Only(ctx context.Context) (*Attachment, error) {
nodes, err := _q.Limit(2).All(setContextOp(ctx, _q.ctx, ent.OpQueryOnly))
func (aq *AttachmentQuery) Only(ctx context.Context) (*Attachment, error) {
nodes, err := aq.Limit(2).All(setContextOp(ctx, aq.ctx, ent.OpQueryOnly))
if err != nil {
return nil, err
}
@@ -171,8 +172,8 @@ func (_q *AttachmentQuery) Only(ctx context.Context) (*Attachment, error) {
}
// OnlyX is like Only, but panics if an error occurs.
func (_q *AttachmentQuery) OnlyX(ctx context.Context) *Attachment {
node, err := _q.Only(ctx)
func (aq *AttachmentQuery) OnlyX(ctx context.Context) *Attachment {
node, err := aq.Only(ctx)
if err != nil {
panic(err)
}
@@ -182,9 +183,9 @@ func (_q *AttachmentQuery) OnlyX(ctx context.Context) *Attachment {
// OnlyID is like Only, but returns the only Attachment ID in the query.
// Returns a *NotSingularError when more than one Attachment ID is found.
// Returns a *NotFoundError when no entities are found.
func (_q *AttachmentQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) {
func (aq *AttachmentQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = _q.Limit(2).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryOnlyID)); err != nil {
if ids, err = aq.Limit(2).IDs(setContextOp(ctx, aq.ctx, ent.OpQueryOnlyID)); err != nil {
return
}
switch len(ids) {
@@ -199,8 +200,8 @@ func (_q *AttachmentQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error)
}
// OnlyIDX is like OnlyID, but panics if an error occurs.
func (_q *AttachmentQuery) OnlyIDX(ctx context.Context) uuid.UUID {
id, err := _q.OnlyID(ctx)
func (aq *AttachmentQuery) OnlyIDX(ctx context.Context) uuid.UUID {
id, err := aq.OnlyID(ctx)
if err != nil {
panic(err)
}
@@ -208,18 +209,18 @@ func (_q *AttachmentQuery) OnlyIDX(ctx context.Context) uuid.UUID {
}
// All executes the query and returns a list of Attachments.
func (_q *AttachmentQuery) All(ctx context.Context) ([]*Attachment, error) {
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll)
if err := _q.prepareQuery(ctx); err != nil {
func (aq *AttachmentQuery) All(ctx context.Context) ([]*Attachment, error) {
ctx = setContextOp(ctx, aq.ctx, ent.OpQueryAll)
if err := aq.prepareQuery(ctx); err != nil {
return nil, err
}
qr := querierAll[[]*Attachment, *AttachmentQuery]()
return withInterceptors[[]*Attachment](ctx, _q, qr, _q.inters)
return withInterceptors[[]*Attachment](ctx, aq, qr, aq.inters)
}
// AllX is like All, but panics if an error occurs.
func (_q *AttachmentQuery) AllX(ctx context.Context) []*Attachment {
nodes, err := _q.All(ctx)
func (aq *AttachmentQuery) AllX(ctx context.Context) []*Attachment {
nodes, err := aq.All(ctx)
if err != nil {
panic(err)
}
@@ -227,20 +228,20 @@ func (_q *AttachmentQuery) AllX(ctx context.Context) []*Attachment {
}
// IDs executes the query and returns a list of Attachment IDs.
func (_q *AttachmentQuery) IDs(ctx context.Context) (ids []uuid.UUID, err error) {
if _q.ctx.Unique == nil && _q.path != nil {
_q.Unique(true)
func (aq *AttachmentQuery) IDs(ctx context.Context) (ids []uuid.UUID, err error) {
if aq.ctx.Unique == nil && aq.path != nil {
aq.Unique(true)
}
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryIDs)
if err = _q.Select(attachment.FieldID).Scan(ctx, &ids); err != nil {
ctx = setContextOp(ctx, aq.ctx, ent.OpQueryIDs)
if err = aq.Select(attachment.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
return ids, nil
}
// IDsX is like IDs, but panics if an error occurs.
func (_q *AttachmentQuery) IDsX(ctx context.Context) []uuid.UUID {
ids, err := _q.IDs(ctx)
func (aq *AttachmentQuery) IDsX(ctx context.Context) []uuid.UUID {
ids, err := aq.IDs(ctx)
if err != nil {
panic(err)
}
@@ -248,17 +249,17 @@ func (_q *AttachmentQuery) IDsX(ctx context.Context) []uuid.UUID {
}
// Count returns the count of the given query.
func (_q *AttachmentQuery) Count(ctx context.Context) (int, error) {
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryCount)
if err := _q.prepareQuery(ctx); err != nil {
func (aq *AttachmentQuery) Count(ctx context.Context) (int, error) {
ctx = setContextOp(ctx, aq.ctx, ent.OpQueryCount)
if err := aq.prepareQuery(ctx); err != nil {
return 0, err
}
return withInterceptors[int](ctx, _q, querierCount[*AttachmentQuery](), _q.inters)
return withInterceptors[int](ctx, aq, querierCount[*AttachmentQuery](), aq.inters)
}
// CountX is like Count, but panics if an error occurs.
func (_q *AttachmentQuery) CountX(ctx context.Context) int {
count, err := _q.Count(ctx)
func (aq *AttachmentQuery) CountX(ctx context.Context) int {
count, err := aq.Count(ctx)
if err != nil {
panic(err)
}
@@ -266,9 +267,9 @@ func (_q *AttachmentQuery) CountX(ctx context.Context) int {
}
// Exist returns true if the query has elements in the graph.
func (_q *AttachmentQuery) Exist(ctx context.Context) (bool, error) {
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryExist)
switch _, err := _q.FirstID(ctx); {
func (aq *AttachmentQuery) Exist(ctx context.Context) (bool, error) {
ctx = setContextOp(ctx, aq.ctx, ent.OpQueryExist)
switch _, err := aq.FirstID(ctx); {
case IsNotFound(err):
return false, nil
case err != nil:
@@ -279,8 +280,8 @@ func (_q *AttachmentQuery) Exist(ctx context.Context) (bool, error) {
}
// ExistX is like Exist, but panics if an error occurs.
func (_q *AttachmentQuery) ExistX(ctx context.Context) bool {
exist, err := _q.Exist(ctx)
func (aq *AttachmentQuery) ExistX(ctx context.Context) bool {
exist, err := aq.Exist(ctx)
if err != nil {
panic(err)
}
@@ -289,44 +290,44 @@ func (_q *AttachmentQuery) ExistX(ctx context.Context) bool {
// Clone returns a duplicate of the AttachmentQuery builder, including all associated steps. It can be
// used to prepare common query builders and use them differently after the clone is made.
func (_q *AttachmentQuery) Clone() *AttachmentQuery {
if _q == nil {
func (aq *AttachmentQuery) Clone() *AttachmentQuery {
if aq == nil {
return nil
}
return &AttachmentQuery{
config: _q.config,
ctx: _q.ctx.Clone(),
order: append([]attachment.OrderOption{}, _q.order...),
inters: append([]Interceptor{}, _q.inters...),
predicates: append([]predicate.Attachment{}, _q.predicates...),
withItem: _q.withItem.Clone(),
withThumbnail: _q.withThumbnail.Clone(),
config: aq.config,
ctx: aq.ctx.Clone(),
order: append([]attachment.OrderOption{}, aq.order...),
inters: append([]Interceptor{}, aq.inters...),
predicates: append([]predicate.Attachment{}, aq.predicates...),
withItem: aq.withItem.Clone(),
withDocument: aq.withDocument.Clone(),
// clone intermediate query.
sql: _q.sql.Clone(),
path: _q.path,
sql: aq.sql.Clone(),
path: aq.path,
}
}
// WithItem tells the query-builder to eager-load the nodes that are connected to
// the "item" edge. The optional arguments are used to configure the query builder of the edge.
func (_q *AttachmentQuery) WithItem(opts ...func(*ItemQuery)) *AttachmentQuery {
query := (&ItemClient{config: _q.config}).Query()
func (aq *AttachmentQuery) WithItem(opts ...func(*ItemQuery)) *AttachmentQuery {
query := (&ItemClient{config: aq.config}).Query()
for _, opt := range opts {
opt(query)
}
_q.withItem = query
return _q
aq.withItem = query
return aq
}
// WithThumbnail tells the query-builder to eager-load the nodes that are connected to
// the "thumbnail" edge. The optional arguments are used to configure the query builder of the edge.
func (_q *AttachmentQuery) WithThumbnail(opts ...func(*AttachmentQuery)) *AttachmentQuery {
query := (&AttachmentClient{config: _q.config}).Query()
// WithDocument tells the query-builder to eager-load the nodes that are connected to
// the "document" edge. The optional arguments are used to configure the query builder of the edge.
func (aq *AttachmentQuery) WithDocument(opts ...func(*DocumentQuery)) *AttachmentQuery {
query := (&DocumentClient{config: aq.config}).Query()
for _, opt := range opts {
opt(query)
}
_q.withThumbnail = query
return _q
aq.withDocument = query
return aq
}
// GroupBy is used to group vertices by one or more fields/columns.
@@ -343,10 +344,10 @@ func (_q *AttachmentQuery) WithThumbnail(opts ...func(*AttachmentQuery)) *Attach
// GroupBy(attachment.FieldCreatedAt).
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (_q *AttachmentQuery) GroupBy(field string, fields ...string) *AttachmentGroupBy {
_q.ctx.Fields = append([]string{field}, fields...)
grbuild := &AttachmentGroupBy{build: _q}
grbuild.flds = &_q.ctx.Fields
func (aq *AttachmentQuery) GroupBy(field string, fields ...string) *AttachmentGroupBy {
aq.ctx.Fields = append([]string{field}, fields...)
grbuild := &AttachmentGroupBy{build: aq}
grbuild.flds = &aq.ctx.Fields
grbuild.label = attachment.Label
grbuild.scan = grbuild.Scan
return grbuild
@@ -364,56 +365,56 @@ func (_q *AttachmentQuery) GroupBy(field string, fields ...string) *AttachmentGr
// client.Attachment.Query().
// Select(attachment.FieldCreatedAt).
// Scan(ctx, &v)
func (_q *AttachmentQuery) Select(fields ...string) *AttachmentSelect {
_q.ctx.Fields = append(_q.ctx.Fields, fields...)
sbuild := &AttachmentSelect{AttachmentQuery: _q}
func (aq *AttachmentQuery) Select(fields ...string) *AttachmentSelect {
aq.ctx.Fields = append(aq.ctx.Fields, fields...)
sbuild := &AttachmentSelect{AttachmentQuery: aq}
sbuild.label = attachment.Label
sbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan
sbuild.flds, sbuild.scan = &aq.ctx.Fields, sbuild.Scan
return sbuild
}
// Aggregate returns a AttachmentSelect configured with the given aggregations.
func (_q *AttachmentQuery) Aggregate(fns ...AggregateFunc) *AttachmentSelect {
return _q.Select().Aggregate(fns...)
func (aq *AttachmentQuery) Aggregate(fns ...AggregateFunc) *AttachmentSelect {
return aq.Select().Aggregate(fns...)
}
func (_q *AttachmentQuery) prepareQuery(ctx context.Context) error {
for _, inter := range _q.inters {
func (aq *AttachmentQuery) prepareQuery(ctx context.Context) error {
for _, inter := range aq.inters {
if inter == nil {
return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)")
}
if trv, ok := inter.(Traverser); ok {
if err := trv.Traverse(ctx, _q); err != nil {
if err := trv.Traverse(ctx, aq); err != nil {
return err
}
}
}
for _, f := range _q.ctx.Fields {
for _, f := range aq.ctx.Fields {
if !attachment.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
}
if _q.path != nil {
prev, err := _q.path(ctx)
if aq.path != nil {
prev, err := aq.path(ctx)
if err != nil {
return err
}
_q.sql = prev
aq.sql = prev
}
return nil
}
func (_q *AttachmentQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Attachment, error) {
func (aq *AttachmentQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Attachment, error) {
var (
nodes = []*Attachment{}
withFKs = _q.withFKs
_spec = _q.querySpec()
withFKs = aq.withFKs
_spec = aq.querySpec()
loadedTypes = [2]bool{
_q.withItem != nil,
_q.withThumbnail != nil,
aq.withItem != nil,
aq.withDocument != nil,
}
)
if _q.withItem != nil || _q.withThumbnail != nil {
if aq.withItem != nil || aq.withDocument != nil {
withFKs = true
}
if withFKs {
@@ -423,7 +424,7 @@ func (_q *AttachmentQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*A
return (*Attachment).scanValues(nil, columns)
}
_spec.Assign = func(columns []string, values []any) error {
node := &Attachment{config: _q.config}
node := &Attachment{config: aq.config}
nodes = append(nodes, node)
node.Edges.loadedTypes = loadedTypes
return node.assignValues(columns, values)
@@ -431,28 +432,28 @@ func (_q *AttachmentQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*A
for i := range hooks {
hooks[i](ctx, _spec)
}
if err := sqlgraph.QueryNodes(ctx, _q.driver, _spec); err != nil {
if err := sqlgraph.QueryNodes(ctx, aq.driver, _spec); err != nil {
return nil, err
}
if len(nodes) == 0 {
return nodes, nil
}
if query := _q.withItem; query != nil {
if err := _q.loadItem(ctx, query, nodes, nil,
if query := aq.withItem; query != nil {
if err := aq.loadItem(ctx, query, nodes, nil,
func(n *Attachment, e *Item) { n.Edges.Item = e }); err != nil {
return nil, err
}
}
if query := _q.withThumbnail; query != nil {
if err := _q.loadThumbnail(ctx, query, nodes, nil,
func(n *Attachment, e *Attachment) { n.Edges.Thumbnail = e }); err != nil {
if query := aq.withDocument; query != nil {
if err := aq.loadDocument(ctx, query, nodes, nil,
func(n *Attachment, e *Document) { n.Edges.Document = e }); err != nil {
return nil, err
}
}
return nodes, nil
}
func (_q *AttachmentQuery) loadItem(ctx context.Context, query *ItemQuery, nodes []*Attachment, init func(*Attachment), assign func(*Attachment, *Item)) error {
func (aq *AttachmentQuery) loadItem(ctx context.Context, query *ItemQuery, nodes []*Attachment, init func(*Attachment), assign func(*Attachment, *Item)) error {
ids := make([]uuid.UUID, 0, len(nodes))
nodeids := make(map[uuid.UUID][]*Attachment)
for i := range nodes {
@@ -484,14 +485,14 @@ func (_q *AttachmentQuery) loadItem(ctx context.Context, query *ItemQuery, nodes
}
return nil
}
func (_q *AttachmentQuery) loadThumbnail(ctx context.Context, query *AttachmentQuery, nodes []*Attachment, init func(*Attachment), assign func(*Attachment, *Attachment)) error {
func (aq *AttachmentQuery) loadDocument(ctx context.Context, query *DocumentQuery, nodes []*Attachment, init func(*Attachment), assign func(*Attachment, *Document)) error {
ids := make([]uuid.UUID, 0, len(nodes))
nodeids := make(map[uuid.UUID][]*Attachment)
for i := range nodes {
if nodes[i].attachment_thumbnail == nil {
if nodes[i].document_attachments == nil {
continue
}
fk := *nodes[i].attachment_thumbnail
fk := *nodes[i].document_attachments
if _, ok := nodeids[fk]; !ok {
ids = append(ids, fk)
}
@@ -500,7 +501,7 @@ func (_q *AttachmentQuery) loadThumbnail(ctx context.Context, query *AttachmentQ
if len(ids) == 0 {
return nil
}
query.Where(attachment.IDIn(ids...))
query.Where(document.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
return err
@@ -508,7 +509,7 @@ func (_q *AttachmentQuery) loadThumbnail(ctx context.Context, query *AttachmentQ
for _, n := range neighbors {
nodes, ok := nodeids[n.ID]
if !ok {
return fmt.Errorf(`unexpected foreign-key "attachment_thumbnail" returned %v`, n.ID)
return fmt.Errorf(`unexpected foreign-key "document_attachments" returned %v`, n.ID)
}
for i := range nodes {
assign(nodes[i], n)
@@ -517,24 +518,24 @@ func (_q *AttachmentQuery) loadThumbnail(ctx context.Context, query *AttachmentQ
return nil
}
func (_q *AttachmentQuery) sqlCount(ctx context.Context) (int, error) {
_spec := _q.querySpec()
_spec.Node.Columns = _q.ctx.Fields
if len(_q.ctx.Fields) > 0 {
_spec.Unique = _q.ctx.Unique != nil && *_q.ctx.Unique
func (aq *AttachmentQuery) sqlCount(ctx context.Context) (int, error) {
_spec := aq.querySpec()
_spec.Node.Columns = aq.ctx.Fields
if len(aq.ctx.Fields) > 0 {
_spec.Unique = aq.ctx.Unique != nil && *aq.ctx.Unique
}
return sqlgraph.CountNodes(ctx, _q.driver, _spec)
return sqlgraph.CountNodes(ctx, aq.driver, _spec)
}
func (_q *AttachmentQuery) querySpec() *sqlgraph.QuerySpec {
func (aq *AttachmentQuery) querySpec() *sqlgraph.QuerySpec {
_spec := sqlgraph.NewQuerySpec(attachment.Table, attachment.Columns, sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID))
_spec.From = _q.sql
if unique := _q.ctx.Unique; unique != nil {
_spec.From = aq.sql
if unique := aq.ctx.Unique; unique != nil {
_spec.Unique = *unique
} else if _q.path != nil {
} else if aq.path != nil {
_spec.Unique = true
}
if fields := _q.ctx.Fields; len(fields) > 0 {
if fields := aq.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, attachment.FieldID)
for i := range fields {
@@ -543,20 +544,20 @@ func (_q *AttachmentQuery) querySpec() *sqlgraph.QuerySpec {
}
}
}
if ps := _q.predicates; len(ps) > 0 {
if ps := aq.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if limit := _q.ctx.Limit; limit != nil {
if limit := aq.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := _q.ctx.Offset; offset != nil {
if offset := aq.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := _q.order; len(ps) > 0 {
if ps := aq.order; len(ps) > 0 {
_spec.Order = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
@@ -566,33 +567,33 @@ func (_q *AttachmentQuery) querySpec() *sqlgraph.QuerySpec {
return _spec
}
func (_q *AttachmentQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(_q.driver.Dialect())
func (aq *AttachmentQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(aq.driver.Dialect())
t1 := builder.Table(attachment.Table)
columns := _q.ctx.Fields
columns := aq.ctx.Fields
if len(columns) == 0 {
columns = attachment.Columns
}
selector := builder.Select(t1.Columns(columns...)...).From(t1)
if _q.sql != nil {
selector = _q.sql
if aq.sql != nil {
selector = aq.sql
selector.Select(selector.Columns(columns...)...)
}
if _q.ctx.Unique != nil && *_q.ctx.Unique {
if aq.ctx.Unique != nil && *aq.ctx.Unique {
selector.Distinct()
}
for _, p := range _q.predicates {
for _, p := range aq.predicates {
p(selector)
}
for _, p := range _q.order {
for _, p := range aq.order {
p(selector)
}
if offset := _q.ctx.Offset; offset != nil {
if offset := aq.ctx.Offset; offset != nil {
// limit is mandatory for offset clause. We start
// with default value, and override it below if needed.
selector.Offset(*offset).Limit(math.MaxInt32)
}
if limit := _q.ctx.Limit; limit != nil {
if limit := aq.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
@@ -605,41 +606,41 @@ type AttachmentGroupBy struct {
}
// Aggregate adds the given aggregation functions to the group-by query.
func (_g *AttachmentGroupBy) Aggregate(fns ...AggregateFunc) *AttachmentGroupBy {
_g.fns = append(_g.fns, fns...)
return _g
func (agb *AttachmentGroupBy) Aggregate(fns ...AggregateFunc) *AttachmentGroupBy {
agb.fns = append(agb.fns, fns...)
return agb
}
// Scan applies the selector query and scans the result into the given value.
func (_g *AttachmentGroupBy) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, _g.build.ctx, ent.OpQueryGroupBy)
if err := _g.build.prepareQuery(ctx); err != nil {
func (agb *AttachmentGroupBy) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, agb.build.ctx, ent.OpQueryGroupBy)
if err := agb.build.prepareQuery(ctx); err != nil {
return err
}
return scanWithInterceptors[*AttachmentQuery, *AttachmentGroupBy](ctx, _g.build, _g, _g.build.inters, v)
return scanWithInterceptors[*AttachmentQuery, *AttachmentGroupBy](ctx, agb.build, agb, agb.build.inters, v)
}
func (_g *AttachmentGroupBy) sqlScan(ctx context.Context, root *AttachmentQuery, v any) error {
func (agb *AttachmentGroupBy) sqlScan(ctx context.Context, root *AttachmentQuery, v any) error {
selector := root.sqlQuery(ctx).Select()
aggregation := make([]string, 0, len(_g.fns))
for _, fn := range _g.fns {
aggregation := make([]string, 0, len(agb.fns))
for _, fn := range agb.fns {
aggregation = append(aggregation, fn(selector))
}
if len(selector.SelectedColumns()) == 0 {
columns := make([]string, 0, len(*_g.flds)+len(_g.fns))
for _, f := range *_g.flds {
columns := make([]string, 0, len(*agb.flds)+len(agb.fns))
for _, f := range *agb.flds {
columns = append(columns, selector.C(f))
}
columns = append(columns, aggregation...)
selector.Select(columns...)
}
selector.GroupBy(selector.Columns(*_g.flds...)...)
selector.GroupBy(selector.Columns(*agb.flds...)...)
if err := selector.Err(); err != nil {
return err
}
rows := &sql.Rows{}
query, args := selector.Query()
if err := _g.build.driver.Query(ctx, query, args, rows); err != nil {
if err := agb.build.driver.Query(ctx, query, args, rows); err != nil {
return err
}
defer rows.Close()
@@ -653,27 +654,27 @@ type AttachmentSelect struct {
}
// Aggregate adds the given aggregation functions to the selector query.
func (_s *AttachmentSelect) Aggregate(fns ...AggregateFunc) *AttachmentSelect {
_s.fns = append(_s.fns, fns...)
return _s
func (as *AttachmentSelect) Aggregate(fns ...AggregateFunc) *AttachmentSelect {
as.fns = append(as.fns, fns...)
return as
}
// Scan applies the selector query and scans the result into the given value.
func (_s *AttachmentSelect) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, _s.ctx, ent.OpQuerySelect)
if err := _s.prepareQuery(ctx); err != nil {
func (as *AttachmentSelect) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, as.ctx, ent.OpQuerySelect)
if err := as.prepareQuery(ctx); err != nil {
return err
}
return scanWithInterceptors[*AttachmentQuery, *AttachmentSelect](ctx, _s.AttachmentQuery, _s, _s.inters, v)
return scanWithInterceptors[*AttachmentQuery, *AttachmentSelect](ctx, as.AttachmentQuery, as, as.inters, v)
}
func (_s *AttachmentSelect) sqlScan(ctx context.Context, root *AttachmentQuery, v any) error {
func (as *AttachmentSelect) sqlScan(ctx context.Context, root *AttachmentQuery, v any) error {
selector := root.sqlQuery(ctx)
aggregation := make([]string, 0, len(_s.fns))
for _, fn := range _s.fns {
aggregation := make([]string, 0, len(as.fns))
for _, fn := range as.fns {
aggregation = append(aggregation, fn(selector))
}
switch n := len(*_s.selector.flds); {
switch n := len(*as.selector.flds); {
case n == 0 && len(aggregation) > 0:
selector.Select(aggregation...)
case n != 0 && len(aggregation) > 0:
@@ -681,7 +682,7 @@ func (_s *AttachmentSelect) sqlScan(ctx context.Context, root *AttachmentQuery,
}
rows := &sql.Rows{}
query, args := selector.Query()
if err := _s.driver.Query(ctx, query, args, rows); err != nil {
if err := as.driver.Query(ctx, query, args, rows); err != nil {
return err
}
defer rows.Close()

View File

@@ -13,6 +13,7 @@ import (
"entgo.io/ent/schema/field"
"github.com/google/uuid"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/attachment"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/document"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/item"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/predicate"
)
@@ -25,151 +26,93 @@ type AttachmentUpdate struct {
}
// Where appends a list predicates to the AttachmentUpdate builder.
func (_u *AttachmentUpdate) Where(ps ...predicate.Attachment) *AttachmentUpdate {
_u.mutation.Where(ps...)
return _u
func (au *AttachmentUpdate) Where(ps ...predicate.Attachment) *AttachmentUpdate {
au.mutation.Where(ps...)
return au
}
// SetUpdatedAt sets the "updated_at" field.
func (_u *AttachmentUpdate) SetUpdatedAt(v time.Time) *AttachmentUpdate {
_u.mutation.SetUpdatedAt(v)
return _u
func (au *AttachmentUpdate) SetUpdatedAt(t time.Time) *AttachmentUpdate {
au.mutation.SetUpdatedAt(t)
return au
}
// SetType sets the "type" field.
func (_u *AttachmentUpdate) SetType(v attachment.Type) *AttachmentUpdate {
_u.mutation.SetType(v)
return _u
func (au *AttachmentUpdate) SetType(a attachment.Type) *AttachmentUpdate {
au.mutation.SetType(a)
return au
}
// SetNillableType sets the "type" field if the given value is not nil.
func (_u *AttachmentUpdate) SetNillableType(v *attachment.Type) *AttachmentUpdate {
if v != nil {
_u.SetType(*v)
func (au *AttachmentUpdate) SetNillableType(a *attachment.Type) *AttachmentUpdate {
if a != nil {
au.SetType(*a)
}
return _u
return au
}
// SetPrimary sets the "primary" field.
func (_u *AttachmentUpdate) SetPrimary(v bool) *AttachmentUpdate {
_u.mutation.SetPrimary(v)
return _u
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 (_u *AttachmentUpdate) SetNillablePrimary(v *bool) *AttachmentUpdate {
if v != nil {
_u.SetPrimary(*v)
func (au *AttachmentUpdate) SetNillablePrimary(b *bool) *AttachmentUpdate {
if b != nil {
au.SetPrimary(*b)
}
return _u
}
// SetTitle sets the "title" field.
func (_u *AttachmentUpdate) SetTitle(v string) *AttachmentUpdate {
_u.mutation.SetTitle(v)
return _u
}
// SetNillableTitle sets the "title" field if the given value is not nil.
func (_u *AttachmentUpdate) SetNillableTitle(v *string) *AttachmentUpdate {
if v != nil {
_u.SetTitle(*v)
}
return _u
}
// SetPath sets the "path" field.
func (_u *AttachmentUpdate) SetPath(v string) *AttachmentUpdate {
_u.mutation.SetPath(v)
return _u
}
// SetNillablePath sets the "path" field if the given value is not nil.
func (_u *AttachmentUpdate) SetNillablePath(v *string) *AttachmentUpdate {
if v != nil {
_u.SetPath(*v)
}
return _u
}
// SetMimeType sets the "mime_type" field.
func (_u *AttachmentUpdate) SetMimeType(v string) *AttachmentUpdate {
_u.mutation.SetMimeType(v)
return _u
}
// SetNillableMimeType sets the "mime_type" field if the given value is not nil.
func (_u *AttachmentUpdate) SetNillableMimeType(v *string) *AttachmentUpdate {
if v != nil {
_u.SetMimeType(*v)
}
return _u
return au
}
// SetItemID sets the "item" edge to the Item entity by ID.
func (_u *AttachmentUpdate) SetItemID(id uuid.UUID) *AttachmentUpdate {
_u.mutation.SetItemID(id)
return _u
}
// SetNillableItemID sets the "item" edge to the Item entity by ID if the given value is not nil.
func (_u *AttachmentUpdate) SetNillableItemID(id *uuid.UUID) *AttachmentUpdate {
if id != nil {
_u = _u.SetItemID(*id)
}
return _u
func (au *AttachmentUpdate) SetItemID(id uuid.UUID) *AttachmentUpdate {
au.mutation.SetItemID(id)
return au
}
// SetItem sets the "item" edge to the Item entity.
func (_u *AttachmentUpdate) SetItem(v *Item) *AttachmentUpdate {
return _u.SetItemID(v.ID)
func (au *AttachmentUpdate) SetItem(i *Item) *AttachmentUpdate {
return au.SetItemID(i.ID)
}
// SetThumbnailID sets the "thumbnail" edge to the Attachment entity by ID.
func (_u *AttachmentUpdate) SetThumbnailID(id uuid.UUID) *AttachmentUpdate {
_u.mutation.SetThumbnailID(id)
return _u
// SetDocumentID sets the "document" edge to the Document entity by ID.
func (au *AttachmentUpdate) SetDocumentID(id uuid.UUID) *AttachmentUpdate {
au.mutation.SetDocumentID(id)
return au
}
// SetNillableThumbnailID sets the "thumbnail" edge to the Attachment entity by ID if the given value is not nil.
func (_u *AttachmentUpdate) SetNillableThumbnailID(id *uuid.UUID) *AttachmentUpdate {
if id != nil {
_u = _u.SetThumbnailID(*id)
}
return _u
}
// SetThumbnail sets the "thumbnail" edge to the Attachment entity.
func (_u *AttachmentUpdate) SetThumbnail(v *Attachment) *AttachmentUpdate {
return _u.SetThumbnailID(v.ID)
// SetDocument sets the "document" edge to the Document entity.
func (au *AttachmentUpdate) SetDocument(d *Document) *AttachmentUpdate {
return au.SetDocumentID(d.ID)
}
// Mutation returns the AttachmentMutation object of the builder.
func (_u *AttachmentUpdate) Mutation() *AttachmentMutation {
return _u.mutation
func (au *AttachmentUpdate) Mutation() *AttachmentMutation {
return au.mutation
}
// ClearItem clears the "item" edge to the Item entity.
func (_u *AttachmentUpdate) ClearItem() *AttachmentUpdate {
_u.mutation.ClearItem()
return _u
func (au *AttachmentUpdate) ClearItem() *AttachmentUpdate {
au.mutation.ClearItem()
return au
}
// ClearThumbnail clears the "thumbnail" edge to the Attachment entity.
func (_u *AttachmentUpdate) ClearThumbnail() *AttachmentUpdate {
_u.mutation.ClearThumbnail()
return _u
// ClearDocument clears the "document" edge to the Document entity.
func (au *AttachmentUpdate) ClearDocument() *AttachmentUpdate {
au.mutation.ClearDocument()
return au
}
// Save executes the query and returns the number of nodes affected by the update operation.
func (_u *AttachmentUpdate) Save(ctx context.Context) (int, error) {
_u.defaults()
return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)
func (au *AttachmentUpdate) Save(ctx context.Context) (int, error) {
au.defaults()
return withHooks(ctx, au.sqlSave, au.mutation, au.hooks)
}
// SaveX is like Save, but panics if an error occurs.
func (_u *AttachmentUpdate) SaveX(ctx context.Context) int {
affected, err := _u.Save(ctx)
func (au *AttachmentUpdate) SaveX(ctx context.Context) int {
affected, err := au.Save(ctx)
if err != nil {
panic(err)
}
@@ -177,67 +120,64 @@ func (_u *AttachmentUpdate) SaveX(ctx context.Context) int {
}
// Exec executes the query.
func (_u *AttachmentUpdate) Exec(ctx context.Context) error {
_, err := _u.Save(ctx)
func (au *AttachmentUpdate) Exec(ctx context.Context) error {
_, err := au.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (_u *AttachmentUpdate) ExecX(ctx context.Context) {
if err := _u.Exec(ctx); err != nil {
func (au *AttachmentUpdate) ExecX(ctx context.Context) {
if err := au.Exec(ctx); err != nil {
panic(err)
}
}
// defaults sets the default values of the builder before save.
func (_u *AttachmentUpdate) defaults() {
if _, ok := _u.mutation.UpdatedAt(); !ok {
func (au *AttachmentUpdate) defaults() {
if _, ok := au.mutation.UpdatedAt(); !ok {
v := attachment.UpdateDefaultUpdatedAt()
_u.mutation.SetUpdatedAt(v)
au.mutation.SetUpdatedAt(v)
}
}
// check runs all checks and user-defined validators on the builder.
func (_u *AttachmentUpdate) check() error {
if v, ok := _u.mutation.GetType(); ok {
func (au *AttachmentUpdate) check() error {
if v, ok := au.mutation.GetType(); ok {
if err := attachment.TypeValidator(v); err != nil {
return &ValidationError{Name: "type", err: fmt.Errorf(`ent: validator failed for field "Attachment.type": %w`, err)}
}
}
if au.mutation.ItemCleared() && len(au.mutation.ItemIDs()) > 0 {
return errors.New(`ent: clearing a required unique edge "Attachment.item"`)
}
if au.mutation.DocumentCleared() && len(au.mutation.DocumentIDs()) > 0 {
return errors.New(`ent: clearing a required unique edge "Attachment.document"`)
}
return nil
}
func (_u *AttachmentUpdate) sqlSave(ctx context.Context) (_node int, err error) {
if err := _u.check(); err != nil {
return _node, err
func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) {
if err := au.check(); err != nil {
return n, err
}
_spec := sqlgraph.NewUpdateSpec(attachment.Table, attachment.Columns, sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID))
if ps := _u.mutation.predicates; len(ps) > 0 {
if ps := au.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if value, ok := _u.mutation.UpdatedAt(); ok {
if value, ok := au.mutation.UpdatedAt(); ok {
_spec.SetField(attachment.FieldUpdatedAt, field.TypeTime, value)
}
if value, ok := _u.mutation.GetType(); ok {
if value, ok := au.mutation.GetType(); ok {
_spec.SetField(attachment.FieldType, field.TypeEnum, value)
}
if value, ok := _u.mutation.Primary(); ok {
if value, ok := au.mutation.Primary(); ok {
_spec.SetField(attachment.FieldPrimary, field.TypeBool, value)
}
if value, ok := _u.mutation.Title(); ok {
_spec.SetField(attachment.FieldTitle, field.TypeString, value)
}
if value, ok := _u.mutation.Path(); ok {
_spec.SetField(attachment.FieldPath, field.TypeString, value)
}
if value, ok := _u.mutation.MimeType(); ok {
_spec.SetField(attachment.FieldMimeType, field.TypeString, value)
}
if _u.mutation.ItemCleared() {
if au.mutation.ItemCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
@@ -250,7 +190,7 @@ func (_u *AttachmentUpdate) sqlSave(ctx context.Context) (_node int, err error)
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := _u.mutation.ItemIDs(); len(nodes) > 0 {
if nodes := au.mutation.ItemIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
@@ -266,28 +206,28 @@ func (_u *AttachmentUpdate) sqlSave(ctx context.Context) (_node int, err error)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if _u.mutation.ThumbnailCleared() {
if au.mutation.DocumentCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2O,
Inverse: false,
Table: attachment.ThumbnailTable,
Columns: []string{attachment.ThumbnailColumn},
Bidi: true,
Rel: sqlgraph.M2O,
Inverse: true,
Table: attachment.DocumentTable,
Columns: []string{attachment.DocumentColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID),
IDSpec: sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := _u.mutation.ThumbnailIDs(); len(nodes) > 0 {
if nodes := au.mutation.DocumentIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2O,
Inverse: false,
Table: attachment.ThumbnailTable,
Columns: []string{attachment.ThumbnailColumn},
Bidi: true,
Rel: sqlgraph.M2O,
Inverse: true,
Table: attachment.DocumentTable,
Columns: []string{attachment.DocumentColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID),
IDSpec: sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
@@ -295,7 +235,7 @@ func (_u *AttachmentUpdate) sqlSave(ctx context.Context) (_node int, err error)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil {
if n, err = sqlgraph.UpdateNodes(ctx, au.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{attachment.Label}
} else if sqlgraph.IsConstraintError(err) {
@@ -303,8 +243,8 @@ func (_u *AttachmentUpdate) sqlSave(ctx context.Context) (_node int, err error)
}
return 0, err
}
_u.mutation.done = true
return _node, nil
au.mutation.done = true
return n, nil
}
// AttachmentUpdateOne is the builder for updating a single Attachment entity.
@@ -316,158 +256,100 @@ type AttachmentUpdateOne struct {
}
// SetUpdatedAt sets the "updated_at" field.
func (_u *AttachmentUpdateOne) SetUpdatedAt(v time.Time) *AttachmentUpdateOne {
_u.mutation.SetUpdatedAt(v)
return _u
func (auo *AttachmentUpdateOne) SetUpdatedAt(t time.Time) *AttachmentUpdateOne {
auo.mutation.SetUpdatedAt(t)
return auo
}
// SetType sets the "type" field.
func (_u *AttachmentUpdateOne) SetType(v attachment.Type) *AttachmentUpdateOne {
_u.mutation.SetType(v)
return _u
func (auo *AttachmentUpdateOne) SetType(a attachment.Type) *AttachmentUpdateOne {
auo.mutation.SetType(a)
return auo
}
// SetNillableType sets the "type" field if the given value is not nil.
func (_u *AttachmentUpdateOne) SetNillableType(v *attachment.Type) *AttachmentUpdateOne {
if v != nil {
_u.SetType(*v)
func (auo *AttachmentUpdateOne) SetNillableType(a *attachment.Type) *AttachmentUpdateOne {
if a != nil {
auo.SetType(*a)
}
return _u
return auo
}
// SetPrimary sets the "primary" field.
func (_u *AttachmentUpdateOne) SetPrimary(v bool) *AttachmentUpdateOne {
_u.mutation.SetPrimary(v)
return _u
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 (_u *AttachmentUpdateOne) SetNillablePrimary(v *bool) *AttachmentUpdateOne {
if v != nil {
_u.SetPrimary(*v)
func (auo *AttachmentUpdateOne) SetNillablePrimary(b *bool) *AttachmentUpdateOne {
if b != nil {
auo.SetPrimary(*b)
}
return _u
}
// SetTitle sets the "title" field.
func (_u *AttachmentUpdateOne) SetTitle(v string) *AttachmentUpdateOne {
_u.mutation.SetTitle(v)
return _u
}
// SetNillableTitle sets the "title" field if the given value is not nil.
func (_u *AttachmentUpdateOne) SetNillableTitle(v *string) *AttachmentUpdateOne {
if v != nil {
_u.SetTitle(*v)
}
return _u
}
// SetPath sets the "path" field.
func (_u *AttachmentUpdateOne) SetPath(v string) *AttachmentUpdateOne {
_u.mutation.SetPath(v)
return _u
}
// SetNillablePath sets the "path" field if the given value is not nil.
func (_u *AttachmentUpdateOne) SetNillablePath(v *string) *AttachmentUpdateOne {
if v != nil {
_u.SetPath(*v)
}
return _u
}
// SetMimeType sets the "mime_type" field.
func (_u *AttachmentUpdateOne) SetMimeType(v string) *AttachmentUpdateOne {
_u.mutation.SetMimeType(v)
return _u
}
// SetNillableMimeType sets the "mime_type" field if the given value is not nil.
func (_u *AttachmentUpdateOne) SetNillableMimeType(v *string) *AttachmentUpdateOne {
if v != nil {
_u.SetMimeType(*v)
}
return _u
return auo
}
// SetItemID sets the "item" edge to the Item entity by ID.
func (_u *AttachmentUpdateOne) SetItemID(id uuid.UUID) *AttachmentUpdateOne {
_u.mutation.SetItemID(id)
return _u
}
// SetNillableItemID sets the "item" edge to the Item entity by ID if the given value is not nil.
func (_u *AttachmentUpdateOne) SetNillableItemID(id *uuid.UUID) *AttachmentUpdateOne {
if id != nil {
_u = _u.SetItemID(*id)
}
return _u
func (auo *AttachmentUpdateOne) SetItemID(id uuid.UUID) *AttachmentUpdateOne {
auo.mutation.SetItemID(id)
return auo
}
// SetItem sets the "item" edge to the Item entity.
func (_u *AttachmentUpdateOne) SetItem(v *Item) *AttachmentUpdateOne {
return _u.SetItemID(v.ID)
func (auo *AttachmentUpdateOne) SetItem(i *Item) *AttachmentUpdateOne {
return auo.SetItemID(i.ID)
}
// SetThumbnailID sets the "thumbnail" edge to the Attachment entity by ID.
func (_u *AttachmentUpdateOne) SetThumbnailID(id uuid.UUID) *AttachmentUpdateOne {
_u.mutation.SetThumbnailID(id)
return _u
// SetDocumentID sets the "document" edge to the Document entity by ID.
func (auo *AttachmentUpdateOne) SetDocumentID(id uuid.UUID) *AttachmentUpdateOne {
auo.mutation.SetDocumentID(id)
return auo
}
// SetNillableThumbnailID sets the "thumbnail" edge to the Attachment entity by ID if the given value is not nil.
func (_u *AttachmentUpdateOne) SetNillableThumbnailID(id *uuid.UUID) *AttachmentUpdateOne {
if id != nil {
_u = _u.SetThumbnailID(*id)
}
return _u
}
// SetThumbnail sets the "thumbnail" edge to the Attachment entity.
func (_u *AttachmentUpdateOne) SetThumbnail(v *Attachment) *AttachmentUpdateOne {
return _u.SetThumbnailID(v.ID)
// SetDocument sets the "document" edge to the Document entity.
func (auo *AttachmentUpdateOne) SetDocument(d *Document) *AttachmentUpdateOne {
return auo.SetDocumentID(d.ID)
}
// Mutation returns the AttachmentMutation object of the builder.
func (_u *AttachmentUpdateOne) Mutation() *AttachmentMutation {
return _u.mutation
func (auo *AttachmentUpdateOne) Mutation() *AttachmentMutation {
return auo.mutation
}
// ClearItem clears the "item" edge to the Item entity.
func (_u *AttachmentUpdateOne) ClearItem() *AttachmentUpdateOne {
_u.mutation.ClearItem()
return _u
func (auo *AttachmentUpdateOne) ClearItem() *AttachmentUpdateOne {
auo.mutation.ClearItem()
return auo
}
// ClearThumbnail clears the "thumbnail" edge to the Attachment entity.
func (_u *AttachmentUpdateOne) ClearThumbnail() *AttachmentUpdateOne {
_u.mutation.ClearThumbnail()
return _u
// ClearDocument clears the "document" edge to the Document entity.
func (auo *AttachmentUpdateOne) ClearDocument() *AttachmentUpdateOne {
auo.mutation.ClearDocument()
return auo
}
// Where appends a list predicates to the AttachmentUpdate builder.
func (_u *AttachmentUpdateOne) Where(ps ...predicate.Attachment) *AttachmentUpdateOne {
_u.mutation.Where(ps...)
return _u
func (auo *AttachmentUpdateOne) Where(ps ...predicate.Attachment) *AttachmentUpdateOne {
auo.mutation.Where(ps...)
return auo
}
// Select allows selecting one or more fields (columns) of the returned entity.
// The default is selecting all fields defined in the entity schema.
func (_u *AttachmentUpdateOne) Select(field string, fields ...string) *AttachmentUpdateOne {
_u.fields = append([]string{field}, fields...)
return _u
func (auo *AttachmentUpdateOne) Select(field string, fields ...string) *AttachmentUpdateOne {
auo.fields = append([]string{field}, fields...)
return auo
}
// Save executes the query and returns the updated Attachment entity.
func (_u *AttachmentUpdateOne) Save(ctx context.Context) (*Attachment, error) {
_u.defaults()
return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)
func (auo *AttachmentUpdateOne) Save(ctx context.Context) (*Attachment, error) {
auo.defaults()
return withHooks(ctx, auo.sqlSave, auo.mutation, auo.hooks)
}
// SaveX is like Save, but panics if an error occurs.
func (_u *AttachmentUpdateOne) SaveX(ctx context.Context) *Attachment {
node, err := _u.Save(ctx)
func (auo *AttachmentUpdateOne) SaveX(ctx context.Context) *Attachment {
node, err := auo.Save(ctx)
if err != nil {
panic(err)
}
@@ -475,47 +357,53 @@ func (_u *AttachmentUpdateOne) SaveX(ctx context.Context) *Attachment {
}
// Exec executes the query on the entity.
func (_u *AttachmentUpdateOne) Exec(ctx context.Context) error {
_, err := _u.Save(ctx)
func (auo *AttachmentUpdateOne) Exec(ctx context.Context) error {
_, err := auo.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (_u *AttachmentUpdateOne) ExecX(ctx context.Context) {
if err := _u.Exec(ctx); err != nil {
func (auo *AttachmentUpdateOne) ExecX(ctx context.Context) {
if err := auo.Exec(ctx); err != nil {
panic(err)
}
}
// defaults sets the default values of the builder before save.
func (_u *AttachmentUpdateOne) defaults() {
if _, ok := _u.mutation.UpdatedAt(); !ok {
func (auo *AttachmentUpdateOne) defaults() {
if _, ok := auo.mutation.UpdatedAt(); !ok {
v := attachment.UpdateDefaultUpdatedAt()
_u.mutation.SetUpdatedAt(v)
auo.mutation.SetUpdatedAt(v)
}
}
// check runs all checks and user-defined validators on the builder.
func (_u *AttachmentUpdateOne) check() error {
if v, ok := _u.mutation.GetType(); ok {
func (auo *AttachmentUpdateOne) check() error {
if v, ok := auo.mutation.GetType(); ok {
if err := attachment.TypeValidator(v); err != nil {
return &ValidationError{Name: "type", err: fmt.Errorf(`ent: validator failed for field "Attachment.type": %w`, err)}
}
}
if auo.mutation.ItemCleared() && len(auo.mutation.ItemIDs()) > 0 {
return errors.New(`ent: clearing a required unique edge "Attachment.item"`)
}
if auo.mutation.DocumentCleared() && len(auo.mutation.DocumentIDs()) > 0 {
return errors.New(`ent: clearing a required unique edge "Attachment.document"`)
}
return nil
}
func (_u *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment, err error) {
if err := _u.check(); err != nil {
func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment, err error) {
if err := auo.check(); err != nil {
return _node, err
}
_spec := sqlgraph.NewUpdateSpec(attachment.Table, attachment.Columns, sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID))
id, ok := _u.mutation.ID()
id, ok := auo.mutation.ID()
if !ok {
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Attachment.id" for update`)}
}
_spec.Node.ID.Value = id
if fields := _u.fields; len(fields) > 0 {
if fields := auo.fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, attachment.FieldID)
for _, f := range fields {
@@ -527,32 +415,23 @@ func (_u *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
}
}
}
if ps := _u.mutation.predicates; len(ps) > 0 {
if ps := auo.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if value, ok := _u.mutation.UpdatedAt(); ok {
if value, ok := auo.mutation.UpdatedAt(); ok {
_spec.SetField(attachment.FieldUpdatedAt, field.TypeTime, value)
}
if value, ok := _u.mutation.GetType(); ok {
if value, ok := auo.mutation.GetType(); ok {
_spec.SetField(attachment.FieldType, field.TypeEnum, value)
}
if value, ok := _u.mutation.Primary(); ok {
if value, ok := auo.mutation.Primary(); ok {
_spec.SetField(attachment.FieldPrimary, field.TypeBool, value)
}
if value, ok := _u.mutation.Title(); ok {
_spec.SetField(attachment.FieldTitle, field.TypeString, value)
}
if value, ok := _u.mutation.Path(); ok {
_spec.SetField(attachment.FieldPath, field.TypeString, value)
}
if value, ok := _u.mutation.MimeType(); ok {
_spec.SetField(attachment.FieldMimeType, field.TypeString, value)
}
if _u.mutation.ItemCleared() {
if auo.mutation.ItemCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
@@ -565,7 +444,7 @@ func (_u *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := _u.mutation.ItemIDs(); len(nodes) > 0 {
if nodes := auo.mutation.ItemIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
@@ -581,28 +460,28 @@ func (_u *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if _u.mutation.ThumbnailCleared() {
if auo.mutation.DocumentCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2O,
Inverse: false,
Table: attachment.ThumbnailTable,
Columns: []string{attachment.ThumbnailColumn},
Bidi: true,
Rel: sqlgraph.M2O,
Inverse: true,
Table: attachment.DocumentTable,
Columns: []string{attachment.DocumentColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID),
IDSpec: sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := _u.mutation.ThumbnailIDs(); len(nodes) > 0 {
if nodes := auo.mutation.DocumentIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2O,
Inverse: false,
Table: attachment.ThumbnailTable,
Columns: []string{attachment.ThumbnailColumn},
Bidi: true,
Rel: sqlgraph.M2O,
Inverse: true,
Table: attachment.DocumentTable,
Columns: []string{attachment.DocumentColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID),
IDSpec: sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
@@ -610,10 +489,10 @@ func (_u *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
_node = &Attachment{config: _u.config}
_node = &Attachment{config: auo.config}
_spec.Assign = _node.assignValues
_spec.ScanValues = _node.scanValues
if err = sqlgraph.UpdateNode(ctx, _u.driver, _spec); err != nil {
if err = sqlgraph.UpdateNode(ctx, auo.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{attachment.Label}
} else if sqlgraph.IsConstraintError(err) {
@@ -621,6 +500,6 @@ func (_u *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
}
return nil, err
}
_u.mutation.done = true
auo.mutation.done = true
return _node, nil
}

View File

@@ -67,7 +67,7 @@ func (*AuthRoles) scanValues(columns []string) ([]any, error) {
// assignValues assigns the values that were returned from sql.Rows (after scanning)
// to the AuthRoles fields.
func (_m *AuthRoles) assignValues(columns []string, values []any) error {
func (ar *AuthRoles) assignValues(columns []string, values []any) error {
if m, n := len(values), len(columns); m < n {
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
}
@@ -78,22 +78,22 @@ func (_m *AuthRoles) assignValues(columns []string, values []any) error {
if !ok {
return fmt.Errorf("unexpected type %T for field id", value)
}
_m.ID = int(value.Int64)
ar.ID = int(value.Int64)
case authroles.FieldRole:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field role", values[i])
} else if value.Valid {
_m.Role = authroles.Role(value.String)
ar.Role = authroles.Role(value.String)
}
case authroles.ForeignKeys[0]:
if value, ok := values[i].(*sql.NullScanner); !ok {
return fmt.Errorf("unexpected type %T for field auth_tokens_roles", values[i])
} else if value.Valid {
_m.auth_tokens_roles = new(uuid.UUID)
*_m.auth_tokens_roles = *value.S.(*uuid.UUID)
ar.auth_tokens_roles = new(uuid.UUID)
*ar.auth_tokens_roles = *value.S.(*uuid.UUID)
}
default:
_m.selectValues.Set(columns[i], values[i])
ar.selectValues.Set(columns[i], values[i])
}
}
return nil
@@ -101,40 +101,40 @@ func (_m *AuthRoles) assignValues(columns []string, values []any) error {
// Value returns the ent.Value that was dynamically selected and assigned to the AuthRoles.
// This includes values selected through modifiers, order, etc.
func (_m *AuthRoles) Value(name string) (ent.Value, error) {
return _m.selectValues.Get(name)
func (ar *AuthRoles) Value(name string) (ent.Value, error) {
return ar.selectValues.Get(name)
}
// QueryToken queries the "token" edge of the AuthRoles entity.
func (_m *AuthRoles) QueryToken() *AuthTokensQuery {
return NewAuthRolesClient(_m.config).QueryToken(_m)
func (ar *AuthRoles) QueryToken() *AuthTokensQuery {
return NewAuthRolesClient(ar.config).QueryToken(ar)
}
// Update returns a builder for updating this AuthRoles.
// Note that you need to call AuthRoles.Unwrap() before calling this method if this AuthRoles
// was returned from a transaction, and the transaction was committed or rolled back.
func (_m *AuthRoles) Update() *AuthRolesUpdateOne {
return NewAuthRolesClient(_m.config).UpdateOne(_m)
func (ar *AuthRoles) Update() *AuthRolesUpdateOne {
return NewAuthRolesClient(ar.config).UpdateOne(ar)
}
// Unwrap unwraps the AuthRoles entity that was returned from a transaction after it was closed,
// so that all future queries will be executed through the driver which created the transaction.
func (_m *AuthRoles) Unwrap() *AuthRoles {
_tx, ok := _m.config.driver.(*txDriver)
func (ar *AuthRoles) Unwrap() *AuthRoles {
_tx, ok := ar.config.driver.(*txDriver)
if !ok {
panic("ent: AuthRoles is not a transactional entity")
}
_m.config.driver = _tx.drv
return _m
ar.config.driver = _tx.drv
return ar
}
// String implements the fmt.Stringer.
func (_m *AuthRoles) String() string {
func (ar *AuthRoles) String() string {
var builder strings.Builder
builder.WriteString("AuthRoles(")
builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID))
builder.WriteString(fmt.Sprintf("id=%v, ", ar.ID))
builder.WriteString("role=")
builder.WriteString(fmt.Sprintf("%v", _m.Role))
builder.WriteString(fmt.Sprintf("%v", ar.Role))
builder.WriteByte(')')
return builder.String()
}

View File

@@ -22,52 +22,52 @@ type AuthRolesCreate struct {
}
// SetRole sets the "role" field.
func (_c *AuthRolesCreate) SetRole(v authroles.Role) *AuthRolesCreate {
_c.mutation.SetRole(v)
return _c
func (arc *AuthRolesCreate) SetRole(a authroles.Role) *AuthRolesCreate {
arc.mutation.SetRole(a)
return arc
}
// SetNillableRole sets the "role" field if the given value is not nil.
func (_c *AuthRolesCreate) SetNillableRole(v *authroles.Role) *AuthRolesCreate {
if v != nil {
_c.SetRole(*v)
func (arc *AuthRolesCreate) SetNillableRole(a *authroles.Role) *AuthRolesCreate {
if a != nil {
arc.SetRole(*a)
}
return _c
return arc
}
// SetTokenID sets the "token" edge to the AuthTokens entity by ID.
func (_c *AuthRolesCreate) SetTokenID(id uuid.UUID) *AuthRolesCreate {
_c.mutation.SetTokenID(id)
return _c
func (arc *AuthRolesCreate) SetTokenID(id uuid.UUID) *AuthRolesCreate {
arc.mutation.SetTokenID(id)
return arc
}
// SetNillableTokenID sets the "token" edge to the AuthTokens entity by ID if the given value is not nil.
func (_c *AuthRolesCreate) SetNillableTokenID(id *uuid.UUID) *AuthRolesCreate {
func (arc *AuthRolesCreate) SetNillableTokenID(id *uuid.UUID) *AuthRolesCreate {
if id != nil {
_c = _c.SetTokenID(*id)
arc = arc.SetTokenID(*id)
}
return _c
return arc
}
// SetToken sets the "token" edge to the AuthTokens entity.
func (_c *AuthRolesCreate) SetToken(v *AuthTokens) *AuthRolesCreate {
return _c.SetTokenID(v.ID)
func (arc *AuthRolesCreate) SetToken(a *AuthTokens) *AuthRolesCreate {
return arc.SetTokenID(a.ID)
}
// Mutation returns the AuthRolesMutation object of the builder.
func (_c *AuthRolesCreate) Mutation() *AuthRolesMutation {
return _c.mutation
func (arc *AuthRolesCreate) Mutation() *AuthRolesMutation {
return arc.mutation
}
// Save creates the AuthRoles in the database.
func (_c *AuthRolesCreate) Save(ctx context.Context) (*AuthRoles, error) {
_c.defaults()
return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks)
func (arc *AuthRolesCreate) Save(ctx context.Context) (*AuthRoles, error) {
arc.defaults()
return withHooks(ctx, arc.sqlSave, arc.mutation, arc.hooks)
}
// SaveX calls Save and panics if Save returns an error.
func (_c *AuthRolesCreate) SaveX(ctx context.Context) *AuthRoles {
v, err := _c.Save(ctx)
func (arc *AuthRolesCreate) SaveX(ctx context.Context) *AuthRoles {
v, err := arc.Save(ctx)
if err != nil {
panic(err)
}
@@ -75,32 +75,32 @@ func (_c *AuthRolesCreate) SaveX(ctx context.Context) *AuthRoles {
}
// Exec executes the query.
func (_c *AuthRolesCreate) Exec(ctx context.Context) error {
_, err := _c.Save(ctx)
func (arc *AuthRolesCreate) Exec(ctx context.Context) error {
_, err := arc.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (_c *AuthRolesCreate) ExecX(ctx context.Context) {
if err := _c.Exec(ctx); err != nil {
func (arc *AuthRolesCreate) ExecX(ctx context.Context) {
if err := arc.Exec(ctx); err != nil {
panic(err)
}
}
// defaults sets the default values of the builder before save.
func (_c *AuthRolesCreate) defaults() {
if _, ok := _c.mutation.Role(); !ok {
func (arc *AuthRolesCreate) defaults() {
if _, ok := arc.mutation.Role(); !ok {
v := authroles.DefaultRole
_c.mutation.SetRole(v)
arc.mutation.SetRole(v)
}
}
// check runs all checks and user-defined validators on the builder.
func (_c *AuthRolesCreate) check() error {
if _, ok := _c.mutation.Role(); !ok {
func (arc *AuthRolesCreate) check() error {
if _, ok := arc.mutation.Role(); !ok {
return &ValidationError{Name: "role", err: errors.New(`ent: missing required field "AuthRoles.role"`)}
}
if v, ok := _c.mutation.Role(); ok {
if v, ok := arc.mutation.Role(); ok {
if err := authroles.RoleValidator(v); err != nil {
return &ValidationError{Name: "role", err: fmt.Errorf(`ent: validator failed for field "AuthRoles.role": %w`, err)}
}
@@ -108,12 +108,12 @@ func (_c *AuthRolesCreate) check() error {
return nil
}
func (_c *AuthRolesCreate) sqlSave(ctx context.Context) (*AuthRoles, error) {
if err := _c.check(); err != nil {
func (arc *AuthRolesCreate) sqlSave(ctx context.Context) (*AuthRoles, error) {
if err := arc.check(); err != nil {
return nil, err
}
_node, _spec := _c.createSpec()
if err := sqlgraph.CreateNode(ctx, _c.driver, _spec); err != nil {
_node, _spec := arc.createSpec()
if err := sqlgraph.CreateNode(ctx, arc.driver, _spec); err != nil {
if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
@@ -121,21 +121,21 @@ func (_c *AuthRolesCreate) sqlSave(ctx context.Context) (*AuthRoles, error) {
}
id := _spec.ID.Value.(int64)
_node.ID = int(id)
_c.mutation.id = &_node.ID
_c.mutation.done = true
arc.mutation.id = &_node.ID
arc.mutation.done = true
return _node, nil
}
func (_c *AuthRolesCreate) createSpec() (*AuthRoles, *sqlgraph.CreateSpec) {
func (arc *AuthRolesCreate) createSpec() (*AuthRoles, *sqlgraph.CreateSpec) {
var (
_node = &AuthRoles{config: _c.config}
_node = &AuthRoles{config: arc.config}
_spec = sqlgraph.NewCreateSpec(authroles.Table, sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt))
)
if value, ok := _c.mutation.Role(); ok {
if value, ok := arc.mutation.Role(); ok {
_spec.SetField(authroles.FieldRole, field.TypeEnum, value)
_node.Role = value
}
if nodes := _c.mutation.TokenIDs(); len(nodes) > 0 {
if nodes := arc.mutation.TokenIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2O,
Inverse: true,
@@ -163,16 +163,16 @@ type AuthRolesCreateBulk struct {
}
// Save creates the AuthRoles entities in the database.
func (_c *AuthRolesCreateBulk) Save(ctx context.Context) ([]*AuthRoles, error) {
if _c.err != nil {
return nil, _c.err
func (arcb *AuthRolesCreateBulk) Save(ctx context.Context) ([]*AuthRoles, error) {
if arcb.err != nil {
return nil, arcb.err
}
specs := make([]*sqlgraph.CreateSpec, len(_c.builders))
nodes := make([]*AuthRoles, len(_c.builders))
mutators := make([]Mutator, len(_c.builders))
for i := range _c.builders {
specs := make([]*sqlgraph.CreateSpec, len(arcb.builders))
nodes := make([]*AuthRoles, len(arcb.builders))
mutators := make([]Mutator, len(arcb.builders))
for i := range arcb.builders {
func(i int, root context.Context) {
builder := _c.builders[i]
builder := arcb.builders[i]
builder.defaults()
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
mutation, ok := m.(*AuthRolesMutation)
@@ -186,11 +186,11 @@ func (_c *AuthRolesCreateBulk) Save(ctx context.Context) ([]*AuthRoles, error) {
var err error
nodes[i], specs[i] = builder.createSpec()
if i < len(mutators)-1 {
_, err = mutators[i+1].Mutate(root, _c.builders[i+1].mutation)
_, err = mutators[i+1].Mutate(root, arcb.builders[i+1].mutation)
} else {
spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
// Invoke the actual operation on the latest mutation in the chain.
if err = sqlgraph.BatchCreate(ctx, _c.driver, spec); err != nil {
if err = sqlgraph.BatchCreate(ctx, arcb.driver, spec); err != nil {
if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
@@ -214,7 +214,7 @@ func (_c *AuthRolesCreateBulk) Save(ctx context.Context) ([]*AuthRoles, error) {
}(i, ctx)
}
if len(mutators) > 0 {
if _, err := mutators[0].Mutate(ctx, _c.builders[0].mutation); err != nil {
if _, err := mutators[0].Mutate(ctx, arcb.builders[0].mutation); err != nil {
return nil, err
}
}
@@ -222,8 +222,8 @@ func (_c *AuthRolesCreateBulk) Save(ctx context.Context) ([]*AuthRoles, error) {
}
// SaveX is like Save, but panics if an error occurs.
func (_c *AuthRolesCreateBulk) SaveX(ctx context.Context) []*AuthRoles {
v, err := _c.Save(ctx)
func (arcb *AuthRolesCreateBulk) SaveX(ctx context.Context) []*AuthRoles {
v, err := arcb.Save(ctx)
if err != nil {
panic(err)
}
@@ -231,14 +231,14 @@ func (_c *AuthRolesCreateBulk) SaveX(ctx context.Context) []*AuthRoles {
}
// Exec executes the query.
func (_c *AuthRolesCreateBulk) Exec(ctx context.Context) error {
_, err := _c.Save(ctx)
func (arcb *AuthRolesCreateBulk) Exec(ctx context.Context) error {
_, err := arcb.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (_c *AuthRolesCreateBulk) ExecX(ctx context.Context) {
if err := _c.Exec(ctx); err != nil {
func (arcb *AuthRolesCreateBulk) ExecX(ctx context.Context) {
if err := arcb.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -20,56 +20,56 @@ type AuthRolesDelete struct {
}
// Where appends a list predicates to the AuthRolesDelete builder.
func (_d *AuthRolesDelete) Where(ps ...predicate.AuthRoles) *AuthRolesDelete {
_d.mutation.Where(ps...)
return _d
func (ard *AuthRolesDelete) Where(ps ...predicate.AuthRoles) *AuthRolesDelete {
ard.mutation.Where(ps...)
return ard
}
// Exec executes the deletion query and returns how many vertices were deleted.
func (_d *AuthRolesDelete) Exec(ctx context.Context) (int, error) {
return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks)
func (ard *AuthRolesDelete) Exec(ctx context.Context) (int, error) {
return withHooks(ctx, ard.sqlExec, ard.mutation, ard.hooks)
}
// ExecX is like Exec, but panics if an error occurs.
func (_d *AuthRolesDelete) ExecX(ctx context.Context) int {
n, err := _d.Exec(ctx)
func (ard *AuthRolesDelete) ExecX(ctx context.Context) int {
n, err := ard.Exec(ctx)
if err != nil {
panic(err)
}
return n
}
func (_d *AuthRolesDelete) sqlExec(ctx context.Context) (int, error) {
func (ard *AuthRolesDelete) sqlExec(ctx context.Context) (int, error) {
_spec := sqlgraph.NewDeleteSpec(authroles.Table, sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt))
if ps := _d.mutation.predicates; len(ps) > 0 {
if ps := ard.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
affected, err := sqlgraph.DeleteNodes(ctx, _d.driver, _spec)
affected, err := sqlgraph.DeleteNodes(ctx, ard.driver, _spec)
if err != nil && sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
_d.mutation.done = true
ard.mutation.done = true
return affected, err
}
// AuthRolesDeleteOne is the builder for deleting a single AuthRoles entity.
type AuthRolesDeleteOne struct {
_d *AuthRolesDelete
ard *AuthRolesDelete
}
// Where appends a list predicates to the AuthRolesDelete builder.
func (_d *AuthRolesDeleteOne) Where(ps ...predicate.AuthRoles) *AuthRolesDeleteOne {
_d._d.mutation.Where(ps...)
return _d
func (ardo *AuthRolesDeleteOne) Where(ps ...predicate.AuthRoles) *AuthRolesDeleteOne {
ardo.ard.mutation.Where(ps...)
return ardo
}
// Exec executes the deletion query.
func (_d *AuthRolesDeleteOne) Exec(ctx context.Context) error {
n, err := _d._d.Exec(ctx)
func (ardo *AuthRolesDeleteOne) Exec(ctx context.Context) error {
n, err := ardo.ard.Exec(ctx)
switch {
case err != nil:
return err
@@ -81,8 +81,8 @@ func (_d *AuthRolesDeleteOne) Exec(ctx context.Context) error {
}
// ExecX is like Exec, but panics if an error occurs.
func (_d *AuthRolesDeleteOne) ExecX(ctx context.Context) {
if err := _d.Exec(ctx); err != nil {
func (ardo *AuthRolesDeleteOne) ExecX(ctx context.Context) {
if err := ardo.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -32,44 +32,44 @@ type AuthRolesQuery struct {
}
// Where adds a new predicate for the AuthRolesQuery builder.
func (_q *AuthRolesQuery) Where(ps ...predicate.AuthRoles) *AuthRolesQuery {
_q.predicates = append(_q.predicates, ps...)
return _q
func (arq *AuthRolesQuery) Where(ps ...predicate.AuthRoles) *AuthRolesQuery {
arq.predicates = append(arq.predicates, ps...)
return arq
}
// Limit the number of records to be returned by this query.
func (_q *AuthRolesQuery) Limit(limit int) *AuthRolesQuery {
_q.ctx.Limit = &limit
return _q
func (arq *AuthRolesQuery) Limit(limit int) *AuthRolesQuery {
arq.ctx.Limit = &limit
return arq
}
// Offset to start from.
func (_q *AuthRolesQuery) Offset(offset int) *AuthRolesQuery {
_q.ctx.Offset = &offset
return _q
func (arq *AuthRolesQuery) Offset(offset int) *AuthRolesQuery {
arq.ctx.Offset = &offset
return arq
}
// Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method.
func (_q *AuthRolesQuery) Unique(unique bool) *AuthRolesQuery {
_q.ctx.Unique = &unique
return _q
func (arq *AuthRolesQuery) Unique(unique bool) *AuthRolesQuery {
arq.ctx.Unique = &unique
return arq
}
// Order specifies how the records should be ordered.
func (_q *AuthRolesQuery) Order(o ...authroles.OrderOption) *AuthRolesQuery {
_q.order = append(_q.order, o...)
return _q
func (arq *AuthRolesQuery) Order(o ...authroles.OrderOption) *AuthRolesQuery {
arq.order = append(arq.order, o...)
return arq
}
// QueryToken chains the current query on the "token" edge.
func (_q *AuthRolesQuery) QueryToken() *AuthTokensQuery {
query := (&AuthTokensClient{config: _q.config}).Query()
func (arq *AuthRolesQuery) QueryToken() *AuthTokensQuery {
query := (&AuthTokensClient{config: arq.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := _q.prepareQuery(ctx); err != nil {
if err := arq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := _q.sqlQuery(ctx)
selector := arq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
@@ -78,7 +78,7 @@ func (_q *AuthRolesQuery) QueryToken() *AuthTokensQuery {
sqlgraph.To(authtokens.Table, authtokens.FieldID),
sqlgraph.Edge(sqlgraph.O2O, true, authroles.TokenTable, authroles.TokenColumn),
)
fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step)
fromU = sqlgraph.SetNeighbors(arq.driver.Dialect(), step)
return fromU, nil
}
return query
@@ -86,8 +86,8 @@ func (_q *AuthRolesQuery) QueryToken() *AuthTokensQuery {
// First returns the first AuthRoles entity from the query.
// Returns a *NotFoundError when no AuthRoles was found.
func (_q *AuthRolesQuery) First(ctx context.Context) (*AuthRoles, error) {
nodes, err := _q.Limit(1).All(setContextOp(ctx, _q.ctx, ent.OpQueryFirst))
func (arq *AuthRolesQuery) First(ctx context.Context) (*AuthRoles, error) {
nodes, err := arq.Limit(1).All(setContextOp(ctx, arq.ctx, ent.OpQueryFirst))
if err != nil {
return nil, err
}
@@ -98,8 +98,8 @@ func (_q *AuthRolesQuery) First(ctx context.Context) (*AuthRoles, error) {
}
// FirstX is like First, but panics if an error occurs.
func (_q *AuthRolesQuery) FirstX(ctx context.Context) *AuthRoles {
node, err := _q.First(ctx)
func (arq *AuthRolesQuery) FirstX(ctx context.Context) *AuthRoles {
node, err := arq.First(ctx)
if err != nil && !IsNotFound(err) {
panic(err)
}
@@ -108,9 +108,9 @@ func (_q *AuthRolesQuery) FirstX(ctx context.Context) *AuthRoles {
// FirstID returns the first AuthRoles ID from the query.
// Returns a *NotFoundError when no AuthRoles ID was found.
func (_q *AuthRolesQuery) FirstID(ctx context.Context) (id int, err error) {
func (arq *AuthRolesQuery) FirstID(ctx context.Context) (id int, err error) {
var ids []int
if ids, err = _q.Limit(1).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryFirstID)); err != nil {
if ids, err = arq.Limit(1).IDs(setContextOp(ctx, arq.ctx, ent.OpQueryFirstID)); err != nil {
return
}
if len(ids) == 0 {
@@ -121,8 +121,8 @@ func (_q *AuthRolesQuery) FirstID(ctx context.Context) (id int, err error) {
}
// FirstIDX is like FirstID, but panics if an error occurs.
func (_q *AuthRolesQuery) FirstIDX(ctx context.Context) int {
id, err := _q.FirstID(ctx)
func (arq *AuthRolesQuery) FirstIDX(ctx context.Context) int {
id, err := arq.FirstID(ctx)
if err != nil && !IsNotFound(err) {
panic(err)
}
@@ -132,8 +132,8 @@ func (_q *AuthRolesQuery) FirstIDX(ctx context.Context) int {
// Only returns a single AuthRoles entity found by the query, ensuring it only returns one.
// Returns a *NotSingularError when more than one AuthRoles entity is found.
// Returns a *NotFoundError when no AuthRoles entities are found.
func (_q *AuthRolesQuery) Only(ctx context.Context) (*AuthRoles, error) {
nodes, err := _q.Limit(2).All(setContextOp(ctx, _q.ctx, ent.OpQueryOnly))
func (arq *AuthRolesQuery) Only(ctx context.Context) (*AuthRoles, error) {
nodes, err := arq.Limit(2).All(setContextOp(ctx, arq.ctx, ent.OpQueryOnly))
if err != nil {
return nil, err
}
@@ -148,8 +148,8 @@ func (_q *AuthRolesQuery) Only(ctx context.Context) (*AuthRoles, error) {
}
// OnlyX is like Only, but panics if an error occurs.
func (_q *AuthRolesQuery) OnlyX(ctx context.Context) *AuthRoles {
node, err := _q.Only(ctx)
func (arq *AuthRolesQuery) OnlyX(ctx context.Context) *AuthRoles {
node, err := arq.Only(ctx)
if err != nil {
panic(err)
}
@@ -159,9 +159,9 @@ func (_q *AuthRolesQuery) OnlyX(ctx context.Context) *AuthRoles {
// OnlyID is like Only, but returns the only AuthRoles ID in the query.
// Returns a *NotSingularError when more than one AuthRoles ID is found.
// Returns a *NotFoundError when no entities are found.
func (_q *AuthRolesQuery) OnlyID(ctx context.Context) (id int, err error) {
func (arq *AuthRolesQuery) OnlyID(ctx context.Context) (id int, err error) {
var ids []int
if ids, err = _q.Limit(2).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryOnlyID)); err != nil {
if ids, err = arq.Limit(2).IDs(setContextOp(ctx, arq.ctx, ent.OpQueryOnlyID)); err != nil {
return
}
switch len(ids) {
@@ -176,8 +176,8 @@ func (_q *AuthRolesQuery) OnlyID(ctx context.Context) (id int, err error) {
}
// OnlyIDX is like OnlyID, but panics if an error occurs.
func (_q *AuthRolesQuery) OnlyIDX(ctx context.Context) int {
id, err := _q.OnlyID(ctx)
func (arq *AuthRolesQuery) OnlyIDX(ctx context.Context) int {
id, err := arq.OnlyID(ctx)
if err != nil {
panic(err)
}
@@ -185,18 +185,18 @@ func (_q *AuthRolesQuery) OnlyIDX(ctx context.Context) int {
}
// All executes the query and returns a list of AuthRolesSlice.
func (_q *AuthRolesQuery) All(ctx context.Context) ([]*AuthRoles, error) {
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll)
if err := _q.prepareQuery(ctx); err != nil {
func (arq *AuthRolesQuery) All(ctx context.Context) ([]*AuthRoles, error) {
ctx = setContextOp(ctx, arq.ctx, ent.OpQueryAll)
if err := arq.prepareQuery(ctx); err != nil {
return nil, err
}
qr := querierAll[[]*AuthRoles, *AuthRolesQuery]()
return withInterceptors[[]*AuthRoles](ctx, _q, qr, _q.inters)
return withInterceptors[[]*AuthRoles](ctx, arq, qr, arq.inters)
}
// AllX is like All, but panics if an error occurs.
func (_q *AuthRolesQuery) AllX(ctx context.Context) []*AuthRoles {
nodes, err := _q.All(ctx)
func (arq *AuthRolesQuery) AllX(ctx context.Context) []*AuthRoles {
nodes, err := arq.All(ctx)
if err != nil {
panic(err)
}
@@ -204,20 +204,20 @@ func (_q *AuthRolesQuery) AllX(ctx context.Context) []*AuthRoles {
}
// IDs executes the query and returns a list of AuthRoles IDs.
func (_q *AuthRolesQuery) IDs(ctx context.Context) (ids []int, err error) {
if _q.ctx.Unique == nil && _q.path != nil {
_q.Unique(true)
func (arq *AuthRolesQuery) IDs(ctx context.Context) (ids []int, err error) {
if arq.ctx.Unique == nil && arq.path != nil {
arq.Unique(true)
}
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryIDs)
if err = _q.Select(authroles.FieldID).Scan(ctx, &ids); err != nil {
ctx = setContextOp(ctx, arq.ctx, ent.OpQueryIDs)
if err = arq.Select(authroles.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
return ids, nil
}
// IDsX is like IDs, but panics if an error occurs.
func (_q *AuthRolesQuery) IDsX(ctx context.Context) []int {
ids, err := _q.IDs(ctx)
func (arq *AuthRolesQuery) IDsX(ctx context.Context) []int {
ids, err := arq.IDs(ctx)
if err != nil {
panic(err)
}
@@ -225,17 +225,17 @@ func (_q *AuthRolesQuery) IDsX(ctx context.Context) []int {
}
// Count returns the count of the given query.
func (_q *AuthRolesQuery) Count(ctx context.Context) (int, error) {
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryCount)
if err := _q.prepareQuery(ctx); err != nil {
func (arq *AuthRolesQuery) Count(ctx context.Context) (int, error) {
ctx = setContextOp(ctx, arq.ctx, ent.OpQueryCount)
if err := arq.prepareQuery(ctx); err != nil {
return 0, err
}
return withInterceptors[int](ctx, _q, querierCount[*AuthRolesQuery](), _q.inters)
return withInterceptors[int](ctx, arq, querierCount[*AuthRolesQuery](), arq.inters)
}
// CountX is like Count, but panics if an error occurs.
func (_q *AuthRolesQuery) CountX(ctx context.Context) int {
count, err := _q.Count(ctx)
func (arq *AuthRolesQuery) CountX(ctx context.Context) int {
count, err := arq.Count(ctx)
if err != nil {
panic(err)
}
@@ -243,9 +243,9 @@ func (_q *AuthRolesQuery) CountX(ctx context.Context) int {
}
// Exist returns true if the query has elements in the graph.
func (_q *AuthRolesQuery) Exist(ctx context.Context) (bool, error) {
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryExist)
switch _, err := _q.FirstID(ctx); {
func (arq *AuthRolesQuery) Exist(ctx context.Context) (bool, error) {
ctx = setContextOp(ctx, arq.ctx, ent.OpQueryExist)
switch _, err := arq.FirstID(ctx); {
case IsNotFound(err):
return false, nil
case err != nil:
@@ -256,8 +256,8 @@ func (_q *AuthRolesQuery) Exist(ctx context.Context) (bool, error) {
}
// ExistX is like Exist, but panics if an error occurs.
func (_q *AuthRolesQuery) ExistX(ctx context.Context) bool {
exist, err := _q.Exist(ctx)
func (arq *AuthRolesQuery) ExistX(ctx context.Context) bool {
exist, err := arq.Exist(ctx)
if err != nil {
panic(err)
}
@@ -266,32 +266,32 @@ func (_q *AuthRolesQuery) ExistX(ctx context.Context) bool {
// Clone returns a duplicate of the AuthRolesQuery builder, including all associated steps. It can be
// used to prepare common query builders and use them differently after the clone is made.
func (_q *AuthRolesQuery) Clone() *AuthRolesQuery {
if _q == nil {
func (arq *AuthRolesQuery) Clone() *AuthRolesQuery {
if arq == nil {
return nil
}
return &AuthRolesQuery{
config: _q.config,
ctx: _q.ctx.Clone(),
order: append([]authroles.OrderOption{}, _q.order...),
inters: append([]Interceptor{}, _q.inters...),
predicates: append([]predicate.AuthRoles{}, _q.predicates...),
withToken: _q.withToken.Clone(),
config: arq.config,
ctx: arq.ctx.Clone(),
order: append([]authroles.OrderOption{}, arq.order...),
inters: append([]Interceptor{}, arq.inters...),
predicates: append([]predicate.AuthRoles{}, arq.predicates...),
withToken: arq.withToken.Clone(),
// clone intermediate query.
sql: _q.sql.Clone(),
path: _q.path,
sql: arq.sql.Clone(),
path: arq.path,
}
}
// WithToken tells the query-builder to eager-load the nodes that are connected to
// the "token" edge. The optional arguments are used to configure the query builder of the edge.
func (_q *AuthRolesQuery) WithToken(opts ...func(*AuthTokensQuery)) *AuthRolesQuery {
query := (&AuthTokensClient{config: _q.config}).Query()
func (arq *AuthRolesQuery) WithToken(opts ...func(*AuthTokensQuery)) *AuthRolesQuery {
query := (&AuthTokensClient{config: arq.config}).Query()
for _, opt := range opts {
opt(query)
}
_q.withToken = query
return _q
arq.withToken = query
return arq
}
// GroupBy is used to group vertices by one or more fields/columns.
@@ -308,10 +308,10 @@ func (_q *AuthRolesQuery) WithToken(opts ...func(*AuthTokensQuery)) *AuthRolesQu
// GroupBy(authroles.FieldRole).
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (_q *AuthRolesQuery) GroupBy(field string, fields ...string) *AuthRolesGroupBy {
_q.ctx.Fields = append([]string{field}, fields...)
grbuild := &AuthRolesGroupBy{build: _q}
grbuild.flds = &_q.ctx.Fields
func (arq *AuthRolesQuery) GroupBy(field string, fields ...string) *AuthRolesGroupBy {
arq.ctx.Fields = append([]string{field}, fields...)
grbuild := &AuthRolesGroupBy{build: arq}
grbuild.flds = &arq.ctx.Fields
grbuild.label = authroles.Label
grbuild.scan = grbuild.Scan
return grbuild
@@ -329,55 +329,55 @@ func (_q *AuthRolesQuery) GroupBy(field string, fields ...string) *AuthRolesGrou
// client.AuthRoles.Query().
// Select(authroles.FieldRole).
// Scan(ctx, &v)
func (_q *AuthRolesQuery) Select(fields ...string) *AuthRolesSelect {
_q.ctx.Fields = append(_q.ctx.Fields, fields...)
sbuild := &AuthRolesSelect{AuthRolesQuery: _q}
func (arq *AuthRolesQuery) Select(fields ...string) *AuthRolesSelect {
arq.ctx.Fields = append(arq.ctx.Fields, fields...)
sbuild := &AuthRolesSelect{AuthRolesQuery: arq}
sbuild.label = authroles.Label
sbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan
sbuild.flds, sbuild.scan = &arq.ctx.Fields, sbuild.Scan
return sbuild
}
// Aggregate returns a AuthRolesSelect configured with the given aggregations.
func (_q *AuthRolesQuery) Aggregate(fns ...AggregateFunc) *AuthRolesSelect {
return _q.Select().Aggregate(fns...)
func (arq *AuthRolesQuery) Aggregate(fns ...AggregateFunc) *AuthRolesSelect {
return arq.Select().Aggregate(fns...)
}
func (_q *AuthRolesQuery) prepareQuery(ctx context.Context) error {
for _, inter := range _q.inters {
func (arq *AuthRolesQuery) prepareQuery(ctx context.Context) error {
for _, inter := range arq.inters {
if inter == nil {
return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)")
}
if trv, ok := inter.(Traverser); ok {
if err := trv.Traverse(ctx, _q); err != nil {
if err := trv.Traverse(ctx, arq); err != nil {
return err
}
}
}
for _, f := range _q.ctx.Fields {
for _, f := range arq.ctx.Fields {
if !authroles.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
}
if _q.path != nil {
prev, err := _q.path(ctx)
if arq.path != nil {
prev, err := arq.path(ctx)
if err != nil {
return err
}
_q.sql = prev
arq.sql = prev
}
return nil
}
func (_q *AuthRolesQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*AuthRoles, error) {
func (arq *AuthRolesQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*AuthRoles, error) {
var (
nodes = []*AuthRoles{}
withFKs = _q.withFKs
_spec = _q.querySpec()
withFKs = arq.withFKs
_spec = arq.querySpec()
loadedTypes = [1]bool{
_q.withToken != nil,
arq.withToken != nil,
}
)
if _q.withToken != nil {
if arq.withToken != nil {
withFKs = true
}
if withFKs {
@@ -387,7 +387,7 @@ func (_q *AuthRolesQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Au
return (*AuthRoles).scanValues(nil, columns)
}
_spec.Assign = func(columns []string, values []any) error {
node := &AuthRoles{config: _q.config}
node := &AuthRoles{config: arq.config}
nodes = append(nodes, node)
node.Edges.loadedTypes = loadedTypes
return node.assignValues(columns, values)
@@ -395,14 +395,14 @@ func (_q *AuthRolesQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Au
for i := range hooks {
hooks[i](ctx, _spec)
}
if err := sqlgraph.QueryNodes(ctx, _q.driver, _spec); err != nil {
if err := sqlgraph.QueryNodes(ctx, arq.driver, _spec); err != nil {
return nil, err
}
if len(nodes) == 0 {
return nodes, nil
}
if query := _q.withToken; query != nil {
if err := _q.loadToken(ctx, query, nodes, nil,
if query := arq.withToken; query != nil {
if err := arq.loadToken(ctx, query, nodes, nil,
func(n *AuthRoles, e *AuthTokens) { n.Edges.Token = e }); err != nil {
return nil, err
}
@@ -410,7 +410,7 @@ func (_q *AuthRolesQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Au
return nodes, nil
}
func (_q *AuthRolesQuery) loadToken(ctx context.Context, query *AuthTokensQuery, nodes []*AuthRoles, init func(*AuthRoles), assign func(*AuthRoles, *AuthTokens)) error {
func (arq *AuthRolesQuery) loadToken(ctx context.Context, query *AuthTokensQuery, nodes []*AuthRoles, init func(*AuthRoles), assign func(*AuthRoles, *AuthTokens)) error {
ids := make([]uuid.UUID, 0, len(nodes))
nodeids := make(map[uuid.UUID][]*AuthRoles)
for i := range nodes {
@@ -443,24 +443,24 @@ func (_q *AuthRolesQuery) loadToken(ctx context.Context, query *AuthTokensQuery,
return nil
}
func (_q *AuthRolesQuery) sqlCount(ctx context.Context) (int, error) {
_spec := _q.querySpec()
_spec.Node.Columns = _q.ctx.Fields
if len(_q.ctx.Fields) > 0 {
_spec.Unique = _q.ctx.Unique != nil && *_q.ctx.Unique
func (arq *AuthRolesQuery) sqlCount(ctx context.Context) (int, error) {
_spec := arq.querySpec()
_spec.Node.Columns = arq.ctx.Fields
if len(arq.ctx.Fields) > 0 {
_spec.Unique = arq.ctx.Unique != nil && *arq.ctx.Unique
}
return sqlgraph.CountNodes(ctx, _q.driver, _spec)
return sqlgraph.CountNodes(ctx, arq.driver, _spec)
}
func (_q *AuthRolesQuery) querySpec() *sqlgraph.QuerySpec {
func (arq *AuthRolesQuery) querySpec() *sqlgraph.QuerySpec {
_spec := sqlgraph.NewQuerySpec(authroles.Table, authroles.Columns, sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt))
_spec.From = _q.sql
if unique := _q.ctx.Unique; unique != nil {
_spec.From = arq.sql
if unique := arq.ctx.Unique; unique != nil {
_spec.Unique = *unique
} else if _q.path != nil {
} else if arq.path != nil {
_spec.Unique = true
}
if fields := _q.ctx.Fields; len(fields) > 0 {
if fields := arq.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, authroles.FieldID)
for i := range fields {
@@ -469,20 +469,20 @@ func (_q *AuthRolesQuery) querySpec() *sqlgraph.QuerySpec {
}
}
}
if ps := _q.predicates; len(ps) > 0 {
if ps := arq.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if limit := _q.ctx.Limit; limit != nil {
if limit := arq.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := _q.ctx.Offset; offset != nil {
if offset := arq.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := _q.order; len(ps) > 0 {
if ps := arq.order; len(ps) > 0 {
_spec.Order = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
@@ -492,33 +492,33 @@ func (_q *AuthRolesQuery) querySpec() *sqlgraph.QuerySpec {
return _spec
}
func (_q *AuthRolesQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(_q.driver.Dialect())
func (arq *AuthRolesQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(arq.driver.Dialect())
t1 := builder.Table(authroles.Table)
columns := _q.ctx.Fields
columns := arq.ctx.Fields
if len(columns) == 0 {
columns = authroles.Columns
}
selector := builder.Select(t1.Columns(columns...)...).From(t1)
if _q.sql != nil {
selector = _q.sql
if arq.sql != nil {
selector = arq.sql
selector.Select(selector.Columns(columns...)...)
}
if _q.ctx.Unique != nil && *_q.ctx.Unique {
if arq.ctx.Unique != nil && *arq.ctx.Unique {
selector.Distinct()
}
for _, p := range _q.predicates {
for _, p := range arq.predicates {
p(selector)
}
for _, p := range _q.order {
for _, p := range arq.order {
p(selector)
}
if offset := _q.ctx.Offset; offset != nil {
if offset := arq.ctx.Offset; offset != nil {
// limit is mandatory for offset clause. We start
// with default value, and override it below if needed.
selector.Offset(*offset).Limit(math.MaxInt32)
}
if limit := _q.ctx.Limit; limit != nil {
if limit := arq.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
@@ -531,41 +531,41 @@ type AuthRolesGroupBy struct {
}
// Aggregate adds the given aggregation functions to the group-by query.
func (_g *AuthRolesGroupBy) Aggregate(fns ...AggregateFunc) *AuthRolesGroupBy {
_g.fns = append(_g.fns, fns...)
return _g
func (argb *AuthRolesGroupBy) Aggregate(fns ...AggregateFunc) *AuthRolesGroupBy {
argb.fns = append(argb.fns, fns...)
return argb
}
// Scan applies the selector query and scans the result into the given value.
func (_g *AuthRolesGroupBy) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, _g.build.ctx, ent.OpQueryGroupBy)
if err := _g.build.prepareQuery(ctx); err != nil {
func (argb *AuthRolesGroupBy) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, argb.build.ctx, ent.OpQueryGroupBy)
if err := argb.build.prepareQuery(ctx); err != nil {
return err
}
return scanWithInterceptors[*AuthRolesQuery, *AuthRolesGroupBy](ctx, _g.build, _g, _g.build.inters, v)
return scanWithInterceptors[*AuthRolesQuery, *AuthRolesGroupBy](ctx, argb.build, argb, argb.build.inters, v)
}
func (_g *AuthRolesGroupBy) sqlScan(ctx context.Context, root *AuthRolesQuery, v any) error {
func (argb *AuthRolesGroupBy) sqlScan(ctx context.Context, root *AuthRolesQuery, v any) error {
selector := root.sqlQuery(ctx).Select()
aggregation := make([]string, 0, len(_g.fns))
for _, fn := range _g.fns {
aggregation := make([]string, 0, len(argb.fns))
for _, fn := range argb.fns {
aggregation = append(aggregation, fn(selector))
}
if len(selector.SelectedColumns()) == 0 {
columns := make([]string, 0, len(*_g.flds)+len(_g.fns))
for _, f := range *_g.flds {
columns := make([]string, 0, len(*argb.flds)+len(argb.fns))
for _, f := range *argb.flds {
columns = append(columns, selector.C(f))
}
columns = append(columns, aggregation...)
selector.Select(columns...)
}
selector.GroupBy(selector.Columns(*_g.flds...)...)
selector.GroupBy(selector.Columns(*argb.flds...)...)
if err := selector.Err(); err != nil {
return err
}
rows := &sql.Rows{}
query, args := selector.Query()
if err := _g.build.driver.Query(ctx, query, args, rows); err != nil {
if err := argb.build.driver.Query(ctx, query, args, rows); err != nil {
return err
}
defer rows.Close()
@@ -579,27 +579,27 @@ type AuthRolesSelect struct {
}
// Aggregate adds the given aggregation functions to the selector query.
func (_s *AuthRolesSelect) Aggregate(fns ...AggregateFunc) *AuthRolesSelect {
_s.fns = append(_s.fns, fns...)
return _s
func (ars *AuthRolesSelect) Aggregate(fns ...AggregateFunc) *AuthRolesSelect {
ars.fns = append(ars.fns, fns...)
return ars
}
// Scan applies the selector query and scans the result into the given value.
func (_s *AuthRolesSelect) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, _s.ctx, ent.OpQuerySelect)
if err := _s.prepareQuery(ctx); err != nil {
func (ars *AuthRolesSelect) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, ars.ctx, ent.OpQuerySelect)
if err := ars.prepareQuery(ctx); err != nil {
return err
}
return scanWithInterceptors[*AuthRolesQuery, *AuthRolesSelect](ctx, _s.AuthRolesQuery, _s, _s.inters, v)
return scanWithInterceptors[*AuthRolesQuery, *AuthRolesSelect](ctx, ars.AuthRolesQuery, ars, ars.inters, v)
}
func (_s *AuthRolesSelect) sqlScan(ctx context.Context, root *AuthRolesQuery, v any) error {
func (ars *AuthRolesSelect) sqlScan(ctx context.Context, root *AuthRolesQuery, v any) error {
selector := root.sqlQuery(ctx)
aggregation := make([]string, 0, len(_s.fns))
for _, fn := range _s.fns {
aggregation := make([]string, 0, len(ars.fns))
for _, fn := range ars.fns {
aggregation = append(aggregation, fn(selector))
}
switch n := len(*_s.selector.flds); {
switch n := len(*ars.selector.flds); {
case n == 0 && len(aggregation) > 0:
selector.Select(aggregation...)
case n != 0 && len(aggregation) > 0:
@@ -607,7 +607,7 @@ func (_s *AuthRolesSelect) sqlScan(ctx context.Context, root *AuthRolesQuery, v
}
rows := &sql.Rows{}
query, args := selector.Query()
if err := _s.driver.Query(ctx, query, args, rows); err != nil {
if err := ars.driver.Query(ctx, query, args, rows); err != nil {
return err
}
defer rows.Close()

View File

@@ -24,63 +24,63 @@ type AuthRolesUpdate struct {
}
// Where appends a list predicates to the AuthRolesUpdate builder.
func (_u *AuthRolesUpdate) Where(ps ...predicate.AuthRoles) *AuthRolesUpdate {
_u.mutation.Where(ps...)
return _u
func (aru *AuthRolesUpdate) Where(ps ...predicate.AuthRoles) *AuthRolesUpdate {
aru.mutation.Where(ps...)
return aru
}
// SetRole sets the "role" field.
func (_u *AuthRolesUpdate) SetRole(v authroles.Role) *AuthRolesUpdate {
_u.mutation.SetRole(v)
return _u
func (aru *AuthRolesUpdate) SetRole(a authroles.Role) *AuthRolesUpdate {
aru.mutation.SetRole(a)
return aru
}
// SetNillableRole sets the "role" field if the given value is not nil.
func (_u *AuthRolesUpdate) SetNillableRole(v *authroles.Role) *AuthRolesUpdate {
if v != nil {
_u.SetRole(*v)
func (aru *AuthRolesUpdate) SetNillableRole(a *authroles.Role) *AuthRolesUpdate {
if a != nil {
aru.SetRole(*a)
}
return _u
return aru
}
// SetTokenID sets the "token" edge to the AuthTokens entity by ID.
func (_u *AuthRolesUpdate) SetTokenID(id uuid.UUID) *AuthRolesUpdate {
_u.mutation.SetTokenID(id)
return _u
func (aru *AuthRolesUpdate) SetTokenID(id uuid.UUID) *AuthRolesUpdate {
aru.mutation.SetTokenID(id)
return aru
}
// SetNillableTokenID sets the "token" edge to the AuthTokens entity by ID if the given value is not nil.
func (_u *AuthRolesUpdate) SetNillableTokenID(id *uuid.UUID) *AuthRolesUpdate {
func (aru *AuthRolesUpdate) SetNillableTokenID(id *uuid.UUID) *AuthRolesUpdate {
if id != nil {
_u = _u.SetTokenID(*id)
aru = aru.SetTokenID(*id)
}
return _u
return aru
}
// SetToken sets the "token" edge to the AuthTokens entity.
func (_u *AuthRolesUpdate) SetToken(v *AuthTokens) *AuthRolesUpdate {
return _u.SetTokenID(v.ID)
func (aru *AuthRolesUpdate) SetToken(a *AuthTokens) *AuthRolesUpdate {
return aru.SetTokenID(a.ID)
}
// Mutation returns the AuthRolesMutation object of the builder.
func (_u *AuthRolesUpdate) Mutation() *AuthRolesMutation {
return _u.mutation
func (aru *AuthRolesUpdate) Mutation() *AuthRolesMutation {
return aru.mutation
}
// ClearToken clears the "token" edge to the AuthTokens entity.
func (_u *AuthRolesUpdate) ClearToken() *AuthRolesUpdate {
_u.mutation.ClearToken()
return _u
func (aru *AuthRolesUpdate) ClearToken() *AuthRolesUpdate {
aru.mutation.ClearToken()
return aru
}
// Save executes the query and returns the number of nodes affected by the update operation.
func (_u *AuthRolesUpdate) Save(ctx context.Context) (int, error) {
return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)
func (aru *AuthRolesUpdate) Save(ctx context.Context) (int, error) {
return withHooks(ctx, aru.sqlSave, aru.mutation, aru.hooks)
}
// SaveX is like Save, but panics if an error occurs.
func (_u *AuthRolesUpdate) SaveX(ctx context.Context) int {
affected, err := _u.Save(ctx)
func (aru *AuthRolesUpdate) SaveX(ctx context.Context) int {
affected, err := aru.Save(ctx)
if err != nil {
panic(err)
}
@@ -88,21 +88,21 @@ func (_u *AuthRolesUpdate) SaveX(ctx context.Context) int {
}
// Exec executes the query.
func (_u *AuthRolesUpdate) Exec(ctx context.Context) error {
_, err := _u.Save(ctx)
func (aru *AuthRolesUpdate) Exec(ctx context.Context) error {
_, err := aru.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (_u *AuthRolesUpdate) ExecX(ctx context.Context) {
if err := _u.Exec(ctx); err != nil {
func (aru *AuthRolesUpdate) ExecX(ctx context.Context) {
if err := aru.Exec(ctx); err != nil {
panic(err)
}
}
// check runs all checks and user-defined validators on the builder.
func (_u *AuthRolesUpdate) check() error {
if v, ok := _u.mutation.Role(); ok {
func (aru *AuthRolesUpdate) check() error {
if v, ok := aru.mutation.Role(); ok {
if err := authroles.RoleValidator(v); err != nil {
return &ValidationError{Name: "role", err: fmt.Errorf(`ent: validator failed for field "AuthRoles.role": %w`, err)}
}
@@ -110,22 +110,22 @@ func (_u *AuthRolesUpdate) check() error {
return nil
}
func (_u *AuthRolesUpdate) sqlSave(ctx context.Context) (_node int, err error) {
if err := _u.check(); err != nil {
return _node, err
func (aru *AuthRolesUpdate) sqlSave(ctx context.Context) (n int, err error) {
if err := aru.check(); err != nil {
return n, err
}
_spec := sqlgraph.NewUpdateSpec(authroles.Table, authroles.Columns, sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt))
if ps := _u.mutation.predicates; len(ps) > 0 {
if ps := aru.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if value, ok := _u.mutation.Role(); ok {
if value, ok := aru.mutation.Role(); ok {
_spec.SetField(authroles.FieldRole, field.TypeEnum, value)
}
if _u.mutation.TokenCleared() {
if aru.mutation.TokenCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2O,
Inverse: true,
@@ -138,7 +138,7 @@ func (_u *AuthRolesUpdate) sqlSave(ctx context.Context) (_node int, err error) {
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := _u.mutation.TokenIDs(); len(nodes) > 0 {
if nodes := aru.mutation.TokenIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2O,
Inverse: true,
@@ -154,7 +154,7 @@ func (_u *AuthRolesUpdate) sqlSave(ctx context.Context) (_node int, err error) {
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil {
if n, err = sqlgraph.UpdateNodes(ctx, aru.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{authroles.Label}
} else if sqlgraph.IsConstraintError(err) {
@@ -162,8 +162,8 @@ func (_u *AuthRolesUpdate) sqlSave(ctx context.Context) (_node int, err error) {
}
return 0, err
}
_u.mutation.done = true
return _node, nil
aru.mutation.done = true
return n, nil
}
// AuthRolesUpdateOne is the builder for updating a single AuthRoles entity.
@@ -175,70 +175,70 @@ type AuthRolesUpdateOne struct {
}
// SetRole sets the "role" field.
func (_u *AuthRolesUpdateOne) SetRole(v authroles.Role) *AuthRolesUpdateOne {
_u.mutation.SetRole(v)
return _u
func (aruo *AuthRolesUpdateOne) SetRole(a authroles.Role) *AuthRolesUpdateOne {
aruo.mutation.SetRole(a)
return aruo
}
// SetNillableRole sets the "role" field if the given value is not nil.
func (_u *AuthRolesUpdateOne) SetNillableRole(v *authroles.Role) *AuthRolesUpdateOne {
if v != nil {
_u.SetRole(*v)
func (aruo *AuthRolesUpdateOne) SetNillableRole(a *authroles.Role) *AuthRolesUpdateOne {
if a != nil {
aruo.SetRole(*a)
}
return _u
return aruo
}
// SetTokenID sets the "token" edge to the AuthTokens entity by ID.
func (_u *AuthRolesUpdateOne) SetTokenID(id uuid.UUID) *AuthRolesUpdateOne {
_u.mutation.SetTokenID(id)
return _u
func (aruo *AuthRolesUpdateOne) SetTokenID(id uuid.UUID) *AuthRolesUpdateOne {
aruo.mutation.SetTokenID(id)
return aruo
}
// SetNillableTokenID sets the "token" edge to the AuthTokens entity by ID if the given value is not nil.
func (_u *AuthRolesUpdateOne) SetNillableTokenID(id *uuid.UUID) *AuthRolesUpdateOne {
func (aruo *AuthRolesUpdateOne) SetNillableTokenID(id *uuid.UUID) *AuthRolesUpdateOne {
if id != nil {
_u = _u.SetTokenID(*id)
aruo = aruo.SetTokenID(*id)
}
return _u
return aruo
}
// SetToken sets the "token" edge to the AuthTokens entity.
func (_u *AuthRolesUpdateOne) SetToken(v *AuthTokens) *AuthRolesUpdateOne {
return _u.SetTokenID(v.ID)
func (aruo *AuthRolesUpdateOne) SetToken(a *AuthTokens) *AuthRolesUpdateOne {
return aruo.SetTokenID(a.ID)
}
// Mutation returns the AuthRolesMutation object of the builder.
func (_u *AuthRolesUpdateOne) Mutation() *AuthRolesMutation {
return _u.mutation
func (aruo *AuthRolesUpdateOne) Mutation() *AuthRolesMutation {
return aruo.mutation
}
// ClearToken clears the "token" edge to the AuthTokens entity.
func (_u *AuthRolesUpdateOne) ClearToken() *AuthRolesUpdateOne {
_u.mutation.ClearToken()
return _u
func (aruo *AuthRolesUpdateOne) ClearToken() *AuthRolesUpdateOne {
aruo.mutation.ClearToken()
return aruo
}
// Where appends a list predicates to the AuthRolesUpdate builder.
func (_u *AuthRolesUpdateOne) Where(ps ...predicate.AuthRoles) *AuthRolesUpdateOne {
_u.mutation.Where(ps...)
return _u
func (aruo *AuthRolesUpdateOne) Where(ps ...predicate.AuthRoles) *AuthRolesUpdateOne {
aruo.mutation.Where(ps...)
return aruo
}
// Select allows selecting one or more fields (columns) of the returned entity.
// The default is selecting all fields defined in the entity schema.
func (_u *AuthRolesUpdateOne) Select(field string, fields ...string) *AuthRolesUpdateOne {
_u.fields = append([]string{field}, fields...)
return _u
func (aruo *AuthRolesUpdateOne) Select(field string, fields ...string) *AuthRolesUpdateOne {
aruo.fields = append([]string{field}, fields...)
return aruo
}
// Save executes the query and returns the updated AuthRoles entity.
func (_u *AuthRolesUpdateOne) Save(ctx context.Context) (*AuthRoles, error) {
return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)
func (aruo *AuthRolesUpdateOne) Save(ctx context.Context) (*AuthRoles, error) {
return withHooks(ctx, aruo.sqlSave, aruo.mutation, aruo.hooks)
}
// SaveX is like Save, but panics if an error occurs.
func (_u *AuthRolesUpdateOne) SaveX(ctx context.Context) *AuthRoles {
node, err := _u.Save(ctx)
func (aruo *AuthRolesUpdateOne) SaveX(ctx context.Context) *AuthRoles {
node, err := aruo.Save(ctx)
if err != nil {
panic(err)
}
@@ -246,21 +246,21 @@ func (_u *AuthRolesUpdateOne) SaveX(ctx context.Context) *AuthRoles {
}
// Exec executes the query on the entity.
func (_u *AuthRolesUpdateOne) Exec(ctx context.Context) error {
_, err := _u.Save(ctx)
func (aruo *AuthRolesUpdateOne) Exec(ctx context.Context) error {
_, err := aruo.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (_u *AuthRolesUpdateOne) ExecX(ctx context.Context) {
if err := _u.Exec(ctx); err != nil {
func (aruo *AuthRolesUpdateOne) ExecX(ctx context.Context) {
if err := aruo.Exec(ctx); err != nil {
panic(err)
}
}
// check runs all checks and user-defined validators on the builder.
func (_u *AuthRolesUpdateOne) check() error {
if v, ok := _u.mutation.Role(); ok {
func (aruo *AuthRolesUpdateOne) check() error {
if v, ok := aruo.mutation.Role(); ok {
if err := authroles.RoleValidator(v); err != nil {
return &ValidationError{Name: "role", err: fmt.Errorf(`ent: validator failed for field "AuthRoles.role": %w`, err)}
}
@@ -268,17 +268,17 @@ func (_u *AuthRolesUpdateOne) check() error {
return nil
}
func (_u *AuthRolesUpdateOne) sqlSave(ctx context.Context) (_node *AuthRoles, err error) {
if err := _u.check(); err != nil {
func (aruo *AuthRolesUpdateOne) sqlSave(ctx context.Context) (_node *AuthRoles, err error) {
if err := aruo.check(); err != nil {
return _node, err
}
_spec := sqlgraph.NewUpdateSpec(authroles.Table, authroles.Columns, sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt))
id, ok := _u.mutation.ID()
id, ok := aruo.mutation.ID()
if !ok {
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "AuthRoles.id" for update`)}
}
_spec.Node.ID.Value = id
if fields := _u.fields; len(fields) > 0 {
if fields := aruo.fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, authroles.FieldID)
for _, f := range fields {
@@ -290,17 +290,17 @@ func (_u *AuthRolesUpdateOne) sqlSave(ctx context.Context) (_node *AuthRoles, er
}
}
}
if ps := _u.mutation.predicates; len(ps) > 0 {
if ps := aruo.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if value, ok := _u.mutation.Role(); ok {
if value, ok := aruo.mutation.Role(); ok {
_spec.SetField(authroles.FieldRole, field.TypeEnum, value)
}
if _u.mutation.TokenCleared() {
if aruo.mutation.TokenCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2O,
Inverse: true,
@@ -313,7 +313,7 @@ func (_u *AuthRolesUpdateOne) sqlSave(ctx context.Context) (_node *AuthRoles, er
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := _u.mutation.TokenIDs(); len(nodes) > 0 {
if nodes := aruo.mutation.TokenIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2O,
Inverse: true,
@@ -329,10 +329,10 @@ func (_u *AuthRolesUpdateOne) sqlSave(ctx context.Context) (_node *AuthRoles, er
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
_node = &AuthRoles{config: _u.config}
_node = &AuthRoles{config: aruo.config}
_spec.Assign = _node.assignValues
_spec.ScanValues = _node.scanValues
if err = sqlgraph.UpdateNode(ctx, _u.driver, _spec); err != nil {
if err = sqlgraph.UpdateNode(ctx, aruo.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{authroles.Label}
} else if sqlgraph.IsConstraintError(err) {
@@ -340,6 +340,6 @@ func (_u *AuthRolesUpdateOne) sqlSave(ctx context.Context) (_node *AuthRoles, er
}
return nil, err
}
_u.mutation.done = true
aruo.mutation.done = true
return _node, nil
}

View File

@@ -90,7 +90,7 @@ func (*AuthTokens) scanValues(columns []string) ([]any, error) {
// assignValues assigns the values that were returned from sql.Rows (after scanning)
// to the AuthTokens fields.
func (_m *AuthTokens) assignValues(columns []string, values []any) error {
func (at *AuthTokens) assignValues(columns []string, values []any) error {
if m, n := len(values), len(columns); m < n {
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
}
@@ -100,41 +100,41 @@ func (_m *AuthTokens) assignValues(columns []string, values []any) error {
if value, ok := values[i].(*uuid.UUID); !ok {
return fmt.Errorf("unexpected type %T for field id", values[i])
} else if value != nil {
_m.ID = *value
at.ID = *value
}
case authtokens.FieldCreatedAt:
if value, ok := values[i].(*sql.NullTime); !ok {
return fmt.Errorf("unexpected type %T for field created_at", values[i])
} else if value.Valid {
_m.CreatedAt = value.Time
at.CreatedAt = value.Time
}
case authtokens.FieldUpdatedAt:
if value, ok := values[i].(*sql.NullTime); !ok {
return fmt.Errorf("unexpected type %T for field updated_at", values[i])
} else if value.Valid {
_m.UpdatedAt = value.Time
at.UpdatedAt = value.Time
}
case authtokens.FieldToken:
if value, ok := values[i].(*[]byte); !ok {
return fmt.Errorf("unexpected type %T for field token", values[i])
} else if value != nil {
_m.Token = *value
at.Token = *value
}
case authtokens.FieldExpiresAt:
if value, ok := values[i].(*sql.NullTime); !ok {
return fmt.Errorf("unexpected type %T for field expires_at", values[i])
} else if value.Valid {
_m.ExpiresAt = value.Time
at.ExpiresAt = value.Time
}
case authtokens.ForeignKeys[0]:
if value, ok := values[i].(*sql.NullScanner); !ok {
return fmt.Errorf("unexpected type %T for field user_auth_tokens", values[i])
} else if value.Valid {
_m.user_auth_tokens = new(uuid.UUID)
*_m.user_auth_tokens = *value.S.(*uuid.UUID)
at.user_auth_tokens = new(uuid.UUID)
*at.user_auth_tokens = *value.S.(*uuid.UUID)
}
default:
_m.selectValues.Set(columns[i], values[i])
at.selectValues.Set(columns[i], values[i])
}
}
return nil
@@ -142,54 +142,54 @@ func (_m *AuthTokens) assignValues(columns []string, values []any) error {
// Value returns the ent.Value that was dynamically selected and assigned to the AuthTokens.
// This includes values selected through modifiers, order, etc.
func (_m *AuthTokens) Value(name string) (ent.Value, error) {
return _m.selectValues.Get(name)
func (at *AuthTokens) Value(name string) (ent.Value, error) {
return at.selectValues.Get(name)
}
// QueryUser queries the "user" edge of the AuthTokens entity.
func (_m *AuthTokens) QueryUser() *UserQuery {
return NewAuthTokensClient(_m.config).QueryUser(_m)
func (at *AuthTokens) QueryUser() *UserQuery {
return NewAuthTokensClient(at.config).QueryUser(at)
}
// QueryRoles queries the "roles" edge of the AuthTokens entity.
func (_m *AuthTokens) QueryRoles() *AuthRolesQuery {
return NewAuthTokensClient(_m.config).QueryRoles(_m)
func (at *AuthTokens) QueryRoles() *AuthRolesQuery {
return NewAuthTokensClient(at.config).QueryRoles(at)
}
// Update returns a builder for updating this AuthTokens.
// Note that you need to call AuthTokens.Unwrap() before calling this method if this AuthTokens
// was returned from a transaction, and the transaction was committed or rolled back.
func (_m *AuthTokens) Update() *AuthTokensUpdateOne {
return NewAuthTokensClient(_m.config).UpdateOne(_m)
func (at *AuthTokens) Update() *AuthTokensUpdateOne {
return NewAuthTokensClient(at.config).UpdateOne(at)
}
// Unwrap unwraps the AuthTokens entity that was returned from a transaction after it was closed,
// so that all future queries will be executed through the driver which created the transaction.
func (_m *AuthTokens) Unwrap() *AuthTokens {
_tx, ok := _m.config.driver.(*txDriver)
func (at *AuthTokens) Unwrap() *AuthTokens {
_tx, ok := at.config.driver.(*txDriver)
if !ok {
panic("ent: AuthTokens is not a transactional entity")
}
_m.config.driver = _tx.drv
return _m
at.config.driver = _tx.drv
return at
}
// String implements the fmt.Stringer.
func (_m *AuthTokens) String() string {
func (at *AuthTokens) String() string {
var builder strings.Builder
builder.WriteString("AuthTokens(")
builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID))
builder.WriteString(fmt.Sprintf("id=%v, ", at.ID))
builder.WriteString("created_at=")
builder.WriteString(_m.CreatedAt.Format(time.ANSIC))
builder.WriteString(at.CreatedAt.Format(time.ANSIC))
builder.WriteString(", ")
builder.WriteString("updated_at=")
builder.WriteString(_m.UpdatedAt.Format(time.ANSIC))
builder.WriteString(at.UpdatedAt.Format(time.ANSIC))
builder.WriteString(", ")
builder.WriteString("token=")
builder.WriteString(fmt.Sprintf("%v", _m.Token))
builder.WriteString(fmt.Sprintf("%v", at.Token))
builder.WriteString(", ")
builder.WriteString("expires_at=")
builder.WriteString(_m.ExpiresAt.Format(time.ANSIC))
builder.WriteString(at.ExpiresAt.Format(time.ANSIC))
builder.WriteByte(')')
return builder.String()
}

View File

@@ -24,119 +24,119 @@ type AuthTokensCreate struct {
}
// SetCreatedAt sets the "created_at" field.
func (_c *AuthTokensCreate) SetCreatedAt(v time.Time) *AuthTokensCreate {
_c.mutation.SetCreatedAt(v)
return _c
func (atc *AuthTokensCreate) SetCreatedAt(t time.Time) *AuthTokensCreate {
atc.mutation.SetCreatedAt(t)
return atc
}
// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
func (_c *AuthTokensCreate) SetNillableCreatedAt(v *time.Time) *AuthTokensCreate {
if v != nil {
_c.SetCreatedAt(*v)
func (atc *AuthTokensCreate) SetNillableCreatedAt(t *time.Time) *AuthTokensCreate {
if t != nil {
atc.SetCreatedAt(*t)
}
return _c
return atc
}
// SetUpdatedAt sets the "updated_at" field.
func (_c *AuthTokensCreate) SetUpdatedAt(v time.Time) *AuthTokensCreate {
_c.mutation.SetUpdatedAt(v)
return _c
func (atc *AuthTokensCreate) SetUpdatedAt(t time.Time) *AuthTokensCreate {
atc.mutation.SetUpdatedAt(t)
return atc
}
// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil.
func (_c *AuthTokensCreate) SetNillableUpdatedAt(v *time.Time) *AuthTokensCreate {
if v != nil {
_c.SetUpdatedAt(*v)
func (atc *AuthTokensCreate) SetNillableUpdatedAt(t *time.Time) *AuthTokensCreate {
if t != nil {
atc.SetUpdatedAt(*t)
}
return _c
return atc
}
// SetToken sets the "token" field.
func (_c *AuthTokensCreate) SetToken(v []byte) *AuthTokensCreate {
_c.mutation.SetToken(v)
return _c
func (atc *AuthTokensCreate) SetToken(b []byte) *AuthTokensCreate {
atc.mutation.SetToken(b)
return atc
}
// SetExpiresAt sets the "expires_at" field.
func (_c *AuthTokensCreate) SetExpiresAt(v time.Time) *AuthTokensCreate {
_c.mutation.SetExpiresAt(v)
return _c
func (atc *AuthTokensCreate) SetExpiresAt(t time.Time) *AuthTokensCreate {
atc.mutation.SetExpiresAt(t)
return atc
}
// SetNillableExpiresAt sets the "expires_at" field if the given value is not nil.
func (_c *AuthTokensCreate) SetNillableExpiresAt(v *time.Time) *AuthTokensCreate {
if v != nil {
_c.SetExpiresAt(*v)
func (atc *AuthTokensCreate) SetNillableExpiresAt(t *time.Time) *AuthTokensCreate {
if t != nil {
atc.SetExpiresAt(*t)
}
return _c
return atc
}
// SetID sets the "id" field.
func (_c *AuthTokensCreate) SetID(v uuid.UUID) *AuthTokensCreate {
_c.mutation.SetID(v)
return _c
func (atc *AuthTokensCreate) SetID(u uuid.UUID) *AuthTokensCreate {
atc.mutation.SetID(u)
return atc
}
// SetNillableID sets the "id" field if the given value is not nil.
func (_c *AuthTokensCreate) SetNillableID(v *uuid.UUID) *AuthTokensCreate {
if v != nil {
_c.SetID(*v)
func (atc *AuthTokensCreate) SetNillableID(u *uuid.UUID) *AuthTokensCreate {
if u != nil {
atc.SetID(*u)
}
return _c
return atc
}
// SetUserID sets the "user" edge to the User entity by ID.
func (_c *AuthTokensCreate) SetUserID(id uuid.UUID) *AuthTokensCreate {
_c.mutation.SetUserID(id)
return _c
func (atc *AuthTokensCreate) SetUserID(id uuid.UUID) *AuthTokensCreate {
atc.mutation.SetUserID(id)
return atc
}
// SetNillableUserID sets the "user" edge to the User entity by ID if the given value is not nil.
func (_c *AuthTokensCreate) SetNillableUserID(id *uuid.UUID) *AuthTokensCreate {
func (atc *AuthTokensCreate) SetNillableUserID(id *uuid.UUID) *AuthTokensCreate {
if id != nil {
_c = _c.SetUserID(*id)
atc = atc.SetUserID(*id)
}
return _c
return atc
}
// SetUser sets the "user" edge to the User entity.
func (_c *AuthTokensCreate) SetUser(v *User) *AuthTokensCreate {
return _c.SetUserID(v.ID)
func (atc *AuthTokensCreate) SetUser(u *User) *AuthTokensCreate {
return atc.SetUserID(u.ID)
}
// SetRolesID sets the "roles" edge to the AuthRoles entity by ID.
func (_c *AuthTokensCreate) SetRolesID(id int) *AuthTokensCreate {
_c.mutation.SetRolesID(id)
return _c
func (atc *AuthTokensCreate) SetRolesID(id int) *AuthTokensCreate {
atc.mutation.SetRolesID(id)
return atc
}
// SetNillableRolesID sets the "roles" edge to the AuthRoles entity by ID if the given value is not nil.
func (_c *AuthTokensCreate) SetNillableRolesID(id *int) *AuthTokensCreate {
func (atc *AuthTokensCreate) SetNillableRolesID(id *int) *AuthTokensCreate {
if id != nil {
_c = _c.SetRolesID(*id)
atc = atc.SetRolesID(*id)
}
return _c
return atc
}
// SetRoles sets the "roles" edge to the AuthRoles entity.
func (_c *AuthTokensCreate) SetRoles(v *AuthRoles) *AuthTokensCreate {
return _c.SetRolesID(v.ID)
func (atc *AuthTokensCreate) SetRoles(a *AuthRoles) *AuthTokensCreate {
return atc.SetRolesID(a.ID)
}
// Mutation returns the AuthTokensMutation object of the builder.
func (_c *AuthTokensCreate) Mutation() *AuthTokensMutation {
return _c.mutation
func (atc *AuthTokensCreate) Mutation() *AuthTokensMutation {
return atc.mutation
}
// Save creates the AuthTokens in the database.
func (_c *AuthTokensCreate) Save(ctx context.Context) (*AuthTokens, error) {
_c.defaults()
return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks)
func (atc *AuthTokensCreate) Save(ctx context.Context) (*AuthTokens, error) {
atc.defaults()
return withHooks(ctx, atc.sqlSave, atc.mutation, atc.hooks)
}
// SaveX calls Save and panics if Save returns an error.
func (_c *AuthTokensCreate) SaveX(ctx context.Context) *AuthTokens {
v, err := _c.Save(ctx)
func (atc *AuthTokensCreate) SaveX(ctx context.Context) *AuthTokens {
v, err := atc.Save(ctx)
if err != nil {
panic(err)
}
@@ -144,61 +144,61 @@ func (_c *AuthTokensCreate) SaveX(ctx context.Context) *AuthTokens {
}
// Exec executes the query.
func (_c *AuthTokensCreate) Exec(ctx context.Context) error {
_, err := _c.Save(ctx)
func (atc *AuthTokensCreate) Exec(ctx context.Context) error {
_, err := atc.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (_c *AuthTokensCreate) ExecX(ctx context.Context) {
if err := _c.Exec(ctx); err != nil {
func (atc *AuthTokensCreate) ExecX(ctx context.Context) {
if err := atc.Exec(ctx); err != nil {
panic(err)
}
}
// defaults sets the default values of the builder before save.
func (_c *AuthTokensCreate) defaults() {
if _, ok := _c.mutation.CreatedAt(); !ok {
func (atc *AuthTokensCreate) defaults() {
if _, ok := atc.mutation.CreatedAt(); !ok {
v := authtokens.DefaultCreatedAt()
_c.mutation.SetCreatedAt(v)
atc.mutation.SetCreatedAt(v)
}
if _, ok := _c.mutation.UpdatedAt(); !ok {
if _, ok := atc.mutation.UpdatedAt(); !ok {
v := authtokens.DefaultUpdatedAt()
_c.mutation.SetUpdatedAt(v)
atc.mutation.SetUpdatedAt(v)
}
if _, ok := _c.mutation.ExpiresAt(); !ok {
if _, ok := atc.mutation.ExpiresAt(); !ok {
v := authtokens.DefaultExpiresAt()
_c.mutation.SetExpiresAt(v)
atc.mutation.SetExpiresAt(v)
}
if _, ok := _c.mutation.ID(); !ok {
if _, ok := atc.mutation.ID(); !ok {
v := authtokens.DefaultID()
_c.mutation.SetID(v)
atc.mutation.SetID(v)
}
}
// check runs all checks and user-defined validators on the builder.
func (_c *AuthTokensCreate) check() error {
if _, ok := _c.mutation.CreatedAt(); !ok {
func (atc *AuthTokensCreate) check() error {
if _, ok := atc.mutation.CreatedAt(); !ok {
return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "AuthTokens.created_at"`)}
}
if _, ok := _c.mutation.UpdatedAt(); !ok {
if _, ok := atc.mutation.UpdatedAt(); !ok {
return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "AuthTokens.updated_at"`)}
}
if _, ok := _c.mutation.Token(); !ok {
if _, ok := atc.mutation.Token(); !ok {
return &ValidationError{Name: "token", err: errors.New(`ent: missing required field "AuthTokens.token"`)}
}
if _, ok := _c.mutation.ExpiresAt(); !ok {
if _, ok := atc.mutation.ExpiresAt(); !ok {
return &ValidationError{Name: "expires_at", err: errors.New(`ent: missing required field "AuthTokens.expires_at"`)}
}
return nil
}
func (_c *AuthTokensCreate) sqlSave(ctx context.Context) (*AuthTokens, error) {
if err := _c.check(); err != nil {
func (atc *AuthTokensCreate) sqlSave(ctx context.Context) (*AuthTokens, error) {
if err := atc.check(); err != nil {
return nil, err
}
_node, _spec := _c.createSpec()
if err := sqlgraph.CreateNode(ctx, _c.driver, _spec); err != nil {
_node, _spec := atc.createSpec()
if err := sqlgraph.CreateNode(ctx, atc.driver, _spec); err != nil {
if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
@@ -211,37 +211,37 @@ func (_c *AuthTokensCreate) sqlSave(ctx context.Context) (*AuthTokens, error) {
return nil, err
}
}
_c.mutation.id = &_node.ID
_c.mutation.done = true
atc.mutation.id = &_node.ID
atc.mutation.done = true
return _node, nil
}
func (_c *AuthTokensCreate) createSpec() (*AuthTokens, *sqlgraph.CreateSpec) {
func (atc *AuthTokensCreate) createSpec() (*AuthTokens, *sqlgraph.CreateSpec) {
var (
_node = &AuthTokens{config: _c.config}
_node = &AuthTokens{config: atc.config}
_spec = sqlgraph.NewCreateSpec(authtokens.Table, sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID))
)
if id, ok := _c.mutation.ID(); ok {
if id, ok := atc.mutation.ID(); ok {
_node.ID = id
_spec.ID.Value = &id
}
if value, ok := _c.mutation.CreatedAt(); ok {
if value, ok := atc.mutation.CreatedAt(); ok {
_spec.SetField(authtokens.FieldCreatedAt, field.TypeTime, value)
_node.CreatedAt = value
}
if value, ok := _c.mutation.UpdatedAt(); ok {
if value, ok := atc.mutation.UpdatedAt(); ok {
_spec.SetField(authtokens.FieldUpdatedAt, field.TypeTime, value)
_node.UpdatedAt = value
}
if value, ok := _c.mutation.Token(); ok {
if value, ok := atc.mutation.Token(); ok {
_spec.SetField(authtokens.FieldToken, field.TypeBytes, value)
_node.Token = value
}
if value, ok := _c.mutation.ExpiresAt(); ok {
if value, ok := atc.mutation.ExpiresAt(); ok {
_spec.SetField(authtokens.FieldExpiresAt, field.TypeTime, value)
_node.ExpiresAt = value
}
if nodes := _c.mutation.UserIDs(); len(nodes) > 0 {
if nodes := atc.mutation.UserIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
@@ -258,7 +258,7 @@ func (_c *AuthTokensCreate) createSpec() (*AuthTokens, *sqlgraph.CreateSpec) {
_node.user_auth_tokens = &nodes[0]
_spec.Edges = append(_spec.Edges, edge)
}
if nodes := _c.mutation.RolesIDs(); len(nodes) > 0 {
if nodes := atc.mutation.RolesIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2O,
Inverse: false,
@@ -285,16 +285,16 @@ type AuthTokensCreateBulk struct {
}
// Save creates the AuthTokens entities in the database.
func (_c *AuthTokensCreateBulk) Save(ctx context.Context) ([]*AuthTokens, error) {
if _c.err != nil {
return nil, _c.err
func (atcb *AuthTokensCreateBulk) Save(ctx context.Context) ([]*AuthTokens, error) {
if atcb.err != nil {
return nil, atcb.err
}
specs := make([]*sqlgraph.CreateSpec, len(_c.builders))
nodes := make([]*AuthTokens, len(_c.builders))
mutators := make([]Mutator, len(_c.builders))
for i := range _c.builders {
specs := make([]*sqlgraph.CreateSpec, len(atcb.builders))
nodes := make([]*AuthTokens, len(atcb.builders))
mutators := make([]Mutator, len(atcb.builders))
for i := range atcb.builders {
func(i int, root context.Context) {
builder := _c.builders[i]
builder := atcb.builders[i]
builder.defaults()
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
mutation, ok := m.(*AuthTokensMutation)
@@ -308,11 +308,11 @@ func (_c *AuthTokensCreateBulk) Save(ctx context.Context) ([]*AuthTokens, error)
var err error
nodes[i], specs[i] = builder.createSpec()
if i < len(mutators)-1 {
_, err = mutators[i+1].Mutate(root, _c.builders[i+1].mutation)
_, err = mutators[i+1].Mutate(root, atcb.builders[i+1].mutation)
} else {
spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
// Invoke the actual operation on the latest mutation in the chain.
if err = sqlgraph.BatchCreate(ctx, _c.driver, spec); err != nil {
if err = sqlgraph.BatchCreate(ctx, atcb.driver, spec); err != nil {
if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
@@ -332,7 +332,7 @@ func (_c *AuthTokensCreateBulk) Save(ctx context.Context) ([]*AuthTokens, error)
}(i, ctx)
}
if len(mutators) > 0 {
if _, err := mutators[0].Mutate(ctx, _c.builders[0].mutation); err != nil {
if _, err := mutators[0].Mutate(ctx, atcb.builders[0].mutation); err != nil {
return nil, err
}
}
@@ -340,8 +340,8 @@ func (_c *AuthTokensCreateBulk) Save(ctx context.Context) ([]*AuthTokens, error)
}
// SaveX is like Save, but panics if an error occurs.
func (_c *AuthTokensCreateBulk) SaveX(ctx context.Context) []*AuthTokens {
v, err := _c.Save(ctx)
func (atcb *AuthTokensCreateBulk) SaveX(ctx context.Context) []*AuthTokens {
v, err := atcb.Save(ctx)
if err != nil {
panic(err)
}
@@ -349,14 +349,14 @@ func (_c *AuthTokensCreateBulk) SaveX(ctx context.Context) []*AuthTokens {
}
// Exec executes the query.
func (_c *AuthTokensCreateBulk) Exec(ctx context.Context) error {
_, err := _c.Save(ctx)
func (atcb *AuthTokensCreateBulk) Exec(ctx context.Context) error {
_, err := atcb.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (_c *AuthTokensCreateBulk) ExecX(ctx context.Context) {
if err := _c.Exec(ctx); err != nil {
func (atcb *AuthTokensCreateBulk) ExecX(ctx context.Context) {
if err := atcb.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -20,56 +20,56 @@ type AuthTokensDelete struct {
}
// Where appends a list predicates to the AuthTokensDelete builder.
func (_d *AuthTokensDelete) Where(ps ...predicate.AuthTokens) *AuthTokensDelete {
_d.mutation.Where(ps...)
return _d
func (atd *AuthTokensDelete) Where(ps ...predicate.AuthTokens) *AuthTokensDelete {
atd.mutation.Where(ps...)
return atd
}
// Exec executes the deletion query and returns how many vertices were deleted.
func (_d *AuthTokensDelete) Exec(ctx context.Context) (int, error) {
return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks)
func (atd *AuthTokensDelete) Exec(ctx context.Context) (int, error) {
return withHooks(ctx, atd.sqlExec, atd.mutation, atd.hooks)
}
// ExecX is like Exec, but panics if an error occurs.
func (_d *AuthTokensDelete) ExecX(ctx context.Context) int {
n, err := _d.Exec(ctx)
func (atd *AuthTokensDelete) ExecX(ctx context.Context) int {
n, err := atd.Exec(ctx)
if err != nil {
panic(err)
}
return n
}
func (_d *AuthTokensDelete) sqlExec(ctx context.Context) (int, error) {
func (atd *AuthTokensDelete) sqlExec(ctx context.Context) (int, error) {
_spec := sqlgraph.NewDeleteSpec(authtokens.Table, sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID))
if ps := _d.mutation.predicates; len(ps) > 0 {
if ps := atd.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
affected, err := sqlgraph.DeleteNodes(ctx, _d.driver, _spec)
affected, err := sqlgraph.DeleteNodes(ctx, atd.driver, _spec)
if err != nil && sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
_d.mutation.done = true
atd.mutation.done = true
return affected, err
}
// AuthTokensDeleteOne is the builder for deleting a single AuthTokens entity.
type AuthTokensDeleteOne struct {
_d *AuthTokensDelete
atd *AuthTokensDelete
}
// Where appends a list predicates to the AuthTokensDelete builder.
func (_d *AuthTokensDeleteOne) Where(ps ...predicate.AuthTokens) *AuthTokensDeleteOne {
_d._d.mutation.Where(ps...)
return _d
func (atdo *AuthTokensDeleteOne) Where(ps ...predicate.AuthTokens) *AuthTokensDeleteOne {
atdo.atd.mutation.Where(ps...)
return atdo
}
// Exec executes the deletion query.
func (_d *AuthTokensDeleteOne) Exec(ctx context.Context) error {
n, err := _d._d.Exec(ctx)
func (atdo *AuthTokensDeleteOne) Exec(ctx context.Context) error {
n, err := atdo.atd.Exec(ctx)
switch {
case err != nil:
return err
@@ -81,8 +81,8 @@ func (_d *AuthTokensDeleteOne) Exec(ctx context.Context) error {
}
// ExecX is like Exec, but panics if an error occurs.
func (_d *AuthTokensDeleteOne) ExecX(ctx context.Context) {
if err := _d.Exec(ctx); err != nil {
func (atdo *AuthTokensDeleteOne) ExecX(ctx context.Context) {
if err := atdo.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -35,44 +35,44 @@ type AuthTokensQuery struct {
}
// Where adds a new predicate for the AuthTokensQuery builder.
func (_q *AuthTokensQuery) Where(ps ...predicate.AuthTokens) *AuthTokensQuery {
_q.predicates = append(_q.predicates, ps...)
return _q
func (atq *AuthTokensQuery) Where(ps ...predicate.AuthTokens) *AuthTokensQuery {
atq.predicates = append(atq.predicates, ps...)
return atq
}
// Limit the number of records to be returned by this query.
func (_q *AuthTokensQuery) Limit(limit int) *AuthTokensQuery {
_q.ctx.Limit = &limit
return _q
func (atq *AuthTokensQuery) Limit(limit int) *AuthTokensQuery {
atq.ctx.Limit = &limit
return atq
}
// Offset to start from.
func (_q *AuthTokensQuery) Offset(offset int) *AuthTokensQuery {
_q.ctx.Offset = &offset
return _q
func (atq *AuthTokensQuery) Offset(offset int) *AuthTokensQuery {
atq.ctx.Offset = &offset
return atq
}
// Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method.
func (_q *AuthTokensQuery) Unique(unique bool) *AuthTokensQuery {
_q.ctx.Unique = &unique
return _q
func (atq *AuthTokensQuery) Unique(unique bool) *AuthTokensQuery {
atq.ctx.Unique = &unique
return atq
}
// Order specifies how the records should be ordered.
func (_q *AuthTokensQuery) Order(o ...authtokens.OrderOption) *AuthTokensQuery {
_q.order = append(_q.order, o...)
return _q
func (atq *AuthTokensQuery) Order(o ...authtokens.OrderOption) *AuthTokensQuery {
atq.order = append(atq.order, o...)
return atq
}
// QueryUser chains the current query on the "user" edge.
func (_q *AuthTokensQuery) QueryUser() *UserQuery {
query := (&UserClient{config: _q.config}).Query()
func (atq *AuthTokensQuery) QueryUser() *UserQuery {
query := (&UserClient{config: atq.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := _q.prepareQuery(ctx); err != nil {
if err := atq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := _q.sqlQuery(ctx)
selector := atq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
@@ -81,20 +81,20 @@ func (_q *AuthTokensQuery) QueryUser() *UserQuery {
sqlgraph.To(user.Table, user.FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, authtokens.UserTable, authtokens.UserColumn),
)
fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step)
fromU = sqlgraph.SetNeighbors(atq.driver.Dialect(), step)
return fromU, nil
}
return query
}
// QueryRoles chains the current query on the "roles" edge.
func (_q *AuthTokensQuery) QueryRoles() *AuthRolesQuery {
query := (&AuthRolesClient{config: _q.config}).Query()
func (atq *AuthTokensQuery) QueryRoles() *AuthRolesQuery {
query := (&AuthRolesClient{config: atq.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := _q.prepareQuery(ctx); err != nil {
if err := atq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := _q.sqlQuery(ctx)
selector := atq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
@@ -103,7 +103,7 @@ func (_q *AuthTokensQuery) QueryRoles() *AuthRolesQuery {
sqlgraph.To(authroles.Table, authroles.FieldID),
sqlgraph.Edge(sqlgraph.O2O, false, authtokens.RolesTable, authtokens.RolesColumn),
)
fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step)
fromU = sqlgraph.SetNeighbors(atq.driver.Dialect(), step)
return fromU, nil
}
return query
@@ -111,8 +111,8 @@ func (_q *AuthTokensQuery) QueryRoles() *AuthRolesQuery {
// First returns the first AuthTokens entity from the query.
// Returns a *NotFoundError when no AuthTokens was found.
func (_q *AuthTokensQuery) First(ctx context.Context) (*AuthTokens, error) {
nodes, err := _q.Limit(1).All(setContextOp(ctx, _q.ctx, ent.OpQueryFirst))
func (atq *AuthTokensQuery) First(ctx context.Context) (*AuthTokens, error) {
nodes, err := atq.Limit(1).All(setContextOp(ctx, atq.ctx, ent.OpQueryFirst))
if err != nil {
return nil, err
}
@@ -123,8 +123,8 @@ func (_q *AuthTokensQuery) First(ctx context.Context) (*AuthTokens, error) {
}
// FirstX is like First, but panics if an error occurs.
func (_q *AuthTokensQuery) FirstX(ctx context.Context) *AuthTokens {
node, err := _q.First(ctx)
func (atq *AuthTokensQuery) FirstX(ctx context.Context) *AuthTokens {
node, err := atq.First(ctx)
if err != nil && !IsNotFound(err) {
panic(err)
}
@@ -133,9 +133,9 @@ func (_q *AuthTokensQuery) FirstX(ctx context.Context) *AuthTokens {
// FirstID returns the first AuthTokens ID from the query.
// Returns a *NotFoundError when no AuthTokens ID was found.
func (_q *AuthTokensQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) {
func (atq *AuthTokensQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = _q.Limit(1).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryFirstID)); err != nil {
if ids, err = atq.Limit(1).IDs(setContextOp(ctx, atq.ctx, ent.OpQueryFirstID)); err != nil {
return
}
if len(ids) == 0 {
@@ -146,8 +146,8 @@ func (_q *AuthTokensQuery) FirstID(ctx context.Context) (id uuid.UUID, err error
}
// FirstIDX is like FirstID, but panics if an error occurs.
func (_q *AuthTokensQuery) FirstIDX(ctx context.Context) uuid.UUID {
id, err := _q.FirstID(ctx)
func (atq *AuthTokensQuery) FirstIDX(ctx context.Context) uuid.UUID {
id, err := atq.FirstID(ctx)
if err != nil && !IsNotFound(err) {
panic(err)
}
@@ -157,8 +157,8 @@ func (_q *AuthTokensQuery) FirstIDX(ctx context.Context) uuid.UUID {
// Only returns a single AuthTokens entity found by the query, ensuring it only returns one.
// Returns a *NotSingularError when more than one AuthTokens entity is found.
// Returns a *NotFoundError when no AuthTokens entities are found.
func (_q *AuthTokensQuery) Only(ctx context.Context) (*AuthTokens, error) {
nodes, err := _q.Limit(2).All(setContextOp(ctx, _q.ctx, ent.OpQueryOnly))
func (atq *AuthTokensQuery) Only(ctx context.Context) (*AuthTokens, error) {
nodes, err := atq.Limit(2).All(setContextOp(ctx, atq.ctx, ent.OpQueryOnly))
if err != nil {
return nil, err
}
@@ -173,8 +173,8 @@ func (_q *AuthTokensQuery) Only(ctx context.Context) (*AuthTokens, error) {
}
// OnlyX is like Only, but panics if an error occurs.
func (_q *AuthTokensQuery) OnlyX(ctx context.Context) *AuthTokens {
node, err := _q.Only(ctx)
func (atq *AuthTokensQuery) OnlyX(ctx context.Context) *AuthTokens {
node, err := atq.Only(ctx)
if err != nil {
panic(err)
}
@@ -184,9 +184,9 @@ func (_q *AuthTokensQuery) OnlyX(ctx context.Context) *AuthTokens {
// OnlyID is like Only, but returns the only AuthTokens ID in the query.
// Returns a *NotSingularError when more than one AuthTokens ID is found.
// Returns a *NotFoundError when no entities are found.
func (_q *AuthTokensQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) {
func (atq *AuthTokensQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = _q.Limit(2).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryOnlyID)); err != nil {
if ids, err = atq.Limit(2).IDs(setContextOp(ctx, atq.ctx, ent.OpQueryOnlyID)); err != nil {
return
}
switch len(ids) {
@@ -201,8 +201,8 @@ func (_q *AuthTokensQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error)
}
// OnlyIDX is like OnlyID, but panics if an error occurs.
func (_q *AuthTokensQuery) OnlyIDX(ctx context.Context) uuid.UUID {
id, err := _q.OnlyID(ctx)
func (atq *AuthTokensQuery) OnlyIDX(ctx context.Context) uuid.UUID {
id, err := atq.OnlyID(ctx)
if err != nil {
panic(err)
}
@@ -210,18 +210,18 @@ func (_q *AuthTokensQuery) OnlyIDX(ctx context.Context) uuid.UUID {
}
// All executes the query and returns a list of AuthTokensSlice.
func (_q *AuthTokensQuery) All(ctx context.Context) ([]*AuthTokens, error) {
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll)
if err := _q.prepareQuery(ctx); err != nil {
func (atq *AuthTokensQuery) All(ctx context.Context) ([]*AuthTokens, error) {
ctx = setContextOp(ctx, atq.ctx, ent.OpQueryAll)
if err := atq.prepareQuery(ctx); err != nil {
return nil, err
}
qr := querierAll[[]*AuthTokens, *AuthTokensQuery]()
return withInterceptors[[]*AuthTokens](ctx, _q, qr, _q.inters)
return withInterceptors[[]*AuthTokens](ctx, atq, qr, atq.inters)
}
// AllX is like All, but panics if an error occurs.
func (_q *AuthTokensQuery) AllX(ctx context.Context) []*AuthTokens {
nodes, err := _q.All(ctx)
func (atq *AuthTokensQuery) AllX(ctx context.Context) []*AuthTokens {
nodes, err := atq.All(ctx)
if err != nil {
panic(err)
}
@@ -229,20 +229,20 @@ func (_q *AuthTokensQuery) AllX(ctx context.Context) []*AuthTokens {
}
// IDs executes the query and returns a list of AuthTokens IDs.
func (_q *AuthTokensQuery) IDs(ctx context.Context) (ids []uuid.UUID, err error) {
if _q.ctx.Unique == nil && _q.path != nil {
_q.Unique(true)
func (atq *AuthTokensQuery) IDs(ctx context.Context) (ids []uuid.UUID, err error) {
if atq.ctx.Unique == nil && atq.path != nil {
atq.Unique(true)
}
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryIDs)
if err = _q.Select(authtokens.FieldID).Scan(ctx, &ids); err != nil {
ctx = setContextOp(ctx, atq.ctx, ent.OpQueryIDs)
if err = atq.Select(authtokens.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
return ids, nil
}
// IDsX is like IDs, but panics if an error occurs.
func (_q *AuthTokensQuery) IDsX(ctx context.Context) []uuid.UUID {
ids, err := _q.IDs(ctx)
func (atq *AuthTokensQuery) IDsX(ctx context.Context) []uuid.UUID {
ids, err := atq.IDs(ctx)
if err != nil {
panic(err)
}
@@ -250,17 +250,17 @@ func (_q *AuthTokensQuery) IDsX(ctx context.Context) []uuid.UUID {
}
// Count returns the count of the given query.
func (_q *AuthTokensQuery) Count(ctx context.Context) (int, error) {
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryCount)
if err := _q.prepareQuery(ctx); err != nil {
func (atq *AuthTokensQuery) Count(ctx context.Context) (int, error) {
ctx = setContextOp(ctx, atq.ctx, ent.OpQueryCount)
if err := atq.prepareQuery(ctx); err != nil {
return 0, err
}
return withInterceptors[int](ctx, _q, querierCount[*AuthTokensQuery](), _q.inters)
return withInterceptors[int](ctx, atq, querierCount[*AuthTokensQuery](), atq.inters)
}
// CountX is like Count, but panics if an error occurs.
func (_q *AuthTokensQuery) CountX(ctx context.Context) int {
count, err := _q.Count(ctx)
func (atq *AuthTokensQuery) CountX(ctx context.Context) int {
count, err := atq.Count(ctx)
if err != nil {
panic(err)
}
@@ -268,9 +268,9 @@ func (_q *AuthTokensQuery) CountX(ctx context.Context) int {
}
// Exist returns true if the query has elements in the graph.
func (_q *AuthTokensQuery) Exist(ctx context.Context) (bool, error) {
ctx = setContextOp(ctx, _q.ctx, ent.OpQueryExist)
switch _, err := _q.FirstID(ctx); {
func (atq *AuthTokensQuery) Exist(ctx context.Context) (bool, error) {
ctx = setContextOp(ctx, atq.ctx, ent.OpQueryExist)
switch _, err := atq.FirstID(ctx); {
case IsNotFound(err):
return false, nil
case err != nil:
@@ -281,8 +281,8 @@ func (_q *AuthTokensQuery) Exist(ctx context.Context) (bool, error) {
}
// ExistX is like Exist, but panics if an error occurs.
func (_q *AuthTokensQuery) ExistX(ctx context.Context) bool {
exist, err := _q.Exist(ctx)
func (atq *AuthTokensQuery) ExistX(ctx context.Context) bool {
exist, err := atq.Exist(ctx)
if err != nil {
panic(err)
}
@@ -291,44 +291,44 @@ func (_q *AuthTokensQuery) ExistX(ctx context.Context) bool {
// Clone returns a duplicate of the AuthTokensQuery builder, including all associated steps. It can be
// used to prepare common query builders and use them differently after the clone is made.
func (_q *AuthTokensQuery) Clone() *AuthTokensQuery {
if _q == nil {
func (atq *AuthTokensQuery) Clone() *AuthTokensQuery {
if atq == nil {
return nil
}
return &AuthTokensQuery{
config: _q.config,
ctx: _q.ctx.Clone(),
order: append([]authtokens.OrderOption{}, _q.order...),
inters: append([]Interceptor{}, _q.inters...),
predicates: append([]predicate.AuthTokens{}, _q.predicates...),
withUser: _q.withUser.Clone(),
withRoles: _q.withRoles.Clone(),
config: atq.config,
ctx: atq.ctx.Clone(),
order: append([]authtokens.OrderOption{}, atq.order...),
inters: append([]Interceptor{}, atq.inters...),
predicates: append([]predicate.AuthTokens{}, atq.predicates...),
withUser: atq.withUser.Clone(),
withRoles: atq.withRoles.Clone(),
// clone intermediate query.
sql: _q.sql.Clone(),
path: _q.path,
sql: atq.sql.Clone(),
path: atq.path,
}
}
// WithUser tells the query-builder to eager-load the nodes that are connected to
// the "user" edge. The optional arguments are used to configure the query builder of the edge.
func (_q *AuthTokensQuery) WithUser(opts ...func(*UserQuery)) *AuthTokensQuery {
query := (&UserClient{config: _q.config}).Query()
func (atq *AuthTokensQuery) WithUser(opts ...func(*UserQuery)) *AuthTokensQuery {
query := (&UserClient{config: atq.config}).Query()
for _, opt := range opts {
opt(query)
}
_q.withUser = query
return _q
atq.withUser = query
return atq
}
// WithRoles tells the query-builder to eager-load the nodes that are connected to
// the "roles" edge. The optional arguments are used to configure the query builder of the edge.
func (_q *AuthTokensQuery) WithRoles(opts ...func(*AuthRolesQuery)) *AuthTokensQuery {
query := (&AuthRolesClient{config: _q.config}).Query()
func (atq *AuthTokensQuery) WithRoles(opts ...func(*AuthRolesQuery)) *AuthTokensQuery {
query := (&AuthRolesClient{config: atq.config}).Query()
for _, opt := range opts {
opt(query)
}
_q.withRoles = query
return _q
atq.withRoles = query
return atq
}
// GroupBy is used to group vertices by one or more fields/columns.
@@ -345,10 +345,10 @@ func (_q *AuthTokensQuery) WithRoles(opts ...func(*AuthRolesQuery)) *AuthTokensQ
// GroupBy(authtokens.FieldCreatedAt).
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (_q *AuthTokensQuery) GroupBy(field string, fields ...string) *AuthTokensGroupBy {
_q.ctx.Fields = append([]string{field}, fields...)
grbuild := &AuthTokensGroupBy{build: _q}
grbuild.flds = &_q.ctx.Fields
func (atq *AuthTokensQuery) GroupBy(field string, fields ...string) *AuthTokensGroupBy {
atq.ctx.Fields = append([]string{field}, fields...)
grbuild := &AuthTokensGroupBy{build: atq}
grbuild.flds = &atq.ctx.Fields
grbuild.label = authtokens.Label
grbuild.scan = grbuild.Scan
return grbuild
@@ -366,56 +366,56 @@ func (_q *AuthTokensQuery) GroupBy(field string, fields ...string) *AuthTokensGr
// client.AuthTokens.Query().
// Select(authtokens.FieldCreatedAt).
// Scan(ctx, &v)
func (_q *AuthTokensQuery) Select(fields ...string) *AuthTokensSelect {
_q.ctx.Fields = append(_q.ctx.Fields, fields...)
sbuild := &AuthTokensSelect{AuthTokensQuery: _q}
func (atq *AuthTokensQuery) Select(fields ...string) *AuthTokensSelect {
atq.ctx.Fields = append(atq.ctx.Fields, fields...)
sbuild := &AuthTokensSelect{AuthTokensQuery: atq}
sbuild.label = authtokens.Label
sbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan
sbuild.flds, sbuild.scan = &atq.ctx.Fields, sbuild.Scan
return sbuild
}
// Aggregate returns a AuthTokensSelect configured with the given aggregations.
func (_q *AuthTokensQuery) Aggregate(fns ...AggregateFunc) *AuthTokensSelect {
return _q.Select().Aggregate(fns...)
func (atq *AuthTokensQuery) Aggregate(fns ...AggregateFunc) *AuthTokensSelect {
return atq.Select().Aggregate(fns...)
}
func (_q *AuthTokensQuery) prepareQuery(ctx context.Context) error {
for _, inter := range _q.inters {
func (atq *AuthTokensQuery) prepareQuery(ctx context.Context) error {
for _, inter := range atq.inters {
if inter == nil {
return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)")
}
if trv, ok := inter.(Traverser); ok {
if err := trv.Traverse(ctx, _q); err != nil {
if err := trv.Traverse(ctx, atq); err != nil {
return err
}
}
}
for _, f := range _q.ctx.Fields {
for _, f := range atq.ctx.Fields {
if !authtokens.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
}
if _q.path != nil {
prev, err := _q.path(ctx)
if atq.path != nil {
prev, err := atq.path(ctx)
if err != nil {
return err
}
_q.sql = prev
atq.sql = prev
}
return nil
}
func (_q *AuthTokensQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*AuthTokens, error) {
func (atq *AuthTokensQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*AuthTokens, error) {
var (
nodes = []*AuthTokens{}
withFKs = _q.withFKs
_spec = _q.querySpec()
withFKs = atq.withFKs
_spec = atq.querySpec()
loadedTypes = [2]bool{
_q.withUser != nil,
_q.withRoles != nil,
atq.withUser != nil,
atq.withRoles != nil,
}
)
if _q.withUser != nil {
if atq.withUser != nil {
withFKs = true
}
if withFKs {
@@ -425,7 +425,7 @@ func (_q *AuthTokensQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*A
return (*AuthTokens).scanValues(nil, columns)
}
_spec.Assign = func(columns []string, values []any) error {
node := &AuthTokens{config: _q.config}
node := &AuthTokens{config: atq.config}
nodes = append(nodes, node)
node.Edges.loadedTypes = loadedTypes
return node.assignValues(columns, values)
@@ -433,20 +433,20 @@ func (_q *AuthTokensQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*A
for i := range hooks {
hooks[i](ctx, _spec)
}
if err := sqlgraph.QueryNodes(ctx, _q.driver, _spec); err != nil {
if err := sqlgraph.QueryNodes(ctx, atq.driver, _spec); err != nil {
return nil, err
}
if len(nodes) == 0 {
return nodes, nil
}
if query := _q.withUser; query != nil {
if err := _q.loadUser(ctx, query, nodes, nil,
if query := atq.withUser; query != nil {
if err := atq.loadUser(ctx, query, nodes, nil,
func(n *AuthTokens, e *User) { n.Edges.User = e }); err != nil {
return nil, err
}
}
if query := _q.withRoles; query != nil {
if err := _q.loadRoles(ctx, query, nodes, nil,
if query := atq.withRoles; query != nil {
if err := atq.loadRoles(ctx, query, nodes, nil,
func(n *AuthTokens, e *AuthRoles) { n.Edges.Roles = e }); err != nil {
return nil, err
}
@@ -454,7 +454,7 @@ func (_q *AuthTokensQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*A
return nodes, nil
}
func (_q *AuthTokensQuery) loadUser(ctx context.Context, query *UserQuery, nodes []*AuthTokens, init func(*AuthTokens), assign func(*AuthTokens, *User)) error {
func (atq *AuthTokensQuery) loadUser(ctx context.Context, query *UserQuery, nodes []*AuthTokens, init func(*AuthTokens), assign func(*AuthTokens, *User)) error {
ids := make([]uuid.UUID, 0, len(nodes))
nodeids := make(map[uuid.UUID][]*AuthTokens)
for i := range nodes {
@@ -486,7 +486,7 @@ func (_q *AuthTokensQuery) loadUser(ctx context.Context, query *UserQuery, nodes
}
return nil
}
func (_q *AuthTokensQuery) loadRoles(ctx context.Context, query *AuthRolesQuery, nodes []*AuthTokens, init func(*AuthTokens), assign func(*AuthTokens, *AuthRoles)) error {
func (atq *AuthTokensQuery) loadRoles(ctx context.Context, query *AuthRolesQuery, nodes []*AuthTokens, init func(*AuthTokens), assign func(*AuthTokens, *AuthRoles)) error {
fks := make([]driver.Value, 0, len(nodes))
nodeids := make(map[uuid.UUID]*AuthTokens)
for i := range nodes {
@@ -515,24 +515,24 @@ func (_q *AuthTokensQuery) loadRoles(ctx context.Context, query *AuthRolesQuery,
return nil
}
func (_q *AuthTokensQuery) sqlCount(ctx context.Context) (int, error) {
_spec := _q.querySpec()
_spec.Node.Columns = _q.ctx.Fields
if len(_q.ctx.Fields) > 0 {
_spec.Unique = _q.ctx.Unique != nil && *_q.ctx.Unique
func (atq *AuthTokensQuery) sqlCount(ctx context.Context) (int, error) {
_spec := atq.querySpec()
_spec.Node.Columns = atq.ctx.Fields
if len(atq.ctx.Fields) > 0 {
_spec.Unique = atq.ctx.Unique != nil && *atq.ctx.Unique
}
return sqlgraph.CountNodes(ctx, _q.driver, _spec)
return sqlgraph.CountNodes(ctx, atq.driver, _spec)
}
func (_q *AuthTokensQuery) querySpec() *sqlgraph.QuerySpec {
func (atq *AuthTokensQuery) querySpec() *sqlgraph.QuerySpec {
_spec := sqlgraph.NewQuerySpec(authtokens.Table, authtokens.Columns, sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID))
_spec.From = _q.sql
if unique := _q.ctx.Unique; unique != nil {
_spec.From = atq.sql
if unique := atq.ctx.Unique; unique != nil {
_spec.Unique = *unique
} else if _q.path != nil {
} else if atq.path != nil {
_spec.Unique = true
}
if fields := _q.ctx.Fields; len(fields) > 0 {
if fields := atq.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, authtokens.FieldID)
for i := range fields {
@@ -541,20 +541,20 @@ func (_q *AuthTokensQuery) querySpec() *sqlgraph.QuerySpec {
}
}
}
if ps := _q.predicates; len(ps) > 0 {
if ps := atq.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if limit := _q.ctx.Limit; limit != nil {
if limit := atq.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := _q.ctx.Offset; offset != nil {
if offset := atq.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := _q.order; len(ps) > 0 {
if ps := atq.order; len(ps) > 0 {
_spec.Order = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
@@ -564,33 +564,33 @@ func (_q *AuthTokensQuery) querySpec() *sqlgraph.QuerySpec {
return _spec
}
func (_q *AuthTokensQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(_q.driver.Dialect())
func (atq *AuthTokensQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(atq.driver.Dialect())
t1 := builder.Table(authtokens.Table)
columns := _q.ctx.Fields
columns := atq.ctx.Fields
if len(columns) == 0 {
columns = authtokens.Columns
}
selector := builder.Select(t1.Columns(columns...)...).From(t1)
if _q.sql != nil {
selector = _q.sql
if atq.sql != nil {
selector = atq.sql
selector.Select(selector.Columns(columns...)...)
}
if _q.ctx.Unique != nil && *_q.ctx.Unique {
if atq.ctx.Unique != nil && *atq.ctx.Unique {
selector.Distinct()
}
for _, p := range _q.predicates {
for _, p := range atq.predicates {
p(selector)
}
for _, p := range _q.order {
for _, p := range atq.order {
p(selector)
}
if offset := _q.ctx.Offset; offset != nil {
if offset := atq.ctx.Offset; offset != nil {
// limit is mandatory for offset clause. We start
// with default value, and override it below if needed.
selector.Offset(*offset).Limit(math.MaxInt32)
}
if limit := _q.ctx.Limit; limit != nil {
if limit := atq.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
@@ -603,41 +603,41 @@ type AuthTokensGroupBy struct {
}
// Aggregate adds the given aggregation functions to the group-by query.
func (_g *AuthTokensGroupBy) Aggregate(fns ...AggregateFunc) *AuthTokensGroupBy {
_g.fns = append(_g.fns, fns...)
return _g
func (atgb *AuthTokensGroupBy) Aggregate(fns ...AggregateFunc) *AuthTokensGroupBy {
atgb.fns = append(atgb.fns, fns...)
return atgb
}
// Scan applies the selector query and scans the result into the given value.
func (_g *AuthTokensGroupBy) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, _g.build.ctx, ent.OpQueryGroupBy)
if err := _g.build.prepareQuery(ctx); err != nil {
func (atgb *AuthTokensGroupBy) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, atgb.build.ctx, ent.OpQueryGroupBy)
if err := atgb.build.prepareQuery(ctx); err != nil {
return err
}
return scanWithInterceptors[*AuthTokensQuery, *AuthTokensGroupBy](ctx, _g.build, _g, _g.build.inters, v)
return scanWithInterceptors[*AuthTokensQuery, *AuthTokensGroupBy](ctx, atgb.build, atgb, atgb.build.inters, v)
}
func (_g *AuthTokensGroupBy) sqlScan(ctx context.Context, root *AuthTokensQuery, v any) error {
func (atgb *AuthTokensGroupBy) sqlScan(ctx context.Context, root *AuthTokensQuery, v any) error {
selector := root.sqlQuery(ctx).Select()
aggregation := make([]string, 0, len(_g.fns))
for _, fn := range _g.fns {
aggregation := make([]string, 0, len(atgb.fns))
for _, fn := range atgb.fns {
aggregation = append(aggregation, fn(selector))
}
if len(selector.SelectedColumns()) == 0 {
columns := make([]string, 0, len(*_g.flds)+len(_g.fns))
for _, f := range *_g.flds {
columns := make([]string, 0, len(*atgb.flds)+len(atgb.fns))
for _, f := range *atgb.flds {
columns = append(columns, selector.C(f))
}
columns = append(columns, aggregation...)
selector.Select(columns...)
}
selector.GroupBy(selector.Columns(*_g.flds...)...)
selector.GroupBy(selector.Columns(*atgb.flds...)...)
if err := selector.Err(); err != nil {
return err
}
rows := &sql.Rows{}
query, args := selector.Query()
if err := _g.build.driver.Query(ctx, query, args, rows); err != nil {
if err := atgb.build.driver.Query(ctx, query, args, rows); err != nil {
return err
}
defer rows.Close()
@@ -651,27 +651,27 @@ type AuthTokensSelect struct {
}
// Aggregate adds the given aggregation functions to the selector query.
func (_s *AuthTokensSelect) Aggregate(fns ...AggregateFunc) *AuthTokensSelect {
_s.fns = append(_s.fns, fns...)
return _s
func (ats *AuthTokensSelect) Aggregate(fns ...AggregateFunc) *AuthTokensSelect {
ats.fns = append(ats.fns, fns...)
return ats
}
// Scan applies the selector query and scans the result into the given value.
func (_s *AuthTokensSelect) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, _s.ctx, ent.OpQuerySelect)
if err := _s.prepareQuery(ctx); err != nil {
func (ats *AuthTokensSelect) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, ats.ctx, ent.OpQuerySelect)
if err := ats.prepareQuery(ctx); err != nil {
return err
}
return scanWithInterceptors[*AuthTokensQuery, *AuthTokensSelect](ctx, _s.AuthTokensQuery, _s, _s.inters, v)
return scanWithInterceptors[*AuthTokensQuery, *AuthTokensSelect](ctx, ats.AuthTokensQuery, ats, ats.inters, v)
}
func (_s *AuthTokensSelect) sqlScan(ctx context.Context, root *AuthTokensQuery, v any) error {
func (ats *AuthTokensSelect) sqlScan(ctx context.Context, root *AuthTokensQuery, v any) error {
selector := root.sqlQuery(ctx)
aggregation := make([]string, 0, len(_s.fns))
for _, fn := range _s.fns {
aggregation := make([]string, 0, len(ats.fns))
for _, fn := range ats.fns {
aggregation = append(aggregation, fn(selector))
}
switch n := len(*_s.selector.flds); {
switch n := len(*ats.selector.flds); {
case n == 0 && len(aggregation) > 0:
selector.Select(aggregation...)
case n != 0 && len(aggregation) > 0:
@@ -679,7 +679,7 @@ func (_s *AuthTokensSelect) sqlScan(ctx context.Context, root *AuthTokensQuery,
}
rows := &sql.Rows{}
query, args := selector.Query()
if err := _s.driver.Query(ctx, query, args, rows); err != nil {
if err := ats.driver.Query(ctx, query, args, rows); err != nil {
return err
}
defer rows.Close()

View File

@@ -26,101 +26,101 @@ type AuthTokensUpdate struct {
}
// Where appends a list predicates to the AuthTokensUpdate builder.
func (_u *AuthTokensUpdate) Where(ps ...predicate.AuthTokens) *AuthTokensUpdate {
_u.mutation.Where(ps...)
return _u
func (atu *AuthTokensUpdate) Where(ps ...predicate.AuthTokens) *AuthTokensUpdate {
atu.mutation.Where(ps...)
return atu
}
// SetUpdatedAt sets the "updated_at" field.
func (_u *AuthTokensUpdate) SetUpdatedAt(v time.Time) *AuthTokensUpdate {
_u.mutation.SetUpdatedAt(v)
return _u
func (atu *AuthTokensUpdate) SetUpdatedAt(t time.Time) *AuthTokensUpdate {
atu.mutation.SetUpdatedAt(t)
return atu
}
// SetToken sets the "token" field.
func (_u *AuthTokensUpdate) SetToken(v []byte) *AuthTokensUpdate {
_u.mutation.SetToken(v)
return _u
func (atu *AuthTokensUpdate) SetToken(b []byte) *AuthTokensUpdate {
atu.mutation.SetToken(b)
return atu
}
// SetExpiresAt sets the "expires_at" field.
func (_u *AuthTokensUpdate) SetExpiresAt(v time.Time) *AuthTokensUpdate {
_u.mutation.SetExpiresAt(v)
return _u
func (atu *AuthTokensUpdate) SetExpiresAt(t time.Time) *AuthTokensUpdate {
atu.mutation.SetExpiresAt(t)
return atu
}
// SetNillableExpiresAt sets the "expires_at" field if the given value is not nil.
func (_u *AuthTokensUpdate) SetNillableExpiresAt(v *time.Time) *AuthTokensUpdate {
if v != nil {
_u.SetExpiresAt(*v)
func (atu *AuthTokensUpdate) SetNillableExpiresAt(t *time.Time) *AuthTokensUpdate {
if t != nil {
atu.SetExpiresAt(*t)
}
return _u
return atu
}
// SetUserID sets the "user" edge to the User entity by ID.
func (_u *AuthTokensUpdate) SetUserID(id uuid.UUID) *AuthTokensUpdate {
_u.mutation.SetUserID(id)
return _u
func (atu *AuthTokensUpdate) SetUserID(id uuid.UUID) *AuthTokensUpdate {
atu.mutation.SetUserID(id)
return atu
}
// SetNillableUserID sets the "user" edge to the User entity by ID if the given value is not nil.
func (_u *AuthTokensUpdate) SetNillableUserID(id *uuid.UUID) *AuthTokensUpdate {
func (atu *AuthTokensUpdate) SetNillableUserID(id *uuid.UUID) *AuthTokensUpdate {
if id != nil {
_u = _u.SetUserID(*id)
atu = atu.SetUserID(*id)
}
return _u
return atu
}
// SetUser sets the "user" edge to the User entity.
func (_u *AuthTokensUpdate) SetUser(v *User) *AuthTokensUpdate {
return _u.SetUserID(v.ID)
func (atu *AuthTokensUpdate) SetUser(u *User) *AuthTokensUpdate {
return atu.SetUserID(u.ID)
}
// SetRolesID sets the "roles" edge to the AuthRoles entity by ID.
func (_u *AuthTokensUpdate) SetRolesID(id int) *AuthTokensUpdate {
_u.mutation.SetRolesID(id)
return _u
func (atu *AuthTokensUpdate) SetRolesID(id int) *AuthTokensUpdate {
atu.mutation.SetRolesID(id)
return atu
}
// SetNillableRolesID sets the "roles" edge to the AuthRoles entity by ID if the given value is not nil.
func (_u *AuthTokensUpdate) SetNillableRolesID(id *int) *AuthTokensUpdate {
func (atu *AuthTokensUpdate) SetNillableRolesID(id *int) *AuthTokensUpdate {
if id != nil {
_u = _u.SetRolesID(*id)
atu = atu.SetRolesID(*id)
}
return _u
return atu
}
// SetRoles sets the "roles" edge to the AuthRoles entity.
func (_u *AuthTokensUpdate) SetRoles(v *AuthRoles) *AuthTokensUpdate {
return _u.SetRolesID(v.ID)
func (atu *AuthTokensUpdate) SetRoles(a *AuthRoles) *AuthTokensUpdate {
return atu.SetRolesID(a.ID)
}
// Mutation returns the AuthTokensMutation object of the builder.
func (_u *AuthTokensUpdate) Mutation() *AuthTokensMutation {
return _u.mutation
func (atu *AuthTokensUpdate) Mutation() *AuthTokensMutation {
return atu.mutation
}
// ClearUser clears the "user" edge to the User entity.
func (_u *AuthTokensUpdate) ClearUser() *AuthTokensUpdate {
_u.mutation.ClearUser()
return _u
func (atu *AuthTokensUpdate) ClearUser() *AuthTokensUpdate {
atu.mutation.ClearUser()
return atu
}
// ClearRoles clears the "roles" edge to the AuthRoles entity.
func (_u *AuthTokensUpdate) ClearRoles() *AuthTokensUpdate {
_u.mutation.ClearRoles()
return _u
func (atu *AuthTokensUpdate) ClearRoles() *AuthTokensUpdate {
atu.mutation.ClearRoles()
return atu
}
// Save executes the query and returns the number of nodes affected by the update operation.
func (_u *AuthTokensUpdate) Save(ctx context.Context) (int, error) {
_u.defaults()
return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)
func (atu *AuthTokensUpdate) Save(ctx context.Context) (int, error) {
atu.defaults()
return withHooks(ctx, atu.sqlSave, atu.mutation, atu.hooks)
}
// SaveX is like Save, but panics if an error occurs.
func (_u *AuthTokensUpdate) SaveX(ctx context.Context) int {
affected, err := _u.Save(ctx)
func (atu *AuthTokensUpdate) SaveX(ctx context.Context) int {
affected, err := atu.Save(ctx)
if err != nil {
panic(err)
}
@@ -128,45 +128,45 @@ func (_u *AuthTokensUpdate) SaveX(ctx context.Context) int {
}
// Exec executes the query.
func (_u *AuthTokensUpdate) Exec(ctx context.Context) error {
_, err := _u.Save(ctx)
func (atu *AuthTokensUpdate) Exec(ctx context.Context) error {
_, err := atu.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (_u *AuthTokensUpdate) ExecX(ctx context.Context) {
if err := _u.Exec(ctx); err != nil {
func (atu *AuthTokensUpdate) ExecX(ctx context.Context) {
if err := atu.Exec(ctx); err != nil {
panic(err)
}
}
// defaults sets the default values of the builder before save.
func (_u *AuthTokensUpdate) defaults() {
if _, ok := _u.mutation.UpdatedAt(); !ok {
func (atu *AuthTokensUpdate) defaults() {
if _, ok := atu.mutation.UpdatedAt(); !ok {
v := authtokens.UpdateDefaultUpdatedAt()
_u.mutation.SetUpdatedAt(v)
atu.mutation.SetUpdatedAt(v)
}
}
func (_u *AuthTokensUpdate) sqlSave(ctx context.Context) (_node int, err error) {
func (atu *AuthTokensUpdate) sqlSave(ctx context.Context) (n int, err error) {
_spec := sqlgraph.NewUpdateSpec(authtokens.Table, authtokens.Columns, sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID))
if ps := _u.mutation.predicates; len(ps) > 0 {
if ps := atu.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if value, ok := _u.mutation.UpdatedAt(); ok {
if value, ok := atu.mutation.UpdatedAt(); ok {
_spec.SetField(authtokens.FieldUpdatedAt, field.TypeTime, value)
}
if value, ok := _u.mutation.Token(); ok {
if value, ok := atu.mutation.Token(); ok {
_spec.SetField(authtokens.FieldToken, field.TypeBytes, value)
}
if value, ok := _u.mutation.ExpiresAt(); ok {
if value, ok := atu.mutation.ExpiresAt(); ok {
_spec.SetField(authtokens.FieldExpiresAt, field.TypeTime, value)
}
if _u.mutation.UserCleared() {
if atu.mutation.UserCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
@@ -179,7 +179,7 @@ func (_u *AuthTokensUpdate) sqlSave(ctx context.Context) (_node int, err error)
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := _u.mutation.UserIDs(); len(nodes) > 0 {
if nodes := atu.mutation.UserIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
@@ -195,7 +195,7 @@ func (_u *AuthTokensUpdate) sqlSave(ctx context.Context) (_node int, err error)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if _u.mutation.RolesCleared() {
if atu.mutation.RolesCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2O,
Inverse: false,
@@ -208,7 +208,7 @@ func (_u *AuthTokensUpdate) sqlSave(ctx context.Context) (_node int, err error)
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := _u.mutation.RolesIDs(); len(nodes) > 0 {
if nodes := atu.mutation.RolesIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2O,
Inverse: false,
@@ -224,7 +224,7 @@ func (_u *AuthTokensUpdate) sqlSave(ctx context.Context) (_node int, err error)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil {
if n, err = sqlgraph.UpdateNodes(ctx, atu.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{authtokens.Label}
} else if sqlgraph.IsConstraintError(err) {
@@ -232,8 +232,8 @@ func (_u *AuthTokensUpdate) sqlSave(ctx context.Context) (_node int, err error)
}
return 0, err
}
_u.mutation.done = true
return _node, nil
atu.mutation.done = true
return n, nil
}
// AuthTokensUpdateOne is the builder for updating a single AuthTokens entity.
@@ -245,108 +245,108 @@ type AuthTokensUpdateOne struct {
}
// SetUpdatedAt sets the "updated_at" field.
func (_u *AuthTokensUpdateOne) SetUpdatedAt(v time.Time) *AuthTokensUpdateOne {
_u.mutation.SetUpdatedAt(v)
return _u
func (atuo *AuthTokensUpdateOne) SetUpdatedAt(t time.Time) *AuthTokensUpdateOne {
atuo.mutation.SetUpdatedAt(t)
return atuo
}
// SetToken sets the "token" field.
func (_u *AuthTokensUpdateOne) SetToken(v []byte) *AuthTokensUpdateOne {
_u.mutation.SetToken(v)
return _u
func (atuo *AuthTokensUpdateOne) SetToken(b []byte) *AuthTokensUpdateOne {
atuo.mutation.SetToken(b)
return atuo
}
// SetExpiresAt sets the "expires_at" field.
func (_u *AuthTokensUpdateOne) SetExpiresAt(v time.Time) *AuthTokensUpdateOne {
_u.mutation.SetExpiresAt(v)
return _u
func (atuo *AuthTokensUpdateOne) SetExpiresAt(t time.Time) *AuthTokensUpdateOne {
atuo.mutation.SetExpiresAt(t)
return atuo
}
// SetNillableExpiresAt sets the "expires_at" field if the given value is not nil.
func (_u *AuthTokensUpdateOne) SetNillableExpiresAt(v *time.Time) *AuthTokensUpdateOne {
if v != nil {
_u.SetExpiresAt(*v)
func (atuo *AuthTokensUpdateOne) SetNillableExpiresAt(t *time.Time) *AuthTokensUpdateOne {
if t != nil {
atuo.SetExpiresAt(*t)
}
return _u
return atuo
}
// SetUserID sets the "user" edge to the User entity by ID.
func (_u *AuthTokensUpdateOne) SetUserID(id uuid.UUID) *AuthTokensUpdateOne {
_u.mutation.SetUserID(id)
return _u
func (atuo *AuthTokensUpdateOne) SetUserID(id uuid.UUID) *AuthTokensUpdateOne {
atuo.mutation.SetUserID(id)
return atuo
}
// SetNillableUserID sets the "user" edge to the User entity by ID if the given value is not nil.
func (_u *AuthTokensUpdateOne) SetNillableUserID(id *uuid.UUID) *AuthTokensUpdateOne {
func (atuo *AuthTokensUpdateOne) SetNillableUserID(id *uuid.UUID) *AuthTokensUpdateOne {
if id != nil {
_u = _u.SetUserID(*id)
atuo = atuo.SetUserID(*id)
}
return _u
return atuo
}
// SetUser sets the "user" edge to the User entity.
func (_u *AuthTokensUpdateOne) SetUser(v *User) *AuthTokensUpdateOne {
return _u.SetUserID(v.ID)
func (atuo *AuthTokensUpdateOne) SetUser(u *User) *AuthTokensUpdateOne {
return atuo.SetUserID(u.ID)
}
// SetRolesID sets the "roles" edge to the AuthRoles entity by ID.
func (_u *AuthTokensUpdateOne) SetRolesID(id int) *AuthTokensUpdateOne {
_u.mutation.SetRolesID(id)
return _u
func (atuo *AuthTokensUpdateOne) SetRolesID(id int) *AuthTokensUpdateOne {
atuo.mutation.SetRolesID(id)
return atuo
}
// SetNillableRolesID sets the "roles" edge to the AuthRoles entity by ID if the given value is not nil.
func (_u *AuthTokensUpdateOne) SetNillableRolesID(id *int) *AuthTokensUpdateOne {
func (atuo *AuthTokensUpdateOne) SetNillableRolesID(id *int) *AuthTokensUpdateOne {
if id != nil {
_u = _u.SetRolesID(*id)
atuo = atuo.SetRolesID(*id)
}
return _u
return atuo
}
// SetRoles sets the "roles" edge to the AuthRoles entity.
func (_u *AuthTokensUpdateOne) SetRoles(v *AuthRoles) *AuthTokensUpdateOne {
return _u.SetRolesID(v.ID)
func (atuo *AuthTokensUpdateOne) SetRoles(a *AuthRoles) *AuthTokensUpdateOne {
return atuo.SetRolesID(a.ID)
}
// Mutation returns the AuthTokensMutation object of the builder.
func (_u *AuthTokensUpdateOne) Mutation() *AuthTokensMutation {
return _u.mutation
func (atuo *AuthTokensUpdateOne) Mutation() *AuthTokensMutation {
return atuo.mutation
}
// ClearUser clears the "user" edge to the User entity.
func (_u *AuthTokensUpdateOne) ClearUser() *AuthTokensUpdateOne {
_u.mutation.ClearUser()
return _u
func (atuo *AuthTokensUpdateOne) ClearUser() *AuthTokensUpdateOne {
atuo.mutation.ClearUser()
return atuo
}
// ClearRoles clears the "roles" edge to the AuthRoles entity.
func (_u *AuthTokensUpdateOne) ClearRoles() *AuthTokensUpdateOne {
_u.mutation.ClearRoles()
return _u
func (atuo *AuthTokensUpdateOne) ClearRoles() *AuthTokensUpdateOne {
atuo.mutation.ClearRoles()
return atuo
}
// Where appends a list predicates to the AuthTokensUpdate builder.
func (_u *AuthTokensUpdateOne) Where(ps ...predicate.AuthTokens) *AuthTokensUpdateOne {
_u.mutation.Where(ps...)
return _u
func (atuo *AuthTokensUpdateOne) Where(ps ...predicate.AuthTokens) *AuthTokensUpdateOne {
atuo.mutation.Where(ps...)
return atuo
}
// Select allows selecting one or more fields (columns) of the returned entity.
// The default is selecting all fields defined in the entity schema.
func (_u *AuthTokensUpdateOne) Select(field string, fields ...string) *AuthTokensUpdateOne {
_u.fields = append([]string{field}, fields...)
return _u
func (atuo *AuthTokensUpdateOne) Select(field string, fields ...string) *AuthTokensUpdateOne {
atuo.fields = append([]string{field}, fields...)
return atuo
}
// Save executes the query and returns the updated AuthTokens entity.
func (_u *AuthTokensUpdateOne) Save(ctx context.Context) (*AuthTokens, error) {
_u.defaults()
return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)
func (atuo *AuthTokensUpdateOne) Save(ctx context.Context) (*AuthTokens, error) {
atuo.defaults()
return withHooks(ctx, atuo.sqlSave, atuo.mutation, atuo.hooks)
}
// SaveX is like Save, but panics if an error occurs.
func (_u *AuthTokensUpdateOne) SaveX(ctx context.Context) *AuthTokens {
node, err := _u.Save(ctx)
func (atuo *AuthTokensUpdateOne) SaveX(ctx context.Context) *AuthTokens {
node, err := atuo.Save(ctx)
if err != nil {
panic(err)
}
@@ -354,34 +354,34 @@ func (_u *AuthTokensUpdateOne) SaveX(ctx context.Context) *AuthTokens {
}
// Exec executes the query on the entity.
func (_u *AuthTokensUpdateOne) Exec(ctx context.Context) error {
_, err := _u.Save(ctx)
func (atuo *AuthTokensUpdateOne) Exec(ctx context.Context) error {
_, err := atuo.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (_u *AuthTokensUpdateOne) ExecX(ctx context.Context) {
if err := _u.Exec(ctx); err != nil {
func (atuo *AuthTokensUpdateOne) ExecX(ctx context.Context) {
if err := atuo.Exec(ctx); err != nil {
panic(err)
}
}
// defaults sets the default values of the builder before save.
func (_u *AuthTokensUpdateOne) defaults() {
if _, ok := _u.mutation.UpdatedAt(); !ok {
func (atuo *AuthTokensUpdateOne) defaults() {
if _, ok := atuo.mutation.UpdatedAt(); !ok {
v := authtokens.UpdateDefaultUpdatedAt()
_u.mutation.SetUpdatedAt(v)
atuo.mutation.SetUpdatedAt(v)
}
}
func (_u *AuthTokensUpdateOne) sqlSave(ctx context.Context) (_node *AuthTokens, err error) {
func (atuo *AuthTokensUpdateOne) sqlSave(ctx context.Context) (_node *AuthTokens, err error) {
_spec := sqlgraph.NewUpdateSpec(authtokens.Table, authtokens.Columns, sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID))
id, ok := _u.mutation.ID()
id, ok := atuo.mutation.ID()
if !ok {
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "AuthTokens.id" for update`)}
}
_spec.Node.ID.Value = id
if fields := _u.fields; len(fields) > 0 {
if fields := atuo.fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, authtokens.FieldID)
for _, f := range fields {
@@ -393,23 +393,23 @@ func (_u *AuthTokensUpdateOne) sqlSave(ctx context.Context) (_node *AuthTokens,
}
}
}
if ps := _u.mutation.predicates; len(ps) > 0 {
if ps := atuo.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if value, ok := _u.mutation.UpdatedAt(); ok {
if value, ok := atuo.mutation.UpdatedAt(); ok {
_spec.SetField(authtokens.FieldUpdatedAt, field.TypeTime, value)
}
if value, ok := _u.mutation.Token(); ok {
if value, ok := atuo.mutation.Token(); ok {
_spec.SetField(authtokens.FieldToken, field.TypeBytes, value)
}
if value, ok := _u.mutation.ExpiresAt(); ok {
if value, ok := atuo.mutation.ExpiresAt(); ok {
_spec.SetField(authtokens.FieldExpiresAt, field.TypeTime, value)
}
if _u.mutation.UserCleared() {
if atuo.mutation.UserCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
@@ -422,7 +422,7 @@ func (_u *AuthTokensUpdateOne) sqlSave(ctx context.Context) (_node *AuthTokens,
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := _u.mutation.UserIDs(); len(nodes) > 0 {
if nodes := atuo.mutation.UserIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
@@ -438,7 +438,7 @@ func (_u *AuthTokensUpdateOne) sqlSave(ctx context.Context) (_node *AuthTokens,
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if _u.mutation.RolesCleared() {
if atuo.mutation.RolesCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2O,
Inverse: false,
@@ -451,7 +451,7 @@ func (_u *AuthTokensUpdateOne) sqlSave(ctx context.Context) (_node *AuthTokens,
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := _u.mutation.RolesIDs(); len(nodes) > 0 {
if nodes := atuo.mutation.RolesIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2O,
Inverse: false,
@@ -467,10 +467,10 @@ func (_u *AuthTokensUpdateOne) sqlSave(ctx context.Context) (_node *AuthTokens,
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
_node = &AuthTokens{config: _u.config}
_node = &AuthTokens{config: atuo.config}
_spec.Assign = _node.assignValues
_spec.ScanValues = _node.scanValues
if err = sqlgraph.UpdateNode(ctx, _u.driver, _spec); err != nil {
if err = sqlgraph.UpdateNode(ctx, atuo.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{authtokens.Label}
} else if sqlgraph.IsConstraintError(err) {
@@ -478,6 +478,6 @@ func (_u *AuthTokensUpdateOne) sqlSave(ctx context.Context) (_node *AuthTokens,
}
return nil, err
}
_u.mutation.done = true
atuo.mutation.done = true
return _node, nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,195 @@
// Code generated by ent, DO NOT EDIT.
package ent
import (
"fmt"
"strings"
"time"
"entgo.io/ent"
"entgo.io/ent/dialect/sql"
"github.com/google/uuid"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/document"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/group"
)
// Document is the model entity for the Document schema.
type Document struct {
config `json:"-"`
// ID of the ent.
ID uuid.UUID `json:"id,omitempty"`
// CreatedAt holds the value of the "created_at" field.
CreatedAt time.Time `json:"created_at,omitempty"`
// UpdatedAt holds the value of the "updated_at" field.
UpdatedAt time.Time `json:"updated_at,omitempty"`
// Title holds the value of the "title" field.
Title string `json:"title,omitempty"`
// Path holds the value of the "path" field.
Path string `json:"path,omitempty"`
// Edges holds the relations/edges for other nodes in the graph.
// 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.
type DocumentEdges struct {
// Group holds the value of the group edge.
Group *Group `json:"group,omitempty"`
// Attachments holds the value of the attachments edge.
Attachments []*Attachment `json:"attachments,omitempty"`
// loadedTypes holds the information for reporting if a
// type was loaded (or requested) in eager-loading or not.
loadedTypes [2]bool
}
// GroupOrErr returns the Group value or an error if the edge
// was not loaded in eager-loading, or loaded but was not found.
func (e DocumentEdges) GroupOrErr() (*Group, error) {
if e.Group != nil {
return e.Group, nil
} else if e.loadedTypes[0] {
return nil, &NotFoundError{label: group.Label}
}
return nil, &NotLoadedError{edge: "group"}
}
// AttachmentsOrErr returns the Attachments value or an error if the edge
// was not loaded in eager-loading.
func (e DocumentEdges) AttachmentsOrErr() ([]*Attachment, error) {
if e.loadedTypes[1] {
return e.Attachments, nil
}
return nil, &NotLoadedError{edge: "attachments"}
}
// scanValues returns the types for scanning values from sql.Rows.
func (*Document) scanValues(columns []string) ([]any, error) {
values := make([]any, len(columns))
for i := range columns {
switch columns[i] {
case document.FieldTitle, document.FieldPath:
values[i] = new(sql.NullString)
case document.FieldCreatedAt, document.FieldUpdatedAt:
values[i] = new(sql.NullTime)
case document.FieldID:
values[i] = new(uuid.UUID)
case document.ForeignKeys[0]: // group_documents
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
default:
values[i] = new(sql.UnknownType)
}
}
return values, nil
}
// assignValues assigns the values that were returned from sql.Rows (after scanning)
// to the Document fields.
func (d *Document) assignValues(columns []string, values []any) error {
if m, n := len(values), len(columns); m < n {
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
}
for i := range columns {
switch columns[i] {
case document.FieldID:
if value, ok := values[i].(*uuid.UUID); !ok {
return fmt.Errorf("unexpected type %T for field id", values[i])
} else if value != nil {
d.ID = *value
}
case document.FieldCreatedAt:
if value, ok := values[i].(*sql.NullTime); !ok {
return fmt.Errorf("unexpected type %T for field created_at", values[i])
} else if value.Valid {
d.CreatedAt = value.Time
}
case document.FieldUpdatedAt:
if value, ok := values[i].(*sql.NullTime); !ok {
return fmt.Errorf("unexpected type %T for field updated_at", values[i])
} else if value.Valid {
d.UpdatedAt = value.Time
}
case document.FieldTitle:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field title", values[i])
} else if value.Valid {
d.Title = value.String
}
case document.FieldPath:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field path", values[i])
} else if value.Valid {
d.Path = value.String
}
case document.ForeignKeys[0]:
if value, ok := values[i].(*sql.NullScanner); !ok {
return fmt.Errorf("unexpected type %T for field group_documents", values[i])
} else if value.Valid {
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)
}
// QueryAttachments queries the "attachments" edge of the Document entity.
func (d *Document) QueryAttachments() *AttachmentQuery {
return NewDocumentClient(d.config).QueryAttachments(d)
}
// Update returns a builder for updating this Document.
// Note that you need to call Document.Unwrap() before calling this method if this Document
// was returned from a transaction, and the transaction was committed or rolled back.
func (d *Document) Update() *DocumentUpdateOne {
return NewDocumentClient(d.config).UpdateOne(d)
}
// Unwrap unwraps the Document entity that was returned from a transaction after it was closed,
// so that all future queries will be executed through the driver which created the transaction.
func (d *Document) Unwrap() *Document {
_tx, ok := d.config.driver.(*txDriver)
if !ok {
panic("ent: Document is not a transactional entity")
}
d.config.driver = _tx.drv
return d
}
// String implements the fmt.Stringer.
func (d *Document) String() string {
var builder strings.Builder
builder.WriteString("Document(")
builder.WriteString(fmt.Sprintf("id=%v, ", d.ID))
builder.WriteString("created_at=")
builder.WriteString(d.CreatedAt.Format(time.ANSIC))
builder.WriteString(", ")
builder.WriteString("updated_at=")
builder.WriteString(d.UpdatedAt.Format(time.ANSIC))
builder.WriteString(", ")
builder.WriteString("title=")
builder.WriteString(d.Title)
builder.WriteString(", ")
builder.WriteString("path=")
builder.WriteString(d.Path)
builder.WriteByte(')')
return builder.String()
}
// Documents is a parsable slice of Document.
type Documents []*Document

View File

@@ -0,0 +1,154 @@
// Code generated by ent, DO NOT EDIT.
package document
import (
"time"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"github.com/google/uuid"
)
const (
// Label holds the string label denoting the document type in the database.
Label = "document"
// FieldID holds the string denoting the id field in the database.
FieldID = "id"
// FieldCreatedAt holds the string denoting the created_at field in the database.
FieldCreatedAt = "created_at"
// FieldUpdatedAt holds the string denoting the updated_at field in the database.
FieldUpdatedAt = "updated_at"
// FieldTitle holds the string denoting the title field in the database.
FieldTitle = "title"
// FieldPath holds the string denoting the path field in the database.
FieldPath = "path"
// EdgeGroup holds the string denoting the group edge name in mutations.
EdgeGroup = "group"
// EdgeAttachments holds the string denoting the attachments edge name in mutations.
EdgeAttachments = "attachments"
// Table holds the table name of the document in the database.
Table = "documents"
// GroupTable is the table that holds the group relation/edge.
GroupTable = "documents"
// GroupInverseTable is the table name for the Group entity.
// It exists in this package in order to avoid circular dependency with the "group" package.
GroupInverseTable = "groups"
// GroupColumn is the table column denoting the group relation/edge.
GroupColumn = "group_documents"
// AttachmentsTable is the table that holds the attachments relation/edge.
AttachmentsTable = "attachments"
// AttachmentsInverseTable is the table name for the Attachment entity.
// It exists in this package in order to avoid circular dependency with the "attachment" package.
AttachmentsInverseTable = "attachments"
// AttachmentsColumn is the table column denoting the attachments relation/edge.
AttachmentsColumn = "document_attachments"
)
// Columns holds all SQL columns for document fields.
var Columns = []string{
FieldID,
FieldCreatedAt,
FieldUpdatedAt,
FieldTitle,
FieldPath,
}
// ForeignKeys holds the SQL foreign-keys that are owned by the "documents"
// table and are not defined as standalone fields in the schema.
var ForeignKeys = []string{
"group_documents",
}
// ValidColumn reports if the column name is valid (part of the table columns).
func ValidColumn(column string) bool {
for i := range Columns {
if column == Columns[i] {
return true
}
}
for i := range ForeignKeys {
if column == ForeignKeys[i] {
return true
}
}
return false
}
var (
// DefaultCreatedAt holds the default value on creation for the "created_at" field.
DefaultCreatedAt func() time.Time
// DefaultUpdatedAt holds the default value on creation for the "updated_at" field.
DefaultUpdatedAt func() time.Time
// UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field.
UpdateDefaultUpdatedAt func() time.Time
// TitleValidator is a validator for the "title" field. It is called by the builders before save.
TitleValidator func(string) error
// PathValidator is a validator for the "path" field. It is called by the builders before save.
PathValidator func(string) error
// 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),
)
}

View File

@@ -0,0 +1,348 @@
// Code generated by ent, DO NOT EDIT.
package document
import (
"time"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"github.com/google/uuid"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/predicate"
)
// ID filters vertices based on their ID field.
func ID(id uuid.UUID) predicate.Document {
return predicate.Document(sql.FieldEQ(FieldID, id))
}
// IDEQ applies the EQ predicate on the ID field.
func IDEQ(id uuid.UUID) predicate.Document {
return predicate.Document(sql.FieldEQ(FieldID, id))
}
// IDNEQ applies the NEQ predicate on the ID field.
func IDNEQ(id uuid.UUID) predicate.Document {
return predicate.Document(sql.FieldNEQ(FieldID, id))
}
// IDIn applies the In predicate on the ID field.
func IDIn(ids ...uuid.UUID) predicate.Document {
return predicate.Document(sql.FieldIn(FieldID, ids...))
}
// IDNotIn applies the NotIn predicate on the ID field.
func IDNotIn(ids ...uuid.UUID) predicate.Document {
return predicate.Document(sql.FieldNotIn(FieldID, ids...))
}
// IDGT applies the GT predicate on the ID field.
func IDGT(id uuid.UUID) predicate.Document {
return predicate.Document(sql.FieldGT(FieldID, id))
}
// IDGTE applies the GTE predicate on the ID field.
func IDGTE(id uuid.UUID) predicate.Document {
return predicate.Document(sql.FieldGTE(FieldID, id))
}
// IDLT applies the LT predicate on the ID field.
func IDLT(id uuid.UUID) predicate.Document {
return predicate.Document(sql.FieldLT(FieldID, id))
}
// IDLTE applies the LTE predicate on the ID field.
func IDLTE(id uuid.UUID) predicate.Document {
return predicate.Document(sql.FieldLTE(FieldID, id))
}
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
func CreatedAt(v time.Time) predicate.Document {
return predicate.Document(sql.FieldEQ(FieldCreatedAt, v))
}
// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ.
func UpdatedAt(v time.Time) predicate.Document {
return predicate.Document(sql.FieldEQ(FieldUpdatedAt, v))
}
// Title applies equality check predicate on the "title" field. It's identical to TitleEQ.
func Title(v string) predicate.Document {
return predicate.Document(sql.FieldEQ(FieldTitle, v))
}
// Path applies equality check predicate on the "path" field. It's identical to PathEQ.
func Path(v string) predicate.Document {
return predicate.Document(sql.FieldEQ(FieldPath, v))
}
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
func CreatedAtEQ(v time.Time) predicate.Document {
return predicate.Document(sql.FieldEQ(FieldCreatedAt, v))
}
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
func CreatedAtNEQ(v time.Time) predicate.Document {
return predicate.Document(sql.FieldNEQ(FieldCreatedAt, v))
}
// CreatedAtIn applies the In predicate on the "created_at" field.
func CreatedAtIn(vs ...time.Time) predicate.Document {
return predicate.Document(sql.FieldIn(FieldCreatedAt, vs...))
}
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
func CreatedAtNotIn(vs ...time.Time) predicate.Document {
return predicate.Document(sql.FieldNotIn(FieldCreatedAt, vs...))
}
// CreatedAtGT applies the GT predicate on the "created_at" field.
func CreatedAtGT(v time.Time) predicate.Document {
return predicate.Document(sql.FieldGT(FieldCreatedAt, v))
}
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
func CreatedAtGTE(v time.Time) predicate.Document {
return predicate.Document(sql.FieldGTE(FieldCreatedAt, v))
}
// CreatedAtLT applies the LT predicate on the "created_at" field.
func CreatedAtLT(v time.Time) predicate.Document {
return predicate.Document(sql.FieldLT(FieldCreatedAt, v))
}
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
func CreatedAtLTE(v time.Time) predicate.Document {
return predicate.Document(sql.FieldLTE(FieldCreatedAt, v))
}
// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
func UpdatedAtEQ(v time.Time) predicate.Document {
return predicate.Document(sql.FieldEQ(FieldUpdatedAt, v))
}
// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
func UpdatedAtNEQ(v time.Time) predicate.Document {
return predicate.Document(sql.FieldNEQ(FieldUpdatedAt, v))
}
// UpdatedAtIn applies the In predicate on the "updated_at" field.
func UpdatedAtIn(vs ...time.Time) predicate.Document {
return predicate.Document(sql.FieldIn(FieldUpdatedAt, vs...))
}
// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
func UpdatedAtNotIn(vs ...time.Time) predicate.Document {
return predicate.Document(sql.FieldNotIn(FieldUpdatedAt, vs...))
}
// UpdatedAtGT applies the GT predicate on the "updated_at" field.
func UpdatedAtGT(v time.Time) predicate.Document {
return predicate.Document(sql.FieldGT(FieldUpdatedAt, v))
}
// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
func UpdatedAtGTE(v time.Time) predicate.Document {
return predicate.Document(sql.FieldGTE(FieldUpdatedAt, v))
}
// UpdatedAtLT applies the LT predicate on the "updated_at" field.
func UpdatedAtLT(v time.Time) predicate.Document {
return predicate.Document(sql.FieldLT(FieldUpdatedAt, v))
}
// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
func UpdatedAtLTE(v time.Time) predicate.Document {
return predicate.Document(sql.FieldLTE(FieldUpdatedAt, v))
}
// TitleEQ applies the EQ predicate on the "title" field.
func TitleEQ(v string) predicate.Document {
return predicate.Document(sql.FieldEQ(FieldTitle, v))
}
// TitleNEQ applies the NEQ predicate on the "title" field.
func TitleNEQ(v string) predicate.Document {
return predicate.Document(sql.FieldNEQ(FieldTitle, v))
}
// TitleIn applies the In predicate on the "title" field.
func TitleIn(vs ...string) predicate.Document {
return predicate.Document(sql.FieldIn(FieldTitle, vs...))
}
// TitleNotIn applies the NotIn predicate on the "title" field.
func TitleNotIn(vs ...string) predicate.Document {
return predicate.Document(sql.FieldNotIn(FieldTitle, vs...))
}
// TitleGT applies the GT predicate on the "title" field.
func TitleGT(v string) predicate.Document {
return predicate.Document(sql.FieldGT(FieldTitle, v))
}
// TitleGTE applies the GTE predicate on the "title" field.
func TitleGTE(v string) predicate.Document {
return predicate.Document(sql.FieldGTE(FieldTitle, v))
}
// TitleLT applies the LT predicate on the "title" field.
func TitleLT(v string) predicate.Document {
return predicate.Document(sql.FieldLT(FieldTitle, v))
}
// TitleLTE applies the LTE predicate on the "title" field.
func TitleLTE(v string) predicate.Document {
return predicate.Document(sql.FieldLTE(FieldTitle, v))
}
// TitleContains applies the Contains predicate on the "title" field.
func TitleContains(v string) predicate.Document {
return predicate.Document(sql.FieldContains(FieldTitle, v))
}
// TitleHasPrefix applies the HasPrefix predicate on the "title" field.
func TitleHasPrefix(v string) predicate.Document {
return predicate.Document(sql.FieldHasPrefix(FieldTitle, v))
}
// TitleHasSuffix applies the HasSuffix predicate on the "title" field.
func TitleHasSuffix(v string) predicate.Document {
return predicate.Document(sql.FieldHasSuffix(FieldTitle, v))
}
// TitleEqualFold applies the EqualFold predicate on the "title" field.
func TitleEqualFold(v string) predicate.Document {
return predicate.Document(sql.FieldEqualFold(FieldTitle, v))
}
// TitleContainsFold applies the ContainsFold predicate on the "title" field.
func TitleContainsFold(v string) predicate.Document {
return predicate.Document(sql.FieldContainsFold(FieldTitle, v))
}
// PathEQ applies the EQ predicate on the "path" field.
func PathEQ(v string) predicate.Document {
return predicate.Document(sql.FieldEQ(FieldPath, v))
}
// PathNEQ applies the NEQ predicate on the "path" field.
func PathNEQ(v string) predicate.Document {
return predicate.Document(sql.FieldNEQ(FieldPath, v))
}
// PathIn applies the In predicate on the "path" field.
func PathIn(vs ...string) predicate.Document {
return predicate.Document(sql.FieldIn(FieldPath, vs...))
}
// PathNotIn applies the NotIn predicate on the "path" field.
func PathNotIn(vs ...string) predicate.Document {
return predicate.Document(sql.FieldNotIn(FieldPath, vs...))
}
// PathGT applies the GT predicate on the "path" field.
func PathGT(v string) predicate.Document {
return predicate.Document(sql.FieldGT(FieldPath, v))
}
// PathGTE applies the GTE predicate on the "path" field.
func PathGTE(v string) predicate.Document {
return predicate.Document(sql.FieldGTE(FieldPath, v))
}
// PathLT applies the LT predicate on the "path" field.
func PathLT(v string) predicate.Document {
return predicate.Document(sql.FieldLT(FieldPath, v))
}
// PathLTE applies the LTE predicate on the "path" field.
func PathLTE(v string) predicate.Document {
return predicate.Document(sql.FieldLTE(FieldPath, v))
}
// PathContains applies the Contains predicate on the "path" field.
func PathContains(v string) predicate.Document {
return predicate.Document(sql.FieldContains(FieldPath, v))
}
// PathHasPrefix applies the HasPrefix predicate on the "path" field.
func PathHasPrefix(v string) predicate.Document {
return predicate.Document(sql.FieldHasPrefix(FieldPath, v))
}
// PathHasSuffix applies the HasSuffix predicate on the "path" field.
func PathHasSuffix(v string) predicate.Document {
return predicate.Document(sql.FieldHasSuffix(FieldPath, v))
}
// PathEqualFold applies the EqualFold predicate on the "path" field.
func PathEqualFold(v string) predicate.Document {
return predicate.Document(sql.FieldEqualFold(FieldPath, v))
}
// PathContainsFold applies the ContainsFold predicate on the "path" field.
func PathContainsFold(v string) predicate.Document {
return predicate.Document(sql.FieldContainsFold(FieldPath, v))
}
// HasGroup applies the HasEdge predicate on the "group" edge.
func HasGroup() predicate.Document {
return predicate.Document(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn),
)
sqlgraph.HasNeighbors(s, step)
})
}
// 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()
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds {
p(s)
}
})
})
}
// HasAttachments applies the HasEdge predicate on the "attachments" edge.
func HasAttachments() predicate.Document {
return predicate.Document(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, AttachmentsTable, AttachmentsColumn),
)
sqlgraph.HasNeighbors(s, step)
})
}
// 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()
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds {
p(s)
}
})
})
}
// And groups predicates with the AND operator between them.
func And(predicates ...predicate.Document) predicate.Document {
return predicate.Document(sql.AndPredicates(predicates...))
}
// Or groups predicates with the OR operator between them.
func Or(predicates ...predicate.Document) predicate.Document {
return predicate.Document(sql.OrPredicates(predicates...))
}
// Not applies the not operator on the given predicate.
func Not(p predicate.Document) predicate.Document {
return predicate.Document(sql.NotPredicates(p))
}

View File

@@ -0,0 +1,351 @@
// Code generated by ent, DO NOT EDIT.
package ent
import (
"context"
"errors"
"fmt"
"time"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/google/uuid"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/attachment"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/document"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/group"
)
// DocumentCreate is the builder for creating a Document entity.
type DocumentCreate struct {
config
mutation *DocumentMutation
hooks []Hook
}
// SetCreatedAt sets the "created_at" field.
func (dc *DocumentCreate) SetCreatedAt(t time.Time) *DocumentCreate {
dc.mutation.SetCreatedAt(t)
return dc
}
// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
func (dc *DocumentCreate) SetNillableCreatedAt(t *time.Time) *DocumentCreate {
if t != nil {
dc.SetCreatedAt(*t)
}
return dc
}
// SetUpdatedAt sets the "updated_at" field.
func (dc *DocumentCreate) SetUpdatedAt(t time.Time) *DocumentCreate {
dc.mutation.SetUpdatedAt(t)
return dc
}
// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil.
func (dc *DocumentCreate) SetNillableUpdatedAt(t *time.Time) *DocumentCreate {
if t != nil {
dc.SetUpdatedAt(*t)
}
return dc
}
// SetTitle sets the "title" field.
func (dc *DocumentCreate) SetTitle(s string) *DocumentCreate {
dc.mutation.SetTitle(s)
return dc
}
// SetPath sets the "path" field.
func (dc *DocumentCreate) SetPath(s string) *DocumentCreate {
dc.mutation.SetPath(s)
return dc
}
// SetID sets the "id" field.
func (dc *DocumentCreate) SetID(u uuid.UUID) *DocumentCreate {
dc.mutation.SetID(u)
return dc
}
// SetNillableID sets the "id" field if the given value is not nil.
func (dc *DocumentCreate) SetNillableID(u *uuid.UUID) *DocumentCreate {
if u != nil {
dc.SetID(*u)
}
return dc
}
// SetGroupID sets the "group" edge to the Group entity by ID.
func (dc *DocumentCreate) SetGroupID(id uuid.UUID) *DocumentCreate {
dc.mutation.SetGroupID(id)
return dc
}
// SetGroup sets the "group" edge to the Group entity.
func (dc *DocumentCreate) SetGroup(g *Group) *DocumentCreate {
return dc.SetGroupID(g.ID)
}
// AddAttachmentIDs adds the "attachments" edge to the Attachment entity by IDs.
func (dc *DocumentCreate) AddAttachmentIDs(ids ...uuid.UUID) *DocumentCreate {
dc.mutation.AddAttachmentIDs(ids...)
return dc
}
// AddAttachments adds the "attachments" edges to the Attachment entity.
func (dc *DocumentCreate) AddAttachments(a ...*Attachment) *DocumentCreate {
ids := make([]uuid.UUID, len(a))
for i := range a {
ids[i] = a[i].ID
}
return dc.AddAttachmentIDs(ids...)
}
// Mutation returns the DocumentMutation object of the builder.
func (dc *DocumentCreate) Mutation() *DocumentMutation {
return dc.mutation
}
// 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)
}
// SaveX calls Save and panics if Save returns an error.
func (dc *DocumentCreate) SaveX(ctx context.Context) *Document {
v, err := dc.Save(ctx)
if err != nil {
panic(err)
}
return v
}
// Exec executes the query.
func (dc *DocumentCreate) Exec(ctx context.Context) error {
_, err := dc.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (dc *DocumentCreate) ExecX(ctx context.Context) {
if err := dc.Exec(ctx); err != nil {
panic(err)
}
}
// defaults sets the default values of the builder before save.
func (dc *DocumentCreate) defaults() {
if _, ok := dc.mutation.CreatedAt(); !ok {
v := document.DefaultCreatedAt()
dc.mutation.SetCreatedAt(v)
}
if _, ok := dc.mutation.UpdatedAt(); !ok {
v := document.DefaultUpdatedAt()
dc.mutation.SetUpdatedAt(v)
}
if _, ok := dc.mutation.ID(); !ok {
v := document.DefaultID()
dc.mutation.SetID(v)
}
}
// check runs all checks and user-defined validators on the builder.
func (dc *DocumentCreate) check() error {
if _, ok := dc.mutation.CreatedAt(); !ok {
return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "Document.created_at"`)}
}
if _, ok := dc.mutation.UpdatedAt(); !ok {
return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "Document.updated_at"`)}
}
if _, ok := dc.mutation.Title(); !ok {
return &ValidationError{Name: "title", err: errors.New(`ent: missing required field "Document.title"`)}
}
if v, ok := dc.mutation.Title(); ok {
if err := document.TitleValidator(v); err != nil {
return &ValidationError{Name: "title", err: fmt.Errorf(`ent: validator failed for field "Document.title": %w`, err)}
}
}
if _, ok := dc.mutation.Path(); !ok {
return &ValidationError{Name: "path", err: errors.New(`ent: missing required field "Document.path"`)}
}
if v, ok := dc.mutation.Path(); ok {
if err := document.PathValidator(v); err != nil {
return &ValidationError{Name: "path", err: fmt.Errorf(`ent: validator failed for field "Document.path": %w`, err)}
}
}
if len(dc.mutation.GroupIDs()) == 0 {
return &ValidationError{Name: "group", err: errors.New(`ent: missing required edge "Document.group"`)}
}
return nil
}
func (dc *DocumentCreate) sqlSave(ctx context.Context) (*Document, error) {
if err := dc.check(); err != nil {
return nil, err
}
_node, _spec := dc.createSpec()
if err := sqlgraph.CreateNode(ctx, dc.driver, _spec); err != nil {
if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
return nil, err
}
if _spec.ID.Value != nil {
if id, ok := _spec.ID.Value.(*uuid.UUID); ok {
_node.ID = *id
} else if err := _node.ID.Scan(_spec.ID.Value); err != nil {
return nil, err
}
}
dc.mutation.id = &_node.ID
dc.mutation.done = true
return _node, nil
}
func (dc *DocumentCreate) createSpec() (*Document, *sqlgraph.CreateSpec) {
var (
_node = &Document{config: dc.config}
_spec = sqlgraph.NewCreateSpec(document.Table, sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID))
)
if id, ok := dc.mutation.ID(); ok {
_node.ID = id
_spec.ID.Value = &id
}
if value, ok := dc.mutation.CreatedAt(); ok {
_spec.SetField(document.FieldCreatedAt, field.TypeTime, value)
_node.CreatedAt = value
}
if value, ok := dc.mutation.UpdatedAt(); ok {
_spec.SetField(document.FieldUpdatedAt, field.TypeTime, value)
_node.UpdatedAt = value
}
if value, ok := dc.mutation.Title(); ok {
_spec.SetField(document.FieldTitle, field.TypeString, value)
_node.Title = value
}
if value, ok := dc.mutation.Path(); ok {
_spec.SetField(document.FieldPath, field.TypeString, value)
_node.Path = value
}
if nodes := dc.mutation.GroupIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: document.GroupTable,
Columns: []string{document.GroupColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_node.group_documents = &nodes[0]
_spec.Edges = append(_spec.Edges, edge)
}
if nodes := dc.mutation.AttachmentsIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: document.AttachmentsTable,
Columns: []string{document.AttachmentsColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges = append(_spec.Edges, edge)
}
return _node, _spec
}
// 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))
for i := range dcb.builders {
func(i int, root context.Context) {
builder := dcb.builders[i]
builder.defaults()
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
mutation, ok := m.(*DocumentMutation)
if !ok {
return nil, fmt.Errorf("unexpected mutation type %T", m)
}
if err := builder.check(); err != nil {
return nil, err
}
builder.mutation = mutation
var err error
nodes[i], specs[i] = builder.createSpec()
if i < len(mutators)-1 {
_, err = mutators[i+1].Mutate(root, dcb.builders[i+1].mutation)
} else {
spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
// Invoke the actual operation on the latest mutation in the chain.
if err = sqlgraph.BatchCreate(ctx, dcb.driver, spec); err != nil {
if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
}
}
if err != nil {
return nil, err
}
mutation.id = &nodes[i].ID
mutation.done = true
return nodes[i], nil
})
for i := len(builder.hooks) - 1; i >= 0; i-- {
mut = builder.hooks[i](mut)
}
mutators[i] = mut
}(i, ctx)
}
if len(mutators) > 0 {
if _, err := mutators[0].Mutate(ctx, dcb.builders[0].mutation); err != nil {
return nil, err
}
}
return nodes, nil
}
// SaveX is like Save, but panics if an error occurs.
func (dcb *DocumentCreateBulk) SaveX(ctx context.Context) []*Document {
v, err := dcb.Save(ctx)
if err != nil {
panic(err)
}
return v
}
// Exec executes the query.
func (dcb *DocumentCreateBulk) Exec(ctx context.Context) error {
_, err := dcb.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (dcb *DocumentCreateBulk) ExecX(ctx context.Context) {
if err := dcb.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -0,0 +1,88 @@
// Code generated by ent, DO NOT EDIT.
package ent
import (
"context"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/document"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/predicate"
)
// DocumentDelete is the builder for deleting a Document entity.
type DocumentDelete struct {
config
hooks []Hook
mutation *DocumentMutation
}
// Where appends a list predicates to the DocumentDelete builder.
func (dd *DocumentDelete) Where(ps ...predicate.Document) *DocumentDelete {
dd.mutation.Where(ps...)
return dd
}
// 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)
}
// ExecX is like Exec, but panics if an error occurs.
func (dd *DocumentDelete) ExecX(ctx context.Context) int {
n, err := dd.Exec(ctx)
if err != nil {
panic(err)
}
return n
}
func (dd *DocumentDelete) sqlExec(ctx context.Context) (int, error) {
_spec := sqlgraph.NewDeleteSpec(document.Table, sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID))
if ps := dd.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
affected, err := sqlgraph.DeleteNodes(ctx, dd.driver, _spec)
if err != nil && sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
dd.mutation.done = true
return affected, err
}
// DocumentDeleteOne is the builder for deleting a single Document entity.
type DocumentDeleteOne struct {
dd *DocumentDelete
}
// Where appends a list predicates to the DocumentDelete builder.
func (ddo *DocumentDeleteOne) Where(ps ...predicate.Document) *DocumentDeleteOne {
ddo.dd.mutation.Where(ps...)
return ddo
}
// Exec executes the deletion query.
func (ddo *DocumentDeleteOne) Exec(ctx context.Context) error {
n, err := ddo.dd.Exec(ctx)
switch {
case err != nil:
return err
case n == 0:
return &NotFoundError{document.Label}
default:
return nil
}
}
// ExecX is like Exec, but panics if an error occurs.
func (ddo *DocumentDeleteOne) ExecX(ctx context.Context) {
if err := ddo.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -0,0 +1,691 @@
// Code generated by ent, DO NOT EDIT.
package ent
import (
"context"
"database/sql/driver"
"fmt"
"math"
"entgo.io/ent"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/google/uuid"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/attachment"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/document"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/group"
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/predicate"
)
// DocumentQuery is the builder for querying Document entities.
type DocumentQuery struct {
config
ctx *QueryContext
order []document.OrderOption
inters []Interceptor
predicates []predicate.Document
withGroup *GroupQuery
withAttachments *AttachmentQuery
withFKs bool
// intermediate query (i.e. traversal path).
sql *sql.Selector
path func(context.Context) (*sql.Selector, error)
}
// Where adds a new predicate for the DocumentQuery builder.
func (dq *DocumentQuery) Where(ps ...predicate.Document) *DocumentQuery {
dq.predicates = append(dq.predicates, ps...)
return dq
}
// Limit the number of records to be returned by this query.
func (dq *DocumentQuery) Limit(limit int) *DocumentQuery {
dq.ctx.Limit = &limit
return dq
}
// Offset to start from.
func (dq *DocumentQuery) Offset(offset int) *DocumentQuery {
dq.ctx.Offset = &offset
return dq
}
// Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method.
func (dq *DocumentQuery) Unique(unique bool) *DocumentQuery {
dq.ctx.Unique = &unique
return dq
}
// Order specifies how the records should be ordered.
func (dq *DocumentQuery) Order(o ...document.OrderOption) *DocumentQuery {
dq.order = append(dq.order, o...)
return dq
}
// QueryGroup chains the current query on the "group" edge.
func (dq *DocumentQuery) QueryGroup() *GroupQuery {
query := (&GroupClient{config: dq.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := dq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := dq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(document.Table, document.FieldID, selector),
sqlgraph.To(group.Table, group.FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, document.GroupTable, document.GroupColumn),
)
fromU = sqlgraph.SetNeighbors(dq.driver.Dialect(), step)
return fromU, nil
}
return query
}
// QueryAttachments chains the current query on the "attachments" edge.
func (dq *DocumentQuery) QueryAttachments() *AttachmentQuery {
query := (&AttachmentClient{config: dq.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := dq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := dq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(document.Table, document.FieldID, selector),
sqlgraph.To(attachment.Table, attachment.FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, document.AttachmentsTable, document.AttachmentsColumn),
)
fromU = sqlgraph.SetNeighbors(dq.driver.Dialect(), step)
return fromU, nil
}
return query
}
// First returns the first Document entity from the query.
// Returns a *NotFoundError when no Document was found.
func (dq *DocumentQuery) First(ctx context.Context) (*Document, error) {
nodes, err := dq.Limit(1).All(setContextOp(ctx, dq.ctx, ent.OpQueryFirst))
if err != nil {
return nil, err
}
if len(nodes) == 0 {
return nil, &NotFoundError{document.Label}
}
return nodes[0], nil
}
// FirstX is like First, but panics if an error occurs.
func (dq *DocumentQuery) FirstX(ctx context.Context) *Document {
node, err := dq.First(ctx)
if err != nil && !IsNotFound(err) {
panic(err)
}
return node
}
// FirstID returns the first Document ID from the query.
// Returns a *NotFoundError when no Document ID was found.
func (dq *DocumentQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = dq.Limit(1).IDs(setContextOp(ctx, dq.ctx, ent.OpQueryFirstID)); err != nil {
return
}
if len(ids) == 0 {
err = &NotFoundError{document.Label}
return
}
return ids[0], nil
}
// FirstIDX is like FirstID, but panics if an error occurs.
func (dq *DocumentQuery) FirstIDX(ctx context.Context) uuid.UUID {
id, err := dq.FirstID(ctx)
if err != nil && !IsNotFound(err) {
panic(err)
}
return id
}
// Only returns a single Document entity found by the query, ensuring it only returns one.
// Returns a *NotSingularError when more than one Document entity is found.
// Returns a *NotFoundError when no Document entities are found.
func (dq *DocumentQuery) Only(ctx context.Context) (*Document, error) {
nodes, err := dq.Limit(2).All(setContextOp(ctx, dq.ctx, ent.OpQueryOnly))
if err != nil {
return nil, err
}
switch len(nodes) {
case 1:
return nodes[0], nil
case 0:
return nil, &NotFoundError{document.Label}
default:
return nil, &NotSingularError{document.Label}
}
}
// OnlyX is like Only, but panics if an error occurs.
func (dq *DocumentQuery) OnlyX(ctx context.Context) *Document {
node, err := dq.Only(ctx)
if err != nil {
panic(err)
}
return node
}
// OnlyID is like Only, but returns the only Document ID in the query.
// Returns a *NotSingularError when more than one Document ID is found.
// Returns a *NotFoundError when no entities are found.
func (dq *DocumentQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) {
var ids []uuid.UUID
if ids, err = dq.Limit(2).IDs(setContextOp(ctx, dq.ctx, ent.OpQueryOnlyID)); err != nil {
return
}
switch len(ids) {
case 1:
id = ids[0]
case 0:
err = &NotFoundError{document.Label}
default:
err = &NotSingularError{document.Label}
}
return
}
// OnlyIDX is like OnlyID, but panics if an error occurs.
func (dq *DocumentQuery) OnlyIDX(ctx context.Context) uuid.UUID {
id, err := dq.OnlyID(ctx)
if err != nil {
panic(err)
}
return id
}
// All executes the query and returns a list of Documents.
func (dq *DocumentQuery) All(ctx context.Context) ([]*Document, error) {
ctx = setContextOp(ctx, dq.ctx, ent.OpQueryAll)
if err := dq.prepareQuery(ctx); err != nil {
return nil, err
}
qr := querierAll[[]*Document, *DocumentQuery]()
return withInterceptors[[]*Document](ctx, dq, qr, dq.inters)
}
// AllX is like All, but panics if an error occurs.
func (dq *DocumentQuery) AllX(ctx context.Context) []*Document {
nodes, err := dq.All(ctx)
if err != nil {
panic(err)
}
return nodes
}
// IDs executes the query and returns a list of Document IDs.
func (dq *DocumentQuery) IDs(ctx context.Context) (ids []uuid.UUID, err error) {
if dq.ctx.Unique == nil && dq.path != nil {
dq.Unique(true)
}
ctx = setContextOp(ctx, dq.ctx, ent.OpQueryIDs)
if err = dq.Select(document.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
return ids, nil
}
// IDsX is like IDs, but panics if an error occurs.
func (dq *DocumentQuery) IDsX(ctx context.Context) []uuid.UUID {
ids, err := dq.IDs(ctx)
if err != nil {
panic(err)
}
return ids
}
// Count returns the count of the given query.
func (dq *DocumentQuery) Count(ctx context.Context) (int, error) {
ctx = setContextOp(ctx, dq.ctx, ent.OpQueryCount)
if err := dq.prepareQuery(ctx); err != nil {
return 0, err
}
return withInterceptors[int](ctx, dq, querierCount[*DocumentQuery](), dq.inters)
}
// CountX is like Count, but panics if an error occurs.
func (dq *DocumentQuery) CountX(ctx context.Context) int {
count, err := dq.Count(ctx)
if err != nil {
panic(err)
}
return count
}
// Exist returns true if the query has elements in the graph.
func (dq *DocumentQuery) Exist(ctx context.Context) (bool, error) {
ctx = setContextOp(ctx, dq.ctx, ent.OpQueryExist)
switch _, err := dq.FirstID(ctx); {
case IsNotFound(err):
return false, nil
case err != nil:
return false, fmt.Errorf("ent: check existence: %w", err)
default:
return true, nil
}
}
// ExistX is like Exist, but panics if an error occurs.
func (dq *DocumentQuery) ExistX(ctx context.Context) bool {
exist, err := dq.Exist(ctx)
if err != nil {
panic(err)
}
return exist
}
// Clone returns a duplicate of the DocumentQuery builder, including all associated steps. It can be
// used to prepare common query builders and use them differently after the clone is made.
func (dq *DocumentQuery) Clone() *DocumentQuery {
if dq == nil {
return nil
}
return &DocumentQuery{
config: dq.config,
ctx: dq.ctx.Clone(),
order: append([]document.OrderOption{}, dq.order...),
inters: append([]Interceptor{}, dq.inters...),
predicates: append([]predicate.Document{}, dq.predicates...),
withGroup: dq.withGroup.Clone(),
withAttachments: dq.withAttachments.Clone(),
// clone intermediate query.
sql: dq.sql.Clone(),
path: dq.path,
}
}
// WithGroup tells the query-builder to eager-load the nodes that are connected to
// the "group" edge. The optional arguments are used to configure the query builder of the edge.
func (dq *DocumentQuery) WithGroup(opts ...func(*GroupQuery)) *DocumentQuery {
query := (&GroupClient{config: dq.config}).Query()
for _, opt := range opts {
opt(query)
}
dq.withGroup = query
return dq
}
// WithAttachments tells the query-builder to eager-load the nodes that are connected to
// the "attachments" edge. The optional arguments are used to configure the query builder of the edge.
func (dq *DocumentQuery) WithAttachments(opts ...func(*AttachmentQuery)) *DocumentQuery {
query := (&AttachmentClient{config: dq.config}).Query()
for _, opt := range opts {
opt(query)
}
dq.withAttachments = query
return dq
}
// GroupBy is used to group vertices by one or more fields/columns.
// It is often used with aggregate functions, like: count, max, mean, min, sum.
//
// Example:
//
// var v []struct {
// CreatedAt time.Time `json:"created_at,omitempty"`
// Count int `json:"count,omitempty"`
// }
//
// client.Document.Query().
// GroupBy(document.FieldCreatedAt).
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (dq *DocumentQuery) GroupBy(field string, fields ...string) *DocumentGroupBy {
dq.ctx.Fields = append([]string{field}, fields...)
grbuild := &DocumentGroupBy{build: dq}
grbuild.flds = &dq.ctx.Fields
grbuild.label = document.Label
grbuild.scan = grbuild.Scan
return grbuild
}
// Select allows the selection one or more fields/columns for the given query,
// instead of selecting all fields in the entity.
//
// Example:
//
// var v []struct {
// CreatedAt time.Time `json:"created_at,omitempty"`
// }
//
// client.Document.Query().
// Select(document.FieldCreatedAt).
// Scan(ctx, &v)
func (dq *DocumentQuery) Select(fields ...string) *DocumentSelect {
dq.ctx.Fields = append(dq.ctx.Fields, fields...)
sbuild := &DocumentSelect{DocumentQuery: dq}
sbuild.label = document.Label
sbuild.flds, sbuild.scan = &dq.ctx.Fields, sbuild.Scan
return sbuild
}
// Aggregate returns a DocumentSelect configured with the given aggregations.
func (dq *DocumentQuery) Aggregate(fns ...AggregateFunc) *DocumentSelect {
return dq.Select().Aggregate(fns...)
}
func (dq *DocumentQuery) prepareQuery(ctx context.Context) error {
for _, inter := range dq.inters {
if inter == nil {
return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)")
}
if trv, ok := inter.(Traverser); ok {
if err := trv.Traverse(ctx, dq); err != nil {
return err
}
}
}
for _, f := range dq.ctx.Fields {
if !document.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
}
if dq.path != nil {
prev, err := dq.path(ctx)
if err != nil {
return err
}
dq.sql = prev
}
return nil
}
func (dq *DocumentQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Document, error) {
var (
nodes = []*Document{}
withFKs = dq.withFKs
_spec = dq.querySpec()
loadedTypes = [2]bool{
dq.withGroup != nil,
dq.withAttachments != nil,
}
)
if dq.withGroup != nil {
withFKs = true
}
if withFKs {
_spec.Node.Columns = append(_spec.Node.Columns, document.ForeignKeys...)
}
_spec.ScanValues = func(columns []string) ([]any, error) {
return (*Document).scanValues(nil, columns)
}
_spec.Assign = func(columns []string, values []any) error {
node := &Document{config: dq.config}
nodes = append(nodes, node)
node.Edges.loadedTypes = loadedTypes
return node.assignValues(columns, values)
}
for i := range hooks {
hooks[i](ctx, _spec)
}
if err := sqlgraph.QueryNodes(ctx, dq.driver, _spec); err != nil {
return nil, err
}
if len(nodes) == 0 {
return nodes, nil
}
if query := dq.withGroup; query != nil {
if err := dq.loadGroup(ctx, query, nodes, nil,
func(n *Document, e *Group) { n.Edges.Group = e }); err != nil {
return nil, err
}
}
if query := dq.withAttachments; query != nil {
if err := dq.loadAttachments(ctx, query, nodes,
func(n *Document) { n.Edges.Attachments = []*Attachment{} },
func(n *Document, e *Attachment) { n.Edges.Attachments = append(n.Edges.Attachments, e) }); err != nil {
return nil, err
}
}
return nodes, nil
}
func (dq *DocumentQuery) loadGroup(ctx context.Context, query *GroupQuery, nodes []*Document, init func(*Document), assign func(*Document, *Group)) error {
ids := make([]uuid.UUID, 0, len(nodes))
nodeids := make(map[uuid.UUID][]*Document)
for i := range nodes {
if nodes[i].group_documents == nil {
continue
}
fk := *nodes[i].group_documents
if _, ok := nodeids[fk]; !ok {
ids = append(ids, fk)
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(group.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
nodes, ok := nodeids[n.ID]
if !ok {
return fmt.Errorf(`unexpected foreign-key "group_documents" returned %v`, n.ID)
}
for i := range nodes {
assign(nodes[i], n)
}
}
return nil
}
func (dq *DocumentQuery) loadAttachments(ctx context.Context, query *AttachmentQuery, nodes []*Document, init func(*Document), assign func(*Document, *Attachment)) error {
fks := make([]driver.Value, 0, len(nodes))
nodeids := make(map[uuid.UUID]*Document)
for i := range nodes {
fks = append(fks, nodes[i].ID)
nodeids[nodes[i].ID] = nodes[i]
if init != nil {
init(nodes[i])
}
}
query.withFKs = true
query.Where(predicate.Attachment(func(s *sql.Selector) {
s.Where(sql.InValues(s.C(document.AttachmentsColumn), fks...))
}))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
fk := n.document_attachments
if fk == nil {
return fmt.Errorf(`foreign-key "document_attachments" is nil for node %v`, n.ID)
}
node, ok := nodeids[*fk]
if !ok {
return fmt.Errorf(`unexpected referenced foreign-key "document_attachments" returned %v for node %v`, *fk, n.ID)
}
assign(node, n)
}
return nil
}
func (dq *DocumentQuery) sqlCount(ctx context.Context) (int, error) {
_spec := dq.querySpec()
_spec.Node.Columns = dq.ctx.Fields
if len(dq.ctx.Fields) > 0 {
_spec.Unique = dq.ctx.Unique != nil && *dq.ctx.Unique
}
return sqlgraph.CountNodes(ctx, dq.driver, _spec)
}
func (dq *DocumentQuery) querySpec() *sqlgraph.QuerySpec {
_spec := sqlgraph.NewQuerySpec(document.Table, document.Columns, sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID))
_spec.From = dq.sql
if unique := dq.ctx.Unique; unique != nil {
_spec.Unique = *unique
} else if dq.path != nil {
_spec.Unique = true
}
if fields := dq.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, document.FieldID)
for i := range fields {
if fields[i] != document.FieldID {
_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
}
}
}
if ps := dq.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if limit := dq.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := dq.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := dq.order; len(ps) > 0 {
_spec.Order = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
return _spec
}
func (dq *DocumentQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(dq.driver.Dialect())
t1 := builder.Table(document.Table)
columns := dq.ctx.Fields
if len(columns) == 0 {
columns = document.Columns
}
selector := builder.Select(t1.Columns(columns...)...).From(t1)
if dq.sql != nil {
selector = dq.sql
selector.Select(selector.Columns(columns...)...)
}
if dq.ctx.Unique != nil && *dq.ctx.Unique {
selector.Distinct()
}
for _, p := range dq.predicates {
p(selector)
}
for _, p := range dq.order {
p(selector)
}
if offset := dq.ctx.Offset; offset != nil {
// limit is mandatory for offset clause. We start
// with default value, and override it below if needed.
selector.Offset(*offset).Limit(math.MaxInt32)
}
if limit := dq.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
}
// DocumentGroupBy is the group-by builder for Document entities.
type DocumentGroupBy struct {
selector
build *DocumentQuery
}
// Aggregate adds the given aggregation functions to the group-by query.
func (dgb *DocumentGroupBy) Aggregate(fns ...AggregateFunc) *DocumentGroupBy {
dgb.fns = append(dgb.fns, fns...)
return dgb
}
// Scan applies the selector query and scans the result into the given value.
func (dgb *DocumentGroupBy) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, dgb.build.ctx, ent.OpQueryGroupBy)
if err := dgb.build.prepareQuery(ctx); err != nil {
return err
}
return scanWithInterceptors[*DocumentQuery, *DocumentGroupBy](ctx, dgb.build, dgb, dgb.build.inters, v)
}
func (dgb *DocumentGroupBy) sqlScan(ctx context.Context, root *DocumentQuery, v any) error {
selector := root.sqlQuery(ctx).Select()
aggregation := make([]string, 0, len(dgb.fns))
for _, fn := range dgb.fns {
aggregation = append(aggregation, fn(selector))
}
if len(selector.SelectedColumns()) == 0 {
columns := make([]string, 0, len(*dgb.flds)+len(dgb.fns))
for _, f := range *dgb.flds {
columns = append(columns, selector.C(f))
}
columns = append(columns, aggregation...)
selector.Select(columns...)
}
selector.GroupBy(selector.Columns(*dgb.flds...)...)
if err := selector.Err(); err != nil {
return err
}
rows := &sql.Rows{}
query, args := selector.Query()
if err := dgb.build.driver.Query(ctx, query, args, rows); err != nil {
return err
}
defer rows.Close()
return sql.ScanSlice(rows, v)
}
// DocumentSelect is the builder for selecting fields of Document entities.
type DocumentSelect struct {
*DocumentQuery
selector
}
// Aggregate adds the given aggregation functions to the selector query.
func (ds *DocumentSelect) Aggregate(fns ...AggregateFunc) *DocumentSelect {
ds.fns = append(ds.fns, fns...)
return ds
}
// Scan applies the selector query and scans the result into the given value.
func (ds *DocumentSelect) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, ds.ctx, ent.OpQuerySelect)
if err := ds.prepareQuery(ctx); err != nil {
return err
}
return scanWithInterceptors[*DocumentQuery, *DocumentSelect](ctx, ds.DocumentQuery, ds, ds.inters, v)
}
func (ds *DocumentSelect) sqlScan(ctx context.Context, root *DocumentQuery, v any) error {
selector := root.sqlQuery(ctx)
aggregation := make([]string, 0, len(ds.fns))
for _, fn := range ds.fns {
aggregation = append(aggregation, fn(selector))
}
switch n := len(*ds.selector.flds); {
case n == 0 && len(aggregation) > 0:
selector.Select(aggregation...)
case n != 0 && len(aggregation) > 0:
selector.AppendSelect(aggregation...)
}
rows := &sql.Rows{}
query, args := selector.Query()
if err := ds.driver.Query(ctx, query, args, rows); err != nil {
return err
}
defer rows.Close()
return sql.ScanSlice(rows, v)
}

Some files were not shown because too many files have changed in this diff Show More