mirror of
https://github.com/sysadminsmedia/homebox.git
synced 2025-12-27 15:41:42 +01:00
Compare commits
202 Commits
v0.5.1
...
fix/web-so
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2cd107b8bd | ||
|
|
a3cce59a2a | ||
|
|
9fa17bec90 | ||
|
|
b5987f2e8d | ||
|
|
2cbcc8bb1d | ||
|
|
cceec06148 | ||
|
|
2e2eed143d | ||
|
|
272cc5a370 | ||
|
|
275e106d72 | ||
|
|
3f0e65a2ad | ||
|
|
22bbaae08f | ||
|
|
8c7d91ea52 | ||
|
|
5a219f6a9c | ||
|
|
895017b28e | ||
|
|
02ce52dbe3 | ||
|
|
c5ae6b17f9 | ||
|
|
371fc0a6af | ||
|
|
016780920d | ||
|
|
06eb6c1f91 | ||
|
|
27dad0e118 | ||
|
|
dc9446516a | ||
|
|
a042496c71 | ||
|
|
feab9f4c46 | ||
|
|
fe5622d62a | ||
|
|
e759f2817e | ||
|
|
60cc5c2710 | ||
|
|
25ccd678c9 | ||
|
|
a77b4cbe71 | ||
|
|
aae32b0d74 | ||
|
|
a94b43a19e | ||
|
|
9a4c2df552 | ||
|
|
d5b89a755e | ||
|
|
a9acf62d93 | ||
|
|
c896e198dd | ||
|
|
c538518b4b | ||
|
|
f66d14eeea | ||
|
|
bc8feac83c | ||
|
|
40a98bcf30 | ||
|
|
045e91d9ac | ||
|
|
a80ab0f3e9 | ||
|
|
e5d209d407 | ||
|
|
ef1531e561 | ||
|
|
4dd036abb2 | ||
|
|
81e909ccfb | ||
|
|
0cb9d2a8e4 | ||
|
|
cb16c0e829 | ||
|
|
9e067ee230 | ||
|
|
8b53d40a2a | ||
|
|
4c0ad7a5d8 | ||
|
|
66e25ba068 | ||
|
|
56c98e6e3a | ||
|
|
01f305a98e | ||
|
|
e14cdaccdd | ||
|
|
4ece25b58d | ||
|
|
c1957bb927 | ||
|
|
636ca155e5 | ||
|
|
17a5b43609 | ||
|
|
b2b3ccf923 | ||
|
|
2272c7eb6b | ||
|
|
181c324dd4 | ||
|
|
89912b18d7 | ||
|
|
85f2af4bc3 | ||
|
|
21ad5a32c1 | ||
|
|
4b51a4ad9a | ||
|
|
dd7e634b69 | ||
|
|
351ec64bbc | ||
|
|
3a758e012f | ||
|
|
c16084d99f | ||
|
|
5591267124 | ||
|
|
d46c16f01f | ||
|
|
18c22e8a68 | ||
|
|
64b3ac3e94 | ||
|
|
c36b9dcf5d | ||
|
|
d3b6c93b63 | ||
|
|
3b862e36c8 | ||
|
|
f3bb86d905 | ||
|
|
4dd925caf0 | ||
|
|
ced5aef6d1 | ||
|
|
6a853c07a0 | ||
|
|
f0b9a0fce4 | ||
|
|
00f09fec2f | ||
|
|
6e1863b515 | ||
|
|
dfe2084c74 | ||
|
|
0825f055a7 | ||
|
|
e1e04d49aa | ||
|
|
9020587c9e | ||
|
|
bd0db1ea37 | ||
|
|
d2985ff72c | ||
|
|
8c57ff841e | ||
|
|
0264bfb8c1 | ||
|
|
5dd6844536 | ||
|
|
0f8db862b4 | ||
|
|
be6b5c9c56 | ||
|
|
faed343eda | ||
|
|
ed1230e17d | ||
|
|
2d768e2b9c | ||
|
|
40e76bac0c | ||
|
|
840d220d4f | ||
|
|
975e636fb6 | ||
|
|
d1076baf84 | ||
|
|
40fcef4e9b | ||
|
|
97fb94d231 | ||
|
|
4a8ba6231d | ||
|
|
db80f8a159 | ||
|
|
184b494fc3 | ||
|
|
5a3fa23332 | ||
|
|
ef0690d511 | ||
|
|
9e55c880f6 | ||
|
|
cb9b20e2d2 | ||
|
|
a79e780b4e | ||
|
|
90cbb9bfd1 | ||
|
|
dc08dbbd7a | ||
|
|
1f47d96e4c | ||
|
|
23b5892aef | ||
|
|
2665b666f1 | ||
|
|
14315cb88a | ||
|
|
cf536393f5 | ||
|
|
025521431e | ||
|
|
70297b9d27 | ||
|
|
729293745f | ||
|
|
a6bcb36c5b | ||
|
|
a005fa5b9b | ||
|
|
a2dfa9dcef | ||
|
|
32216f63bd | ||
|
|
ef190e26df | ||
|
|
c3e3702a7e | ||
|
|
fb57120067 | ||
|
|
9d9b05d8a6 | ||
|
|
3ac6c7c858 | ||
|
|
859d3b9ffe | ||
|
|
6cfa6c9fc8 | ||
|
|
12975ce26e | ||
|
|
bd321af29f | ||
|
|
88f9ff90d4 | ||
|
|
354f1adbee | ||
|
|
2a62a43493 | ||
|
|
673db41f37 | ||
|
|
830ce2b0a9 | ||
|
|
e8e6a425dd | ||
|
|
da00db0608 | ||
|
|
efd7069fe4 | ||
|
|
dd349aa98e | ||
|
|
607b06d2f2 | ||
|
|
44f13f751a | ||
|
|
986d2c586e | ||
|
|
9361997a42 | ||
|
|
2e96d8c4c2 | ||
|
|
ff75daf6b3 | ||
|
|
c0953bbd26 | ||
|
|
1f7e917c70 | ||
|
|
6ff2d64996 | ||
|
|
ab22ea6a25 | ||
|
|
ce2fc7712a | ||
|
|
bd933af874 | ||
|
|
f36f17b57d | ||
|
|
504569bed0 | ||
|
|
bd06fdafaf | ||
|
|
7b28973c60 | ||
|
|
cbac17c059 | ||
|
|
6ed1f3695a | ||
|
|
3d295b5132 | ||
|
|
4d220cdd9c | ||
|
|
ad20e4e39b | ||
|
|
3e2f6a96bf | ||
|
|
2ece97c42a | ||
|
|
a8ee4d421b | ||
|
|
91d0c588d9 | ||
|
|
c19fe94c08 | ||
|
|
f532b39c46 | ||
|
|
243742a75c | ||
|
|
2b7c1fa429 | ||
|
|
125b8f5ecd | ||
|
|
580de45cec | ||
|
|
da52b4ec64 | ||
|
|
5b0dba854d | ||
|
|
984c1a08ac | ||
|
|
8419a17109 | ||
|
|
f3406eec19 | ||
|
|
3ed07a909f | ||
|
|
07441eec8e | ||
|
|
c78f10ba5d | ||
|
|
490a0ece86 | ||
|
|
891d41b75f | ||
|
|
58d6f9a28c | ||
|
|
6a8a25e3f8 | ||
|
|
a3954dab0f | ||
|
|
08d483d907 | ||
|
|
a53f89ceac | ||
|
|
5bbb969763 | ||
|
|
d6da63187b | ||
|
|
de419dc37d | ||
|
|
974d6914a2 | ||
|
|
d2aa022347 | ||
|
|
6af048dc93 | ||
|
|
73c42f4784 | ||
|
|
f42a917390 | ||
|
|
f149c3e4ab | ||
|
|
1dc1ee54e2 | ||
|
|
e8f215ce34 | ||
|
|
1aafbcd201 | ||
|
|
6dc2ae1bea | ||
|
|
976f68252d |
@@ -35,6 +35,6 @@
|
|||||||
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||||
"remoteUser": "node",
|
"remoteUser": "node",
|
||||||
"features": {
|
"features": {
|
||||||
"golang": "1.19"
|
"golang": "1.20"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,3 +22,4 @@
|
|||||||
**/secrets.dev.yaml
|
**/secrets.dev.yaml
|
||||||
**/values.dev.yaml
|
**/values.dev.yaml
|
||||||
README.md
|
README.md
|
||||||
|
!Dockerfile.rootless
|
||||||
|
|||||||
31
.github/dependabot.yml
vendored
31
.github/dependabot.yml
vendored
@@ -1,31 +0,0 @@
|
|||||||
version: 2
|
|
||||||
updates:
|
|
||||||
# Fetch and update latest `npm` packages
|
|
||||||
- package-ecosystem: npm
|
|
||||||
directory: "/frontend"
|
|
||||||
schedule:
|
|
||||||
interval: daily
|
|
||||||
time: "00:00"
|
|
||||||
open-pull-requests-limit: 10
|
|
||||||
reviewers:
|
|
||||||
- hay-kot
|
|
||||||
assignees:
|
|
||||||
- hay-kot
|
|
||||||
commit-message:
|
|
||||||
prefix: fix
|
|
||||||
prefix-development: chore
|
|
||||||
include: scope
|
|
||||||
- package-ecosystem: gomod
|
|
||||||
directory: backend
|
|
||||||
schedule:
|
|
||||||
interval: daily
|
|
||||||
time: "00:00"
|
|
||||||
open-pull-requests-limit: 10
|
|
||||||
reviewers:
|
|
||||||
- hay-kot
|
|
||||||
assignees:
|
|
||||||
- hay-kot
|
|
||||||
commit-message:
|
|
||||||
prefix: fix
|
|
||||||
prefix-development: chore
|
|
||||||
include: scope
|
|
||||||
6
.github/workflows/partial-backend.yaml
vendored
6
.github/workflows/partial-backend.yaml
vendored
@@ -7,12 +7,12 @@ jobs:
|
|||||||
Go:
|
Go:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: 1.19
|
go-version: "1.20"
|
||||||
|
|
||||||
- name: Install Task
|
- name: Install Task
|
||||||
uses: arduino/setup-task@v1
|
uses: arduino/setup-task@v1
|
||||||
|
|||||||
40
.github/workflows/partial-frontend.yaml
vendored
40
.github/workflows/partial-frontend.yaml
vendored
@@ -4,11 +4,37 @@ on:
|
|||||||
workflow_call:
|
workflow_call:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Frontend:
|
lint:
|
||||||
|
name: Lint
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- uses: pnpm/action-setup@v2.2.4
|
||||||
|
with:
|
||||||
|
version: 6.0.2
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install --shamefully-hoist
|
||||||
|
working-directory: frontend
|
||||||
|
|
||||||
|
- name: Run Lint
|
||||||
|
run: pnpm run lint:ci
|
||||||
|
working-directory: frontend
|
||||||
|
|
||||||
|
- name: Run Typecheck
|
||||||
|
run: pnpm run typecheck
|
||||||
|
working-directory: frontend
|
||||||
|
|
||||||
|
integration-tests:
|
||||||
|
name: Integration Tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
@@ -18,15 +44,15 @@ jobs:
|
|||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: 1.19
|
go-version: "1.20"
|
||||||
|
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v2.2.2
|
- uses: pnpm/action-setup@v2.2.4
|
||||||
with:
|
with:
|
||||||
version: 6.0.2
|
version: 6.0.2
|
||||||
|
|
||||||
@@ -34,9 +60,5 @@ jobs:
|
|||||||
run: pnpm install
|
run: pnpm install
|
||||||
working-directory: frontend
|
working-directory: frontend
|
||||||
|
|
||||||
- name: Run linter 👀
|
|
||||||
run: pnpm lint
|
|
||||||
working-directory: "frontend"
|
|
||||||
|
|
||||||
- name: Run Integration Tests
|
- name: Run Integration Tests
|
||||||
run: task test:ci
|
run: task test:ci
|
||||||
|
|||||||
35
.github/workflows/partial-publish.yaml
vendored
35
.github/workflows/partial-publish.yaml
vendored
@@ -20,22 +20,22 @@ jobs:
|
|||||||
name: "Publish Homebox"
|
name: "Publish Homebox"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: 1.19
|
go-version: "1.20"
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
id: qemu
|
id: qemu
|
||||||
uses: docker/setup-qemu-action@v1
|
uses: docker/setup-qemu-action@v2
|
||||||
with:
|
with:
|
||||||
image: tonistiigi/binfmt:latest
|
image: tonistiigi/binfmt:latest
|
||||||
platforms: all
|
platforms: all
|
||||||
|
|
||||||
- name: install buildx
|
- name: install buildx
|
||||||
id: buildx
|
id: buildx
|
||||||
uses: docker/setup-buildx-action@v1
|
uses: docker/setup-buildx-action@v2
|
||||||
with:
|
with:
|
||||||
install: true
|
install: true
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CR_PAT: ${{ secrets.GH_TOKEN }}
|
CR_PAT: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
- name: build nightly the image
|
- name: build nightly image
|
||||||
if: ${{ inputs.release == false }}
|
if: ${{ inputs.release == false }}
|
||||||
run: |
|
run: |
|
||||||
docker build --push --no-cache \
|
docker build --push --no-cache \
|
||||||
@@ -53,6 +53,16 @@ jobs:
|
|||||||
--build-arg=BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
|
--build-arg=BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
|
||||||
--platform=linux/amd64,linux/arm64,linux/arm/v7 .
|
--platform=linux/amd64,linux/arm64,linux/arm/v7 .
|
||||||
|
|
||||||
|
- name: build nightly-rootless image
|
||||||
|
if: ${{ inputs.release == false }}
|
||||||
|
run: |
|
||||||
|
docker build --push --no-cache \
|
||||||
|
--tag=ghcr.io/hay-kot/homebox:${{ inputs.tag }}-rootless \
|
||||||
|
--build-arg=COMMIT=$(git rev-parse HEAD) \
|
||||||
|
--build-arg=BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
|
||||||
|
--file Dockerfile.rootless \
|
||||||
|
--platform=linux/amd64,linux/arm64,linux/arm/v7 .
|
||||||
|
|
||||||
- name: build release tagged the image
|
- name: build release tagged the image
|
||||||
if: ${{ inputs.release == true }}
|
if: ${{ inputs.release == true }}
|
||||||
run: |
|
run: |
|
||||||
@@ -64,3 +74,16 @@ jobs:
|
|||||||
--build-arg COMMIT=$(git rev-parse HEAD) \
|
--build-arg COMMIT=$(git rev-parse HEAD) \
|
||||||
--build-arg BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
|
--build-arg BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
|
||||||
--platform linux/amd64,linux/arm64,linux/arm/v7 .
|
--platform linux/amd64,linux/arm64,linux/arm/v7 .
|
||||||
|
|
||||||
|
- name: build release tagged the rootless image
|
||||||
|
if: ${{ inputs.release == true }}
|
||||||
|
run: |
|
||||||
|
docker build --push --no-cache \
|
||||||
|
--tag ghcr.io/hay-kot/homebox:nightly-rootless \
|
||||||
|
--tag ghcr.io/hay-kot/homebox:latest-rootless \
|
||||||
|
--tag ghcr.io/hay-kot/homebox:${{ inputs.tag }}-rootless \
|
||||||
|
--build-arg VERSION=${{ inputs.tag }} \
|
||||||
|
--build-arg COMMIT=$(git rev-parse HEAD) \
|
||||||
|
--build-arg BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
|
||||||
|
--platform linux/amd64,linux/arm64,linux/arm/v7 \
|
||||||
|
--file Dockerfile.rootless .
|
||||||
|
|||||||
48
.github/workflows/publish.yaml
vendored
48
.github/workflows/publish.yaml
vendored
@@ -1,73 +1,29 @@
|
|||||||
name: Build Nightly
|
name: Publish Dockers
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
release:
|
|
||||||
types:
|
|
||||||
- published
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
|
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
backend-tests:
|
|
||||||
name: "Backend Server Tests"
|
|
||||||
uses: hay-kot/homebox/.github/workflows/partial-backend.yaml@main
|
|
||||||
|
|
||||||
frontend-tests:
|
|
||||||
name: "Frontend and End-to-End Tests"
|
|
||||||
uses: hay-kot/homebox/.github/workflows/partial-frontend.yaml@main
|
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
name: "Deploy Nightly to Fly.io"
|
name: "Deploy Nightly to Fly.io"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs:
|
|
||||||
- backend-tests
|
|
||||||
- frontend-tests
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: superfly/flyctl-actions/setup-flyctl@master
|
- uses: superfly/flyctl-actions/setup-flyctl@master
|
||||||
- run: flyctl deploy --remote-only
|
- run: flyctl deploy --remote-only
|
||||||
|
|
||||||
publish-nightly:
|
publish-nightly:
|
||||||
name: "Publish Nightly"
|
name: "Publish Nightly"
|
||||||
if: github.event_name != 'release'
|
if: github.event_name != 'release'
|
||||||
needs:
|
|
||||||
- backend-tests
|
|
||||||
- frontend-tests
|
|
||||||
uses: hay-kot/homebox/.github/workflows/partial-publish.yaml@main
|
uses: hay-kot/homebox/.github/workflows/partial-publish.yaml@main
|
||||||
with:
|
with:
|
||||||
tag: nightly
|
tag: nightly
|
||||||
secrets:
|
secrets:
|
||||||
GH_TOKEN: ${{ secrets.CR_PAT }}
|
GH_TOKEN: ${{ secrets.CR_PAT }}
|
||||||
|
|
||||||
publish-tag:
|
|
||||||
name: "Publish Tag"
|
|
||||||
if: github.event_name == 'release'
|
|
||||||
needs:
|
|
||||||
- backend-tests
|
|
||||||
- frontend-tests
|
|
||||||
uses: hay-kot/homebox/.github/workflows/partial-publish.yaml@main
|
|
||||||
with:
|
|
||||||
release: true
|
|
||||||
tag: ${{ github.event.release.tag_name }}
|
|
||||||
secrets:
|
|
||||||
GH_TOKEN: ${{ secrets.CR_PAT }}
|
|
||||||
|
|
||||||
deploy-docs:
|
|
||||||
name: Deploy docs
|
|
||||||
needs:
|
|
||||||
- publish-tag
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout main
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Deploy docs
|
|
||||||
uses: mhausenblas/mkdocs-deploy-gh-pages@master
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
CONFIG_FILE: docs/mkdocs.yml
|
|
||||||
EXTRA_PACKAGES: build-base
|
|
||||||
|
|||||||
2
.github/workflows/pull-requests.yaml
vendored
2
.github/workflows/pull-requests.yaml
vendored
@@ -12,4 +12,4 @@ jobs:
|
|||||||
|
|
||||||
frontend-tests:
|
frontend-tests:
|
||||||
name: "Frontend and End-to-End Tests"
|
name: "Frontend and End-to-End Tests"
|
||||||
uses: ./.github/workflows/partial-frontend.yaml
|
uses: ./.github/workflows/partial-frontend.yaml
|
||||||
77
.github/workflows/tag.yaml
vendored
Normal file
77
.github/workflows/tag.yaml
vendored
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
name: Publish Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- v*
|
||||||
|
|
||||||
|
env:
|
||||||
|
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
backend-tests:
|
||||||
|
name: "Backend Server Tests"
|
||||||
|
uses: hay-kot/homebox/.github/workflows/partial-backend.yaml@main
|
||||||
|
|
||||||
|
frontend-tests:
|
||||||
|
name: "Frontend and End-to-End Tests"
|
||||||
|
uses: hay-kot/homebox/.github/workflows/partial-frontend.yaml@main
|
||||||
|
|
||||||
|
goreleaser:
|
||||||
|
name: goreleaser
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v4
|
||||||
|
|
||||||
|
- uses: pnpm/action-setup@v2
|
||||||
|
with:
|
||||||
|
version: 7.30.1
|
||||||
|
|
||||||
|
- name: Build Frontend and Copy to Backend
|
||||||
|
working-directory: frontend
|
||||||
|
run: |
|
||||||
|
pnpm install --shamefully-hoist
|
||||||
|
pnpm run build
|
||||||
|
cp -r ./.output/public ../backend/app/api/static/
|
||||||
|
|
||||||
|
- name: Run GoReleaser
|
||||||
|
uses: goreleaser/goreleaser-action@v4
|
||||||
|
with:
|
||||||
|
workdir: "backend"
|
||||||
|
distribution: goreleaser
|
||||||
|
version: latest
|
||||||
|
args: release --clean
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
publish-tag:
|
||||||
|
name: "Publish Tag"
|
||||||
|
uses: hay-kot/homebox/.github/workflows/partial-publish.yaml@main
|
||||||
|
with:
|
||||||
|
release: true
|
||||||
|
tag: ${{ github.ref_name }}
|
||||||
|
secrets:
|
||||||
|
GH_TOKEN: ${{ secrets.CR_PAT }}
|
||||||
|
|
||||||
|
deploy-docs:
|
||||||
|
name: Deploy docs
|
||||||
|
needs:
|
||||||
|
- publish-tag
|
||||||
|
- goreleaser
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout main
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Deploy docs
|
||||||
|
uses: mhausenblas/mkdocs-deploy-gh-pages@master
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
CONFIG_FILE: docs/mkdocs.yml
|
||||||
|
EXTRA_PACKAGES: build-base
|
||||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -45,3 +45,12 @@ node_modules
|
|||||||
.output
|
.output
|
||||||
.env
|
.env
|
||||||
dist
|
dist
|
||||||
|
|
||||||
|
.pnpm-store
|
||||||
|
backend/app/api/app
|
||||||
|
backend/app/api/__debug_bin
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# Nuxt Publish Dir
|
||||||
|
backend/app/api/static/public/*
|
||||||
|
!backend/app/api/static/public/.gitkeep
|
||||||
33
.scaffold/model/scaffold.yaml
Normal file
33
.scaffold/model/scaffold.yaml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
# yaml-language-server: $schema=https://hay-kot.github.io/scaffold/schema.json
|
||||||
|
messages:
|
||||||
|
pre: |
|
||||||
|
# Ent Model Generation
|
||||||
|
|
||||||
|
With Boilerplate!
|
||||||
|
post: |
|
||||||
|
Complete!
|
||||||
|
|
||||||
|
questions:
|
||||||
|
- name: "model"
|
||||||
|
prompt:
|
||||||
|
message: "What is the name of the model? (PascalCase)"
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- name: "by_group"
|
||||||
|
prompt:
|
||||||
|
confirm: "Include a Group Edge? (group_id -> id)"
|
||||||
|
required: true
|
||||||
|
|
||||||
|
rewrites:
|
||||||
|
- from: 'templates/model.go'
|
||||||
|
to: 'backend/internal/data/ent/schema/{{ lower .Scaffold.model }}.go'
|
||||||
|
|
||||||
|
inject:
|
||||||
|
- name: "Insert Groups Edge"
|
||||||
|
path: 'backend/internal/data/ent/schema/group.go'
|
||||||
|
at: // $scaffold_edge
|
||||||
|
template: |
|
||||||
|
{{- if .Scaffold.by_group -}}
|
||||||
|
owned("{{ lower .Scaffold.model }}s", {{ .Scaffold.model }}.Type),
|
||||||
|
{{- end -}}
|
||||||
40
.scaffold/model/templates/model.go
Normal file
40
.scaffold/model/templates/model.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"entgo.io/ent"
|
||||||
|
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/ent/schema/mixins"
|
||||||
|
)
|
||||||
|
|
||||||
|
type {{ .Scaffold.model }} struct {
|
||||||
|
ent.Schema
|
||||||
|
}
|
||||||
|
|
||||||
|
func ({{ .Scaffold.model }}) Mixin() []ent.Mixin {
|
||||||
|
return []ent.Mixin{
|
||||||
|
mixins.BaseMixin{},
|
||||||
|
{{- if .Scaffold.by_group }}
|
||||||
|
GroupMixin{ref: "{{ snakecase .Scaffold.model }}s"},
|
||||||
|
{{- end }}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fields of the {{ .Scaffold.model }}.
|
||||||
|
func ({{ .Scaffold.model }}) Fields() []ent.Field {
|
||||||
|
return []ent.Field{
|
||||||
|
// field.String("name").
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Edges of the {{ .Scaffold.model }}.
|
||||||
|
func ({{ .Scaffold.model }}) Edges() []ent.Edge {
|
||||||
|
return []ent.Edge{
|
||||||
|
// edge.From("group", Group.Type).
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ({{ .Scaffold.model }}) Indexes() []ent.Index {
|
||||||
|
return []ent.Index{
|
||||||
|
// index.Fields("token"),
|
||||||
|
}
|
||||||
|
}
|
||||||
47
.vscode/launch.json
vendored
Normal file
47
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"compounds": [
|
||||||
|
{
|
||||||
|
"name": "Full Stack",
|
||||||
|
"configurations": ["Launch Backend", "Launch Frontend"],
|
||||||
|
"stopAll": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Launch Backend",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "debug",
|
||||||
|
"program": "${workspaceRoot}/backend/app/api/",
|
||||||
|
"args": [],
|
||||||
|
"env": {
|
||||||
|
"HBOX_DEMO": "true",
|
||||||
|
"HBOX_LOG_LEVEL": "debug",
|
||||||
|
"HBOX_DEBUG_ENABLED": "true",
|
||||||
|
"HBOX_STORAGE_DATA": "${workspaceRoot}/backend/.data",
|
||||||
|
"HBOX_STORAGE_SQLITE_URL": "${workspaceRoot}/backend/.data/homebox.db?_fk=1"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Launch Frontend",
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"runtimeExecutable": "pnpm",
|
||||||
|
"runtimeArgs": [
|
||||||
|
"run",
|
||||||
|
"dev"
|
||||||
|
],
|
||||||
|
"cwd": "${workspaceFolder}/frontend",
|
||||||
|
"serverReadyAction": {
|
||||||
|
"action": "debugWithChrome",
|
||||||
|
"pattern": "Local: http://localhost:([0-9]+)",
|
||||||
|
"uriFormat": "http://localhost:%s",
|
||||||
|
"webRoot": "${workspaceFolder}/frontend"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
27
.vscode/settings.json
vendored
27
.vscode/settings.json
vendored
@@ -1,7 +1,4 @@
|
|||||||
{
|
{
|
||||||
"editor.codeActionsOnSave": {
|
|
||||||
"source.fixAll.eslint": true
|
|
||||||
},
|
|
||||||
"yaml.schemas": {
|
"yaml.schemas": {
|
||||||
"https://squidfunk.github.io/mkdocs-material/schema.json": "mkdocs.yml"
|
"https://squidfunk.github.io/mkdocs-material/schema.json": "mkdocs.yml"
|
||||||
},
|
},
|
||||||
@@ -12,6 +9,26 @@
|
|||||||
"README.md": "LICENSE, SECURITY.md"
|
"README.md": "LICENSE, SECURITY.md"
|
||||||
},
|
},
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"debughandlers"
|
"debughandlers",
|
||||||
]
|
"Homebox"
|
||||||
|
],
|
||||||
|
// use ESLint to format code on save
|
||||||
|
"editor.formatOnSave": false,
|
||||||
|
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.eslint": true
|
||||||
|
},
|
||||||
|
"[typescript]": {
|
||||||
|
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||||
|
},
|
||||||
|
"eslint.format.enable": true,
|
||||||
|
"css.validate": false,
|
||||||
|
"tailwindCSS.includeLanguages": {
|
||||||
|
"vue": "html",
|
||||||
|
"vue-html": "html"
|
||||||
|
},
|
||||||
|
"editor.quickSuggestions": {
|
||||||
|
"strings": true
|
||||||
|
},
|
||||||
|
"tailwindCSS.experimental.configFile": "./frontend/tailwind.config.js"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,4 +48,10 @@ start command `task: ui:dev`
|
|||||||
|
|
||||||
1. The frontend is a Vue 3 app with Nuxt.js that uses Tailwind and DaisyUI 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`.
|
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.
|
3. Tests require the API server to be running and in some cases the first run will fail due to a race condition. If this happens just run the tests again and they should pass.
|
||||||
|
|
||||||
|
## Publishing Release
|
||||||
|
|
||||||
|
Create a new tag in github with the version number vX.X.X. This will trigger a new release to be created.
|
||||||
|
|
||||||
|
Test -> Goreleaser -> Publish Release -> Trigger Docker Builds -> Deploy Docs + Fly.io Demo
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
# Build Nuxt
|
# Build Nuxt
|
||||||
FROM node:17-alpine as frontend-builder
|
FROM node:18-alpine as frontend-builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN npm install -g pnpm
|
RUN npm install -g pnpm
|
||||||
COPY frontend/package.json frontend/pnpm-lock.yaml ./
|
COPY frontend/package.json frontend/pnpm-lock.yaml ./
|
||||||
@@ -22,7 +22,7 @@ COPY ./backend .
|
|||||||
RUN go get -d -v ./...
|
RUN go get -d -v ./...
|
||||||
RUN rm -rf ./app/api/public
|
RUN rm -rf ./app/api/public
|
||||||
COPY --from=frontend-builder /app/.output/public ./app/api/static/public
|
COPY --from=frontend-builder /app/.output/public ./app/api/static/public
|
||||||
RUN CGO_ENABLED=1 GOOS=linux go build \
|
RUN CGO_ENABLED=0 GOOS=linux go build \
|
||||||
-ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \
|
-ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \
|
||||||
-o /go/bin/api \
|
-o /go/bin/api \
|
||||||
-v ./app/api/*.go
|
-v ./app/api/*.go
|
||||||
@@ -41,9 +41,10 @@ COPY --from=builder /go/bin/api /app
|
|||||||
RUN chmod +x /app/api
|
RUN chmod +x /app/api
|
||||||
|
|
||||||
LABEL Name=homebox Version=0.0.1
|
LABEL Name=homebox Version=0.0.1
|
||||||
|
LABEL org.opencontainers.image.source="https://github.com/hay-kot/homebox"
|
||||||
EXPOSE 7745
|
EXPOSE 7745
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
VOLUME [ "/data" ]
|
VOLUME [ "/data" ]
|
||||||
|
|
||||||
ENTRYPOINT [ "/app/api" ]
|
ENTRYPOINT [ "/app/api" ]
|
||||||
CMD [ "/data/config.yml" ]
|
CMD [ "/data/config.yml" ]
|
||||||
|
|||||||
53
Dockerfile.rootless
Normal file
53
Dockerfile.rootless
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
|
||||||
|
# Build Nuxt
|
||||||
|
FROM node:17-alpine as frontend-builder
|
||||||
|
WORKDIR /app
|
||||||
|
RUN npm install -g pnpm
|
||||||
|
COPY frontend/package.json frontend/pnpm-lock.yaml ./
|
||||||
|
RUN pnpm install --frozen-lockfile --shamefully-hoist
|
||||||
|
COPY frontend .
|
||||||
|
RUN pnpm build
|
||||||
|
|
||||||
|
# Build API
|
||||||
|
FROM golang:alpine AS builder
|
||||||
|
ARG BUILD_TIME
|
||||||
|
ARG COMMIT
|
||||||
|
ARG VERSION
|
||||||
|
RUN apk update && \
|
||||||
|
apk upgrade && \
|
||||||
|
apk add --update git build-base gcc g++
|
||||||
|
|
||||||
|
WORKDIR /go/src/app
|
||||||
|
COPY ./backend .
|
||||||
|
RUN go get -d -v ./...
|
||||||
|
RUN rm -rf ./app/api/public
|
||||||
|
COPY --from=frontend-builder /app/.output/public ./app/api/static/public
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux go build \
|
||||||
|
-ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \
|
||||||
|
-o /go/bin/api \
|
||||||
|
-v ./app/api/*.go && \
|
||||||
|
chmod +x /go/bin/api && \
|
||||||
|
# create a directory so that we can copy it in the next stage
|
||||||
|
mkdir /data
|
||||||
|
|
||||||
|
# Production Stage
|
||||||
|
FROM gcr.io/distroless/static
|
||||||
|
|
||||||
|
ENV HBOX_MODE=production
|
||||||
|
ENV HBOX_STORAGE_DATA=/data/
|
||||||
|
ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_fk=1
|
||||||
|
|
||||||
|
# Copy the binary and the (empty) /data dir and
|
||||||
|
# change the ownership to the low-privileged user
|
||||||
|
COPY --from=builder --chown=nonroot /go/bin/api /app
|
||||||
|
COPY --from=builder --chown=nonroot /data /data
|
||||||
|
|
||||||
|
LABEL Name=homebox Version=0.0.1
|
||||||
|
LABEL org.opencontainers.image.source="https://github.com/hay-kot/homebox"
|
||||||
|
EXPOSE 7745
|
||||||
|
VOLUME [ "/data" ]
|
||||||
|
|
||||||
|
# Drop root and run as low-privileged user
|
||||||
|
USER nonroot
|
||||||
|
ENTRYPOINT [ "/app" ]
|
||||||
|
CMD [ "/data/config.yml" ]
|
||||||
16
README.md
16
README.md
@@ -16,10 +16,18 @@
|
|||||||
[Configuration & Docker Compose](https://hay-kot.github.io/homebox/quick-start)
|
[Configuration & Docker Compose](https://hay-kot.github.io/homebox/quick-start)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run --name=homebox \
|
# If using the rootless image, ensure data
|
||||||
--restart=always \
|
# folder has correct permissions
|
||||||
--publish=3100:7745 \
|
mkdir -p /path/to/data/folder
|
||||||
ghcr.io/hay-kot/homebox:latest
|
chown 65532:65532 -R /path/to/data/folder
|
||||||
|
docker run -d \
|
||||||
|
--name homebox \
|
||||||
|
--restart unless-stopped \
|
||||||
|
--publish 3100:7745 \
|
||||||
|
--env TZ=Europe/Bucharest \
|
||||||
|
--volume /path/to/data/folder/:/data \
|
||||||
|
ghcr.io/hay-kot/homebox:latest
|
||||||
|
# ghcr.io/hay-kot/homebox:latest-rootless
|
||||||
```
|
```
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|||||||
65
Taskfile.yml
65
Taskfile.yml
@@ -1,7 +1,8 @@
|
|||||||
version: "3"
|
version: "3"
|
||||||
|
|
||||||
env:
|
env:
|
||||||
HBOX_STORAGE_SQLITE_URL: .data/homebox.db?_fk=1
|
HBOX_STORAGE_SQLITE_URL: .data/homebox.db?_pragma=busy_timeout=1000&_pragma=journal_mode=WAL&_fk=1
|
||||||
|
HBOX_OPTIONS_ALLOW_REGISTRATION: true
|
||||||
UNSAFE_DISABLE_PASSWORD_PROJECTION: "yes_i_am_sure"
|
UNSAFE_DISABLE_PASSWORD_PROJECTION: "yes_i_am_sure"
|
||||||
tasks:
|
tasks:
|
||||||
setup:
|
setup:
|
||||||
@@ -26,46 +27,47 @@ tasks:
|
|||||||
--modular \
|
--modular \
|
||||||
--path ./backend/app/api/static/docs/swagger.json \
|
--path ./backend/app/api/static/docs/swagger.json \
|
||||||
--output ./frontend/lib/api/types
|
--output ./frontend/lib/api/types
|
||||||
- python3 ./scripts/process-types.py ./frontend/lib/api/types/data-contracts.ts
|
- go run ./backend/app/tools/typegen/main.go ./frontend/lib/api/types/data-contracts.ts
|
||||||
|
- cp ./backend/app/api/static/docs/swagger.json docs/docs/api/openapi-2.0.json
|
||||||
sources:
|
sources:
|
||||||
- "./backend/app/api/**/*"
|
- "./backend/app/api/**/*"
|
||||||
- "./backend/internal/data/**"
|
- "./backend/internal/data/**"
|
||||||
- "./backend/internal/services/**/*"
|
- "./backend/internal/core/services/**/*"
|
||||||
- "./scripts/process-types.py"
|
- "./backend/app/tools/typegen/main.go"
|
||||||
generates:
|
|
||||||
- "./frontend/lib/api/types/data-contracts.ts"
|
|
||||||
- "./backend/internal/data/ent/schema"
|
|
||||||
- "./backend/app/api/static/docs/swagger.json"
|
|
||||||
- "./backend/app/api/static/docs/swagger.yaml"
|
|
||||||
|
|
||||||
go:run:
|
go:run:
|
||||||
desc: Starts the backend api server (depends on generate task)
|
desc: Starts the backend api server (depends on generate task)
|
||||||
|
dir: backend
|
||||||
deps:
|
deps:
|
||||||
- generate
|
- generate
|
||||||
cmds:
|
cmds:
|
||||||
- cd backend && go run ./app/api/ {{ .CLI_ARGS }}
|
- go run ./app/api/ {{ .CLI_ARGS }}
|
||||||
silent: false
|
silent: false
|
||||||
|
|
||||||
go:test:
|
go:test:
|
||||||
desc: Runs all go tests using gotestsum - supports passing gotestsum args
|
desc: Runs all go tests using gotestsum - supports passing gotestsum args
|
||||||
|
dir: backend
|
||||||
cmds:
|
cmds:
|
||||||
- cd backend && gotestsum {{ .CLI_ARGS }} ./...
|
- gotestsum {{ .CLI_ARGS }} ./...
|
||||||
|
|
||||||
go:coverage:
|
go:coverage:
|
||||||
desc: Runs all go tests with -race flag and generates a coverage report
|
desc: Runs all go tests with -race flag and generates a coverage report
|
||||||
|
dir: backend
|
||||||
cmds:
|
cmds:
|
||||||
- cd backend && go test -race -coverprofile=coverage.out -covermode=atomic ./app/... ./internal/... ./pkgs/... -v -cover
|
- go test -race -coverprofile=coverage.out -covermode=atomic ./app/... ./internal/... ./pkgs/... -v -cover
|
||||||
silent: true
|
silent: true
|
||||||
|
|
||||||
go:tidy:
|
go:tidy:
|
||||||
desc: Runs go mod tidy on the backend
|
desc: Runs go mod tidy on the backend
|
||||||
|
dir: backend
|
||||||
cmds:
|
cmds:
|
||||||
- cd backend && go mod tidy
|
- go mod tidy
|
||||||
|
|
||||||
go:lint:
|
go:lint:
|
||||||
desc: Runs golangci-lint
|
desc: Runs golangci-lint
|
||||||
|
dir: backend
|
||||||
cmds:
|
cmds:
|
||||||
- cd backend && golangci-lint run ./...
|
- golangci-lint run ./...
|
||||||
|
|
||||||
go:all:
|
go:all:
|
||||||
desc: Runs all go test and lint related tasks
|
desc: Runs all go test and lint related tasks
|
||||||
@@ -76,19 +78,19 @@ tasks:
|
|||||||
|
|
||||||
go:build:
|
go:build:
|
||||||
desc: Builds the backend binary
|
desc: Builds the backend binary
|
||||||
|
dir: backend
|
||||||
cmds:
|
cmds:
|
||||||
- cd backend && go build -o ../build/backend ./app/api
|
- go build -o ../build/backend ./app/api
|
||||||
|
|
||||||
db:generate:
|
db:generate:
|
||||||
desc: Run Entgo.io Code Generation
|
desc: Run Entgo.io Code Generation
|
||||||
|
dir: backend/internal/
|
||||||
cmds:
|
cmds:
|
||||||
- |
|
- |
|
||||||
cd backend/internal/ && go generate ./... \
|
go generate ./... \
|
||||||
--template=./data/ent/schema/templates/has_id.tmpl
|
--template=./data/ent/schema/templates/has_id.tmpl
|
||||||
sources:
|
sources:
|
||||||
- "./backend/internal/data/ent/schema/**/*"
|
- "./backend/internal/data/ent/schema/**/*"
|
||||||
generates:
|
|
||||||
- "./backend/internal/ent/"
|
|
||||||
|
|
||||||
db:migration:
|
db:migration:
|
||||||
desc: Runs the database diff engine to generate a SQL migration files
|
desc: Runs the database diff engine to generate a SQL migration files
|
||||||
@@ -99,13 +101,27 @@ tasks:
|
|||||||
|
|
||||||
ui:watch:
|
ui:watch:
|
||||||
desc: Starts the vitest test runner in watch mode
|
desc: Starts the vitest test runner in watch mode
|
||||||
|
dir: frontend
|
||||||
cmds:
|
cmds:
|
||||||
- cd frontend && pnpm run test:watch
|
- pnpm run test:watch
|
||||||
|
|
||||||
ui:dev:
|
ui:dev:
|
||||||
desc: Run frontend development server
|
desc: Run frontend development server
|
||||||
|
dir: frontend
|
||||||
cmds:
|
cmds:
|
||||||
- cd frontend && pnpm dev
|
- pnpm dev
|
||||||
|
|
||||||
|
ui:fix:
|
||||||
|
desc: Runs prettier and eslint on the frontend
|
||||||
|
dir: frontend
|
||||||
|
cmds:
|
||||||
|
- pnpm run lint:fix
|
||||||
|
|
||||||
|
ui:check:
|
||||||
|
desc: Runs type checking
|
||||||
|
dir: frontend
|
||||||
|
cmds:
|
||||||
|
- pnpm run typecheck
|
||||||
|
|
||||||
test:ci:
|
test:ci:
|
||||||
desc: Runs end-to-end test on a live server (only for use in CI)
|
desc: Runs end-to-end test on a live server (only for use in CI)
|
||||||
@@ -115,3 +131,12 @@ tasks:
|
|||||||
- sleep 5
|
- sleep 5
|
||||||
- cd frontend && pnpm run test:ci
|
- cd frontend && pnpm run test:ci
|
||||||
silent: true
|
silent: true
|
||||||
|
|
||||||
|
pr:
|
||||||
|
desc: Runs all tasks required for a PR
|
||||||
|
cmds:
|
||||||
|
- task: generate
|
||||||
|
- task: go:all
|
||||||
|
- task: ui:check
|
||||||
|
- task: ui:fix
|
||||||
|
- task: test:ci
|
||||||
|
|||||||
2
backend/.gitignore
vendored
Normal file
2
backend/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
dist/
|
||||||
54
backend/.goreleaser.yaml
Normal file
54
backend/.goreleaser.yaml
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# This is an example .goreleaser.yml file with some sensible defaults.
|
||||||
|
# Make sure to check the documentation at https://goreleaser.com
|
||||||
|
before:
|
||||||
|
hooks:
|
||||||
|
# you may remove this if you don't need go generate
|
||||||
|
- go generate ./...
|
||||||
|
builds:
|
||||||
|
- main: ./app/api
|
||||||
|
env:
|
||||||
|
- CGO_ENABLED=0
|
||||||
|
goos:
|
||||||
|
- linux
|
||||||
|
- windows
|
||||||
|
- darwin
|
||||||
|
goarch:
|
||||||
|
- amd64
|
||||||
|
- "386"
|
||||||
|
- arm
|
||||||
|
- arm64
|
||||||
|
ignore:
|
||||||
|
- goos: windows
|
||||||
|
goarch: arm
|
||||||
|
- goos: windows
|
||||||
|
goarch: "386"
|
||||||
|
|
||||||
|
archives:
|
||||||
|
- format: tar.gz
|
||||||
|
# this name template makes the OS and Arch compatible with the results of uname.
|
||||||
|
name_template: >-
|
||||||
|
{{ .ProjectName }}_
|
||||||
|
{{- title .Os }}_
|
||||||
|
{{- if eq .Arch "amd64" }}x86_64
|
||||||
|
{{- else if eq .Arch "386" }}i386
|
||||||
|
{{- else }}{{ .Arch }}{{ end }}
|
||||||
|
{{- if .Arm }}v{{ .Arm }}{{ end }}
|
||||||
|
# use zip for windows archives
|
||||||
|
format_overrides:
|
||||||
|
- goos: windows
|
||||||
|
format: zip
|
||||||
|
checksum:
|
||||||
|
name_template: 'checksums.txt'
|
||||||
|
snapshot:
|
||||||
|
name_template: "{{ incpatch .Version }}-next"
|
||||||
|
changelog:
|
||||||
|
sort: asc
|
||||||
|
filters:
|
||||||
|
exclude:
|
||||||
|
- '^docs:'
|
||||||
|
- '^test:'
|
||||||
|
|
||||||
|
# The lines beneath this are called `modelines`. See `:help modeline`
|
||||||
|
# Feel free to remove those if you don't want/use them.
|
||||||
|
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
|
||||||
|
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
|
||||||
BIN
backend/api
Executable file
BIN
backend/api
Executable file
Binary file not shown.
@@ -4,11 +4,12 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
"github.com/hay-kot/homebox/backend/internal/sys/config"
|
"github.com/hay-kot/homebox/backend/internal/sys/config"
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/mailer"
|
"github.com/hay-kot/homebox/backend/pkgs/mailer"
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
"github.com/hay-kot/httpkit/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
type app struct {
|
type app struct {
|
||||||
@@ -18,6 +19,7 @@ type app struct {
|
|||||||
server *server.Server
|
server *server.Server
|
||||||
repos *repo.AllRepos
|
repos *repo.AllRepos
|
||||||
services *services.AllServices
|
services *services.AllServices
|
||||||
|
bus *eventbus.EventBus
|
||||||
}
|
}
|
||||||
|
|
||||||
func new(conf *config.Config) *app {
|
func new(conf *config.Config) *app {
|
||||||
@@ -37,8 +39,11 @@ func new(conf *config.Config) *app {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *app) startBgTask(t time.Duration, fn func()) {
|
func (a *app) startBgTask(t time.Duration, fn func()) {
|
||||||
|
timer := time.NewTimer(t)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
timer.Reset(t)
|
||||||
a.server.Background(fn)
|
a.server.Background(fn)
|
||||||
time.Sleep(t)
|
<-timer.C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/csv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
@@ -10,7 +9,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (a *app) SetupDemo() {
|
func (a *app) SetupDemo() {
|
||||||
csvText := `Import Ref,Location,Labels,Quantity,Name,Description,Insured,Serial Number,Model Number,Manufacturer,Notes,Purchase From,Purchased Price,Purchased Time,Lifetime Warranty,Warranty Expires,Warranty Details,Sold To,Sold Price,Sold Time,Sold Notes
|
csvText := `HB.import_ref,HB.location,HB.labels,HB.quantity,HB.name,HB.description,HB.insured,HB.serial_number,HB.model_number,HB.manufacturer,HB.notes,HB.purchase_from,HB.purchase_price,HB.purchase_time,HB.lifetime_warranty,HB.warranty_expires,HB.warranty_details,HB.sold_to,HB.sold_price,HB.sold_time,HB.sold_notes
|
||||||
,Garage,IOT;Home Assistant; Z-Wave,1,Zooz Universal Relay ZEN17,"Zooz 700 Series Z-Wave Universal Relay ZEN17 for Awnings, Garage Doors, Sprinklers, and More | 2 NO-C-NC Relays (20A, 10A) | Signal Repeater | Hub Required (Compatible with SmartThings and Hubitat)",,,ZEN17,Zooz,,Amazon,39.95,10/13/2021,,,,,,,
|
,Garage,IOT;Home Assistant; Z-Wave,1,Zooz Universal Relay ZEN17,"Zooz 700 Series Z-Wave Universal Relay ZEN17 for Awnings, Garage Doors, Sprinklers, and More | 2 NO-C-NC Relays (20A, 10A) | Signal Repeater | Hub Required (Compatible with SmartThings and Hubitat)",,,ZEN17,Zooz,,Amazon,39.95,10/13/2021,,,,,,,
|
||||||
,Living Room,IOT;Home Assistant; Z-Wave,1,Zooz Motion Sensor,"Zooz Z-Wave Plus S2 Motion Sensor ZSE18 with Magnetic Mount, Works with Vera and SmartThings",,,ZSE18,Zooz,,Amazon,29.95,10/15/2021,,,,,,,
|
,Living Room,IOT;Home Assistant; Z-Wave,1,Zooz Motion Sensor,"Zooz Z-Wave Plus S2 Motion Sensor ZSE18 with Magnetic Mount, Works with Vera and SmartThings",,,ZSE18,Zooz,,Amazon,29.95,10/15/2021,,,,,,,
|
||||||
,Office,IOT;Home Assistant; Z-Wave,1,Zooz 110v Power Switch,"Zooz Z-Wave Plus Power Switch ZEN15 for 110V AC Units, Sump Pumps, Humidifiers, and More",,,ZEN15,Zooz,,Amazon,39.95,10/13/2021,,,,,,,
|
,Office,IOT;Home Assistant; Z-Wave,1,Zooz 110v Power Switch,"Zooz Z-Wave Plus Power Switch ZEN15 for 110V AC Units, Sump Pumps, Humidifiers, and More",,,ZEN15,Zooz,,Amazon,39.95,10/13/2021,,,,,,,
|
||||||
@@ -19,16 +18,14 @@ func (a *app) SetupDemo() {
|
|||||||
,Kitchen,IOT;Home Assistant; Z-Wave,1,Smart Rocker Light Dimmer,"UltraPro Z-Wave Smart Rocker Light Dimmer with QuickFit and SimpleWire, 3-Way Ready, Compatible with Alexa, Google Assistant, ZWave Hub Required, Repeater/Range Extender, White Paddle Only, 39351",,,39351,Honeywell,,Amazon,65.98,09/30/0202,,,,,,,
|
,Kitchen,IOT;Home Assistant; Z-Wave,1,Smart Rocker Light Dimmer,"UltraPro Z-Wave Smart Rocker Light Dimmer with QuickFit and SimpleWire, 3-Way Ready, Compatible with Alexa, Google Assistant, ZWave Hub Required, Repeater/Range Extender, White Paddle Only, 39351",,,39351,Honeywell,,Amazon,65.98,09/30/0202,,,,,,,
|
||||||
`
|
`
|
||||||
|
|
||||||
var (
|
registration := services.UserRegistration{
|
||||||
registration = services.UserRegistration{
|
Email: "demo@example.com",
|
||||||
Email: "demo@example.com",
|
Name: "Demo",
|
||||||
Name: "Demo",
|
Password: "demo",
|
||||||
Password: "demo",
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// First check if we've already setup a demo user and skip if so
|
// First check if we've already setup a demo user and skip if so
|
||||||
_, err := a.services.User.Login(context.Background(), registration.Email, registration.Password)
|
_, err := a.services.User.Login(context.Background(), registration.Email, registration.Password, false)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -39,20 +36,10 @@ func (a *app) SetupDemo() {
|
|||||||
log.Fatal().Msg("Failed to setup demo")
|
log.Fatal().Msg("Failed to setup demo")
|
||||||
}
|
}
|
||||||
|
|
||||||
token, _ := a.services.User.Login(context.Background(), registration.Email, registration.Password)
|
token, _ := a.services.User.Login(context.Background(), registration.Email, registration.Password, false)
|
||||||
self, _ := a.services.User.GetSelf(context.Background(), token.Raw)
|
self, _ := a.services.User.GetSelf(context.Background(), token.Raw)
|
||||||
|
|
||||||
// Read CSV Text
|
_, err = a.services.Items.CsvImport(context.Background(), self.GroupID, strings.NewReader(csvText))
|
||||||
reader := csv.NewReader(strings.NewReader(csvText))
|
|
||||||
reader.Comma = ','
|
|
||||||
|
|
||||||
records, err := reader.ReadAll()
|
|
||||||
if err != nil {
|
|
||||||
log.Err(err).Msg("Failed to read CSV")
|
|
||||||
log.Fatal().Msg("Failed to setup demo")
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = a.services.Items.CsvImport(context.Background(), self.GroupID, records)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg("Failed to import CSV")
|
log.Err(err).Msg("Failed to import CSV")
|
||||||
log.Fatal().Msg("Failed to setup demo")
|
log.Fatal().Msg("Failed to setup demo")
|
||||||
|
|||||||
BIN
backend/app/api/handlers/v1/assets/QRIcon.png
Normal file
BIN
backend/app/api/handlers/v1/assets/QRIcon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
@@ -1,13 +1,36 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
|
"github.com/hay-kot/httpkit/server"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
|
"github.com/olahol/melody"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Results[T any] struct {
|
||||||
|
Items []T `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func WrapResults[T any](items []T) Results[T] {
|
||||||
|
return Results[T]{Items: items}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Wrapped struct {
|
||||||
|
Item interface{} `json:"item"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func Wrap(v any) Wrapped {
|
||||||
|
return Wrapped{Item: v}
|
||||||
|
}
|
||||||
|
|
||||||
func WithMaxUploadSize(maxUploadSize int64) func(*V1Controller) {
|
func WithMaxUploadSize(maxUploadSize int64) func(*V1Controller) {
|
||||||
return func(ctrl *V1Controller) {
|
return func(ctrl *V1Controller) {
|
||||||
ctrl.maxUploadSize = maxUploadSize
|
ctrl.maxUploadSize = maxUploadSize
|
||||||
@@ -32,6 +55,7 @@ type V1Controller struct {
|
|||||||
maxUploadSize int64
|
maxUploadSize int64
|
||||||
isDemo bool
|
isDemo bool
|
||||||
allowRegistration bool
|
allowRegistration bool
|
||||||
|
bus *eventbus.EventBus
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@@ -44,12 +68,13 @@ type (
|
|||||||
}
|
}
|
||||||
|
|
||||||
ApiSummary struct {
|
ApiSummary struct {
|
||||||
Healthy bool `json:"health"`
|
Healthy bool `json:"health"`
|
||||||
Versions []string `json:"versions"`
|
Versions []string `json:"versions"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
Build Build `json:"build"`
|
Build Build `json:"build"`
|
||||||
Demo bool `json:"demo"`
|
Demo bool `json:"demo"`
|
||||||
|
AllowRegistration bool `json:"allowRegistration"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -59,11 +84,12 @@ func BaseUrlFunc(prefix string) func(s string) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewControllerV1(svc *services.AllServices, repos *repo.AllRepos, options ...func(*V1Controller)) *V1Controller {
|
func NewControllerV1(svc *services.AllServices, repos *repo.AllRepos, bus *eventbus.EventBus, options ...func(*V1Controller)) *V1Controller {
|
||||||
ctrl := &V1Controller{
|
ctrl := &V1Controller{
|
||||||
repo: repos,
|
repo: repos,
|
||||||
svc: svc,
|
svc: svc,
|
||||||
allowRegistration: true,
|
allowRegistration: true,
|
||||||
|
bus: bus,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, opt := range options {
|
for _, opt := range options {
|
||||||
@@ -74,19 +100,60 @@ func NewControllerV1(svc *services.AllServices, repos *repo.AllRepos, options ..
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HandleBase godoc
|
// HandleBase godoc
|
||||||
// @Summary Retrieves the basic information about the API
|
//
|
||||||
// @Tags Base
|
// @Summary Application Info
|
||||||
// @Produce json
|
// @Tags Base
|
||||||
// @Success 200 {object} ApiSummary
|
// @Produce json
|
||||||
// @Router /v1/status [GET]
|
// @Success 200 {object} ApiSummary
|
||||||
func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) server.HandlerFunc {
|
// @Router /v1/status [GET]
|
||||||
|
func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) errchain.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
return server.Respond(w, http.StatusOK, ApiSummary{
|
return server.JSON(w, http.StatusOK, ApiSummary{
|
||||||
Healthy: ready(),
|
Healthy: ready(),
|
||||||
Title: "Go API Template",
|
Title: "Homebox",
|
||||||
Message: "Welcome to the Go API Template Application!",
|
Message: "Track, Manage, and Organize your Things",
|
||||||
Build: build,
|
Build: build,
|
||||||
Demo: ctrl.isDemo,
|
Demo: ctrl.isDemo,
|
||||||
|
AllowRegistration: ctrl.allowRegistration,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ctrl *V1Controller) HandleCacheWS() errchain.HandlerFunc {
|
||||||
|
m := melody.New()
|
||||||
|
|
||||||
|
m.HandleConnect(func(s *melody.Session) {
|
||||||
|
auth := services.NewContext(s.Request.Context())
|
||||||
|
s.Set("gid", auth.GID)
|
||||||
|
})
|
||||||
|
|
||||||
|
factory := func(e string) func(data any) {
|
||||||
|
return func(data any) {
|
||||||
|
eventData, ok := data.(eventbus.GroupMutationEvent)
|
||||||
|
if !ok {
|
||||||
|
log.Log().Msgf("invalid event data: %v", data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonStr := fmt.Sprintf(`{"event": "%s"}`, e)
|
||||||
|
|
||||||
|
_ = m.BroadcastFilter([]byte(jsonStr), func(s *melody.Session) bool {
|
||||||
|
groupIDStr, ok := s.Get("gid")
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
GID := groupIDStr.(uuid.UUID)
|
||||||
|
return GID == eventData.GID
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl.bus.Subscribe(eventbus.EventLabelMutation, factory("label.mutation"))
|
||||||
|
ctrl.bus.Subscribe(eventbus.EventLocationMutation, factory("location.mutation"))
|
||||||
|
ctrl.bus.Subscribe(eventbus.EventItemMutation, factory("item.mutation"))
|
||||||
|
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
return m.HandleRequest(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func (ctrl *V1Controller) routeID(r *http.Request) (uuid.UUID, error) {
|
|||||||
func (ctrl *V1Controller) routeUUID(r *http.Request, key string) (uuid.UUID, error) {
|
func (ctrl *V1Controller) routeUUID(r *http.Request, key string) (uuid.UUID, error) {
|
||||||
ID, err := uuid.Parse(chi.URLParam(r, key))
|
ID, err := uuid.Parse(chi.URLParam(r, key))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return uuid.Nil, validate.NewInvalidRouteKeyError(key)
|
return uuid.Nil, validate.NewRouteKeyError(key)
|
||||||
}
|
}
|
||||||
return ID, nil
|
return ID, nil
|
||||||
}
|
}
|
||||||
|
|||||||
70
backend/app/api/handlers/v1/v1_ctrl_actions.go
Normal file
70
backend/app/api/handlers/v1/v1_ctrl_actions.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
||||||
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
|
"github.com/hay-kot/httpkit/server"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ActionAmountResult struct {
|
||||||
|
Completed int `json:"completed"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func actionHandlerFactory(ref string, fn func(context.Context, uuid.UUID) (int, error)) errchain.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
ctx := services.NewContext(r.Context())
|
||||||
|
|
||||||
|
totalCompleted, err := fn(ctx, ctx.GID)
|
||||||
|
if err != nil {
|
||||||
|
log.Err(err).Str("action_ref", ref).Msg("failed to run action")
|
||||||
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return server.JSON(w, http.StatusOK, ActionAmountResult{Completed: totalCompleted})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleEnsureAssetID godoc
|
||||||
|
//
|
||||||
|
// @Summary Ensure Asset IDs
|
||||||
|
// @Description Ensures all items in the database have an asset ID
|
||||||
|
// @Tags Actions
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} ActionAmountResult
|
||||||
|
// @Router /v1/actions/ensure-asset-ids [Post]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleEnsureAssetID() errchain.HandlerFunc {
|
||||||
|
return actionHandlerFactory("ensure asset IDs", ctrl.svc.Items.EnsureAssetID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleEnsureImportRefs godoc
|
||||||
|
//
|
||||||
|
// @Summary Ensures Import Refs
|
||||||
|
// @Description Ensures all items in the database have an import ref
|
||||||
|
// @Tags Actions
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} ActionAmountResult
|
||||||
|
// @Router /v1/actions/ensure-import-refs [Post]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleEnsureImportRefs() errchain.HandlerFunc {
|
||||||
|
return actionHandlerFactory("ensure import refs", ctrl.svc.Items.EnsureImportRef)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleItemDateZeroOut godoc
|
||||||
|
//
|
||||||
|
// @Summary Zero Out Time Fields
|
||||||
|
// @Description Resets all item date fields to the beginning of the day
|
||||||
|
// @Tags Actions
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} ActionAmountResult
|
||||||
|
// @Router /v1/actions/zero-item-time-fields [Post]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleItemDateZeroOut() errchain.HandlerFunc {
|
||||||
|
return actionHandlerFactory("zero out date time", ctrl.repo.Items.ZeroOutTimeFields)
|
||||||
|
}
|
||||||
62
backend/app/api/handlers/v1/v1_ctrl_assets.go
Normal file
62
backend/app/api/handlers/v1/v1_ctrl_assets.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
||||||
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
|
"github.com/hay-kot/httpkit/server"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandleAssetGet godocs
|
||||||
|
//
|
||||||
|
// @Summary Get Item by Asset ID
|
||||||
|
// @Tags Items
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "Asset ID"
|
||||||
|
// @Success 200 {object} repo.PaginationResult[repo.ItemSummary]{}
|
||||||
|
// @Router /v1/assets/{id} [GET]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleAssetGet() errchain.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
ctx := services.NewContext(r.Context())
|
||||||
|
assetIdParam := chi.URLParam(r, "id")
|
||||||
|
assetIdParam = strings.ReplaceAll(assetIdParam, "-", "") // Remove dashes
|
||||||
|
// Convert the asset ID to an int64
|
||||||
|
assetId, err := strconv.ParseInt(assetIdParam, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pageParam := r.URL.Query().Get("page")
|
||||||
|
var page int64 = -1
|
||||||
|
if pageParam != "" {
|
||||||
|
page, err = strconv.ParseInt(pageParam, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return server.JSON(w, http.StatusBadRequest, "Invalid page number")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pageSizeParam := r.URL.Query().Get("pageSize")
|
||||||
|
var pageSize int64 = -1
|
||||||
|
if pageSizeParam != "" {
|
||||||
|
pageSize, err = strconv.ParseInt(pageSizeParam, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return server.JSON(w, http.StatusBadRequest, "Invalid page size")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
items, err := ctrl.repo.Items.QueryByAssetID(r.Context(), ctx.GID, repo.AssetID(assetId), int(page), int(pageSize))
|
||||||
|
if err != nil {
|
||||||
|
log.Err(err).Msg("failed to get item")
|
||||||
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return server.JSON(w, http.StatusOK, items)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,57 +3,64 @@ package v1
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
|
"github.com/hay-kot/httpkit/server"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
TokenResponse struct {
|
TokenResponse struct {
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
ExpiresAt time.Time `json:"expiresAt"`
|
ExpiresAt time.Time `json:"expiresAt"`
|
||||||
|
AttachmentToken string `json:"attachmentToken"`
|
||||||
}
|
}
|
||||||
|
|
||||||
LoginForm struct {
|
LoginForm struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
|
StayLoggedIn bool `json:"stayLoggedIn"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// HandleAuthLogin godoc
|
// HandleAuthLogin godoc
|
||||||
// @Summary User Login
|
//
|
||||||
// @Tags Authentication
|
// @Summary User Login
|
||||||
// @Accept x-www-form-urlencoded
|
// @Tags Authentication
|
||||||
// @Accept application/json
|
// @Accept x-www-form-urlencoded
|
||||||
// @Param username formData string false "string" example(admin@admin.com)
|
// @Accept application/json
|
||||||
// @Param password formData string false "string" example(admin)
|
// @Param username formData string false "string" example(admin@admin.com)
|
||||||
// @Produce json
|
// @Param password formData string false "string" example(admin)
|
||||||
// @Success 200 {object} TokenResponse
|
// @Param payload body LoginForm true "Login Data"
|
||||||
// @Router /v1/users/login [POST]
|
// @Produce json
|
||||||
func (ctrl *V1Controller) HandleAuthLogin() server.HandlerFunc {
|
// @Success 200 {object} TokenResponse
|
||||||
|
// @Router /v1/users/login [POST]
|
||||||
|
func (ctrl *V1Controller) HandleAuthLogin() errchain.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
loginForm := &LoginForm{}
|
loginForm := &LoginForm{}
|
||||||
|
|
||||||
switch r.Header.Get("Content-Type") {
|
switch r.Header.Get("Content-Type") {
|
||||||
case server.ContentFormUrlEncoded:
|
case "application/x-www-form-urlencoded":
|
||||||
err := r.ParseForm()
|
err := r.ParseForm()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return server.Respond(w, http.StatusBadRequest, server.Wrap(err))
|
return errors.New("failed to parse form")
|
||||||
}
|
}
|
||||||
|
|
||||||
loginForm.Username = r.PostFormValue("username")
|
loginForm.Username = r.PostFormValue("username")
|
||||||
loginForm.Password = r.PostFormValue("password")
|
loginForm.Password = r.PostFormValue("password")
|
||||||
case server.ContentJSON:
|
loginForm.StayLoggedIn = r.PostFormValue("stayLoggedIn") == "true"
|
||||||
|
case "application/json":
|
||||||
err := server.Decode(r, loginForm)
|
err := server.Decode(r, loginForm)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg("failed to decode login form")
|
log.Err(err).Msg("failed to decode login form")
|
||||||
|
return errors.New("failed to decode login form")
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return server.Respond(w, http.StatusBadRequest, errors.New("invalid content type"))
|
return server.JSON(w, http.StatusBadRequest, errors.New("invalid content type"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if loginForm.Username == "" || loginForm.Password == "" {
|
if loginForm.Username == "" || loginForm.Password == "" {
|
||||||
@@ -69,26 +76,27 @@ func (ctrl *V1Controller) HandleAuthLogin() server.HandlerFunc {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
newToken, err := ctrl.svc.User.Login(r.Context(), loginForm.Username, loginForm.Password)
|
newToken, err := ctrl.svc.User.Login(r.Context(), strings.ToLower(loginForm.Username), loginForm.Password, loginForm.StayLoggedIn)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return validate.NewRequestError(errors.New("authentication failed"), http.StatusInternalServerError)
|
return validate.NewRequestError(errors.New("authentication failed"), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
return server.Respond(w, http.StatusOK, TokenResponse{
|
return server.JSON(w, http.StatusOK, TokenResponse{
|
||||||
Token: "Bearer " + newToken.Raw,
|
Token: "Bearer " + newToken.Raw,
|
||||||
ExpiresAt: newToken.ExpiresAt,
|
ExpiresAt: newToken.ExpiresAt,
|
||||||
|
AttachmentToken: newToken.AttachmentToken,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleAuthLogout godoc
|
// HandleAuthLogout godoc
|
||||||
// @Summary User Logout
|
//
|
||||||
// @Tags Authentication
|
// @Summary User Logout
|
||||||
// @Success 204
|
// @Tags Authentication
|
||||||
// @Router /v1/users/logout [POST]
|
// @Success 204
|
||||||
// @Security Bearer
|
// @Router /v1/users/logout [POST]
|
||||||
func (ctrl *V1Controller) HandleAuthLogout() server.HandlerFunc {
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleAuthLogout() errchain.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
token := services.UseTokenCtx(r.Context())
|
token := services.UseTokenCtx(r.Context())
|
||||||
if token == "" {
|
if token == "" {
|
||||||
@@ -100,19 +108,20 @@ func (ctrl *V1Controller) HandleAuthLogout() server.HandlerFunc {
|
|||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
return server.Respond(w, http.StatusNoContent, nil)
|
return server.JSON(w, http.StatusNoContent, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleAuthLogout godoc
|
// HandleAuthLogout godoc
|
||||||
// @Summary User Token Refresh
|
//
|
||||||
// @Description handleAuthRefresh returns a handler that will issue a new token from an existing token.
|
// @Summary User Token Refresh
|
||||||
// @Description This does not validate that the user still exists within the database.
|
// @Description handleAuthRefresh returns a handler that will issue a new token from an existing token.
|
||||||
// @Tags Authentication
|
// @Description This does not validate that the user still exists within the database.
|
||||||
// @Success 200
|
// @Tags Authentication
|
||||||
// @Router /v1/users/refresh [GET]
|
// @Success 200
|
||||||
// @Security Bearer
|
// @Router /v1/users/refresh [GET]
|
||||||
func (ctrl *V1Controller) HandleAuthRefresh() server.HandlerFunc {
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleAuthRefresh() errchain.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
requestToken := services.UseTokenCtx(r.Context())
|
requestToken := services.UseTokenCtx(r.Context())
|
||||||
if requestToken == "" {
|
if requestToken == "" {
|
||||||
@@ -124,6 +133,6 @@ func (ctrl *V1Controller) HandleAuthRefresh() server.HandlerFunc {
|
|||||||
return validate.NewUnauthorizedError()
|
return validate.NewUnauthorizedError()
|
||||||
}
|
}
|
||||||
|
|
||||||
return server.Respond(w, http.StatusOK, newToken)
|
return server.JSON(w, http.StatusOK, newToken)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,14 +6,13 @@ import (
|
|||||||
|
|
||||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
"github.com/hay-kot/homebox/backend/internal/web/adapters"
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
GroupInvitationCreate struct {
|
GroupInvitationCreate struct {
|
||||||
Uses int `json:"uses"`
|
Uses int `json:"uses" validate:"required,min=1,max=100"`
|
||||||
ExpiresAt time.Time `json:"expiresAt"`
|
ExpiresAt time.Time `json:"expiresAt"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,113 +24,65 @@ type (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// HandleGroupGet godoc
|
// HandleGroupGet godoc
|
||||||
// @Summary Get the current user's group
|
//
|
||||||
// @Tags Group
|
// @Summary Get Group
|
||||||
// @Produce json
|
// @Tags Group
|
||||||
// @Success 200 {object} repo.GroupStatistics
|
// @Produce json
|
||||||
// @Router /v1/groups/statistics [Get]
|
// @Success 200 {object} repo.Group
|
||||||
// @Security Bearer
|
// @Router /v1/groups [Get]
|
||||||
func (ctrl *V1Controller) HandleGroupStatistics() server.HandlerFunc {
|
// @Security Bearer
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
func (ctrl *V1Controller) HandleGroupGet() errchain.HandlerFunc {
|
||||||
ctx := services.NewContext(r.Context())
|
fn := func(r *http.Request) (repo.Group, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
stats, err := ctrl.repo.Groups.GroupStatistics(ctx, ctx.GID)
|
return ctrl.repo.Groups.GroupByID(auth, auth.GID)
|
||||||
if err != nil {
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
return server.Respond(w, http.StatusOK, stats)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// HandleGroupGet godoc
|
return adapters.Command(fn, http.StatusOK)
|
||||||
// @Summary Get the current user's group
|
|
||||||
// @Tags Group
|
|
||||||
// @Produce json
|
|
||||||
// @Success 200 {object} repo.Group
|
|
||||||
// @Router /v1/groups [Get]
|
|
||||||
// @Security Bearer
|
|
||||||
func (ctrl *V1Controller) HandleGroupGet() server.HandlerFunc {
|
|
||||||
return ctrl.handleGroupGeneral()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleGroupUpdate godoc
|
// HandleGroupUpdate godoc
|
||||||
// @Summary Updates some fields of the current users group
|
//
|
||||||
// @Tags Group
|
// @Summary Update Group
|
||||||
// @Produce json
|
// @Tags Group
|
||||||
// @Param payload body repo.GroupUpdate true "User Data"
|
// @Produce json
|
||||||
// @Success 200 {object} repo.Group
|
// @Param payload body repo.GroupUpdate true "User Data"
|
||||||
// @Router /v1/groups [Put]
|
// @Success 200 {object} repo.Group
|
||||||
// @Security Bearer
|
// @Router /v1/groups [Put]
|
||||||
func (ctrl *V1Controller) HandleGroupUpdate() server.HandlerFunc {
|
// @Security Bearer
|
||||||
return ctrl.handleGroupGeneral()
|
func (ctrl *V1Controller) HandleGroupUpdate() errchain.HandlerFunc {
|
||||||
}
|
fn := func(r *http.Request, body repo.GroupUpdate) (repo.Group, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
func (ctrl *V1Controller) handleGroupGeneral() server.HandlerFunc {
|
return ctrl.svc.Group.UpdateGroup(auth, body)
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
|
||||||
ctx := services.NewContext(r.Context())
|
|
||||||
|
|
||||||
switch r.Method {
|
|
||||||
case http.MethodGet:
|
|
||||||
group, err := ctrl.repo.Groups.GroupByID(ctx, ctx.GID)
|
|
||||||
if err != nil {
|
|
||||||
log.Err(err).Msg("failed to get group")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
return server.Respond(w, http.StatusOK, group)
|
|
||||||
|
|
||||||
case http.MethodPut:
|
|
||||||
data := repo.GroupUpdate{}
|
|
||||||
if err := server.Decode(r, &data); err != nil {
|
|
||||||
return validate.NewRequestError(err, http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
group, err := ctrl.svc.Group.UpdateGroup(ctx, data)
|
|
||||||
if err != nil {
|
|
||||||
log.Err(err).Msg("failed to update group")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
return server.Respond(w, http.StatusOK, group)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return adapters.Action(fn, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleGroupInvitationsCreate godoc
|
// HandleGroupInvitationsCreate godoc
|
||||||
// @Summary Get the current user
|
//
|
||||||
// @Tags Group
|
// @Summary Create Group Invitation
|
||||||
// @Produce json
|
// @Tags Group
|
||||||
// @Param payload body GroupInvitationCreate true "User Data"
|
// @Produce json
|
||||||
// @Success 200 {object} GroupInvitation
|
// @Param payload body GroupInvitationCreate true "User Data"
|
||||||
// @Router /v1/groups/invitations [Post]
|
// @Success 200 {object} GroupInvitation
|
||||||
// @Security Bearer
|
// @Router /v1/groups/invitations [Post]
|
||||||
func (ctrl *V1Controller) HandleGroupInvitationsCreate() server.HandlerFunc {
|
// @Security Bearer
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
func (ctrl *V1Controller) HandleGroupInvitationsCreate() errchain.HandlerFunc {
|
||||||
data := GroupInvitationCreate{}
|
fn := func(r *http.Request, body GroupInvitationCreate) (GroupInvitation, error) {
|
||||||
if err := server.Decode(r, &data); err != nil {
|
if body.ExpiresAt.IsZero() {
|
||||||
log.Err(err).Msg("failed to decode user registration data")
|
body.ExpiresAt = time.Now().Add(time.Hour * 24)
|
||||||
return validate.NewRequestError(err, http.StatusBadRequest)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.ExpiresAt.IsZero() {
|
auth := services.NewContext(r.Context())
|
||||||
data.ExpiresAt = time.Now().Add(time.Hour * 24)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := services.NewContext(r.Context())
|
token, err := ctrl.svc.Group.NewInvitation(auth, body.Uses, body.ExpiresAt)
|
||||||
|
|
||||||
token, err := ctrl.svc.Group.NewInvitation(ctx, data.Uses, data.ExpiresAt)
|
return GroupInvitation{
|
||||||
if err != nil {
|
|
||||||
log.Err(err).Msg("failed to create new token")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
return server.Respond(w, http.StatusCreated, GroupInvitation{
|
|
||||||
Token: token,
|
Token: token,
|
||||||
ExpiresAt: data.ExpiresAt,
|
ExpiresAt: body.ExpiresAt,
|
||||||
Uses: data.Uses,
|
Uses: body.Uses,
|
||||||
})
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return adapters.Action(fn, http.StatusCreated)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,171 +1,251 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"encoding/csv"
|
"encoding/csv"
|
||||||
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
"github.com/hay-kot/homebox/backend/internal/web/adapters"
|
||||||
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
|
"github.com/hay-kot/httpkit/server"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HandleItemsGetAll godoc
|
// HandleItemsGetAll godoc
|
||||||
// @Summary Get All Items
|
//
|
||||||
// @Tags Items
|
// @Summary Query All Items
|
||||||
// @Produce json
|
// @Tags Items
|
||||||
// @Param q query string false "search string"
|
// @Produce json
|
||||||
// @Param page query int false "page number"
|
// @Param q query string false "search string"
|
||||||
// @Param pageSize query int false "items per page"
|
// @Param page query int false "page number"
|
||||||
// @Param labels query []string false "label Ids" collectionFormat(multi)
|
// @Param pageSize query int false "items per page"
|
||||||
// @Param locations query []string false "location Ids" collectionFormat(multi)
|
// @Param labels query []string false "label Ids" collectionFormat(multi)
|
||||||
// @Success 200 {object} repo.PaginationResult[repo.ItemSummary]{}
|
// @Param locations query []string false "location Ids" collectionFormat(multi)
|
||||||
// @Router /v1/items [GET]
|
// @Success 200 {object} repo.PaginationResult[repo.ItemSummary]{}
|
||||||
// @Security Bearer
|
// @Router /v1/items [GET]
|
||||||
func (ctrl *V1Controller) HandleItemsGetAll() server.HandlerFunc {
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleItemsGetAll() errchain.HandlerFunc {
|
||||||
extractQuery := func(r *http.Request) repo.ItemQuery {
|
extractQuery := func(r *http.Request) repo.ItemQuery {
|
||||||
params := r.URL.Query()
|
params := r.URL.Query()
|
||||||
|
|
||||||
return repo.ItemQuery{
|
filterFieldItems := func(raw []string) []repo.FieldQuery {
|
||||||
|
var items []repo.FieldQuery
|
||||||
|
|
||||||
|
for _, v := range raw {
|
||||||
|
parts := strings.SplitN(v, "=", 2)
|
||||||
|
if len(parts) == 2 {
|
||||||
|
items = append(items, repo.FieldQuery{
|
||||||
|
Name: parts[0],
|
||||||
|
Value: parts[1],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
v := repo.ItemQuery{
|
||||||
Page: queryIntOrNegativeOne(params.Get("page")),
|
Page: queryIntOrNegativeOne(params.Get("page")),
|
||||||
PageSize: queryIntOrNegativeOne(params.Get("perPage")),
|
PageSize: queryIntOrNegativeOne(params.Get("pageSize")),
|
||||||
Search: params.Get("q"),
|
Search: params.Get("q"),
|
||||||
LocationIDs: queryUUIDList(params, "locations"),
|
LocationIDs: queryUUIDList(params, "locations"),
|
||||||
LabelIDs: queryUUIDList(params, "labels"),
|
LabelIDs: queryUUIDList(params, "labels"),
|
||||||
IncludeArchived: queryBool(params.Get("includeArchived")),
|
IncludeArchived: queryBool(params.Get("includeArchived")),
|
||||||
|
Fields: filterFieldItems(params["fields"]),
|
||||||
|
OrderBy: params.Get("orderBy"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(v.Search, "#") {
|
||||||
|
aidStr := strings.TrimPrefix(v.Search, "#")
|
||||||
|
|
||||||
|
aid, ok := repo.ParseAssetID(aidStr)
|
||||||
|
if ok {
|
||||||
|
v.Search = ""
|
||||||
|
v.AssetID = aid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
ctx := services.NewContext(r.Context())
|
ctx := services.NewContext(r.Context())
|
||||||
|
|
||||||
items, err := ctrl.repo.Items.QueryByGroup(ctx, ctx.GID, extractQuery(r))
|
items, err := ctrl.repo.Items.QueryByGroup(ctx, ctx.GID, extractQuery(r))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return server.JSON(w, http.StatusOK, repo.PaginationResult[repo.ItemSummary]{
|
||||||
|
Items: []repo.ItemSummary{},
|
||||||
|
})
|
||||||
|
}
|
||||||
log.Err(err).Msg("failed to get items")
|
log.Err(err).Msg("failed to get items")
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
return server.Respond(w, http.StatusOK, items)
|
return server.JSON(w, http.StatusOK, items)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleItemsCreate godoc
|
// HandleItemsCreate godoc
|
||||||
// @Summary Create a new item
|
//
|
||||||
// @Tags Items
|
// @Summary Create Item
|
||||||
// @Produce json
|
// @Tags Items
|
||||||
// @Param payload body repo.ItemCreate true "Item Data"
|
// @Produce json
|
||||||
// @Success 200 {object} repo.ItemSummary
|
// @Param payload body repo.ItemCreate true "Item Data"
|
||||||
// @Router /v1/items [POST]
|
// @Success 201 {object} repo.ItemSummary
|
||||||
// @Security Bearer
|
// @Router /v1/items [POST]
|
||||||
func (ctrl *V1Controller) HandleItemsCreate() server.HandlerFunc {
|
// @Security Bearer
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
func (ctrl *V1Controller) HandleItemsCreate() errchain.HandlerFunc {
|
||||||
createData := repo.ItemCreate{}
|
fn := func(r *http.Request, body repo.ItemCreate) (repo.ItemOut, error) {
|
||||||
if err := server.Decode(r, &createData); err != nil {
|
return ctrl.svc.Items.Create(services.NewContext(r.Context()), body)
|
||||||
log.Err(err).Msg("failed to decode request body")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
user := services.UseUserCtx(r.Context())
|
|
||||||
item, err := ctrl.repo.Items.Create(r.Context(), user.GroupID, createData)
|
|
||||||
if err != nil {
|
|
||||||
log.Err(err).Msg("failed to create item")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
return server.Respond(w, http.StatusCreated, item)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return adapters.Action(fn, http.StatusCreated)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleItemGet godocs
|
// HandleItemGet godocs
|
||||||
// @Summary Gets a item and fields
|
//
|
||||||
// @Tags Items
|
// @Summary Get Item
|
||||||
// @Produce json
|
// @Tags Items
|
||||||
// @Param id path string true "Item ID"
|
// @Produce json
|
||||||
// @Success 200 {object} repo.ItemOut
|
// @Param id path string true "Item ID"
|
||||||
// @Router /v1/items/{id} [GET]
|
// @Success 200 {object} repo.ItemOut
|
||||||
// @Security Bearer
|
// @Router /v1/items/{id} [GET]
|
||||||
func (ctrl *V1Controller) HandleItemGet() server.HandlerFunc {
|
// @Security Bearer
|
||||||
return ctrl.handleItemsGeneral()
|
func (ctrl *V1Controller) HandleItemGet() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request, ID uuid.UUID) (repo.ItemOut, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
|
||||||
|
return ctrl.repo.Items.GetOneByGroup(auth, auth.GID, ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.CommandID("id", fn, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleItemDelete godocs
|
// HandleItemDelete godocs
|
||||||
// @Summary deletes a item
|
//
|
||||||
// @Tags Items
|
// @Summary Delete Item
|
||||||
// @Produce json
|
// @Tags Items
|
||||||
// @Param id path string true "Item ID"
|
// @Produce json
|
||||||
// @Success 204
|
// @Param id path string true "Item ID"
|
||||||
// @Router /v1/items/{id} [DELETE]
|
// @Success 204
|
||||||
// @Security Bearer
|
// @Router /v1/items/{id} [DELETE]
|
||||||
func (ctrl *V1Controller) HandleItemDelete() server.HandlerFunc {
|
// @Security Bearer
|
||||||
return ctrl.handleItemsGeneral()
|
func (ctrl *V1Controller) HandleItemDelete() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request, ID uuid.UUID) (any, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
err := ctrl.repo.Items.DeleteByGroup(auth, auth.GID, ID)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.CommandID("id", fn, http.StatusNoContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleItemUpdate godocs
|
// HandleItemUpdate godocs
|
||||||
// @Summary updates a item
|
//
|
||||||
// @Tags Items
|
// @Summary Update Item
|
||||||
// @Produce json
|
// @Tags Items
|
||||||
// @Param id path string true "Item ID"
|
// @Produce json
|
||||||
// @Param payload body repo.ItemUpdate true "Item Data"
|
// @Param id path string true "Item ID"
|
||||||
// @Success 200 {object} repo.ItemOut
|
// @Param payload body repo.ItemUpdate true "Item Data"
|
||||||
// @Router /v1/items/{id} [PUT]
|
// @Success 200 {object} repo.ItemOut
|
||||||
// @Security Bearer
|
// @Router /v1/items/{id} [PUT]
|
||||||
func (ctrl *V1Controller) HandleItemUpdate() server.HandlerFunc {
|
// @Security Bearer
|
||||||
return ctrl.handleItemsGeneral()
|
func (ctrl *V1Controller) HandleItemUpdate() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request, ID uuid.UUID, body repo.ItemUpdate) (repo.ItemOut, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
|
||||||
|
body.ID = ID
|
||||||
|
return ctrl.repo.Items.UpdateByGroup(auth, auth.GID, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.ActionID("id", fn, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctrl *V1Controller) handleItemsGeneral() server.HandlerFunc {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
|
||||||
ctx := services.NewContext(r.Context())
|
|
||||||
ID, err := ctrl.routeID(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch r.Method {
|
// HandleItemPatch godocs
|
||||||
case http.MethodGet:
|
//
|
||||||
items, err := ctrl.repo.Items.GetOneByGroup(r.Context(), ctx.GID, ID)
|
// @Summary Update Item
|
||||||
if err != nil {
|
// @Tags Items
|
||||||
log.Err(err).Msg("failed to get item")
|
// @Produce json
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
// @Param id path string true "Item ID"
|
||||||
}
|
// @Param payload body repo.ItemPatch true "Item Data"
|
||||||
return server.Respond(w, http.StatusOK, items)
|
// @Success 200 {object} repo.ItemOut
|
||||||
case http.MethodDelete:
|
// @Router /v1/items/{id} [Patch]
|
||||||
err = ctrl.repo.Items.DeleteByGroup(r.Context(), ctx.GID, ID)
|
// @Security Bearer
|
||||||
if err != nil {
|
func (ctrl *V1Controller) HandleItemPatch() errchain.HandlerFunc {
|
||||||
log.Err(err).Msg("failed to delete item")
|
fn := func(r *http.Request, ID uuid.UUID, body repo.ItemPatch) (repo.ItemOut, error) {
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
auth := services.NewContext(r.Context())
|
||||||
}
|
|
||||||
return server.Respond(w, http.StatusNoContent, nil)
|
|
||||||
case http.MethodPut:
|
|
||||||
body := repo.ItemUpdate{}
|
|
||||||
if err := server.Decode(r, &body); err != nil {
|
|
||||||
log.Err(err).Msg("failed to decode request body")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
body.ID = ID
|
|
||||||
result, err := ctrl.repo.Items.UpdateByGroup(r.Context(), ctx.GID, body)
|
|
||||||
if err != nil {
|
|
||||||
log.Err(err).Msg("failed to update item")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
return server.Respond(w, http.StatusOK, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
body.ID = ID
|
||||||
|
err := ctrl.repo.Items.Patch(auth, auth.GID, ID, body)
|
||||||
|
if err != nil {
|
||||||
|
return repo.ItemOut{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrl.repo.Items.GetOneByGroup(auth, auth.GID, ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return adapters.ActionID("id", fn, http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleGetAllCustomFieldNames godocs
|
||||||
|
//
|
||||||
|
// @Summary Get All Custom Field Names
|
||||||
|
// @Tags Items
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200
|
||||||
|
// @Router /v1/items/fields [GET]
|
||||||
|
// @Success 200 {object} []string
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleGetAllCustomFieldNames() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request) ([]string, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
return ctrl.repo.Items.GetAllCustomFieldNames(auth, auth.GID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.Command(fn, http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleGetAllCustomFieldValues godocs
|
||||||
|
//
|
||||||
|
// @Summary Get All Custom Field Values
|
||||||
|
// @Tags Items
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200
|
||||||
|
// @Router /v1/items/fields/values [GET]
|
||||||
|
// @Success 200 {object} []string
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleGetAllCustomFieldValues() errchain.HandlerFunc {
|
||||||
|
type query struct {
|
||||||
|
Field string `schema:"field" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn := func(r *http.Request, q query) ([]string, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
return ctrl.repo.Items.GetAllCustomFieldValues(auth, auth.GID, q.Field)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.Action(fn, http.StatusOK)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleItemsImport godocs
|
// HandleItemsImport godocs
|
||||||
// @Summary imports items into the database
|
//
|
||||||
// @Tags Items
|
// @Summary Import Items
|
||||||
// @Produce json
|
// @Tags Items
|
||||||
// @Success 204
|
// @Produce json
|
||||||
// @Param csv formData file true "Image to upload"
|
// @Success 204
|
||||||
// @Router /v1/items/import [Post]
|
// @Param csv formData file true "Image to upload"
|
||||||
// @Security Bearer
|
// @Router /v1/items/import [Post]
|
||||||
func (ctrl *V1Controller) HandleItemsImport() server.HandlerFunc {
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleItemsImport() errchain.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
|
||||||
err := r.ParseMultipartForm(ctrl.maxUploadSize << 20)
|
err := r.ParseMultipartForm(ctrl.maxUploadSize << 20)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg("failed to parse multipart form")
|
log.Err(err).Msg("failed to parse multipart form")
|
||||||
@@ -178,21 +258,40 @@ func (ctrl *V1Controller) HandleItemsImport() server.HandlerFunc {
|
|||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
reader := csv.NewReader(file)
|
|
||||||
data, err := reader.ReadAll()
|
|
||||||
if err != nil {
|
|
||||||
log.Err(err).Msg("failed to read csv")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
user := services.UseUserCtx(r.Context())
|
user := services.UseUserCtx(r.Context())
|
||||||
|
|
||||||
_, err = ctrl.svc.Items.CsvImport(r.Context(), user.GroupID, data)
|
_, err = ctrl.svc.Items.CsvImport(r.Context(), user.GroupID, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg("failed to import items")
|
log.Err(err).Msg("failed to import items")
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
return server.Respond(w, http.StatusNoContent, nil)
|
return server.JSON(w, http.StatusNoContent, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleItemsExport godocs
|
||||||
|
//
|
||||||
|
// @Summary Export Items
|
||||||
|
// @Tags Items
|
||||||
|
// @Success 200 {string} string "text/csv"
|
||||||
|
// @Router /v1/items/export [GET]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleItemsExport() errchain.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
ctx := services.NewContext(r.Context())
|
||||||
|
|
||||||
|
csvData, err := ctrl.svc.Items.ExportTSV(r.Context(), ctx.GID)
|
||||||
|
if err != nil {
|
||||||
|
log.Err(err).Msg("failed to export items")
|
||||||
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "text/tsv")
|
||||||
|
w.Header().Set("Content-Disposition", "attachment;filename=homebox-items.tsv")
|
||||||
|
|
||||||
|
writer := csv.NewWriter(w)
|
||||||
|
writer.Comma = '\t'
|
||||||
|
return writer.WriteAll(csvData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ package v1
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
|
"github.com/hay-kot/httpkit/server"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -19,19 +19,20 @@ type (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// HandleItemsImport godocs
|
// HandleItemAttachmentCreate godocs
|
||||||
// @Summary imports items into the database
|
//
|
||||||
// @Tags Items Attachments
|
// @Summary Create Item Attachment
|
||||||
// @Produce json
|
// @Tags Items Attachments
|
||||||
// @Param id path string true "Item ID"
|
// @Produce json
|
||||||
// @Param file formData file true "File attachment"
|
// @Param id path string true "Item ID"
|
||||||
// @Param type formData string true "Type of file"
|
// @Param file formData file true "File attachment"
|
||||||
// @Param name formData string true "name of the file including extension"
|
// @Param type formData string true "Type of file"
|
||||||
// @Success 200 {object} repo.ItemOut
|
// @Param name formData string true "name of the file including extension"
|
||||||
// @Failure 422 {object} server.ErrorResponse
|
// @Success 200 {object} repo.ItemOut
|
||||||
// @Router /v1/items/{id}/attachments [POST]
|
// @Failure 422 {object} validate.ErrorResponse
|
||||||
// @Security Bearer
|
// @Router /v1/items/{id}/attachments [POST]
|
||||||
func (ctrl *V1Controller) HandleItemAttachmentCreate() server.HandlerFunc {
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleItemAttachmentCreate() errchain.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
err := r.ParseMultipartForm(ctrl.maxUploadSize << 20)
|
err := r.ParseMultipartForm(ctrl.maxUploadSize << 20)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -61,7 +62,7 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() server.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !errs.Nil() {
|
if !errs.Nil() {
|
||||||
return server.Respond(w, http.StatusUnprocessableEntity, errs)
|
return server.JSON(w, http.StatusUnprocessableEntity, errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
attachmentType := r.FormValue("type")
|
attachmentType := r.FormValue("type")
|
||||||
@@ -83,78 +84,53 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() server.HandlerFunc {
|
|||||||
attachment.Type(attachmentType),
|
attachment.Type(attachmentType),
|
||||||
file,
|
file,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg("failed to add attachment")
|
log.Err(err).Msg("failed to add attachment")
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
return server.Respond(w, http.StatusCreated, item)
|
return server.JSON(w, http.StatusCreated, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleItemAttachmentGet godocs
|
// HandleItemAttachmentGet godocs
|
||||||
// @Summary retrieves an attachment for an item
|
//
|
||||||
// @Tags Items Attachments
|
// @Summary Get Item Attachment
|
||||||
// @Produce application/octet-stream
|
// @Tags Items Attachments
|
||||||
// @Param id path string true "Item ID"
|
// @Produce application/octet-stream
|
||||||
// @Param token query string true "Attachment token"
|
// @Param id path string true "Item ID"
|
||||||
// @Success 200
|
// @Param attachment_id path string true "Attachment ID"
|
||||||
// @Router /v1/items/{id}/attachments/download [GET]
|
// @Success 200 {object} ItemAttachmentToken
|
||||||
// @Security Bearer
|
// @Router /v1/items/{id}/attachments/{attachment_id} [GET]
|
||||||
func (ctrl *V1Controller) HandleItemAttachmentDownload() server.HandlerFunc {
|
// @Security Bearer
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
func (ctrl *V1Controller) HandleItemAttachmentGet() errchain.HandlerFunc {
|
||||||
token := server.GetParam(r, "token", "")
|
|
||||||
|
|
||||||
doc, err := ctrl.svc.Items.AttachmentPath(r.Context(), token)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Err(err).Msg("failed to get attachment")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", doc.Title))
|
|
||||||
w.Header().Set("Content-Type", "application/octet-stream")
|
|
||||||
http.ServeFile(w, r, doc.Path)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleItemAttachmentToken godocs
|
|
||||||
// @Summary retrieves an attachment for an item
|
|
||||||
// @Tags Items Attachments
|
|
||||||
// @Produce application/octet-stream
|
|
||||||
// @Param id path string true "Item ID"
|
|
||||||
// @Param attachment_id path string true "Attachment ID"
|
|
||||||
// @Success 200 {object} ItemAttachmentToken
|
|
||||||
// @Router /v1/items/{id}/attachments/{attachment_id} [GET]
|
|
||||||
// @Security Bearer
|
|
||||||
func (ctrl *V1Controller) HandleItemAttachmentToken() server.HandlerFunc {
|
|
||||||
return ctrl.handleItemAttachmentsHandler
|
return ctrl.handleItemAttachmentsHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleItemAttachmentDelete godocs
|
// HandleItemAttachmentDelete godocs
|
||||||
// @Summary retrieves an attachment for an item
|
//
|
||||||
// @Tags Items Attachments
|
// @Summary Delete Item Attachment
|
||||||
// @Param id path string true "Item ID"
|
// @Tags Items Attachments
|
||||||
// @Param attachment_id path string true "Attachment ID"
|
// @Param id path string true "Item ID"
|
||||||
// @Success 204
|
// @Param attachment_id path string true "Attachment ID"
|
||||||
// @Router /v1/items/{id}/attachments/{attachment_id} [DELETE]
|
// @Success 204
|
||||||
// @Security Bearer
|
// @Router /v1/items/{id}/attachments/{attachment_id} [DELETE]
|
||||||
func (ctrl *V1Controller) HandleItemAttachmentDelete() server.HandlerFunc {
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleItemAttachmentDelete() errchain.HandlerFunc {
|
||||||
return ctrl.handleItemAttachmentsHandler
|
return ctrl.handleItemAttachmentsHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleItemAttachmentUpdate godocs
|
// HandleItemAttachmentUpdate godocs
|
||||||
// @Summary retrieves an attachment for an item
|
//
|
||||||
// @Tags Items Attachments
|
// @Summary Update Item Attachment
|
||||||
// @Param id path string true "Item ID"
|
// @Tags Items Attachments
|
||||||
// @Param attachment_id path string true "Attachment ID"
|
// @Param id path string true "Item ID"
|
||||||
// @Param payload body repo.ItemAttachmentUpdate true "Attachment Update"
|
// @Param attachment_id path string true "Attachment ID"
|
||||||
// @Success 200 {object} repo.ItemOut
|
// @Param payload body repo.ItemAttachmentUpdate true "Attachment Update"
|
||||||
// @Router /v1/items/{id}/attachments/{attachment_id} [PUT]
|
// @Success 200 {object} repo.ItemOut
|
||||||
// @Security Bearer
|
// @Router /v1/items/{id}/attachments/{attachment_id} [PUT]
|
||||||
func (ctrl *V1Controller) HandleItemAttachmentUpdate() server.HandlerFunc {
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleItemAttachmentUpdate() errchain.HandlerFunc {
|
||||||
return ctrl.handleItemAttachmentsHandler
|
return ctrl.handleItemAttachmentsHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,33 +147,15 @@ func (ctrl *V1Controller) handleItemAttachmentsHandler(w http.ResponseWriter, r
|
|||||||
|
|
||||||
ctx := services.NewContext(r.Context())
|
ctx := services.NewContext(r.Context())
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
// Token Handler
|
|
||||||
case http.MethodGet:
|
case http.MethodGet:
|
||||||
token, err := ctrl.svc.Items.AttachmentToken(ctx, ID, attachmentID)
|
doc, err := ctrl.svc.Items.AttachmentPath(r.Context(), attachmentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch err {
|
log.Err(err).Msg("failed to get attachment path")
|
||||||
case services.ErrNotFound:
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
log.Err(err).
|
|
||||||
Str("id", attachmentID.String()).
|
|
||||||
Msg("failed to find attachment with id")
|
|
||||||
|
|
||||||
return validate.NewRequestError(err, http.StatusNotFound)
|
|
||||||
|
|
||||||
case services.ErrFileNotFound:
|
|
||||||
log.Err(err).
|
|
||||||
Str("id", attachmentID.String()).
|
|
||||||
Msg("failed to find file path for attachment with id")
|
|
||||||
log.Warn().Msg("attachment with no file path removed from database")
|
|
||||||
|
|
||||||
return validate.NewRequestError(err, http.StatusNotFound)
|
|
||||||
|
|
||||||
default:
|
|
||||||
log.Err(err).Msg("failed to get attachment")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return server.Respond(w, http.StatusOK, ItemAttachmentToken{Token: token})
|
http.ServeFile(w, r, doc.Path)
|
||||||
|
return nil
|
||||||
|
|
||||||
// Delete Attachment Handler
|
// Delete Attachment Handler
|
||||||
case http.MethodDelete:
|
case http.MethodDelete:
|
||||||
@@ -207,7 +165,7 @@ func (ctrl *V1Controller) handleItemAttachmentsHandler(w http.ResponseWriter, r
|
|||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
return server.Respond(w, http.StatusNoContent, nil)
|
return server.JSON(w, http.StatusNoContent, nil)
|
||||||
|
|
||||||
// Update Attachment Handler
|
// Update Attachment Handler
|
||||||
case http.MethodPut:
|
case http.MethodPut:
|
||||||
@@ -225,7 +183,7 @@ func (ctrl *V1Controller) handleItemAttachmentsHandler(w http.ResponseWriter, r
|
|||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
return server.Respond(w, http.StatusOK, val)
|
return server.JSON(w, http.StatusOK, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -3,141 +3,100 @@ package v1
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
"github.com/hay-kot/homebox/backend/internal/web/adapters"
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// HandleLabelsGetAll godoc
|
// HandleLabelsGetAll godoc
|
||||||
// @Summary Get All Labels
|
//
|
||||||
// @Tags Labels
|
// @Summary Get All Labels
|
||||||
// @Produce json
|
// @Tags Labels
|
||||||
// @Success 200 {object} server.Results{items=[]repo.LabelOut}
|
// @Produce json
|
||||||
// @Router /v1/labels [GET]
|
// @Success 200 {object} []repo.LabelOut
|
||||||
// @Security Bearer
|
// @Router /v1/labels [GET]
|
||||||
func (ctrl *V1Controller) HandleLabelsGetAll() server.HandlerFunc {
|
// @Security Bearer
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
func (ctrl *V1Controller) HandleLabelsGetAll() errchain.HandlerFunc {
|
||||||
user := services.UseUserCtx(r.Context())
|
fn := func(r *http.Request) ([]repo.LabelSummary, error) {
|
||||||
labels, err := ctrl.repo.Labels.GetAll(r.Context(), user.GroupID)
|
auth := services.NewContext(r.Context())
|
||||||
if err != nil {
|
return ctrl.repo.Labels.GetAll(auth, auth.GID)
|
||||||
log.Err(err).Msg("error getting labels")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
return server.Respond(w, http.StatusOK, server.Results{Items: labels})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return adapters.Command(fn, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleLabelsCreate godoc
|
// HandleLabelsCreate godoc
|
||||||
// @Summary Create a new label
|
//
|
||||||
// @Tags Labels
|
// @Summary Create Label
|
||||||
// @Produce json
|
// @Tags Labels
|
||||||
// @Param payload body repo.LabelCreate true "Label Data"
|
// @Produce json
|
||||||
// @Success 200 {object} repo.LabelSummary
|
// @Param payload body repo.LabelCreate true "Label Data"
|
||||||
// @Router /v1/labels [POST]
|
// @Success 200 {object} repo.LabelSummary
|
||||||
// @Security Bearer
|
// @Router /v1/labels [POST]
|
||||||
func (ctrl *V1Controller) HandleLabelsCreate() server.HandlerFunc {
|
// @Security Bearer
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
func (ctrl *V1Controller) HandleLabelsCreate() errchain.HandlerFunc {
|
||||||
createData := repo.LabelCreate{}
|
fn := func(r *http.Request, data repo.LabelCreate) (repo.LabelOut, error) {
|
||||||
if err := server.Decode(r, &createData); err != nil {
|
auth := services.NewContext(r.Context())
|
||||||
log.Err(err).Msg("error decoding label create data")
|
return ctrl.repo.Labels.Create(auth, auth.GID, data)
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
user := services.UseUserCtx(r.Context())
|
|
||||||
label, err := ctrl.repo.Labels.Create(r.Context(), user.GroupID, createData)
|
|
||||||
if err != nil {
|
|
||||||
log.Err(err).Msg("error creating label")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
return server.Respond(w, http.StatusCreated, label)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return adapters.Action(fn, http.StatusCreated)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleLabelDelete godocs
|
// HandleLabelDelete godocs
|
||||||
// @Summary deletes a label
|
//
|
||||||
// @Tags Labels
|
// @Summary Delete Label
|
||||||
// @Produce json
|
// @Tags Labels
|
||||||
// @Param id path string true "Label ID"
|
// @Produce json
|
||||||
// @Success 204
|
// @Param id path string true "Label ID"
|
||||||
// @Router /v1/labels/{id} [DELETE]
|
// @Success 204
|
||||||
// @Security Bearer
|
// @Router /v1/labels/{id} [DELETE]
|
||||||
func (ctrl *V1Controller) HandleLabelDelete() server.HandlerFunc {
|
// @Security Bearer
|
||||||
return ctrl.handleLabelsGeneral()
|
func (ctrl *V1Controller) HandleLabelDelete() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request, ID uuid.UUID) (any, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
err := ctrl.repo.Labels.DeleteByGroup(auth, auth.GID, ID)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.CommandID("id", fn, http.StatusNoContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleLabelGet godocs
|
// HandleLabelGet godocs
|
||||||
// @Summary Gets a label and fields
|
//
|
||||||
// @Tags Labels
|
// @Summary Get Label
|
||||||
// @Produce json
|
// @Tags Labels
|
||||||
// @Param id path string true "Label ID"
|
// @Produce json
|
||||||
// @Success 200 {object} repo.LabelOut
|
// @Param id path string true "Label ID"
|
||||||
// @Router /v1/labels/{id} [GET]
|
// @Success 200 {object} repo.LabelOut
|
||||||
// @Security Bearer
|
// @Router /v1/labels/{id} [GET]
|
||||||
func (ctrl *V1Controller) HandleLabelGet() server.HandlerFunc {
|
// @Security Bearer
|
||||||
return ctrl.handleLabelsGeneral()
|
func (ctrl *V1Controller) HandleLabelGet() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request, ID uuid.UUID) (repo.LabelOut, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
return ctrl.repo.Labels.GetOneByGroup(auth, auth.GID, ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.CommandID("id", fn, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleLabelUpdate godocs
|
// HandleLabelUpdate godocs
|
||||||
// @Summary updates a label
|
//
|
||||||
// @Tags Labels
|
// @Summary Update Label
|
||||||
// @Produce json
|
// @Tags Labels
|
||||||
// @Param id path string true "Label ID"
|
// @Produce json
|
||||||
// @Success 200 {object} repo.LabelOut
|
// @Param id path string true "Label ID"
|
||||||
// @Router /v1/labels/{id} [PUT]
|
// @Success 200 {object} repo.LabelOut
|
||||||
// @Security Bearer
|
// @Router /v1/labels/{id} [PUT]
|
||||||
func (ctrl *V1Controller) HandleLabelUpdate() server.HandlerFunc {
|
// @Security Bearer
|
||||||
return ctrl.handleLabelsGeneral()
|
func (ctrl *V1Controller) HandleLabelUpdate() errchain.HandlerFunc {
|
||||||
}
|
fn := func(r *http.Request, ID uuid.UUID, data repo.LabelUpdate) (repo.LabelOut, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
func (ctrl *V1Controller) handleLabelsGeneral() server.HandlerFunc {
|
data.ID = ID
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
return ctrl.repo.Labels.UpdateByGroup(auth, auth.GID, data)
|
||||||
ctx := services.NewContext(r.Context())
|
|
||||||
ID, err := ctrl.routeID(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch r.Method {
|
|
||||||
case http.MethodGet:
|
|
||||||
labels, err := ctrl.repo.Labels.GetOneByGroup(r.Context(), ctx.GID, ID)
|
|
||||||
if err != nil {
|
|
||||||
if ent.IsNotFound(err) {
|
|
||||||
log.Err(err).
|
|
||||||
Str("id", ID.String()).
|
|
||||||
Msg("label not found")
|
|
||||||
return validate.NewRequestError(err, http.StatusNotFound)
|
|
||||||
}
|
|
||||||
log.Err(err).Msg("error getting label")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
return server.Respond(w, http.StatusOK, labels)
|
|
||||||
|
|
||||||
case http.MethodDelete:
|
|
||||||
err = ctrl.repo.Labels.DeleteByGroup(ctx, ctx.GID, ID)
|
|
||||||
if err != nil {
|
|
||||||
log.Err(err).Msg("error deleting label")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
return server.Respond(w, http.StatusNoContent, nil)
|
|
||||||
|
|
||||||
case http.MethodPut:
|
|
||||||
body := repo.LabelUpdate{}
|
|
||||||
if err := server.Decode(r, &body); err != nil {
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
body.ID = ID
|
|
||||||
result, err := ctrl.repo.Labels.UpdateByGroup(ctx, ctx.GID, body)
|
|
||||||
if err != nil {
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
return server.Respond(w, http.StatusOK, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return adapters.ActionID("id", fn, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,154 +3,120 @@ package v1
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
"github.com/hay-kot/homebox/backend/internal/web/adapters"
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// HandleLocationGetAll godoc
|
// HandleLocationTreeQuery
|
||||||
// @Summary Get All Locations
|
//
|
||||||
// @Tags Locations
|
// @Summary Get Locations Tree
|
||||||
// @Produce json
|
// @Tags Locations
|
||||||
// @Param filterChildren query bool false "Filter locations with parents"
|
// @Produce json
|
||||||
// @Success 200 {object} server.Results{items=[]repo.LocationOutCount}
|
// @Param withItems query bool false "include items in response tree"
|
||||||
// @Router /v1/locations [GET]
|
// @Success 200 {object} []repo.TreeItem
|
||||||
// @Security Bearer
|
// @Router /v1/locations/tree [GET]
|
||||||
func (ctrl *V1Controller) HandleLocationGetAll() server.HandlerFunc {
|
// @Security Bearer
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
func (ctrl *V1Controller) HandleLocationTreeQuery() errchain.HandlerFunc {
|
||||||
user := services.UseUserCtx(r.Context())
|
fn := func(r *http.Request, query repo.TreeQuery) ([]repo.TreeItem, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
q := r.URL.Query()
|
return ctrl.repo.Locations.Tree(auth, auth.GID, query)
|
||||||
|
|
||||||
filter := repo.LocationQuery{
|
|
||||||
FilterChildren: queryBool(q.Get("filterChildren")),
|
|
||||||
}
|
|
||||||
|
|
||||||
locations, err := ctrl.repo.Locations.GetAll(r.Context(), user.GroupID, filter)
|
|
||||||
if err != nil {
|
|
||||||
log.Err(err).Msg("failed to get locations")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
return server.Respond(w, http.StatusOK, server.Results{Items: locations})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return adapters.Query(fn, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleLocationCreate godoc
|
// HandleLocationGetAll
|
||||||
// @Summary Create a new location
|
//
|
||||||
// @Tags Locations
|
// @Summary Get All Locations
|
||||||
// @Produce json
|
// @Tags Locations
|
||||||
// @Param payload body repo.LocationCreate true "Location Data"
|
// @Produce json
|
||||||
// @Success 200 {object} repo.LocationSummary
|
// @Param filterChildren query bool false "Filter locations with parents"
|
||||||
// @Router /v1/locations [POST]
|
// @Success 200 {object} []repo.LocationOutCount
|
||||||
// @Security Bearer
|
// @Router /v1/locations [GET]
|
||||||
func (ctrl *V1Controller) HandleLocationCreate() server.HandlerFunc {
|
// @Security Bearer
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
func (ctrl *V1Controller) HandleLocationGetAll() errchain.HandlerFunc {
|
||||||
createData := repo.LocationCreate{}
|
fn := func(r *http.Request, q repo.LocationQuery) ([]repo.LocationOutCount, error) {
|
||||||
if err := server.Decode(r, &createData); err != nil {
|
auth := services.NewContext(r.Context())
|
||||||
log.Err(err).Msg("failed to decode location create data")
|
return ctrl.repo.Locations.GetAll(auth, auth.GID, q)
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
user := services.UseUserCtx(r.Context())
|
|
||||||
location, err := ctrl.repo.Locations.Create(r.Context(), user.GroupID, createData)
|
|
||||||
if err != nil {
|
|
||||||
log.Err(err).Msg("failed to create location")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
return server.Respond(w, http.StatusCreated, location)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return adapters.Query(fn, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleLocationDelete godocs
|
// HandleLocationCreate
|
||||||
// @Summary deletes a location
|
//
|
||||||
// @Tags Locations
|
// @Summary Create Location
|
||||||
// @Produce json
|
// @Tags Locations
|
||||||
// @Param id path string true "Location ID"
|
// @Produce json
|
||||||
// @Success 204
|
// @Param payload body repo.LocationCreate true "Location Data"
|
||||||
// @Router /v1/locations/{id} [DELETE]
|
// @Success 200 {object} repo.LocationSummary
|
||||||
// @Security Bearer
|
// @Router /v1/locations [POST]
|
||||||
func (ctrl *V1Controller) HandleLocationDelete() server.HandlerFunc {
|
// @Security Bearer
|
||||||
return ctrl.handleLocationGeneral()
|
func (ctrl *V1Controller) HandleLocationCreate() errchain.HandlerFunc {
|
||||||
}
|
fn := func(r *http.Request, createData repo.LocationCreate) (repo.LocationOut, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
// HandleLocationGet godocs
|
return ctrl.repo.Locations.Create(auth, auth.GID, createData)
|
||||||
// @Summary Gets a location and fields
|
|
||||||
// @Tags Locations
|
|
||||||
// @Produce json
|
|
||||||
// @Param id path string true "Location ID"
|
|
||||||
// @Success 200 {object} repo.LocationOut
|
|
||||||
// @Router /v1/locations/{id} [GET]
|
|
||||||
// @Security Bearer
|
|
||||||
func (ctrl *V1Controller) HandleLocationGet() server.HandlerFunc {
|
|
||||||
return ctrl.handleLocationGeneral()
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleLocationUpdate godocs
|
|
||||||
// @Summary updates a location
|
|
||||||
// @Tags Locations
|
|
||||||
// @Produce json
|
|
||||||
// @Param id path string true "Location ID"
|
|
||||||
// @Param payload body repo.LocationUpdate true "Location Data"
|
|
||||||
// @Success 200 {object} repo.LocationOut
|
|
||||||
// @Router /v1/locations/{id} [PUT]
|
|
||||||
// @Security Bearer
|
|
||||||
func (ctrl *V1Controller) HandleLocationUpdate() server.HandlerFunc {
|
|
||||||
return ctrl.handleLocationGeneral()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctrl *V1Controller) handleLocationGeneral() server.HandlerFunc {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
|
||||||
ctx := services.NewContext(r.Context())
|
|
||||||
ID, err := ctrl.routeID(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch r.Method {
|
|
||||||
case http.MethodGet:
|
|
||||||
location, err := ctrl.repo.Locations.GetOneByGroup(r.Context(), ctx.GID, ID)
|
|
||||||
if err != nil {
|
|
||||||
l := log.Err(err).
|
|
||||||
Str("ID", ID.String()).
|
|
||||||
Str("GID", ctx.GID.String())
|
|
||||||
|
|
||||||
if ent.IsNotFound(err) {
|
|
||||||
l.Msg("location not found")
|
|
||||||
return validate.NewRequestError(err, http.StatusNotFound)
|
|
||||||
}
|
|
||||||
|
|
||||||
l.Msg("failed to get location")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
return server.Respond(w, http.StatusOK, location)
|
|
||||||
case http.MethodPut:
|
|
||||||
body := repo.LocationUpdate{}
|
|
||||||
if err := server.Decode(r, &body); err != nil {
|
|
||||||
log.Err(err).Msg("failed to decode location update data")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
body.ID = ID
|
|
||||||
|
|
||||||
result, err := ctrl.repo.Locations.UpdateOneByGroup(r.Context(), ctx.GID, ID, body)
|
|
||||||
if err != nil {
|
|
||||||
log.Err(err).Msg("failed to update location")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
return server.Respond(w, http.StatusOK, result)
|
|
||||||
case http.MethodDelete:
|
|
||||||
err = ctrl.repo.Locations.DeleteByGroup(r.Context(), ctx.GID, ID)
|
|
||||||
if err != nil {
|
|
||||||
log.Err(err).Msg("failed to delete location")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
return server.Respond(w, http.StatusNoContent, nil)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return adapters.Action(fn, http.StatusCreated)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleLocationDelete
|
||||||
|
//
|
||||||
|
// @Summary Delete Location
|
||||||
|
// @Tags Locations
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "Location ID"
|
||||||
|
// @Success 204
|
||||||
|
// @Router /v1/locations/{id} [DELETE]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleLocationDelete() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request, ID uuid.UUID) (any, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
err := ctrl.repo.Locations.DeleteByGroup(auth, auth.GID, ID)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.CommandID("id", fn, http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleLocationGet
|
||||||
|
//
|
||||||
|
// @Summary Get Location
|
||||||
|
// @Tags Locations
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "Location ID"
|
||||||
|
// @Success 200 {object} repo.LocationOut
|
||||||
|
// @Router /v1/locations/{id} [GET]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleLocationGet() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request, ID uuid.UUID) (repo.LocationOut, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
return ctrl.repo.Locations.GetOneByGroup(auth, auth.GID, ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.CommandID("id", fn, http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleLocationUpdate
|
||||||
|
//
|
||||||
|
// @Summary Update Location
|
||||||
|
// @Tags Locations
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "Location ID"
|
||||||
|
// @Param payload body repo.LocationUpdate true "Location Data"
|
||||||
|
// @Success 200 {object} repo.LocationOut
|
||||||
|
// @Router /v1/locations/{id} [PUT]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleLocationUpdate() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request, ID uuid.UUID, body repo.LocationUpdate) (repo.LocationOut, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
body.ID = ID
|
||||||
|
return ctrl.repo.Locations.UpdateByGroup(auth, auth.GID, ID, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.ActionID("id", fn, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|||||||
82
backend/app/api/handlers/v1/v1_ctrl_maint_entry.go
Normal file
82
backend/app/api/handlers/v1/v1_ctrl_maint_entry.go
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/web/adapters"
|
||||||
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandleMaintenanceGetLog godoc
|
||||||
|
//
|
||||||
|
// @Summary Get Maintenance Log
|
||||||
|
// @Tags Maintenance
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} repo.MaintenanceLog
|
||||||
|
// @Router /v1/items/{id}/maintenance [GET]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleMaintenanceLogGet() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request, ID uuid.UUID, q repo.MaintenanceLogQuery) (repo.MaintenanceLog, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
return ctrl.repo.MaintEntry.GetLog(auth, auth.GID, ID, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.QueryID("id", fn, http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleMaintenanceEntryCreate godoc
|
||||||
|
//
|
||||||
|
// @Summary Create Maintenance Entry
|
||||||
|
// @Tags Maintenance
|
||||||
|
// @Produce json
|
||||||
|
// @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())
|
||||||
|
return ctrl.repo.MaintEntry.Create(auth, itemID, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.ActionID("id", fn, http.StatusCreated)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleMaintenanceEntryDelete godoc
|
||||||
|
//
|
||||||
|
// @Summary Delete Maintenance Entry
|
||||||
|
// @Tags Maintenance
|
||||||
|
// @Produce json
|
||||||
|
// @Success 204
|
||||||
|
// @Router /v1/items/{id}/maintenance/{entry_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())
|
||||||
|
err := ctrl.repo.MaintEntry.Delete(auth, entryID)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.CommandID("entry_id", fn, http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleMaintenanceEntryUpdate godoc
|
||||||
|
//
|
||||||
|
// @Summary Update Maintenance Entry
|
||||||
|
// @Tags Maintenance
|
||||||
|
// @Produce json
|
||||||
|
// @Param payload body repo.MaintenanceEntryUpdate true "Entry Data"
|
||||||
|
// @Success 200 {object} repo.MaintenanceEntry
|
||||||
|
// @Router /v1/items/{id}/maintenance/{entry_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())
|
||||||
|
return ctrl.repo.MaintEntry.Update(auth, entryID, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.ActionID("entry_id", fn, http.StatusOK)
|
||||||
|
}
|
||||||
105
backend/app/api/handlers/v1/v1_ctrl_notifiers.go
Normal file
105
backend/app/api/handlers/v1/v1_ctrl_notifiers.go
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/containrrr/shoutrrr"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/web/adapters"
|
||||||
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandleGetUserNotifiers godoc
|
||||||
|
//
|
||||||
|
// @Summary Get Notifiers
|
||||||
|
// @Tags Notifiers
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} []repo.NotifierOut
|
||||||
|
// @Router /v1/notifiers [GET]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleGetUserNotifiers() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request, _ struct{}) ([]repo.NotifierOut, error) {
|
||||||
|
user := services.UseUserCtx(r.Context())
|
||||||
|
return ctrl.repo.Notifiers.GetByUser(r.Context(), user.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.Query(fn, http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleCreateNotifier godoc
|
||||||
|
//
|
||||||
|
// @Summary Create Notifier
|
||||||
|
// @Tags Notifiers
|
||||||
|
// @Produce json
|
||||||
|
// @Param payload body repo.NotifierCreate true "Notifier Data"
|
||||||
|
// @Success 200 {object} repo.NotifierOut
|
||||||
|
// @Router /v1/notifiers [POST]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleCreateNotifier() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request, in repo.NotifierCreate) (repo.NotifierOut, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
return ctrl.repo.Notifiers.Create(auth, auth.GID, auth.UID, in)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.Action(fn, http.StatusCreated)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleDeleteNotifier godocs
|
||||||
|
//
|
||||||
|
// @Summary Delete a Notifier
|
||||||
|
// @Tags Notifiers
|
||||||
|
// @Param id path string true "Notifier ID"
|
||||||
|
// @Success 204
|
||||||
|
// @Router /v1/notifiers/{id} [DELETE]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleDeleteNotifier() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request, ID uuid.UUID) (any, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
return nil, ctrl.repo.Notifiers.Delete(auth, auth.UID, ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.CommandID("id", fn, http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleUpdateNotifier godocs
|
||||||
|
//
|
||||||
|
// @Summary Update Notifier
|
||||||
|
// @Tags Notifiers
|
||||||
|
// @Param id path string true "Notifier ID"
|
||||||
|
// @Param payload body repo.NotifierUpdate true "Notifier Data"
|
||||||
|
// @Success 200 {object} repo.NotifierOut
|
||||||
|
// @Router /v1/notifiers/{id} [PUT]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleUpdateNotifier() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request, ID uuid.UUID, in repo.NotifierUpdate) (repo.NotifierOut, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
return ctrl.repo.Notifiers.Update(auth, auth.UID, ID, in)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.ActionID("id", fn, http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandlerNotifierTest godoc
|
||||||
|
//
|
||||||
|
// @Summary Test Notifier
|
||||||
|
// @Tags Notifiers
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "Notifier ID"
|
||||||
|
// @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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn := func(r *http.Request, q body) (any, error) {
|
||||||
|
err := shoutrrr.Send(q.URL, "Test message from Homebox")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.Action(fn, http.StatusOK)
|
||||||
|
}
|
||||||
66
backend/app/api/handlers/v1/v1_ctrl_qrcode.go
Normal file
66
backend/app/api/handlers/v1/v1_ctrl_qrcode.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"image/png"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/web/adapters"
|
||||||
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
|
"github.com/yeqown/go-qrcode/v2"
|
||||||
|
"github.com/yeqown/go-qrcode/writer/standard"
|
||||||
|
|
||||||
|
_ "embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed assets/QRIcon.png
|
||||||
|
var qrcodeLogo []byte
|
||||||
|
|
||||||
|
// HandleGenerateQRCode godoc
|
||||||
|
//
|
||||||
|
// @Summary Create QR Code
|
||||||
|
// @Tags Items
|
||||||
|
// @Produce json
|
||||||
|
// @Param data query string false "data to be encoded into qrcode"
|
||||||
|
// @Success 200 {string} string "image/jpeg"
|
||||||
|
// @Router /v1/qrcode [GET]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleGenerateQRCode() errchain.HandlerFunc {
|
||||||
|
type query struct {
|
||||||
|
// 4,296 characters is the maximum length of a QR code
|
||||||
|
Data string `schema:"data" validate:"required,max=4296"`
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
q, err := adapters.DecodeQuery[query](r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
image, err := png.Decode(bytes.NewReader(qrcodeLogo))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
qrc, err := qrcode.New(q.Data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
toWriteCloser := struct {
|
||||||
|
io.Writer
|
||||||
|
io.Closer
|
||||||
|
}{
|
||||||
|
Writer: w,
|
||||||
|
Closer: io.NopCloser(nil),
|
||||||
|
}
|
||||||
|
|
||||||
|
qrwriter := standard.NewWithWriter(toWriteCloser, standard.WithLogoImage(image))
|
||||||
|
|
||||||
|
// Return the QR code as a jpeg image
|
||||||
|
w.Header().Set("Content-Type", "image/jpeg")
|
||||||
|
w.Header().Set("Content-Disposition", "attachment; filename=qrcode.jpg")
|
||||||
|
return qrc.Save(qrwriter)
|
||||||
|
}
|
||||||
|
}
|
||||||
32
backend/app/api/handlers/v1/v1_ctrl_reporting.go
Normal file
32
backend/app/api/handlers/v1/v1_ctrl_reporting.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandleBillOfMaterialsExport godoc
|
||||||
|
//
|
||||||
|
// @Summary Export Bill of Materials
|
||||||
|
// @Tags Reporting
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {string} string "text/csv"
|
||||||
|
// @Router /v1/reporting/bill-of-materials [GET]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleBillOfMaterialsExport() errchain.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
actor := services.UseUserCtx(r.Context())
|
||||||
|
|
||||||
|
csv, err := ctrl.svc.Items.ExportBillOfMaterialsTSV(r.Context(), actor.GroupID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "text/tsv")
|
||||||
|
w.Header().Set("Content-Disposition", "attachment; filename=bill-of-materials.tsv")
|
||||||
|
_, err = w.Write(csv)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
104
backend/app/api/handlers/v1/v1_ctrl_statistics.go
Normal file
104
backend/app/api/handlers/v1/v1_ctrl_statistics.go
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/web/adapters"
|
||||||
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
|
"github.com/hay-kot/httpkit/server"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandleGroupGet godoc
|
||||||
|
//
|
||||||
|
// @Summary Get Location Statistics
|
||||||
|
// @Tags Statistics
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} []repo.TotalsByOrganizer
|
||||||
|
// @Router /v1/groups/statistics/locations [GET]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleGroupStatisticsLocations() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request) ([]repo.TotalsByOrganizer, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
return ctrl.repo.Groups.StatsLocationsByPurchasePrice(auth, auth.GID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.Command(fn, http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleGroupStatisticsLabels godoc
|
||||||
|
//
|
||||||
|
// @Summary Get Label Statistics
|
||||||
|
// @Tags Statistics
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} []repo.TotalsByOrganizer
|
||||||
|
// @Router /v1/groups/statistics/labels [GET]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleGroupStatisticsLabels() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request) ([]repo.TotalsByOrganizer, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
return ctrl.repo.Groups.StatsLabelsByPurchasePrice(auth, auth.GID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.Command(fn, http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleGroupStatistics godoc
|
||||||
|
//
|
||||||
|
// @Summary Get Group Statistics
|
||||||
|
// @Tags Statistics
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} repo.GroupStatistics
|
||||||
|
// @Router /v1/groups/statistics [GET]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleGroupStatistics() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request) (repo.GroupStatistics, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
return ctrl.repo.Groups.StatsGroup(auth, auth.GID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.Command(fn, http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleGroupStatisticsPriceOverTime godoc
|
||||||
|
//
|
||||||
|
// @Summary Get Purchase Price Statistics
|
||||||
|
// @Tags Statistics
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} repo.ValueOverTime
|
||||||
|
// @Param start query string false "start date"
|
||||||
|
// @Param end query string false "end date"
|
||||||
|
// @Router /v1/groups/statistics/purchase-price [GET]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleGroupStatisticsPriceOverTime() errchain.HandlerFunc {
|
||||||
|
parseDate := func(datestr string, defaultDate time.Time) (time.Time, error) {
|
||||||
|
if datestr == "" {
|
||||||
|
return defaultDate, nil
|
||||||
|
}
|
||||||
|
return time.Parse("2006-01-02", datestr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
ctx := services.NewContext(r.Context())
|
||||||
|
|
||||||
|
startDate, err := parseDate(r.URL.Query().Get("start"), time.Now().AddDate(0, -1, 0))
|
||||||
|
if err != nil {
|
||||||
|
return validate.NewRequestError(err, http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
endDate, err := parseDate(r.URL.Query().Get("end"), time.Now())
|
||||||
|
if err != nil {
|
||||||
|
return validate.NewRequestError(err, http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
stats, err := ctrl.repo.Groups.StatsPurchasePrice(ctx, ctx.GID, startDate, endDate)
|
||||||
|
if err != nil {
|
||||||
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return server.JSON(w, http.StatusOK, stats)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,24 +1,27 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
|
"github.com/hay-kot/httpkit/server"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HandleUserSelf godoc
|
// HandleUserRegistration godoc
|
||||||
// @Summary Get the current user
|
//
|
||||||
// @Tags User
|
// @Summary Register New User
|
||||||
// @Produce json
|
// @Tags User
|
||||||
// @Param payload body services.UserRegistration true "User Data"
|
// @Produce json
|
||||||
// @Success 204
|
// @Param payload body services.UserRegistration true "User Data"
|
||||||
// @Router /v1/users/register [Post]
|
// @Success 204
|
||||||
func (ctrl *V1Controller) HandleUserRegistration() server.HandlerFunc {
|
// @Router /v1/users/register [Post]
|
||||||
|
func (ctrl *V1Controller) HandleUserRegistration() errchain.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
regData := services.UserRegistration{}
|
regData := services.UserRegistration{}
|
||||||
|
|
||||||
@@ -28,7 +31,7 @@ func (ctrl *V1Controller) HandleUserRegistration() server.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !ctrl.allowRegistration && regData.GroupToken == "" {
|
if !ctrl.allowRegistration && regData.GroupToken == "" {
|
||||||
return validate.NewRequestError(nil, http.StatusForbidden)
|
return validate.NewRequestError(fmt.Errorf("user registration disabled"), http.StatusForbidden)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := ctrl.svc.User.RegisterUser(r.Context(), regData)
|
_, err := ctrl.svc.User.RegisterUser(r.Context(), regData)
|
||||||
@@ -37,18 +40,19 @@ func (ctrl *V1Controller) HandleUserRegistration() server.HandlerFunc {
|
|||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
return server.Respond(w, http.StatusNoContent, nil)
|
return server.JSON(w, http.StatusNoContent, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleUserSelf godoc
|
// HandleUserSelf godoc
|
||||||
// @Summary Get the current user
|
//
|
||||||
// @Tags User
|
// @Summary Get User Self
|
||||||
// @Produce json
|
// @Tags User
|
||||||
// @Success 200 {object} server.Result{item=repo.UserOut}
|
// @Produce json
|
||||||
// @Router /v1/users/self [GET]
|
// @Success 200 {object} Wrapped{item=repo.UserOut}
|
||||||
// @Security Bearer
|
// @Router /v1/users/self [GET]
|
||||||
func (ctrl *V1Controller) HandleUserSelf() server.HandlerFunc {
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleUserSelf() errchain.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
token := services.UseTokenCtx(r.Context())
|
token := services.UseTokenCtx(r.Context())
|
||||||
usr, err := ctrl.svc.User.GetSelf(r.Context(), token)
|
usr, err := ctrl.svc.User.GetSelf(r.Context(), token)
|
||||||
@@ -57,19 +61,20 @@ func (ctrl *V1Controller) HandleUserSelf() server.HandlerFunc {
|
|||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
return server.Respond(w, http.StatusOK, server.Wrap(usr))
|
return server.JSON(w, http.StatusOK, Wrap(usr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleUserSelfUpdate godoc
|
// HandleUserSelfUpdate godoc
|
||||||
// @Summary Update the current user
|
//
|
||||||
// @Tags User
|
// @Summary Update Account
|
||||||
// @Produce json
|
// @Tags User
|
||||||
// @Param payload body repo.UserUpdate true "User Data"
|
// @Produce json
|
||||||
// @Success 200 {object} server.Result{item=repo.UserUpdate}
|
// @Param payload body repo.UserUpdate true "User Data"
|
||||||
// @Router /v1/users/self [PUT]
|
// @Success 200 {object} Wrapped{item=repo.UserUpdate}
|
||||||
// @Security Bearer
|
// @Router /v1/users/self [PUT]
|
||||||
func (ctrl *V1Controller) HandleUserSelfUpdate() server.HandlerFunc {
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleUserSelfUpdate() errchain.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
updateData := repo.UserUpdate{}
|
updateData := repo.UserUpdate{}
|
||||||
if err := server.Decode(r, &updateData); err != nil {
|
if err := server.Decode(r, &updateData); err != nil {
|
||||||
@@ -79,23 +84,23 @@ func (ctrl *V1Controller) HandleUserSelfUpdate() server.HandlerFunc {
|
|||||||
|
|
||||||
actor := services.UseUserCtx(r.Context())
|
actor := services.UseUserCtx(r.Context())
|
||||||
newData, err := ctrl.svc.User.UpdateSelf(r.Context(), actor.ID, updateData)
|
newData, err := ctrl.svc.User.UpdateSelf(r.Context(), actor.ID, updateData)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
return server.Respond(w, http.StatusOK, server.Wrap(newData))
|
return server.JSON(w, http.StatusOK, Wrap(newData))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleUserSelfDelete godoc
|
// HandleUserSelfDelete godoc
|
||||||
// @Summary Deletes the user account
|
//
|
||||||
// @Tags User
|
// @Summary Delete Account
|
||||||
// @Produce json
|
// @Tags User
|
||||||
// @Success 204
|
// @Produce json
|
||||||
// @Router /v1/users/self [DELETE]
|
// @Success 204
|
||||||
// @Security Bearer
|
// @Router /v1/users/self [DELETE]
|
||||||
func (ctrl *V1Controller) HandleUserSelfDelete() server.HandlerFunc {
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleUserSelfDelete() errchain.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
if ctrl.isDemo {
|
if ctrl.isDemo {
|
||||||
return validate.NewRequestError(nil, http.StatusForbidden)
|
return validate.NewRequestError(nil, http.StatusForbidden)
|
||||||
@@ -106,7 +111,7 @@ func (ctrl *V1Controller) HandleUserSelfDelete() server.HandlerFunc {
|
|||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
return server.Respond(w, http.StatusNoContent, nil)
|
return server.JSON(w, http.StatusNoContent, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,13 +123,14 @@ type (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// HandleUserSelfChangePassword godoc
|
// HandleUserSelfChangePassword godoc
|
||||||
// @Summary Updates the users password
|
//
|
||||||
// @Tags User
|
// @Summary Change Password
|
||||||
// @Success 204
|
// @Tags User
|
||||||
// @Param payload body ChangePassword true "Password Payload"
|
// @Success 204
|
||||||
// @Router /v1/users/change-password [PUT]
|
// @Param payload body ChangePassword true "Password Payload"
|
||||||
// @Security Bearer
|
// @Router /v1/users/change-password [PUT]
|
||||||
func (ctrl *V1Controller) HandleUserSelfChangePassword() server.HandlerFunc {
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleUserSelfChangePassword() errchain.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
if ctrl.isDemo {
|
if ctrl.isDemo {
|
||||||
return validate.NewRequestError(nil, http.StatusForbidden)
|
return validate.NewRequestError(nil, http.StatusForbidden)
|
||||||
@@ -143,6 +149,6 @@ func (ctrl *V1Controller) HandleUserSelfChangePassword() server.HandlerFunc {
|
|||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
return server.Respond(w, http.StatusNoContent, nil)
|
return server.JSON(w, http.StatusNoContent, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -9,16 +10,23 @@ import (
|
|||||||
|
|
||||||
atlas "ariga.io/atlas/sql/migrate"
|
atlas "ariga.io/atlas/sql/migrate"
|
||||||
"entgo.io/ent/dialect/sql/schema"
|
"entgo.io/ent/dialect/sql/schema"
|
||||||
"github.com/hay-kot/homebox/backend/app/api/static/docs"
|
"github.com/go-chi/chi/v5"
|
||||||
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
|
|
||||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/migrations"
|
"github.com/hay-kot/homebox/backend/internal/data/migrations"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
"github.com/hay-kot/homebox/backend/internal/sys/config"
|
"github.com/hay-kot/homebox/backend/internal/sys/config"
|
||||||
"github.com/hay-kot/homebox/backend/internal/web/mid"
|
"github.com/hay-kot/homebox/backend/internal/web/mid"
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
"github.com/hay-kot/httpkit/server"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
"github.com/rs/zerolog/pkgerrors"
|
||||||
|
|
||||||
|
_ "github.com/hay-kot/homebox/backend/pkgs/cgofreesqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -27,24 +35,23 @@ var (
|
|||||||
buildTime = "now"
|
buildTime = "now"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @title Go API Templates
|
// @title Homebox API
|
||||||
// @version 1.0
|
// @version 1.0
|
||||||
// @description This is a simple Rest API Server Template that implements some basic User and Authentication patterns to help you get started and bootstrap your next project!.
|
// @description Track, Manage, and Organize your Things.
|
||||||
// @contact.name Don't
|
// @contact.name Don't
|
||||||
// @license.name MIT
|
|
||||||
// @BasePath /api
|
// @BasePath /api
|
||||||
// @securityDefinitions.apikey Bearer
|
// @securityDefinitions.apikey Bearer
|
||||||
// @in header
|
// @in header
|
||||||
// @name Authorization
|
// @name Authorization
|
||||||
// @description "Type 'Bearer TOKEN' to correctly set the API Key"
|
// @description "Type 'Bearer TOKEN' to correctly set the API Key"
|
||||||
func main() {
|
func main() {
|
||||||
|
zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack
|
||||||
|
|
||||||
cfg, err := config.New()
|
cfg, err := config.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
docs.SwaggerInfo.Host = cfg.Swagger.Host
|
|
||||||
|
|
||||||
if err := run(cfg); err != nil {
|
if err := run(cfg); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -57,7 +64,7 @@ func run(cfg *config.Config) error {
|
|||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Initialize Database & Repos
|
// Initialize Database & Repos
|
||||||
|
|
||||||
err := os.MkdirAll(cfg.Storage.Data, 0755)
|
err := os.MkdirAll(cfg.Storage.Data, 0o755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal().Err(err).Msg("failed to create data directory")
|
log.Fatal().Err(err).Msg("failed to create data directory")
|
||||||
}
|
}
|
||||||
@@ -110,36 +117,43 @@ func run(cfg *config.Config) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.bus = eventbus.New()
|
||||||
app.db = c
|
app.db = c
|
||||||
app.repos = repo.New(c, cfg.Storage.Data)
|
app.repos = repo.New(c, app.bus, cfg.Storage.Data)
|
||||||
app.services = services.New(app.repos)
|
app.services = services.New(
|
||||||
|
app.repos,
|
||||||
|
services.WithAutoIncrementAssetID(cfg.Options.AutoIncrementAssetID),
|
||||||
|
)
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Start Server\
|
// Start Server
|
||||||
|
|
||||||
logger := log.With().Caller().Logger()
|
logger := log.With().Caller().Logger()
|
||||||
|
|
||||||
mwLogger := mid.Logger(logger)
|
router := chi.NewMux()
|
||||||
if app.conf.Mode == config.ModeDevelopment {
|
router.Use(
|
||||||
mwLogger = mid.SugarLogger(logger)
|
middleware.RequestID,
|
||||||
}
|
middleware.RealIP,
|
||||||
|
mid.Logger(logger),
|
||||||
|
middleware.Recoverer,
|
||||||
|
middleware.StripSlashes,
|
||||||
|
)
|
||||||
|
|
||||||
|
chain := errchain.New(mid.Errors(app.server, logger))
|
||||||
|
|
||||||
|
app.mountRoutes(router, chain, app.repos)
|
||||||
|
|
||||||
app.server = server.NewServer(
|
app.server = server.NewServer(
|
||||||
server.WithHost(app.conf.Web.Host),
|
server.WithHost(app.conf.Web.Host),
|
||||||
server.WithPort(app.conf.Web.Port),
|
server.WithPort(app.conf.Web.Port),
|
||||||
server.WithMiddleware(
|
|
||||||
mwLogger,
|
|
||||||
mid.Errors(logger),
|
|
||||||
mid.Panic(app.conf.Mode == config.ModeDevelopment),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
app.mountRoutes(app.repos)
|
|
||||||
|
|
||||||
log.Info().Msgf("Starting HTTP Server on %s:%s", app.server.Host, app.server.Port)
|
log.Info().Msgf("Starting HTTP Server on %s:%s", app.server.Host, app.server.Port)
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Start Reoccurring Tasks
|
// Start Reoccurring Tasks
|
||||||
|
|
||||||
|
go app.bus.Run()
|
||||||
|
|
||||||
go app.startBgTask(time.Duration(24)*time.Hour, func() {
|
go app.startBgTask(time.Duration(24)*time.Hour, func() {
|
||||||
_, err := app.repos.AuthTokens.PurgeExpiredTokens(context.Background())
|
_, err := app.repos.AuthTokens.PurgeExpiredTokens(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -156,6 +170,19 @@ func run(cfg *config.Config) error {
|
|||||||
Msg("failed to purge expired invitations")
|
Msg("failed to purge expired invitations")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
go app.startBgTask(time.Duration(1)*time.Hour, func() {
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// TODO: Remove through external API that does setup
|
// TODO: Remove through external API that does setup
|
||||||
if cfg.Demo {
|
if cfg.Demo {
|
||||||
@@ -172,5 +199,5 @@ func run(cfg *config.Config) error {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
return app.server.Start()
|
return app.server.Start(router)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,150 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
"github.com/hay-kot/homebox/backend/internal/sys/validate"
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type tokenHasKey struct {
|
||||||
|
key string
|
||||||
|
}
|
||||||
|
|
||||||
|
var hashedToken = tokenHasKey{key: "hashedToken"}
|
||||||
|
|
||||||
|
type RoleMode int
|
||||||
|
|
||||||
|
const (
|
||||||
|
RoleModeOr RoleMode = 0
|
||||||
|
RoleModeAnd RoleMode = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// mwRoles is a middleware that will validate the required roles are met. All roles
|
||||||
|
// are required to be met for the request to be allowed. If the user does not have
|
||||||
|
// the required roles, a 403 Forbidden will be returned.
|
||||||
|
//
|
||||||
|
// WARNING: This middleware _MUST_ be called after mwAuthToken or else it will panic
|
||||||
|
func (a *app) mwRoles(rm RoleMode, required ...string) errchain.Middleware {
|
||||||
|
return func(next errchain.Handler) errchain.Handler {
|
||||||
|
return errchain.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
ctx := r.Context()
|
||||||
|
|
||||||
|
maybeToken := ctx.Value(hashedToken)
|
||||||
|
if maybeToken == nil {
|
||||||
|
panic("mwRoles: token not found in context, you must call mwAuthToken before mwRoles")
|
||||||
|
}
|
||||||
|
|
||||||
|
token := maybeToken.(string)
|
||||||
|
|
||||||
|
roles, err := a.repos.AuthTokens.GetRoles(r.Context(), token)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
outer:
|
||||||
|
switch rm {
|
||||||
|
case RoleModeOr:
|
||||||
|
for _, role := range required {
|
||||||
|
if roles.Contains(role) {
|
||||||
|
break outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return validate.NewRequestError(errors.New("Forbidden"), http.StatusForbidden)
|
||||||
|
case RoleModeAnd:
|
||||||
|
for _, req := range required {
|
||||||
|
if !roles.Contains(req) {
|
||||||
|
return validate.NewRequestError(errors.New("Unauthorized"), http.StatusForbidden)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type KeyFunc func(r *http.Request) (string, error)
|
||||||
|
|
||||||
|
func getBearer(r *http.Request) (string, error) {
|
||||||
|
auth := r.Header.Get("Authorization")
|
||||||
|
if auth == "" {
|
||||||
|
return "", errors.New("authorization header is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
return auth, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getQuery(r *http.Request) (string, error) {
|
||||||
|
token := r.URL.Query().Get("access_token")
|
||||||
|
if token == "" {
|
||||||
|
return "", errors.New("access_token query is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := url.QueryUnescape(token)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New("access_token query is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCookie(r *http.Request) (string, error) {
|
||||||
|
cookie, err := r.Cookie("hb.auth.token")
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New("access_token cookie is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := url.QueryUnescape(cookie.Value)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New("access_token cookie is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
// mwAuthToken is a middleware that will check the database for a stateful token
|
// mwAuthToken is a middleware that will check the database for a stateful token
|
||||||
// and attach it to the request context with the user, or return a 401 if it doesn't exist.
|
// and attach it's user to the request context, or return an appropriate error.
|
||||||
func (a *app) mwAuthToken(next server.Handler) server.Handler {
|
// Authorization support is by token via Headers or Query Parameter
|
||||||
return server.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
|
//
|
||||||
requestToken := r.Header.Get("Authorization")
|
// Example:
|
||||||
|
// - header = "Bearer 1234567890"
|
||||||
|
// - query = "?access_token=1234567890"
|
||||||
|
// - cookie = hb.auth.token = 1234567890
|
||||||
|
func (a *app) mwAuthToken(next errchain.Handler) errchain.Handler {
|
||||||
|
return errchain.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
keyFuncs := [...]KeyFunc{
|
||||||
|
getBearer,
|
||||||
|
getCookie,
|
||||||
|
getQuery,
|
||||||
|
}
|
||||||
|
|
||||||
|
var requestToken string
|
||||||
|
for _, keyFunc := range keyFuncs {
|
||||||
|
token, err := keyFunc(r)
|
||||||
|
if err == nil {
|
||||||
|
requestToken = token
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if requestToken == "" {
|
if requestToken == "" {
|
||||||
return validate.NewRequestError(errors.New("Authorization header is required"), http.StatusUnauthorized)
|
return validate.NewRequestError(errors.New("Authorization header or query is required"), http.StatusUnauthorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
requestToken = strings.TrimPrefix(requestToken, "Bearer ")
|
requestToken = strings.TrimPrefix(requestToken, "Bearer ")
|
||||||
usr, err := a.services.User.GetSelf(r.Context(), requestToken)
|
|
||||||
|
|
||||||
|
r = r.WithContext(context.WithValue(r.Context(), hashedToken, requestToken))
|
||||||
|
|
||||||
|
usr, err := a.services.User.GetSelf(r.Context(), requestToken)
|
||||||
// Check the database for the token
|
// Check the database for the token
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return validate.NewRequestError(errors.New("Authorization header is required"), http.StatusUnauthorized)
|
return validate.NewRequestError(errors.New("valid authorization header is required"), http.StatusUnauthorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
r = r.WithContext(services.SetUserCtx(r.Context(), &usr, requestToken))
|
r = r.WithContext(services.SetUserCtx(r.Context(), &usr, requestToken))
|
||||||
|
|||||||
@@ -3,18 +3,19 @@ package main
|
|||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"mime"
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/hay-kot/homebox/backend/app/api/handlers/debughandlers"
|
"github.com/hay-kot/homebox/backend/app/api/handlers/debughandlers"
|
||||||
v1 "github.com/hay-kot/homebox/backend/app/api/handlers/v1"
|
v1 "github.com/hay-kot/homebox/backend/app/api/handlers/v1"
|
||||||
_ "github.com/hay-kot/homebox/backend/app/api/static/docs"
|
_ "github.com/hay-kot/homebox/backend/app/api/static/docs"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/server"
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
httpSwagger "github.com/swaggo/http-swagger" // http-swagger middleware
|
httpSwagger "github.com/swaggo/http-swagger" // http-swagger middleware
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,12 +36,12 @@ func (a *app) debugRouter() *http.ServeMux {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// registerRoutes registers all the routes for the API
|
// registerRoutes registers all the routes for the API
|
||||||
func (a *app) mountRoutes(repos *repo.AllRepos) {
|
func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllRepos) {
|
||||||
registerMimes()
|
registerMimes()
|
||||||
|
|
||||||
a.server.Get("/swagger/*", server.ToHandler(httpSwagger.Handler(
|
r.Get("/swagger/*", httpSwagger.Handler(
|
||||||
httpSwagger.URL(fmt.Sprintf("%s://%s/swagger/doc.json", a.conf.Swagger.Scheme, a.conf.Swagger.Host)),
|
httpSwagger.URL("/swagger/doc.json"),
|
||||||
)))
|
))
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// API Version 1
|
// API Version 1
|
||||||
@@ -50,63 +51,110 @@ func (a *app) mountRoutes(repos *repo.AllRepos) {
|
|||||||
v1Ctrl := v1.NewControllerV1(
|
v1Ctrl := v1.NewControllerV1(
|
||||||
a.services,
|
a.services,
|
||||||
a.repos,
|
a.repos,
|
||||||
|
a.bus,
|
||||||
v1.WithMaxUploadSize(a.conf.Web.MaxUploadSize),
|
v1.WithMaxUploadSize(a.conf.Web.MaxUploadSize),
|
||||||
v1.WithRegistration(a.conf.AllowRegistration),
|
v1.WithRegistration(a.conf.Options.AllowRegistration),
|
||||||
v1.WithDemoStatus(a.conf.Demo), // Disable Password Change in Demo Mode
|
v1.WithDemoStatus(a.conf.Demo), // Disable Password Change in Demo Mode
|
||||||
)
|
)
|
||||||
|
|
||||||
a.server.Get(v1Base("/status"), v1Ctrl.HandleBase(func() bool { return true }, v1.Build{
|
r.Get(v1Base("/status"), chain.ToHandlerFunc(v1Ctrl.HandleBase(func() bool { return true }, v1.Build{
|
||||||
Version: version,
|
Version: version,
|
||||||
Commit: commit,
|
Commit: commit,
|
||||||
BuildTime: buildTime,
|
BuildTime: buildTime,
|
||||||
}))
|
})))
|
||||||
|
|
||||||
a.server.Post(v1Base("/users/register"), v1Ctrl.HandleUserRegistration())
|
r.Post(v1Base("/users/register"), chain.ToHandlerFunc(v1Ctrl.HandleUserRegistration()))
|
||||||
a.server.Post(v1Base("/users/login"), v1Ctrl.HandleAuthLogin())
|
r.Post(v1Base("/users/login"), chain.ToHandlerFunc(v1Ctrl.HandleAuthLogin()))
|
||||||
|
|
||||||
// Attachment download URl needs a `token` query param to be passed in the request.
|
userMW := []errchain.Middleware{
|
||||||
// and also needs to be outside of the `auth` middleware.
|
a.mwAuthToken,
|
||||||
a.server.Get(v1Base("/items/{id}/attachments/download"), v1Ctrl.HandleItemAttachmentDownload())
|
a.mwRoles(RoleModeOr, authroles.RoleUser.String()),
|
||||||
|
}
|
||||||
|
|
||||||
a.server.Get(v1Base("/users/self"), v1Ctrl.HandleUserSelf(), a.mwAuthToken)
|
r.Get(v1Base("/ws/events"), chain.ToHandlerFunc(v1Ctrl.HandleCacheWS(), userMW...))
|
||||||
a.server.Put(v1Base("/users/self"), v1Ctrl.HandleUserSelfUpdate(), a.mwAuthToken)
|
r.Get(v1Base("/users/self"), chain.ToHandlerFunc(v1Ctrl.HandleUserSelf(), userMW...))
|
||||||
a.server.Delete(v1Base("/users/self"), v1Ctrl.HandleUserSelfDelete(), a.mwAuthToken)
|
r.Put(v1Base("/users/self"), chain.ToHandlerFunc(v1Ctrl.HandleUserSelfUpdate(), userMW...))
|
||||||
a.server.Post(v1Base("/users/logout"), v1Ctrl.HandleAuthLogout(), a.mwAuthToken)
|
r.Delete(v1Base("/users/self"), chain.ToHandlerFunc(v1Ctrl.HandleUserSelfDelete(), userMW...))
|
||||||
a.server.Get(v1Base("/users/refresh"), v1Ctrl.HandleAuthRefresh(), a.mwAuthToken)
|
r.Post(v1Base("/users/logout"), chain.ToHandlerFunc(v1Ctrl.HandleAuthLogout(), userMW...))
|
||||||
a.server.Put(v1Base("/users/self/change-password"), v1Ctrl.HandleUserSelfChangePassword(), a.mwAuthToken)
|
r.Get(v1Base("/users/refresh"), chain.ToHandlerFunc(v1Ctrl.HandleAuthRefresh(), userMW...))
|
||||||
|
r.Put(v1Base("/users/self/change-password"), chain.ToHandlerFunc(v1Ctrl.HandleUserSelfChangePassword(), userMW...))
|
||||||
|
|
||||||
a.server.Post(v1Base("/groups/invitations"), v1Ctrl.HandleGroupInvitationsCreate(), a.mwAuthToken)
|
r.Post(v1Base("/groups/invitations"), chain.ToHandlerFunc(v1Ctrl.HandleGroupInvitationsCreate(), userMW...))
|
||||||
a.server.Get(v1Base("/groups/statistics"), v1Ctrl.HandleGroupStatistics(), a.mwAuthToken)
|
r.Get(v1Base("/groups/statistics"), chain.ToHandlerFunc(v1Ctrl.HandleGroupStatistics(), userMW...))
|
||||||
|
r.Get(v1Base("/groups/statistics/purchase-price"), chain.ToHandlerFunc(v1Ctrl.HandleGroupStatisticsPriceOverTime(), userMW...))
|
||||||
|
r.Get(v1Base("/groups/statistics/locations"), chain.ToHandlerFunc(v1Ctrl.HandleGroupStatisticsLocations(), userMW...))
|
||||||
|
r.Get(v1Base("/groups/statistics/labels"), chain.ToHandlerFunc(v1Ctrl.HandleGroupStatisticsLabels(), userMW...))
|
||||||
|
|
||||||
// TODO: I don't like /groups being the URL for users
|
// TODO: I don't like /groups being the URL for users
|
||||||
a.server.Get(v1Base("/groups"), v1Ctrl.HandleGroupGet(), a.mwAuthToken)
|
r.Get(v1Base("/groups"), chain.ToHandlerFunc(v1Ctrl.HandleGroupGet(), userMW...))
|
||||||
a.server.Put(v1Base("/groups"), v1Ctrl.HandleGroupUpdate(), a.mwAuthToken)
|
r.Put(v1Base("/groups"), chain.ToHandlerFunc(v1Ctrl.HandleGroupUpdate(), userMW...))
|
||||||
|
|
||||||
a.server.Get(v1Base("/locations"), v1Ctrl.HandleLocationGetAll(), a.mwAuthToken)
|
r.Post(v1Base("/actions/ensure-asset-ids"), chain.ToHandlerFunc(v1Ctrl.HandleEnsureAssetID(), userMW...))
|
||||||
a.server.Post(v1Base("/locations"), v1Ctrl.HandleLocationCreate(), a.mwAuthToken)
|
r.Post(v1Base("/actions/zero-item-time-fields"), chain.ToHandlerFunc(v1Ctrl.HandleItemDateZeroOut(), userMW...))
|
||||||
a.server.Get(v1Base("/locations/{id}"), v1Ctrl.HandleLocationGet(), a.mwAuthToken)
|
r.Post(v1Base("/actions/ensure-import-refs"), chain.ToHandlerFunc(v1Ctrl.HandleEnsureImportRefs(), userMW...))
|
||||||
a.server.Put(v1Base("/locations/{id}"), v1Ctrl.HandleLocationUpdate(), a.mwAuthToken)
|
|
||||||
a.server.Delete(v1Base("/locations/{id}"), v1Ctrl.HandleLocationDelete(), a.mwAuthToken)
|
|
||||||
|
|
||||||
a.server.Get(v1Base("/labels"), v1Ctrl.HandleLabelsGetAll(), a.mwAuthToken)
|
r.Get(v1Base("/locations"), chain.ToHandlerFunc(v1Ctrl.HandleLocationGetAll(), userMW...))
|
||||||
a.server.Post(v1Base("/labels"), v1Ctrl.HandleLabelsCreate(), a.mwAuthToken)
|
r.Post(v1Base("/locations"), chain.ToHandlerFunc(v1Ctrl.HandleLocationCreate(), userMW...))
|
||||||
a.server.Get(v1Base("/labels/{id}"), v1Ctrl.HandleLabelGet(), a.mwAuthToken)
|
r.Get(v1Base("/locations/tree"), chain.ToHandlerFunc(v1Ctrl.HandleLocationTreeQuery(), userMW...))
|
||||||
a.server.Put(v1Base("/labels/{id}"), v1Ctrl.HandleLabelUpdate(), a.mwAuthToken)
|
r.Get(v1Base("/locations/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleLocationGet(), userMW...))
|
||||||
a.server.Delete(v1Base("/labels/{id}"), v1Ctrl.HandleLabelDelete(), a.mwAuthToken)
|
r.Put(v1Base("/locations/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleLocationUpdate(), userMW...))
|
||||||
|
r.Delete(v1Base("/locations/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleLocationDelete(), userMW...))
|
||||||
|
|
||||||
a.server.Get(v1Base("/items"), v1Ctrl.HandleItemsGetAll(), a.mwAuthToken)
|
r.Get(v1Base("/labels"), chain.ToHandlerFunc(v1Ctrl.HandleLabelsGetAll(), userMW...))
|
||||||
a.server.Post(v1Base("/items/import"), v1Ctrl.HandleItemsImport(), a.mwAuthToken)
|
r.Post(v1Base("/labels"), chain.ToHandlerFunc(v1Ctrl.HandleLabelsCreate(), userMW...))
|
||||||
a.server.Post(v1Base("/items"), v1Ctrl.HandleItemsCreate(), a.mwAuthToken)
|
r.Get(v1Base("/labels/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleLabelGet(), userMW...))
|
||||||
a.server.Get(v1Base("/items/{id}"), v1Ctrl.HandleItemGet(), a.mwAuthToken)
|
r.Put(v1Base("/labels/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleLabelUpdate(), userMW...))
|
||||||
a.server.Put(v1Base("/items/{id}"), v1Ctrl.HandleItemUpdate(), a.mwAuthToken)
|
r.Delete(v1Base("/labels/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleLabelDelete(), userMW...))
|
||||||
a.server.Delete(v1Base("/items/{id}"), v1Ctrl.HandleItemDelete(), a.mwAuthToken)
|
|
||||||
|
|
||||||
a.server.Post(v1Base("/items/{id}/attachments"), v1Ctrl.HandleItemAttachmentCreate(), a.mwAuthToken)
|
r.Get(v1Base("/items"), chain.ToHandlerFunc(v1Ctrl.HandleItemsGetAll(), userMW...))
|
||||||
a.server.Get(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentToken(), a.mwAuthToken)
|
r.Post(v1Base("/items"), chain.ToHandlerFunc(v1Ctrl.HandleItemsCreate(), userMW...))
|
||||||
a.server.Put(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentUpdate(), a.mwAuthToken)
|
r.Post(v1Base("/items/import"), chain.ToHandlerFunc(v1Ctrl.HandleItemsImport(), userMW...))
|
||||||
a.server.Delete(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentDelete(), a.mwAuthToken)
|
r.Get(v1Base("/items/export"), chain.ToHandlerFunc(v1Ctrl.HandleItemsExport(), userMW...))
|
||||||
|
r.Get(v1Base("/items/fields"), chain.ToHandlerFunc(v1Ctrl.HandleGetAllCustomFieldNames(), userMW...))
|
||||||
|
r.Get(v1Base("/items/fields/values"), chain.ToHandlerFunc(v1Ctrl.HandleGetAllCustomFieldValues(), userMW...))
|
||||||
|
|
||||||
a.server.NotFound(notFoundHandler())
|
r.Get(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemGet(), userMW...))
|
||||||
|
r.Put(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemUpdate(), userMW...))
|
||||||
|
r.Patch(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemPatch(), userMW...))
|
||||||
|
r.Delete(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemDelete(), userMW...))
|
||||||
|
|
||||||
|
r.Post(v1Base("/items/{id}/attachments"), chain.ToHandlerFunc(v1Ctrl.HandleItemAttachmentCreate(), userMW...))
|
||||||
|
r.Put(v1Base("/items/{id}/attachments/{attachment_id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemAttachmentUpdate(), userMW...))
|
||||||
|
r.Delete(v1Base("/items/{id}/attachments/{attachment_id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemAttachmentDelete(), userMW...))
|
||||||
|
|
||||||
|
r.Get(v1Base("/items/{id}/maintenance"), chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceLogGet(), userMW...))
|
||||||
|
r.Post(v1Base("/items/{id}/maintenance"), chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceEntryCreate(), userMW...))
|
||||||
|
r.Put(v1Base("/items/{id}/maintenance/{entry_id}"), chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceEntryUpdate(), userMW...))
|
||||||
|
r.Delete(v1Base("/items/{id}/maintenance/{entry_id}"), chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceEntryDelete(), userMW...))
|
||||||
|
|
||||||
|
r.Get(v1Base("/assets/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleAssetGet(), userMW...))
|
||||||
|
|
||||||
|
// Notifiers
|
||||||
|
r.Get(v1Base("/notifiers"), chain.ToHandlerFunc(v1Ctrl.HandleGetUserNotifiers(), userMW...))
|
||||||
|
r.Post(v1Base("/notifiers"), chain.ToHandlerFunc(v1Ctrl.HandleCreateNotifier(), userMW...))
|
||||||
|
r.Put(v1Base("/notifiers/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleUpdateNotifier(), userMW...))
|
||||||
|
r.Delete(v1Base("/notifiers/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleDeleteNotifier(), userMW...))
|
||||||
|
r.Post(v1Base("/notifiers/test"), chain.ToHandlerFunc(v1Ctrl.HandlerNotifierTest(), userMW...))
|
||||||
|
|
||||||
|
// Asset-Like endpoints
|
||||||
|
assetMW := []errchain.Middleware{
|
||||||
|
a.mwAuthToken,
|
||||||
|
a.mwRoles(RoleModeOr, authroles.RoleUser.String(), authroles.RoleAttachments.String()),
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Get(
|
||||||
|
v1Base("/qrcode"),
|
||||||
|
chain.ToHandlerFunc(v1Ctrl.HandleGenerateQRCode(), assetMW...),
|
||||||
|
)
|
||||||
|
r.Get(
|
||||||
|
v1Base("/items/{id}/attachments/{attachment_id}"),
|
||||||
|
chain.ToHandlerFunc(v1Ctrl.HandleItemAttachmentGet(), assetMW...),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reporting Services
|
||||||
|
r.Get(v1Base("/reporting/bill-of-materials"), chain.ToHandlerFunc(v1Ctrl.HandleBillOfMaterialsExport(), userMW...))
|
||||||
|
|
||||||
|
r.NotFound(chain.ToHandlerFunc(notFoundHandler()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerMimes() {
|
func registerMimes() {
|
||||||
@@ -123,7 +171,7 @@ func registerMimes() {
|
|||||||
|
|
||||||
// notFoundHandler perform the main logic around handling the internal SPA embed and ensuring that
|
// notFoundHandler perform the main logic around handling the internal SPA embed and ensuring that
|
||||||
// the client side routing is handled correctly.
|
// the client side routing is handled correctly.
|
||||||
func notFoundHandler() server.HandlerFunc {
|
func notFoundHandler() errchain.HandlerFunc {
|
||||||
tryRead := func(fs embed.FS, prefix, requestedPath string, w http.ResponseWriter) error {
|
tryRead := func(fs embed.FS, prefix, requestedPath string, w http.ResponseWriter) error {
|
||||||
f, err := fs.Open(path.Join(prefix, requestedPath))
|
f, err := fs.Open(path.Join(prefix, requestedPath))
|
||||||
if err != nil {
|
if err != 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
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
@@ -39,4 +40,6 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed generating migration file: %v", err)
|
log.Fatalf("failed generating migration file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println("Migration file generated successfully.")
|
||||||
}
|
}
|
||||||
|
|||||||
81
backend/app/tools/typegen/main.go
Normal file
81
backend/app/tools/typegen/main.go
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ReReplace struct {
|
||||||
|
Regex *regexp.Regexp
|
||||||
|
Text string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewReReplace(regex string, replace string) ReReplace {
|
||||||
|
return ReReplace{
|
||||||
|
Regex: regexp.MustCompile(regex),
|
||||||
|
Text: replace,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewReDate(dateStr string) ReReplace {
|
||||||
|
return ReReplace{
|
||||||
|
Regex: regexp.MustCompile(fmt.Sprintf(`%s: string`, dateStr)),
|
||||||
|
Text: fmt.Sprintf(`%s: Date | string`, dateStr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) != 2 {
|
||||||
|
fmt.Println("Please provide a file path as an argument")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
path := os.Args[1]
|
||||||
|
|
||||||
|
fmt.Printf("Processing %s\n", path)
|
||||||
|
|
||||||
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||||
|
fmt.Printf("File %s does not exist\n", path)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
text := "/* post-processed by ./scripts/process-types.go */\n"
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
text += string(data)
|
||||||
|
|
||||||
|
replaces := [...]ReReplace{
|
||||||
|
NewReReplace(` Repo`, " "),
|
||||||
|
NewReReplace(` PaginationResultRepo`, " PaginationResult"),
|
||||||
|
NewReReplace(` Services`, " "),
|
||||||
|
NewReReplace(` V1`, " "),
|
||||||
|
NewReReplace(`\?:`, ":"),
|
||||||
|
NewReReplace(`(\w+):\s(.*null.*)`, "$1?: $2"), // make null union types optional
|
||||||
|
NewReDate("createdAt"),
|
||||||
|
NewReDate("updatedAt"),
|
||||||
|
NewReDate("soldTime"),
|
||||||
|
NewReDate("purchaseTime"),
|
||||||
|
NewReDate("warrantyExpires"),
|
||||||
|
NewReDate("expiresAt"),
|
||||||
|
NewReDate("date"),
|
||||||
|
NewReDate("completedDate"),
|
||||||
|
NewReDate("scheduledDate"),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, replace := range replaces {
|
||||||
|
fmt.Printf("Replacing '%v' -> '%s'\n", replace.Regex, replace.Text)
|
||||||
|
text = replace.Regex.ReplaceAllString(text, replace.Text)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(path, []byte(text), 0644)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
@@ -1,20 +1,29 @@
|
|||||||
module github.com/hay-kot/homebox/backend
|
module github.com/hay-kot/homebox/backend
|
||||||
|
|
||||||
go 1.19
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
ariga.io/atlas v0.7.2-0.20220927111110-867ee0cca56a
|
ariga.io/atlas v0.12.0
|
||||||
entgo.io/ent v0.11.3
|
entgo.io/ent v0.12.3
|
||||||
github.com/ardanlabs/conf/v2 v2.2.0
|
github.com/ardanlabs/conf/v3 v3.1.6
|
||||||
github.com/go-chi/chi/v5 v5.0.7
|
github.com/containrrr/shoutrrr v0.7.1
|
||||||
github.com/go-playground/validator/v10 v10.11.1
|
github.com/go-chi/chi/v5 v5.0.10
|
||||||
|
github.com/go-playground/validator/v10 v10.14.1
|
||||||
|
github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/mattn/go-sqlite3 v1.14.16
|
github.com/gorilla/schema v1.2.0
|
||||||
github.com/rs/zerolog v1.28.0
|
github.com/hay-kot/httpkit v0.0.3
|
||||||
github.com/stretchr/testify v1.8.1
|
github.com/mattn/go-sqlite3 v1.14.17
|
||||||
github.com/swaggo/http-swagger v1.3.3
|
github.com/olahol/melody v1.1.4
|
||||||
github.com/swaggo/swag v1.8.7
|
github.com/pkg/errors v0.9.1
|
||||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
|
github.com/rs/zerolog v1.29.1
|
||||||
|
github.com/stretchr/testify v1.8.4
|
||||||
|
github.com/swaggo/http-swagger v1.3.4
|
||||||
|
github.com/swaggo/swag v1.16.1
|
||||||
|
github.com/yeqown/go-qrcode/v2 v2.2.2
|
||||||
|
github.com/yeqown/go-qrcode/writer/standard v1.2.1
|
||||||
|
golang.org/x/crypto v0.11.0
|
||||||
|
modernc.org/sqlite v1.24.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -22,28 +31,47 @@ require (
|
|||||||
github.com/agext/levenshtein v1.2.3 // indirect
|
github.com/agext/levenshtein v1.2.3 // indirect
|
||||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
|
github.com/fatih/color v1.15.0 // indirect
|
||||||
|
github.com/fogleman/gg v1.3.0 // indirect
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||||
github.com/go-openapi/inflect v0.19.0 // indirect
|
github.com/go-openapi/inflect v0.19.0 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
github.com/go-openapi/jsonpointer v0.20.0 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||||
github.com/go-openapi/spec v0.20.7 // indirect
|
github.com/go-openapi/spec v0.20.9 // indirect
|
||||||
github.com/go-openapi/swag v0.22.3 // indirect
|
github.com/go-openapi/swag v0.22.4 // indirect
|
||||||
github.com/go-playground/locales v0.14.0 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
github.com/hashicorp/hcl/v2 v2.14.1 // indirect
|
github.com/gorilla/websocket v1.5.0 // indirect
|
||||||
|
github.com/hashicorp/hcl/v2 v2.17.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/leodido/go-urn v1.2.1 // indirect
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||||
|
github.com/leodido/go-urn v1.2.4 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/zclconf/go-cty v1.11.0 // indirect
|
github.com/swaggo/files v1.0.1 // indirect
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
github.com/yeqown/reedsolomon v1.0.0 // indirect
|
||||||
golang.org/x/net v0.0.0-20220923203811-8be639271d50 // indirect
|
github.com/zclconf/go-cty v1.13.2 // indirect
|
||||||
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect
|
golang.org/x/image v0.9.0 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/mod v0.12.0 // indirect
|
||||||
golang.org/x/tools v0.1.13-0.20220804200503-81c7dc4e4efa // indirect
|
golang.org/x/net v0.12.0 // indirect
|
||||||
|
golang.org/x/sys v0.10.0 // indirect
|
||||||
|
golang.org/x/text v0.11.0 // indirect
|
||||||
|
golang.org/x/tools v0.11.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
lukechampine.com/uint128 v1.3.0 // indirect
|
||||||
|
modernc.org/cc/v3 v3.41.0 // indirect
|
||||||
|
modernc.org/ccgo/v3 v3.16.14 // indirect
|
||||||
|
modernc.org/libc v1.24.1 // indirect
|
||||||
|
modernc.org/mathutil v1.6.0 // indirect
|
||||||
|
modernc.org/memory v1.6.0 // indirect
|
||||||
|
modernc.org/opt v0.1.3 // indirect
|
||||||
|
modernc.org/strutil v1.1.3 // indirect
|
||||||
|
modernc.org/token v1.1.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
1263
backend/go.sum
1263
backend/go.sum
File diff suppressed because it is too large
Load Diff
@@ -1,24 +1,48 @@
|
|||||||
package services
|
package services
|
||||||
|
|
||||||
import "github.com/hay-kot/homebox/backend/internal/data/repo"
|
import (
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
|
)
|
||||||
|
|
||||||
type AllServices struct {
|
type AllServices struct {
|
||||||
User *UserService
|
User *UserService
|
||||||
Group *GroupService
|
Group *GroupService
|
||||||
Items *ItemService
|
Items *ItemService
|
||||||
|
BackgroundService *BackgroundService
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(repos *repo.AllRepos) *AllServices {
|
type OptionsFunc func(*options)
|
||||||
|
|
||||||
|
type options struct {
|
||||||
|
autoIncrementAssetID bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithAutoIncrementAssetID(v bool) func(*options) {
|
||||||
|
return func(o *options) {
|
||||||
|
o.autoIncrementAssetID = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(repos *repo.AllRepos, opts ...OptionsFunc) *AllServices {
|
||||||
if repos == nil {
|
if repos == nil {
|
||||||
panic("repos cannot be nil")
|
panic("repos cannot be nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
options := &options{
|
||||||
|
autoIncrementAssetID: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(options)
|
||||||
|
}
|
||||||
|
|
||||||
return &AllServices{
|
return &AllServices{
|
||||||
User: &UserService{repos},
|
User: &UserService{repos},
|
||||||
Group: &GroupService{repos},
|
Group: &GroupService{repos},
|
||||||
Items: &ItemService{
|
Items: &ItemService{
|
||||||
repo: repos,
|
repo: repos,
|
||||||
at: attachmentTokens{},
|
autoIncrementAssetID: options.autoIncrementAssetID,
|
||||||
},
|
},
|
||||||
|
BackgroundService: &BackgroundService{repos},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,10 @@ package services
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/faker"
|
"github.com/hay-kot/homebox/backend/pkgs/faker"
|
||||||
@@ -15,7 +14,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
fk = faker.NewFaker()
|
fk = faker.NewFaker()
|
||||||
|
tbus = eventbus.New()
|
||||||
|
|
||||||
tCtx = Context{}
|
tCtx = Context{}
|
||||||
tClient *ent.Client
|
tClient *ent.Client
|
||||||
@@ -49,8 +49,6 @@ func bootstrap() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
rand.Seed(int64(time.Now().Unix()))
|
|
||||||
|
|
||||||
client, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
|
client, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed opening connection to sqlite: %v", err)
|
log.Fatalf("failed opening connection to sqlite: %v", err)
|
||||||
@@ -62,7 +60,7 @@ func TestMain(m *testing.M) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tClient = client
|
tClient = client
|
||||||
tRepos = repo.New(tClient, os.TempDir()+"/homebox")
|
tRepos = repo.New(tClient, tbus, os.TempDir()+"/homebox")
|
||||||
tSvc = New(tRepos)
|
tSvc = New(tRepos)
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
HB.location,HB.name,HB.quantity,HB.description,HB.field.Custom Field 1,HB.field.Custom Field 2,HB.field.Custom Field 3
|
||||||
|
loc,Item 1,1,Description 1,Value 1[1],Value 1[2],Value 1[3]
|
||||||
|
loc,Item 2,2,Description 2,Value 2[1],Value 2[2],Value 2[3]
|
||||||
|
loc,Item 3,3,Description 3,Value 3[1],Value 3[2],Value 3[3]
|
||||||
|
|
||||||
|
@@ -0,0 +1,4 @@
|
|||||||
|
HB.location,HB.name,HB.quantity,HB.description
|
||||||
|
loc,Item 1,1,Description 1
|
||||||
|
loc,Item 2,2,Description 2
|
||||||
|
loc,Item 3,3,Description 3
|
||||||
|
@@ -0,0 +1,4 @@
|
|||||||
|
HB.name,HB.asset_id,HB.location,HB.labels
|
||||||
|
Item 1,1,Path / To / Location 1,L1 ; L2 ; L3
|
||||||
|
Item 2,000-002,Path /To/ Location 2,L1;L2;L3
|
||||||
|
Item 3,1000-003,Path / To /Location 3 , L1;L2; L3
|
||||||
|
@@ -0,0 +1,42 @@
|
|||||||
|
package reporting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gocarina/gocsv"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// =================================================================================================
|
||||||
|
|
||||||
|
type BillOfMaterialsEntry struct {
|
||||||
|
PurchaseDate types.Date `csv:"Purchase Date"`
|
||||||
|
Name string `csv:"Name"`
|
||||||
|
Description string `csv:"Description"`
|
||||||
|
Manufacturer string `csv:"Manufacturer"`
|
||||||
|
SerialNumber string `csv:"Serial Number"`
|
||||||
|
ModelNumber string `csv:"Model Number"`
|
||||||
|
Quantity int `csv:"Quantity"`
|
||||||
|
Price float64 `csv:"Price"`
|
||||||
|
TotalPrice float64 `csv:"Total Price"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BillOfMaterialsTSV returns a byte slice of the Bill of Materials for a given GID in TSV format
|
||||||
|
// See BillOfMaterialsEntry for the format of the output
|
||||||
|
func BillOfMaterialsTSV(entities []repo.ItemOut) ([]byte, error) {
|
||||||
|
bomEntries := make([]BillOfMaterialsEntry, len(entities))
|
||||||
|
for i, entity := range entities {
|
||||||
|
bomEntries[i] = BillOfMaterialsEntry{
|
||||||
|
PurchaseDate: entity.PurchaseTime,
|
||||||
|
Name: entity.Name,
|
||||||
|
Description: entity.Description,
|
||||||
|
Manufacturer: entity.Manufacturer,
|
||||||
|
SerialNumber: entity.SerialNumber,
|
||||||
|
ModelNumber: entity.ModelNumber,
|
||||||
|
Quantity: entity.Quantity,
|
||||||
|
Price: entity.PurchasePrice,
|
||||||
|
TotalPrice: entity.PurchasePrice * float64(entity.Quantity),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return gocsv.MarshalBytes(&bomEntries)
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
// / Package eventbus provides an interface for event bus.
|
||||||
|
package eventbus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Event string
|
||||||
|
|
||||||
|
const (
|
||||||
|
EventLabelMutation Event = "label.mutation"
|
||||||
|
EventLocationMutation Event = "location.mutation"
|
||||||
|
EventItemMutation Event = "item.mutation"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GroupMutationEvent struct {
|
||||||
|
GID uuid.UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
type eventData struct {
|
||||||
|
event Event
|
||||||
|
data any
|
||||||
|
}
|
||||||
|
|
||||||
|
type EventBus struct {
|
||||||
|
started bool
|
||||||
|
ch chan eventData
|
||||||
|
|
||||||
|
mu sync.RWMutex
|
||||||
|
subscribers map[Event][]func(any)
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() *EventBus {
|
||||||
|
return &EventBus{
|
||||||
|
ch: make(chan eventData, 10),
|
||||||
|
subscribers: map[Event][]func(any){
|
||||||
|
EventLabelMutation: {},
|
||||||
|
EventLocationMutation: {},
|
||||||
|
EventItemMutation: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EventBus) Run() {
|
||||||
|
if e.started {
|
||||||
|
panic("event bus already started")
|
||||||
|
}
|
||||||
|
|
||||||
|
e.started = true
|
||||||
|
|
||||||
|
for event := range e.ch {
|
||||||
|
e.mu.RLock()
|
||||||
|
arr, ok := e.subscribers[event.event]
|
||||||
|
e.mu.RUnlock()
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fn := range arr {
|
||||||
|
fn(event.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EventBus) Publish(event Event, data any) {
|
||||||
|
e.ch <- eventData{
|
||||||
|
event: event,
|
||||||
|
data: data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EventBus) Subscribe(event Event, fn func(any)) {
|
||||||
|
e.mu.Lock()
|
||||||
|
defer e.mu.Unlock()
|
||||||
|
|
||||||
|
arr, ok := e.subscribers[event]
|
||||||
|
if !ok {
|
||||||
|
panic("event not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
e.subscribers[event] = append(arr, fn)
|
||||||
|
}
|
||||||
93
backend/internal/core/services/reporting/import.go
Normal file
93
backend/internal/core/services/reporting/import.go
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
package reporting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/csv"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrNoHomeboxHeaders = errors.New("no headers found")
|
||||||
|
ErrMissingRequiredHeaders = errors.New("missing required headers `HB.location` or `HB.name`")
|
||||||
|
)
|
||||||
|
|
||||||
|
// determineSeparator determines the separator used in the CSV file
|
||||||
|
// It returns the separator as a rune and an error if it could not be determined
|
||||||
|
//
|
||||||
|
// It is assumed that the first row is the header row and that the separator is the same
|
||||||
|
// for all rows.
|
||||||
|
//
|
||||||
|
// Supported separators are `,` and `\t`
|
||||||
|
func determineSeparator(data []byte) (rune, error) {
|
||||||
|
// First row
|
||||||
|
firstRow := bytes.Split(data, []byte("\n"))[0]
|
||||||
|
|
||||||
|
// find first comma or /t
|
||||||
|
comma := bytes.IndexByte(firstRow, ',')
|
||||||
|
tab := bytes.IndexByte(firstRow, '\t')
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case comma == -1 && tab == -1:
|
||||||
|
return 0, errors.New("could not determine separator")
|
||||||
|
case tab > comma:
|
||||||
|
return '\t', nil
|
||||||
|
default:
|
||||||
|
return ',', nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// readRawCsv reads a CSV file and returns the raw data as a 2D string array
|
||||||
|
// It determines the separator used in the CSV file and returns an error if
|
||||||
|
// it could not be determined
|
||||||
|
func readRawCsv(r io.Reader) ([][]string, error) {
|
||||||
|
data, err := io.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
reader := csv.NewReader(bytes.NewReader(data))
|
||||||
|
|
||||||
|
// Determine separator
|
||||||
|
sep, err := determineSeparator(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.Comma = sep
|
||||||
|
|
||||||
|
return reader.ReadAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseHeaders parses the homebox headers from the CSV file and returns a map of the headers
|
||||||
|
// and their column index as well as a list of the field headers (HB.field.*) in the order
|
||||||
|
// they appear in the CSV file
|
||||||
|
//
|
||||||
|
// It returns an error if no homebox headers are found
|
||||||
|
func parseHeaders(headers []string) (hbHeaders map[string]int, fieldHeaders []string, err error) {
|
||||||
|
hbHeaders = map[string]int{} // initialize map
|
||||||
|
|
||||||
|
for col, h := range headers {
|
||||||
|
if strings.HasPrefix(h, "HB.field.") {
|
||||||
|
fieldHeaders = append(fieldHeaders, h)
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(h, "HB.") {
|
||||||
|
hbHeaders[h] = col
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
required := []string{"HB.location", "HB.name"}
|
||||||
|
for _, h := range required {
|
||||||
|
if _, ok := hbHeaders[h]; !ok {
|
||||||
|
return nil, nil, ErrMissingRequiredHeaders
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(hbHeaders) == 0 {
|
||||||
|
return nil, nil, ErrNoHomeboxHeaders
|
||||||
|
}
|
||||||
|
|
||||||
|
return hbHeaders, fieldHeaders, nil
|
||||||
|
}
|
||||||
95
backend/internal/core/services/reporting/io_row.go
Normal file
95
backend/internal/core/services/reporting/io_row.go
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
package reporting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ExportItemFields struct {
|
||||||
|
Name string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExportTSVRow struct {
|
||||||
|
ImportRef string `csv:"HB.import_ref"`
|
||||||
|
Location LocationString `csv:"HB.location"`
|
||||||
|
LabelStr LabelString `csv:"HB.labels"`
|
||||||
|
AssetID repo.AssetID `csv:"HB.asset_id"`
|
||||||
|
Archived bool `csv:"HB.archived"`
|
||||||
|
|
||||||
|
Name string `csv:"HB.name"`
|
||||||
|
Quantity int `csv:"HB.quantity"`
|
||||||
|
Description string `csv:"HB.description"`
|
||||||
|
Insured bool `csv:"HB.insured"`
|
||||||
|
Notes string `csv:"HB.notes"`
|
||||||
|
|
||||||
|
PurchasePrice float64 `csv:"HB.purchase_price"`
|
||||||
|
PurchaseFrom string `csv:"HB.purchase_from"`
|
||||||
|
PurchaseTime types.Date `csv:"HB.purchase_time"`
|
||||||
|
|
||||||
|
Manufacturer string `csv:"HB.manufacturer"`
|
||||||
|
ModelNumber string `csv:"HB.model_number"`
|
||||||
|
SerialNumber string `csv:"HB.serial_number"`
|
||||||
|
|
||||||
|
LifetimeWarranty bool `csv:"HB.lifetime_warranty"`
|
||||||
|
WarrantyExpires types.Date `csv:"HB.warranty_expires"`
|
||||||
|
WarrantyDetails string `csv:"HB.warranty_details"`
|
||||||
|
|
||||||
|
SoldTo string `csv:"HB.sold_to"`
|
||||||
|
SoldPrice float64 `csv:"HB.sold_price"`
|
||||||
|
SoldTime types.Date `csv:"HB.sold_time"`
|
||||||
|
SoldNotes string `csv:"HB.sold_notes"`
|
||||||
|
|
||||||
|
Fields []ExportItemFields `csv:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
// LabelString is a string slice that is used to represent a list of labels.
|
||||||
|
//
|
||||||
|
// For example, a list of labels "Important; Work" would be represented as a
|
||||||
|
// LabelString with the following values:
|
||||||
|
//
|
||||||
|
// LabelString{"Important", "Work"}
|
||||||
|
type LabelString []string
|
||||||
|
|
||||||
|
func parseLabelString(s string) LabelString {
|
||||||
|
v, _ := parseSeparatedString(s, ";")
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls LabelString) String() string {
|
||||||
|
return strings.Join(ls, "; ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
// LocationString is a string slice that is used to represent a location
|
||||||
|
// hierarchy.
|
||||||
|
//
|
||||||
|
// For example, a location hierarchy of "Home / Bedroom / Desk" would be
|
||||||
|
// represented as a LocationString with the following values:
|
||||||
|
//
|
||||||
|
// LocationString{"Home", "Bedroom", "Desk"}
|
||||||
|
type LocationString []string
|
||||||
|
|
||||||
|
func parseLocationString(s string) LocationString {
|
||||||
|
v, _ := parseSeparatedString(s, "/")
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csf LocationString) String() string {
|
||||||
|
return strings.Join(csf, " / ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func fromPathSlice(s []repo.LocationPath) LocationString {
|
||||||
|
v := make(LocationString, len(s))
|
||||||
|
|
||||||
|
for i := range s {
|
||||||
|
v[i] = s[i].Name
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
322
backend/internal/core/services/reporting/io_sheet.go
Normal file
322
backend/internal/core/services/reporting/io_sheet.go
Normal file
@@ -0,0 +1,322 @@
|
|||||||
|
package reporting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/types"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IOSheet is the representation of a CSV/TSV sheet that is used for importing/exporting
|
||||||
|
// items from homebox. It is used to read/write the data from/to a CSV/TSV file given
|
||||||
|
// the standard format of the file.
|
||||||
|
//
|
||||||
|
// See ExportTSVRow for the format of the data in the sheet.
|
||||||
|
type IOSheet struct {
|
||||||
|
headers []string
|
||||||
|
custom []int
|
||||||
|
index map[string]int
|
||||||
|
Rows []ExportTSVRow
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *IOSheet) indexHeaders() {
|
||||||
|
s.index = make(map[string]int)
|
||||||
|
|
||||||
|
for i, h := range s.headers {
|
||||||
|
if strings.HasPrefix(h, "HB.field") {
|
||||||
|
s.custom = append(s.custom, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(h, "HB.") {
|
||||||
|
s.index[h] = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *IOSheet) GetColumn(str string) (col int, ok bool) {
|
||||||
|
if s.index == nil {
|
||||||
|
s.indexHeaders()
|
||||||
|
}
|
||||||
|
|
||||||
|
col, ok = s.index[str]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read reads a CSV/TSV and populates the "Rows" field with the data from the sheet
|
||||||
|
// Custom Fields are supported via the `HB.field.*` headers. The `HB.field.*` the "Name"
|
||||||
|
// of the field is the part after the `HB.field.` prefix. Additionally, Custom Fields with
|
||||||
|
// no value are excluded from the row.Fields slice, this includes empty strings.
|
||||||
|
//
|
||||||
|
// Note That
|
||||||
|
// - the first row is assumed to be the header
|
||||||
|
// - at least 1 row of data is required
|
||||||
|
// - rows and columns must be rectangular (i.e. all rows must have the same number of columns)
|
||||||
|
func (s *IOSheet) Read(data io.Reader) error {
|
||||||
|
sheet, err := readRawCsv(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sheet) < 2 {
|
||||||
|
return fmt.Errorf("sheet must have at least 1 row of data (header + 1)")
|
||||||
|
}
|
||||||
|
|
||||||
|
s.headers = sheet[0]
|
||||||
|
s.Rows = make([]ExportTSVRow, len(sheet)-1)
|
||||||
|
|
||||||
|
for i, row := range sheet[1:] {
|
||||||
|
if len(row) != len(s.headers) {
|
||||||
|
return fmt.Errorf("row has %d columns, expected %d", len(row), len(s.headers))
|
||||||
|
}
|
||||||
|
|
||||||
|
rowData := ExportTSVRow{}
|
||||||
|
|
||||||
|
st := reflect.TypeOf(ExportTSVRow{})
|
||||||
|
|
||||||
|
for i := 0; i < st.NumField(); i++ {
|
||||||
|
field := st.Field(i)
|
||||||
|
tag := field.Tag.Get("csv")
|
||||||
|
if tag == "" || tag == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
col, ok := s.GetColumn(tag)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val := row[col]
|
||||||
|
|
||||||
|
var v interface{}
|
||||||
|
|
||||||
|
switch field.Type {
|
||||||
|
case reflect.TypeOf(""):
|
||||||
|
v = val
|
||||||
|
case reflect.TypeOf(int(0)):
|
||||||
|
v = parseInt(val)
|
||||||
|
case reflect.TypeOf(bool(false)):
|
||||||
|
v = parseBool(val)
|
||||||
|
case reflect.TypeOf(float64(0)):
|
||||||
|
v = parseFloat(val)
|
||||||
|
|
||||||
|
// Custom Types
|
||||||
|
case reflect.TypeOf(types.Date{}):
|
||||||
|
v = types.DateFromString(val)
|
||||||
|
case reflect.TypeOf(repo.AssetID(0)):
|
||||||
|
v, _ = repo.ParseAssetID(val)
|
||||||
|
case reflect.TypeOf(LocationString{}):
|
||||||
|
v = parseLocationString(val)
|
||||||
|
case reflect.TypeOf(LabelString{}):
|
||||||
|
v = parseLabelString(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug().
|
||||||
|
Str("tag", tag).
|
||||||
|
Interface("val", v).
|
||||||
|
Str("type", fmt.Sprintf("%T", v)).
|
||||||
|
Msg("parsed value")
|
||||||
|
|
||||||
|
// Nil values are not allowed at the moment. This may change.
|
||||||
|
if v == nil {
|
||||||
|
return fmt.Errorf("could not convert %q to %s", val, field.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrField := reflect.ValueOf(&rowData).Elem().Field(i)
|
||||||
|
ptrField.Set(reflect.ValueOf(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, col := range s.custom {
|
||||||
|
colName := strings.TrimPrefix(s.headers[col], "HB.field.")
|
||||||
|
customVal := row[col]
|
||||||
|
if customVal == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
rowData.Fields = append(rowData.Fields, ExportItemFields{
|
||||||
|
Name: colName,
|
||||||
|
Value: customVal,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Rows[i] = rowData
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write writes the sheet to a writer.
|
||||||
|
func (s *IOSheet) ReadItems(ctx context.Context, items []repo.ItemOut, GID uuid.UUID, repos *repo.AllRepos) error {
|
||||||
|
s.Rows = make([]ExportTSVRow, len(items))
|
||||||
|
|
||||||
|
extraHeaders := map[string]struct{}{}
|
||||||
|
|
||||||
|
for i := range items {
|
||||||
|
item := items[i]
|
||||||
|
|
||||||
|
// TODO: Support fetching nested locations
|
||||||
|
locId := item.Location.ID
|
||||||
|
|
||||||
|
locPaths, err := repos.Locations.PathForLoc(context.Background(), GID, locId)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("could not get location path")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
locString := fromPathSlice(locPaths)
|
||||||
|
|
||||||
|
labelString := make([]string, len(item.Labels))
|
||||||
|
|
||||||
|
for i, l := range item.Labels {
|
||||||
|
labelString[i] = l.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
customFields := make([]ExportItemFields, len(item.Fields))
|
||||||
|
|
||||||
|
for i, f := range item.Fields {
|
||||||
|
extraHeaders[f.Name] = struct{}{}
|
||||||
|
|
||||||
|
customFields[i] = ExportItemFields{
|
||||||
|
Name: f.Name,
|
||||||
|
Value: f.TextValue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Rows[i] = ExportTSVRow{
|
||||||
|
// fill struct
|
||||||
|
Location: locString,
|
||||||
|
LabelStr: labelString,
|
||||||
|
|
||||||
|
ImportRef: item.ImportRef,
|
||||||
|
AssetID: item.AssetID,
|
||||||
|
Name: item.Name,
|
||||||
|
Quantity: item.Quantity,
|
||||||
|
Description: item.Description,
|
||||||
|
Insured: item.Insured,
|
||||||
|
Archived: item.Archived,
|
||||||
|
|
||||||
|
PurchasePrice: item.PurchasePrice,
|
||||||
|
PurchaseFrom: item.PurchaseFrom,
|
||||||
|
PurchaseTime: item.PurchaseTime,
|
||||||
|
|
||||||
|
Manufacturer: item.Manufacturer,
|
||||||
|
ModelNumber: item.ModelNumber,
|
||||||
|
SerialNumber: item.SerialNumber,
|
||||||
|
|
||||||
|
LifetimeWarranty: item.LifetimeWarranty,
|
||||||
|
WarrantyExpires: item.WarrantyExpires,
|
||||||
|
WarrantyDetails: item.WarrantyDetails,
|
||||||
|
|
||||||
|
SoldTo: item.SoldTo,
|
||||||
|
SoldTime: item.SoldTime,
|
||||||
|
SoldPrice: item.SoldPrice,
|
||||||
|
SoldNotes: item.SoldNotes,
|
||||||
|
|
||||||
|
Fields: customFields,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract and sort additional headers for deterministic output
|
||||||
|
customHeaders := make([]string, 0, len(extraHeaders))
|
||||||
|
|
||||||
|
for k := range extraHeaders {
|
||||||
|
customHeaders = append(customHeaders, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(customHeaders)
|
||||||
|
|
||||||
|
st := reflect.TypeOf(ExportTSVRow{})
|
||||||
|
|
||||||
|
// Write headers
|
||||||
|
for i := 0; i < st.NumField(); i++ {
|
||||||
|
field := st.Field(i)
|
||||||
|
tag := field.Tag.Get("csv")
|
||||||
|
if tag == "" || tag == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
s.headers = append(s.headers, tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, h := range customHeaders {
|
||||||
|
s.headers = append(s.headers, "HB.field."+h)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writes the current sheet to a writer in TSV format.
|
||||||
|
func (s *IOSheet) TSV() ([][]string, error) {
|
||||||
|
memcsv := make([][]string, len(s.Rows)+1)
|
||||||
|
|
||||||
|
memcsv[0] = s.headers
|
||||||
|
|
||||||
|
// use struct tags in rows to dertmine column order
|
||||||
|
for i, row := range s.Rows {
|
||||||
|
rowIdx := i + 1
|
||||||
|
|
||||||
|
memcsv[rowIdx] = make([]string, len(s.headers))
|
||||||
|
|
||||||
|
st := reflect.TypeOf(row)
|
||||||
|
|
||||||
|
for i := 0; i < st.NumField(); i++ {
|
||||||
|
field := st.Field(i)
|
||||||
|
tag := field.Tag.Get("csv")
|
||||||
|
if tag == "" || tag == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
col, ok := s.GetColumn(tag)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val := reflect.ValueOf(row).Field(i)
|
||||||
|
|
||||||
|
var v string
|
||||||
|
|
||||||
|
switch field.Type {
|
||||||
|
case reflect.TypeOf(""):
|
||||||
|
v = val.String()
|
||||||
|
case reflect.TypeOf(int(0)):
|
||||||
|
v = strconv.Itoa(int(val.Int()))
|
||||||
|
case reflect.TypeOf(bool(false)):
|
||||||
|
v = strconv.FormatBool(val.Bool())
|
||||||
|
case reflect.TypeOf(float64(0)):
|
||||||
|
v = strconv.FormatFloat(val.Float(), 'f', -1, 64)
|
||||||
|
|
||||||
|
// Custom Types
|
||||||
|
case reflect.TypeOf(types.Date{}):
|
||||||
|
v = val.Interface().(types.Date).String()
|
||||||
|
case reflect.TypeOf(repo.AssetID(0)):
|
||||||
|
v = val.Interface().(repo.AssetID).String()
|
||||||
|
case reflect.TypeOf(LocationString{}):
|
||||||
|
v = val.Interface().(LocationString).String()
|
||||||
|
case reflect.TypeOf(LabelString{}):
|
||||||
|
v = val.Interface().(LabelString).String()
|
||||||
|
default:
|
||||||
|
log.Debug().Str("type", field.Type.String()).Msg("unknown type")
|
||||||
|
}
|
||||||
|
|
||||||
|
memcsv[rowIdx][col] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range row.Fields {
|
||||||
|
col, ok := s.GetColumn("HB.field." + f.Name)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
memcsv[i+1][col] = f.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return memcsv, nil
|
||||||
|
}
|
||||||
220
backend/internal/core/services/reporting/io_sheet_test.go
Normal file
220
backend/internal/core/services/reporting/io_sheet_test.go
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
package reporting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
_ "embed"
|
||||||
|
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
//go:embed .testdata/import/minimal.csv
|
||||||
|
minimalImportCSV []byte
|
||||||
|
|
||||||
|
//go:embed .testdata/import/fields.csv
|
||||||
|
customFieldImportCSV []byte
|
||||||
|
|
||||||
|
//go:embed .testdata/import/types.csv
|
||||||
|
customTypesImportCSV []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSheet_Read(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
data []byte
|
||||||
|
want []ExportTSVRow
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "minimal import",
|
||||||
|
data: minimalImportCSV,
|
||||||
|
want: []ExportTSVRow{
|
||||||
|
{Location: LocationString{"loc"}, Name: "Item 1", Quantity: 1, Description: "Description 1"},
|
||||||
|
{Location: LocationString{"loc"}, Name: "Item 2", Quantity: 2, Description: "Description 2"},
|
||||||
|
{Location: LocationString{"loc"}, Name: "Item 3", Quantity: 3, Description: "Description 3"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "custom field import",
|
||||||
|
data: customFieldImportCSV,
|
||||||
|
want: []ExportTSVRow{
|
||||||
|
{
|
||||||
|
Location: LocationString{"loc"}, Name: "Item 1", Quantity: 1, Description: "Description 1",
|
||||||
|
Fields: []ExportItemFields{
|
||||||
|
{Name: "Custom Field 1", Value: "Value 1[1]"},
|
||||||
|
{Name: "Custom Field 2", Value: "Value 1[2]"},
|
||||||
|
{Name: "Custom Field 3", Value: "Value 1[3]"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Location: LocationString{"loc"}, Name: "Item 2", Quantity: 2, Description: "Description 2",
|
||||||
|
Fields: []ExportItemFields{
|
||||||
|
{Name: "Custom Field 1", Value: "Value 2[1]"},
|
||||||
|
{Name: "Custom Field 2", Value: "Value 2[2]"},
|
||||||
|
{Name: "Custom Field 3", Value: "Value 2[3]"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Location: LocationString{"loc"}, Name: "Item 3", Quantity: 3, Description: "Description 3",
|
||||||
|
Fields: []ExportItemFields{
|
||||||
|
{Name: "Custom Field 1", Value: "Value 3[1]"},
|
||||||
|
{Name: "Custom Field 2", Value: "Value 3[2]"},
|
||||||
|
{Name: "Custom Field 3", Value: "Value 3[3]"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "custom types import",
|
||||||
|
data: customTypesImportCSV,
|
||||||
|
want: []ExportTSVRow{
|
||||||
|
{
|
||||||
|
Name: "Item 1",
|
||||||
|
AssetID: repo.AssetID(1),
|
||||||
|
Location: LocationString{"Path", "To", "Location 1"},
|
||||||
|
LabelStr: LabelString{"L1", "L2", "L3"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Item 2",
|
||||||
|
AssetID: repo.AssetID(2),
|
||||||
|
Location: LocationString{"Path", "To", "Location 2"},
|
||||||
|
LabelStr: LabelString{"L1", "L2", "L3"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Item 3",
|
||||||
|
AssetID: repo.AssetID(1000003),
|
||||||
|
Location: LocationString{"Path", "To", "Location 3"},
|
||||||
|
LabelStr: LabelString{"L1", "L2", "L3"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
reader := bytes.NewReader(tt.data)
|
||||||
|
|
||||||
|
sheet := &IOSheet{}
|
||||||
|
err := sheet.Read(reader)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case tt.wantErr:
|
||||||
|
assert.Error(t, err)
|
||||||
|
default:
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.ElementsMatch(t, tt.want, sheet.Rows)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_parseHeaders(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
rawHeaders []string
|
||||||
|
wantHbHeaders map[string]int
|
||||||
|
wantFieldHeaders []string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no hombox headers",
|
||||||
|
rawHeaders: []string{"Header 1", "Header 2", "Header 3"},
|
||||||
|
wantHbHeaders: nil,
|
||||||
|
wantFieldHeaders: nil,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "field headers only",
|
||||||
|
rawHeaders: []string{"HB.location", "HB.name", "HB.field.1", "HB.field.2", "HB.field.3"},
|
||||||
|
wantHbHeaders: map[string]int{
|
||||||
|
"HB.location": 0,
|
||||||
|
"HB.name": 1,
|
||||||
|
"HB.field.1": 2,
|
||||||
|
"HB.field.2": 3,
|
||||||
|
"HB.field.3": 4,
|
||||||
|
},
|
||||||
|
wantFieldHeaders: []string{"HB.field.1", "HB.field.2", "HB.field.3"},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mixed headers",
|
||||||
|
rawHeaders: []string{"Header 1", "HB.name", "Header 2", "HB.field.2", "Header 3", "HB.field.3", "HB.location"},
|
||||||
|
wantHbHeaders: map[string]int{
|
||||||
|
"HB.name": 1,
|
||||||
|
"HB.field.2": 3,
|
||||||
|
"HB.field.3": 5,
|
||||||
|
"HB.location": 6,
|
||||||
|
},
|
||||||
|
wantFieldHeaders: []string{"HB.field.2", "HB.field.3"},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gotHbHeaders, gotFieldHeaders, err := parseHeaders(tt.rawHeaders)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("parseHeaders() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(gotHbHeaders, tt.wantHbHeaders) {
|
||||||
|
t.Errorf("parseHeaders() gotHbHeaders = %v, want %v", gotHbHeaders, tt.wantHbHeaders)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(gotFieldHeaders, tt.wantFieldHeaders) {
|
||||||
|
t.Errorf("parseHeaders() gotFieldHeaders = %v, want %v", gotFieldHeaders, tt.wantFieldHeaders)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_determineSeparator(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
data []byte
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want rune
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "comma",
|
||||||
|
args: args{
|
||||||
|
data: []byte("a,b,c"),
|
||||||
|
},
|
||||||
|
want: ',',
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "tab",
|
||||||
|
args: args{
|
||||||
|
data: []byte("a\tb\tc"),
|
||||||
|
},
|
||||||
|
want: '\t',
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid",
|
||||||
|
args: args{
|
||||||
|
data: []byte("a;b;c"),
|
||||||
|
},
|
||||||
|
want: 0,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := determineSeparator(tt.args.data)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("determineSeparator() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("determineSeparator() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
38
backend/internal/core/services/reporting/value_parsers.go
Normal file
38
backend/internal/core/services/reporting/value_parsers.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package reporting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseSeparatedString(s string, sep string) ([]string, error) {
|
||||||
|
list := strings.Split(s, sep)
|
||||||
|
|
||||||
|
csf := make([]string, 0, len(list))
|
||||||
|
for _, s := range list {
|
||||||
|
trimmed := strings.TrimSpace(s)
|
||||||
|
if trimmed != "" {
|
||||||
|
csf = append(csf, trimmed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return csf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseFloat(s string) float64 {
|
||||||
|
if s == "" {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
f, _ := strconv.ParseFloat(s, 64)
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseBool(s string) bool {
|
||||||
|
b, _ := strconv.ParseBool(s)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseInt(s string) int {
|
||||||
|
i, _ := strconv.Atoi(s)
|
||||||
|
return i
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package reporting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_parseSeparatedString(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
s string
|
||||||
|
sep string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want []string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "comma",
|
||||||
|
args: args{
|
||||||
|
s: "a,b,c",
|
||||||
|
sep: ",",
|
||||||
|
},
|
||||||
|
want: []string{"a", "b", "c"},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "trimmed comma",
|
||||||
|
args: args{
|
||||||
|
s: "a, b, c",
|
||||||
|
sep: ",",
|
||||||
|
},
|
||||||
|
want: []string{"a", "b", "c"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "excessive whitespace",
|
||||||
|
args: args{
|
||||||
|
s: " a, b, c ",
|
||||||
|
sep: ",",
|
||||||
|
},
|
||||||
|
want: []string{"a", "b", "c"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
args: args{
|
||||||
|
s: "",
|
||||||
|
sep: ",",
|
||||||
|
},
|
||||||
|
want: []string{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := parseSeparatedString(tt.args.s, tt.args.sep)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("parseSeparatedString() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("parseSeparatedString() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
81
backend/internal/core/services/service_background.go
Normal file
81
backend/internal/core/services/service_background.go
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/containrrr/shoutrrr"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/types"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BackgroundService struct {
|
||||||
|
repos *repo.AllRepos
|
||||||
|
}
|
||||||
|
|
||||||
|
func (svc *BackgroundService) SendNotifiersToday(ctx context.Context) error {
|
||||||
|
// Get All Groups
|
||||||
|
groups, err := svc.repos.Groups.GetAllGroups(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
today := types.DateFromTime(time.Now())
|
||||||
|
|
||||||
|
for i := range groups {
|
||||||
|
group := groups[i]
|
||||||
|
|
||||||
|
entries, err := svc.repos.MaintEntry.GetScheduled(ctx, group.ID, today)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(entries) == 0 {
|
||||||
|
log.Debug().
|
||||||
|
Str("group_name", group.Name).
|
||||||
|
Str("group_id", group.ID.String()).
|
||||||
|
Msg("No scheduled maintenance for today")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
notifiers, err := svc.repos.Notifiers.GetByGroup(ctx, group.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
urls := make([]string, len(notifiers))
|
||||||
|
for i := range notifiers {
|
||||||
|
urls[i] = notifiers[i].URL
|
||||||
|
}
|
||||||
|
|
||||||
|
bldr := strings.Builder{}
|
||||||
|
|
||||||
|
bldr.WriteString("Homebox Maintenance for (")
|
||||||
|
bldr.WriteString(today.String())
|
||||||
|
bldr.WriteString("):\n")
|
||||||
|
|
||||||
|
for i := range entries {
|
||||||
|
entry := entries[i]
|
||||||
|
bldr.WriteString(" - ")
|
||||||
|
bldr.WriteString(entry.Name)
|
||||||
|
bldr.WriteString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
var sendErrs []error
|
||||||
|
for i := range urls {
|
||||||
|
err := shoutrrr.Send(urls[i], bldr.String())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
sendErrs = append(sendErrs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sendErrs) > 0 {
|
||||||
|
return sendErrs[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -3,10 +3,13 @@ package services
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/core/services/reporting"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -18,179 +21,335 @@ type ItemService struct {
|
|||||||
repo *repo.AllRepos
|
repo *repo.AllRepos
|
||||||
|
|
||||||
filepath string
|
filepath string
|
||||||
// at is a map of tokens to attachment IDs. This is used to store the attachment ID
|
|
||||||
// for issued URLs
|
autoIncrementAssetID bool
|
||||||
at attachmentTokens
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *ItemService) CsvImport(ctx context.Context, GID uuid.UUID, data [][]string) (int, error) {
|
func (svc *ItemService) Create(ctx Context, item repo.ItemCreate) (repo.ItemOut, error) {
|
||||||
loaded := []csvRow{}
|
if svc.autoIncrementAssetID {
|
||||||
|
highest, err := svc.repo.Items.GetHighestAssetID(ctx, ctx.GID)
|
||||||
// Skip first row
|
if err != nil {
|
||||||
for _, row := range data[1:] {
|
return repo.ItemOut{}, err
|
||||||
// Skip empty rows
|
|
||||||
if len(row) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(row) != NumOfCols {
|
item.AssetID = repo.AssetID(highest + 1)
|
||||||
return 0, ErrInvalidCsv
|
|
||||||
}
|
|
||||||
|
|
||||||
r := newCsvRow(row)
|
|
||||||
loaded = append(loaded, r)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate rows
|
return svc.repo.Items.Create(ctx, ctx.GID, item)
|
||||||
var errMap = map[int][]error{}
|
}
|
||||||
var hasErr bool
|
|
||||||
for i, r := range loaded {
|
|
||||||
|
|
||||||
errs := r.validate()
|
func (svc *ItemService) EnsureAssetID(ctx context.Context, GID uuid.UUID) (int, error) {
|
||||||
|
items, err := svc.repo.Items.GetAllZeroAssetID(ctx, GID)
|
||||||
if len(errs) > 0 {
|
|
||||||
hasErr = true
|
|
||||||
lineNum := i + 2
|
|
||||||
|
|
||||||
errMap[lineNum] = errs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if hasErr {
|
|
||||||
for lineNum, errs := range errMap {
|
|
||||||
for _, err := range errs {
|
|
||||||
log.Error().Err(err).Int("line", lineNum).Msg("csv import error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bootstrap the locations and labels so we can reuse the created IDs for the items
|
|
||||||
locations := map[string]uuid.UUID{}
|
|
||||||
existingLocation, err := svc.repo.Locations.GetAll(ctx, GID, repo.LocationQuery{})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
for _, loc := range existingLocation {
|
|
||||||
locations[loc.Name] = loc.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
labels := map[string]uuid.UUID{}
|
highest, err := svc.repo.Items.GetHighestAssetID(ctx, GID)
|
||||||
existingLabels, err := svc.repo.Labels.GetAll(ctx, GID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
for _, label := range existingLabels {
|
|
||||||
labels[label.Name] = label.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, row := range loaded {
|
finished := 0
|
||||||
|
for _, item := range items {
|
||||||
|
highest++
|
||||||
|
|
||||||
// Locations
|
err = svc.repo.Items.SetAssetID(ctx, GID, item.ID, repo.AssetID(highest))
|
||||||
if _, exists := locations[row.Location]; !exists {
|
if err != nil {
|
||||||
result, err := svc.repo.Locations.Create(ctx, GID, repo.LocationCreate{
|
return 0, err
|
||||||
Name: row.Location,
|
|
||||||
Description: "",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
locations[row.Location] = result.ID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Labels
|
finished++
|
||||||
|
}
|
||||||
|
|
||||||
for _, label := range row.getLabels() {
|
return finished, nil
|
||||||
if _, exists := labels[label]; exists {
|
}
|
||||||
continue
|
|
||||||
}
|
func (svc *ItemService) EnsureImportRef(ctx context.Context, GID uuid.UUID) (int, error) {
|
||||||
result, err := svc.repo.Labels.Create(ctx, GID, repo.LabelCreate{
|
ids, err := svc.repo.Items.GetAllZeroImportRef(ctx, GID)
|
||||||
Name: label,
|
if err != nil {
|
||||||
Description: "",
|
return 0, err
|
||||||
})
|
}
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
finished := 0
|
||||||
}
|
for _, itemID := range ids {
|
||||||
labels[label] = result.ID
|
ref := uuid.New().String()[0:8]
|
||||||
|
|
||||||
|
err = svc.repo.Items.Patch(ctx, GID, itemID, repo.ItemPatch{ImportRef: &ref})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
finished++
|
||||||
|
}
|
||||||
|
|
||||||
|
return finished, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func serializeLocation[T ~[]string](location T) string {
|
||||||
|
return strings.Join(location, "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
// CsvImport imports items from a CSV file. using the standard defined format.
|
||||||
|
//
|
||||||
|
// CsvImport applies the following rules/operations
|
||||||
|
//
|
||||||
|
// 1. If the item does not exist, it is created.
|
||||||
|
// 2. If the item has a ImportRef and it exists it is skipped
|
||||||
|
// 3. Locations and Labels are created if they do not exist.
|
||||||
|
func (svc *ItemService) CsvImport(ctx context.Context, GID uuid.UUID, data io.Reader) (int, error) {
|
||||||
|
sheet := reporting.IOSheet{}
|
||||||
|
|
||||||
|
err := sheet.Read(data)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// Labels
|
||||||
|
|
||||||
|
labelMap := make(map[string]uuid.UUID)
|
||||||
|
{
|
||||||
|
labels, err := svc.repo.Labels.GetAll(ctx, GID)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, label := range labels {
|
||||||
|
labelMap[label.Name] = label.ID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the items
|
// ========================================
|
||||||
var count int
|
// Locations
|
||||||
for _, row := range loaded {
|
|
||||||
// Check Import Ref
|
locationMap := make(map[string]uuid.UUID)
|
||||||
if row.Item.ImportRef != "" {
|
{
|
||||||
exists, err := svc.repo.Items.CheckRef(ctx, GID, row.Item.ImportRef)
|
locations, err := svc.repo.Locations.Tree(ctx, GID, repo.TreeQuery{WithItems: false})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Traverse the tree and build a map of location full paths to IDs
|
||||||
|
// where the full path is the location name joined by slashes.
|
||||||
|
var traverse func(location *repo.TreeItem, path []string)
|
||||||
|
traverse = func(location *repo.TreeItem, path []string) {
|
||||||
|
path = append(path, location.Name)
|
||||||
|
|
||||||
|
locationMap[serializeLocation(path)] = location.ID
|
||||||
|
|
||||||
|
for _, child := range location.Children {
|
||||||
|
traverse(child, path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, location := range locations {
|
||||||
|
traverse(&location, []string{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// Import items
|
||||||
|
|
||||||
|
// Asset ID Pre-Check
|
||||||
|
highestAID := repo.AssetID(-1)
|
||||||
|
if svc.autoIncrementAssetID {
|
||||||
|
highestAID, err = svc.repo.Items.GetHighestAssetID(ctx, GID)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finished := 0
|
||||||
|
|
||||||
|
for i := range sheet.Rows {
|
||||||
|
row := sheet.Rows[i]
|
||||||
|
|
||||||
|
createRequired := true
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// Preflight check for existing item
|
||||||
|
if row.ImportRef != "" {
|
||||||
|
exists, err := svc.repo.Items.CheckRef(ctx, GID, row.ImportRef)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("error checking for existing item with ref %q: %w", row.ImportRef, err)
|
||||||
|
}
|
||||||
|
|
||||||
if exists {
|
if exists {
|
||||||
continue
|
createRequired = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// Pre-Create Labels as necessary
|
||||||
|
labelIds := make([]uuid.UUID, len(row.LabelStr))
|
||||||
|
|
||||||
|
for j := range row.LabelStr {
|
||||||
|
label := row.LabelStr[j]
|
||||||
|
|
||||||
|
id, ok := labelMap[label]
|
||||||
|
if !ok {
|
||||||
|
newLabel, err := svc.repo.Labels.Create(ctx, GID, repo.LabelCreate{Name: label})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
id = newLabel.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
labelIds[j] = id
|
||||||
|
labelMap[label] = id
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// Pre-Create Locations as necessary
|
||||||
|
path := serializeLocation(row.Location)
|
||||||
|
|
||||||
|
locationID, ok := locationMap[path]
|
||||||
|
if !ok { // Traverse the path of LocationStr and check each path element to see if it exists already, if not create it.
|
||||||
|
paths := []string{}
|
||||||
|
for i, pathElement := range row.Location {
|
||||||
|
paths = append(paths, pathElement)
|
||||||
|
path := serializeLocation(paths)
|
||||||
|
|
||||||
|
locationID, ok = locationMap[path]
|
||||||
|
if !ok {
|
||||||
|
parentID := uuid.Nil
|
||||||
|
|
||||||
|
// Get the parent ID
|
||||||
|
if i > 0 {
|
||||||
|
parentPath := serializeLocation(row.Location[:i])
|
||||||
|
parentID = locationMap[parentPath]
|
||||||
|
}
|
||||||
|
|
||||||
|
newLocation, err := svc.repo.Locations.Create(ctx, GID, repo.LocationCreate{
|
||||||
|
ParentID: parentID,
|
||||||
|
Name: pathElement,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
locationID = newLocation.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
locationMap[path] = locationID
|
||||||
|
}
|
||||||
|
|
||||||
|
locationID, ok = locationMap[path]
|
||||||
|
if !ok {
|
||||||
|
return 0, errors.New("failed to create location")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var effAID repo.AssetID
|
||||||
|
if svc.autoIncrementAssetID && row.AssetID.Nil() {
|
||||||
|
effAID = highestAID + 1
|
||||||
|
highestAID++
|
||||||
|
} else {
|
||||||
|
effAID = row.AssetID
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// Create Item
|
||||||
|
var item repo.ItemOut
|
||||||
|
switch {
|
||||||
|
case createRequired:
|
||||||
|
newItem := repo.ItemCreate{
|
||||||
|
ImportRef: row.ImportRef,
|
||||||
|
Name: row.Name,
|
||||||
|
Description: row.Description,
|
||||||
|
AssetID: effAID,
|
||||||
|
LocationID: locationID,
|
||||||
|
LabelIDs: labelIds,
|
||||||
|
}
|
||||||
|
|
||||||
|
item, err = svc.repo.Items.Create(ctx, GID, newItem)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg("error checking import ref")
|
return 0, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
item, err = svc.repo.Items.GetByRef(ctx, GID, row.ImportRef)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
locationID := locations[row.Location]
|
if item.ID == uuid.Nil {
|
||||||
labelIDs := []uuid.UUID{}
|
panic("item ID is nil on import - this should never happen")
|
||||||
for _, label := range row.getLabels() {
|
|
||||||
labelIDs = append(labelIDs, labels[label])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info().
|
fields := make([]repo.ItemField, len(row.Fields))
|
||||||
Str("name", row.Item.Name).
|
for i := range row.Fields {
|
||||||
Str("location", row.Location).
|
fields[i] = repo.ItemField{
|
||||||
Msgf("Creating Item: %s", row.Item.Name)
|
Name: row.Fields[i].Name,
|
||||||
|
Type: "text",
|
||||||
result, err := svc.repo.Items.Create(ctx, GID, repo.ItemCreate{
|
TextValue: row.Fields[i].Value,
|
||||||
ImportRef: row.Item.ImportRef,
|
}
|
||||||
Name: row.Item.Name,
|
|
||||||
Description: row.Item.Description,
|
|
||||||
LabelIDs: labelIDs,
|
|
||||||
LocationID: locationID,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return count, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the item with the rest of the data
|
updateItem := repo.ItemUpdate{
|
||||||
_, err = svc.repo.Items.UpdateByGroup(ctx, GID, repo.ItemUpdate{
|
ID: item.ID,
|
||||||
// Edges
|
LabelIDs: labelIds,
|
||||||
LocationID: locationID,
|
LocationID: locationID,
|
||||||
LabelIDs: labelIDs,
|
|
||||||
|
|
||||||
// General Fields
|
Name: row.Name,
|
||||||
ID: result.ID,
|
Description: row.Description,
|
||||||
Name: result.Name,
|
AssetID: effAID,
|
||||||
Description: result.Description,
|
Insured: row.Insured,
|
||||||
Insured: row.Item.Insured,
|
Quantity: row.Quantity,
|
||||||
Notes: row.Item.Notes,
|
Archived: row.Archived,
|
||||||
Quantity: row.Item.Quantity,
|
|
||||||
|
|
||||||
// Identifies the item as imported
|
PurchasePrice: row.PurchasePrice,
|
||||||
SerialNumber: row.Item.SerialNumber,
|
PurchaseFrom: row.PurchaseFrom,
|
||||||
ModelNumber: row.Item.ModelNumber,
|
PurchaseTime: row.PurchaseTime,
|
||||||
Manufacturer: row.Item.Manufacturer,
|
|
||||||
|
|
||||||
// Purchase
|
Manufacturer: row.Manufacturer,
|
||||||
PurchaseFrom: row.Item.PurchaseFrom,
|
ModelNumber: row.ModelNumber,
|
||||||
PurchasePrice: row.Item.PurchasePrice,
|
SerialNumber: row.SerialNumber,
|
||||||
PurchaseTime: row.Item.PurchaseTime,
|
|
||||||
|
|
||||||
// Warranty
|
LifetimeWarranty: row.LifetimeWarranty,
|
||||||
LifetimeWarranty: row.Item.LifetimeWarranty,
|
WarrantyExpires: row.WarrantyExpires,
|
||||||
WarrantyExpires: row.Item.WarrantyExpires,
|
WarrantyDetails: row.WarrantyDetails,
|
||||||
WarrantyDetails: row.Item.WarrantyDetails,
|
|
||||||
|
|
||||||
SoldTo: row.Item.SoldTo,
|
SoldTo: row.SoldTo,
|
||||||
SoldPrice: row.Item.SoldPrice,
|
SoldTime: row.SoldTime,
|
||||||
SoldTime: row.Item.SoldTime,
|
SoldPrice: row.SoldPrice,
|
||||||
SoldNotes: row.Item.SoldNotes,
|
SoldNotes: row.SoldNotes,
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
Notes: row.Notes,
|
||||||
return count, err
|
Fields: fields,
|
||||||
}
|
}
|
||||||
|
|
||||||
count++
|
item, err = svc.repo.Items.UpdateByGroup(ctx, GID, updateItem)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
finished++
|
||||||
}
|
}
|
||||||
return count, nil
|
|
||||||
|
return finished, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (svc *ItemService) ExportTSV(ctx context.Context, GID uuid.UUID) ([][]string, error) {
|
||||||
|
items, err := svc.repo.Items.GetAll(ctx, GID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sheet := reporting.IOSheet{}
|
||||||
|
|
||||||
|
err = sheet.ReadItems(ctx, items, GID, svc.repo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sheet.TSV()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (svc *ItemService) ExportBillOfMaterialsTSV(ctx context.Context, GID uuid.UUID) ([]byte, error) {
|
||||||
|
items, err := svc.repo.Items.GetAll(ctx, GID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return reporting.BillOfMaterialsTSV(items)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,71 +4,15 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/hasher"
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: this isn't a scalable solution, tokens should be stored in the database
|
func (svc *ItemService) AttachmentPath(ctx context.Context, attachmentId uuid.UUID) (*ent.Document, error) {
|
||||||
type attachmentTokens map[string]uuid.UUID
|
|
||||||
|
|
||||||
func (at attachmentTokens) Add(token string, id uuid.UUID) {
|
|
||||||
at[token] = id
|
|
||||||
|
|
||||||
log.Debug().Str("token", token).Str("uuid", id.String()).Msg("added token")
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
ch := time.After(1 * time.Minute)
|
|
||||||
<-ch
|
|
||||||
at.Delete(token)
|
|
||||||
log.Debug().Str("token", token).Msg("deleted token")
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (at attachmentTokens) Get(token string) (uuid.UUID, bool) {
|
|
||||||
id, ok := at[token]
|
|
||||||
return id, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (at attachmentTokens) Delete(token string) {
|
|
||||||
delete(at, token)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (svc *ItemService) AttachmentToken(ctx Context, itemId, attachmentId uuid.UUID) (string, error) {
|
|
||||||
_, err := svc.repo.Items.GetOneByGroup(ctx, ctx.GID, itemId)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
token := hasher.GenerateToken()
|
|
||||||
|
|
||||||
// Ensure that the file exists
|
|
||||||
attachment, err := svc.repo.Attachments.Get(ctx, attachmentId)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := os.Stat(attachment.Edges.Document.Path); os.IsNotExist(err) {
|
|
||||||
_ = svc.AttachmentDelete(ctx, ctx.GID, itemId, attachmentId)
|
|
||||||
return "", ErrNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
svc.at.Add(token.Raw, attachmentId)
|
|
||||||
|
|
||||||
return token.Raw, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (svc *ItemService) AttachmentPath(ctx context.Context, token string) (*ent.Document, error) {
|
|
||||||
attachmentId, ok := svc.at.Get(token)
|
|
||||||
if !ok {
|
|
||||||
return nil, ErrNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
attachment, err := svc.repo.Attachments.Get(ctx, attachmentId)
|
attachment, err := svc.repo.Attachments.Get(ctx, attachmentId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -58,5 +58,4 @@ func TestItemService_AddAttachment(t *testing.T) {
|
|||||||
bts, err := os.ReadFile(storedPath)
|
bts, err := os.ReadFile(storedPath)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, contents, string(bts))
|
assert.Equal(t, contents, string(bts))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,118 +0,0 @@
|
|||||||
package services
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ErrInvalidCsv = errors.New("invalid csv")
|
|
||||||
|
|
||||||
const NumOfCols = 21
|
|
||||||
|
|
||||||
func parseFloat(s string) float64 {
|
|
||||||
if s == "" {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
f, _ := strconv.ParseFloat(s, 64)
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseDate(s string) time.Time {
|
|
||||||
if s == "" {
|
|
||||||
return time.Time{}
|
|
||||||
}
|
|
||||||
|
|
||||||
p, _ := time.Parse("01/02/2006", s)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseBool(s string) bool {
|
|
||||||
switch strings.ToLower(s) {
|
|
||||||
case "true", "yes", "1":
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseInt(s string) int {
|
|
||||||
i, _ := strconv.Atoi(s)
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
type csvRow struct {
|
|
||||||
Item repo.ItemOut
|
|
||||||
Location string
|
|
||||||
LabelStr string
|
|
||||||
}
|
|
||||||
|
|
||||||
func newCsvRow(row []string) csvRow {
|
|
||||||
return csvRow{
|
|
||||||
Location: row[1],
|
|
||||||
LabelStr: row[2],
|
|
||||||
Item: repo.ItemOut{
|
|
||||||
ItemSummary: repo.ItemSummary{
|
|
||||||
ImportRef: row[0],
|
|
||||||
Quantity: parseInt(row[3]),
|
|
||||||
Name: row[4],
|
|
||||||
Description: row[5],
|
|
||||||
Insured: parseBool(row[6]),
|
|
||||||
},
|
|
||||||
SerialNumber: row[7],
|
|
||||||
ModelNumber: row[8],
|
|
||||||
Manufacturer: row[9],
|
|
||||||
Notes: row[10],
|
|
||||||
PurchaseFrom: row[11],
|
|
||||||
PurchasePrice: parseFloat(row[12]),
|
|
||||||
PurchaseTime: parseDate(row[13]),
|
|
||||||
LifetimeWarranty: parseBool(row[14]),
|
|
||||||
WarrantyExpires: parseDate(row[15]),
|
|
||||||
WarrantyDetails: row[16],
|
|
||||||
SoldTo: row[17],
|
|
||||||
SoldPrice: parseFloat(row[18]),
|
|
||||||
SoldTime: parseDate(row[19]),
|
|
||||||
SoldNotes: row[20],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c csvRow) getLabels() []string {
|
|
||||||
split := strings.Split(c.LabelStr, ";")
|
|
||||||
|
|
||||||
// Trim each
|
|
||||||
for i, s := range split {
|
|
||||||
split[i] = strings.TrimSpace(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove empty
|
|
||||||
for i, s := range split {
|
|
||||||
if s == "" {
|
|
||||||
split = append(split[:i], split[i+1:]...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return split
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c csvRow) validate() []error {
|
|
||||||
var errs []error
|
|
||||||
|
|
||||||
add := func(err error) {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
required := func(s string, name string) {
|
|
||||||
if s == "" {
|
|
||||||
add(errors.New(name + " is required"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
required(c.Location, "Location")
|
|
||||||
required(c.Item.Name, "Name")
|
|
||||||
|
|
||||||
return errs
|
|
||||||
}
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
package services
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/csv"
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
const CSV_DATA = `
|
|
||||||
Import Ref,Location,Labels,Quantity,Name,Description,Insured,Serial Number,Mode Number,Manufacturer,Notes,Purchase From,Purchased Price,Purchased Time,Lifetime Warranty,Warranty Expires,Warranty Details,Sold To,Sold Price,Sold Time,Sold Notes
|
|
||||||
A,Garage,IOT;Home Assistant; Z-Wave,1,Zooz Universal Relay ZEN17,Description 1,TRUE,,ZEN17,Zooz,,Amazon,39.95,10/13/2021,,10/13/2021,,,,10/13/2021,
|
|
||||||
B,Living Room,IOT;Home Assistant; Z-Wave,1,Zooz Motion Sensor,Description 2,FALSE,,ZSE18,Zooz,,Amazon,29.95,10/15/2021,,10/15/2021,,,,10/15/2021,
|
|
||||||
C,Office,IOT;Home Assistant; Z-Wave,1,Zooz 110v Power Switch,Description 3,TRUE,,ZEN15,Zooz,,Amazon,39.95,10/13/2021,,10/13/2021,,,,10/13/2021,
|
|
||||||
D,Downstairs,IOT;Home Assistant; Z-Wave,1,Ecolink Z-Wave PIR Motion Sensor,Description 4,FALSE,,PIRZWAVE2.5-ECO,Ecolink,,Amazon,35.58,10/21/2020,,10/21/2020,,,,10/21/2020,
|
|
||||||
E,Entry,IOT;Home Assistant; Z-Wave,1,Yale Security Touchscreen Deadbolt,Description 5,TRUE,,YRD226ZW2619,Yale,,Amazon,120.39,10/14/2020,,10/14/2020,,,,10/14/2020,
|
|
||||||
F,Kitchen,IOT;Home Assistant; Z-Wave,1,Smart Rocker Light Dimmer,Description 6,FALSE,,39351,Honeywell,,Amazon,65.98,09/30/2020,,09/30/2020,,,,09/30/2020,`
|
|
||||||
|
|
||||||
func loadcsv() [][]string {
|
|
||||||
reader := csv.NewReader(bytes.NewBuffer([]byte(CSV_DATA)))
|
|
||||||
|
|
||||||
records, err := reader.ReadAll()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return records
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_CorrectDateParsing(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
expected := []time.Time{
|
|
||||||
time.Date(2021, 10, 13, 0, 0, 0, 0, time.UTC),
|
|
||||||
time.Date(2021, 10, 15, 0, 0, 0, 0, time.UTC),
|
|
||||||
time.Date(2021, 10, 13, 0, 0, 0, 0, time.UTC),
|
|
||||||
time.Date(2020, 10, 21, 0, 0, 0, 0, time.UTC),
|
|
||||||
time.Date(2020, 10, 14, 0, 0, 0, 0, time.UTC),
|
|
||||||
time.Date(2020, 9, 30, 0, 0, 0, 0, time.UTC),
|
|
||||||
}
|
|
||||||
|
|
||||||
records := loadcsv()
|
|
||||||
|
|
||||||
for i, record := range records {
|
|
||||||
if i == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
entity := newCsvRow(record)
|
|
||||||
expected := expected[i-1]
|
|
||||||
|
|
||||||
assert.Equal(t, expected, entity.Item.PurchaseTime, fmt.Sprintf("Failed on row %d", i))
|
|
||||||
assert.Equal(t, expected, entity.Item.WarrantyExpires, fmt.Sprintf("Failed on row %d", i))
|
|
||||||
assert.Equal(t, expected, entity.Item.SoldTime, fmt.Sprintf("Failed on row %d", i))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_csvRow_getLabels(t *testing.T) {
|
|
||||||
type fields struct {
|
|
||||||
LabelStr string
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
fields fields
|
|
||||||
want []string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "basic test",
|
|
||||||
fields: fields{
|
|
||||||
LabelStr: "IOT;Home Assistant;Z-Wave",
|
|
||||||
},
|
|
||||||
want: []string{"IOT", "Home Assistant", "Z-Wave"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "no labels",
|
|
||||||
fields: fields{
|
|
||||||
LabelStr: "",
|
|
||||||
},
|
|
||||||
want: []string{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "single label",
|
|
||||||
fields: fields{
|
|
||||||
LabelStr: "IOT",
|
|
||||||
},
|
|
||||||
want: []string{"IOT"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "trailing semicolon",
|
|
||||||
fields: fields{
|
|
||||||
LabelStr: "IOT;",
|
|
||||||
},
|
|
||||||
want: []string{"IOT"},
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "whitespace",
|
|
||||||
fields: fields{
|
|
||||||
LabelStr: " IOT; Home Assistant; Z-Wave ",
|
|
||||||
},
|
|
||||||
want: []string{"IOT", "Home Assistant", "Z-Wave"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
c := csvRow{
|
|
||||||
LabelStr: tt.fields.LabelStr,
|
|
||||||
}
|
|
||||||
if got := c.getLabels(); !reflect.DeepEqual(got, tt.want) {
|
|
||||||
t.Errorf("csvRow.getLabels() = %v, want %v", got, tt.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
package services
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestItemService_CsvImport(t *testing.T) {
|
|
||||||
data := loadcsv()
|
|
||||||
svc := &ItemService{
|
|
||||||
repo: tRepos,
|
|
||||||
}
|
|
||||||
count, err := svc.CsvImport(context.Background(), tGroup.ID, data)
|
|
||||||
assert.Equal(t, 6, count)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// Check import refs are deduplicated
|
|
||||||
count, err = svc.CsvImport(context.Background(), tGroup.ID, data)
|
|
||||||
assert.Equal(t, 0, count)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
items, err := svc.repo.Items.GetAll(context.Background(), tGroup.ID)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
t.Cleanup(func() {
|
|
||||||
for _, item := range items {
|
|
||||||
err := svc.repo.Items.Delete(context.Background(), item.ID)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
assert.Equal(t, len(items), 6)
|
|
||||||
|
|
||||||
dataCsv := []csvRow{}
|
|
||||||
for _, item := range data {
|
|
||||||
dataCsv = append(dataCsv, newCsvRow(item))
|
|
||||||
}
|
|
||||||
|
|
||||||
allLocation, err := tRepos.Locations.GetAll(context.Background(), tGroup.ID, repo.LocationQuery{})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
locNames := []string{}
|
|
||||||
for _, loc := range allLocation {
|
|
||||||
locNames = append(locNames, loc.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
allLabels, err := tRepos.Labels.GetAll(context.Background(), tGroup.ID)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
labelNames := []string{}
|
|
||||||
for _, label := range allLabels {
|
|
||||||
labelNames = append(labelNames, label.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
ids := []uuid.UUID{}
|
|
||||||
t.Cleanup((func() {
|
|
||||||
for _, id := range ids {
|
|
||||||
err := svc.repo.Items.Delete(context.Background(), id)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
|
|
||||||
for _, item := range items {
|
|
||||||
assert.Contains(t, locNames, item.Location.Name)
|
|
||||||
for _, label := range item.Labels {
|
|
||||||
assert.Contains(t, labelNames, label.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, csvRow := range dataCsv {
|
|
||||||
if csvRow.Item.Name == item.Name {
|
|
||||||
assert.Equal(t, csvRow.Item.Description, item.Description)
|
|
||||||
assert.Equal(t, csvRow.Item.Quantity, item.Quantity)
|
|
||||||
assert.Equal(t, csvRow.Item.Insured, item.Insured)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/hasher"
|
"github.com/hay-kot/homebox/backend/pkgs/hasher"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
@@ -30,8 +31,9 @@ type (
|
|||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
UserAuthTokenDetail struct {
|
UserAuthTokenDetail struct {
|
||||||
Raw string `json:"raw"`
|
Raw string `json:"raw"`
|
||||||
ExpiresAt time.Time `json:"expiresAt"`
|
AttachmentToken string `json:"attachmentToken"`
|
||||||
|
ExpiresAt time.Time `json:"expiresAt"`
|
||||||
}
|
}
|
||||||
LoginForm struct {
|
LoginForm struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
@@ -49,21 +51,25 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
|
|||||||
Msg("Registering new user")
|
Msg("Registering new user")
|
||||||
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
group repo.Group
|
group repo.Group
|
||||||
token repo.GroupInvitation
|
token repo.GroupInvitation
|
||||||
isOwner = false
|
|
||||||
|
// creatingGroup is true if the user is creating a new group.
|
||||||
|
creatingGroup = false
|
||||||
)
|
)
|
||||||
|
|
||||||
switch data.GroupToken {
|
switch data.GroupToken {
|
||||||
case "":
|
case "":
|
||||||
isOwner = true
|
log.Debug().Msg("creating new group")
|
||||||
|
creatingGroup = true
|
||||||
group, err = svc.repos.Groups.GroupCreate(ctx, "Home")
|
group, err = svc.repos.Groups.GroupCreate(ctx, "Home")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg("Failed to create group")
|
log.Err(err).Msg("Failed to create group")
|
||||||
return repo.UserOut{}, err
|
return repo.UserOut{}, err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
log.Debug().Msg("joining existing group")
|
||||||
token, err = svc.repos.Groups.InvitationGet(ctx, hasher.HashToken(data.GroupToken))
|
token, err = svc.repos.Groups.InvitationGet(ctx, hasher.HashToken(data.GroupToken))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg("Failed to get invitation token")
|
log.Err(err).Msg("Failed to get invitation token")
|
||||||
@@ -79,7 +85,7 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
|
|||||||
Password: hashed,
|
Password: hashed,
|
||||||
IsSuperuser: false,
|
IsSuperuser: false,
|
||||||
GroupID: group.ID,
|
GroupID: group.ID,
|
||||||
IsOwner: isOwner,
|
IsOwner: creatingGroup,
|
||||||
}
|
}
|
||||||
|
|
||||||
usr, err := svc.repos.Users.Create(ctx, usrCreate)
|
usr, err := svc.repos.Users.Create(ctx, usrCreate)
|
||||||
@@ -87,21 +93,24 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
|
|||||||
return repo.UserOut{}, err
|
return repo.UserOut{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, label := range defaultLabels() {
|
// Create the default labels and locations for the group.
|
||||||
_, err := svc.repos.Labels.Create(ctx, group.ID, label)
|
if creatingGroup {
|
||||||
if err != nil {
|
for _, label := range defaultLabels() {
|
||||||
return repo.UserOut{}, err
|
_, err := svc.repos.Labels.Create(ctx, usr.GroupID, label)
|
||||||
|
if err != nil {
|
||||||
|
return repo.UserOut{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, location := range defaultLocations() {
|
||||||
|
_, err := svc.repos.Locations.Create(ctx, usr.GroupID, location)
|
||||||
|
if err != nil {
|
||||||
|
return repo.UserOut{}, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, location := range defaultLocations() {
|
// Decrement the invitation token if it was used.
|
||||||
_, err := svc.repos.Locations.Create(ctx, group.ID, location)
|
|
||||||
if err != nil {
|
|
||||||
return repo.UserOut{}, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decrement the invitation token if it was used
|
|
||||||
if token.ID != uuid.Nil {
|
if token.ID != uuid.Nil {
|
||||||
err = svc.repos.Groups.InvitationUpdate(ctx, token.ID, token.Uses-1)
|
err = svc.repos.Groups.InvitationUpdate(ctx, token.ID, token.Uses-1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -131,21 +140,46 @@ func (svc *UserService) UpdateSelf(ctx context.Context, ID uuid.UUID, data repo.
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
// User Authentication
|
// User Authentication
|
||||||
|
|
||||||
func (svc *UserService) createToken(ctx context.Context, userId uuid.UUID) (UserAuthTokenDetail, error) {
|
func (svc *UserService) createSessionToken(ctx context.Context, userId uuid.UUID, extendedSession bool) (UserAuthTokenDetail, error) {
|
||||||
newToken := hasher.GenerateToken()
|
attachmentToken := hasher.GenerateToken()
|
||||||
|
|
||||||
created, err := svc.repos.AuthTokens.CreateToken(ctx, repo.UserAuthTokenCreate{
|
expiresAt := time.Now().Add(oneWeek)
|
||||||
|
if extendedSession {
|
||||||
|
expiresAt = time.Now().Add(oneWeek * 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
attachmentData := repo.UserAuthTokenCreate{
|
||||||
UserID: userId,
|
UserID: userId,
|
||||||
TokenHash: newToken.Hash,
|
TokenHash: attachmentToken.Hash,
|
||||||
ExpiresAt: time.Now().Add(oneWeek),
|
ExpiresAt: expiresAt,
|
||||||
})
|
}
|
||||||
|
|
||||||
return UserAuthTokenDetail{Raw: newToken.Raw, ExpiresAt: created.ExpiresAt}, err
|
_, err := svc.repos.AuthTokens.CreateToken(ctx, attachmentData, authroles.RoleAttachments)
|
||||||
|
if err != nil {
|
||||||
|
return UserAuthTokenDetail{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
userToken := hasher.GenerateToken()
|
||||||
|
data := repo.UserAuthTokenCreate{
|
||||||
|
UserID: userId,
|
||||||
|
TokenHash: userToken.Hash,
|
||||||
|
ExpiresAt: expiresAt,
|
||||||
|
}
|
||||||
|
|
||||||
|
created, err := svc.repos.AuthTokens.CreateToken(ctx, data, authroles.RoleUser)
|
||||||
|
if err != nil {
|
||||||
|
return UserAuthTokenDetail{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return UserAuthTokenDetail{
|
||||||
|
Raw: userToken.Raw,
|
||||||
|
ExpiresAt: created.ExpiresAt,
|
||||||
|
AttachmentToken: attachmentToken.Raw,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *UserService) Login(ctx context.Context, username, password string) (UserAuthTokenDetail, error) {
|
func (svc *UserService) Login(ctx context.Context, username, password string, extendedSession bool) (UserAuthTokenDetail, error) {
|
||||||
usr, err := svc.repos.Users.GetOneEmail(ctx, username)
|
usr, err := svc.repos.Users.GetOneEmail(ctx, username)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// SECURITY: Perform hash to ensure response times are the same
|
// SECURITY: Perform hash to ensure response times are the same
|
||||||
hasher.CheckPasswordHash("not-a-real-password", "not-a-real-password")
|
hasher.CheckPasswordHash("not-a-real-password", "not-a-real-password")
|
||||||
@@ -156,7 +190,7 @@ func (svc *UserService) Login(ctx context.Context, username, password string) (U
|
|||||||
return UserAuthTokenDetail{}, ErrorInvalidLogin
|
return UserAuthTokenDetail{}, ErrorInvalidLogin
|
||||||
}
|
}
|
||||||
|
|
||||||
return svc.createToken(ctx, usr.ID)
|
return svc.createSessionToken(ctx, usr.ID, extendedSession)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *UserService) Logout(ctx context.Context, token string) error {
|
func (svc *UserService) Logout(ctx context.Context, token string) error {
|
||||||
@@ -169,14 +203,11 @@ func (svc *UserService) RenewToken(ctx context.Context, token string) (UserAuthT
|
|||||||
hash := hasher.HashToken(token)
|
hash := hasher.HashToken(token)
|
||||||
|
|
||||||
dbToken, err := svc.repos.AuthTokens.GetUserFromToken(ctx, hash)
|
dbToken, err := svc.repos.AuthTokens.GetUserFromToken(ctx, hash)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return UserAuthTokenDetail{}, ErrorInvalidToken
|
return UserAuthTokenDetail{}, ErrorInvalidToken
|
||||||
}
|
}
|
||||||
|
|
||||||
newToken, _ := svc.createToken(ctx, dbToken.ID)
|
return svc.createSessionToken(ctx, dbToken.ID, false)
|
||||||
|
|
||||||
return newToken, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteSelf deletes the user that is currently logged based of the provided UUID
|
// DeleteSelf deletes the user that is currently logged based of the provided UUID
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"entgo.io/ent"
|
||||||
"entgo.io/ent/dialect/sql"
|
"entgo.io/ent/dialect/sql"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
|
||||||
@@ -30,6 +31,7 @@ type Attachment struct {
|
|||||||
Edges AttachmentEdges `json:"edges"`
|
Edges AttachmentEdges `json:"edges"`
|
||||||
document_attachments *uuid.UUID
|
document_attachments *uuid.UUID
|
||||||
item_attachments *uuid.UUID
|
item_attachments *uuid.UUID
|
||||||
|
selectValues sql.SelectValues
|
||||||
}
|
}
|
||||||
|
|
||||||
// AttachmentEdges holds the relations/edges for other nodes in the graph.
|
// AttachmentEdges holds the relations/edges for other nodes in the graph.
|
||||||
@@ -85,7 +87,7 @@ func (*Attachment) scanValues(columns []string) ([]any, error) {
|
|||||||
case attachment.ForeignKeys[1]: // item_attachments
|
case attachment.ForeignKeys[1]: // item_attachments
|
||||||
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
|
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unexpected column %q for type Attachment", columns[i])
|
values[i] = new(sql.UnknownType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return values, nil
|
return values, nil
|
||||||
@@ -137,26 +139,34 @@ func (a *Attachment) assignValues(columns []string, values []any) error {
|
|||||||
a.item_attachments = new(uuid.UUID)
|
a.item_attachments = new(uuid.UUID)
|
||||||
*a.item_attachments = *value.S.(*uuid.UUID)
|
*a.item_attachments = *value.S.(*uuid.UUID)
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
a.selectValues.Set(columns[i], values[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Value returns the ent.Value that was dynamically selected and assigned to the Attachment.
|
||||||
|
// This includes values selected through modifiers, order, etc.
|
||||||
|
func (a *Attachment) Value(name string) (ent.Value, error) {
|
||||||
|
return a.selectValues.Get(name)
|
||||||
|
}
|
||||||
|
|
||||||
// QueryItem queries the "item" edge of the Attachment entity.
|
// QueryItem queries the "item" edge of the Attachment entity.
|
||||||
func (a *Attachment) QueryItem() *ItemQuery {
|
func (a *Attachment) QueryItem() *ItemQuery {
|
||||||
return (&AttachmentClient{config: a.config}).QueryItem(a)
|
return NewAttachmentClient(a.config).QueryItem(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryDocument queries the "document" edge of the Attachment entity.
|
// QueryDocument queries the "document" edge of the Attachment entity.
|
||||||
func (a *Attachment) QueryDocument() *DocumentQuery {
|
func (a *Attachment) QueryDocument() *DocumentQuery {
|
||||||
return (&AttachmentClient{config: a.config}).QueryDocument(a)
|
return NewAttachmentClient(a.config).QueryDocument(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update returns a builder for updating this Attachment.
|
// Update returns a builder for updating this Attachment.
|
||||||
// Note that you need to call Attachment.Unwrap() before calling this method if 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.
|
// was returned from a transaction, and the transaction was committed or rolled back.
|
||||||
func (a *Attachment) Update() *AttachmentUpdateOne {
|
func (a *Attachment) Update() *AttachmentUpdateOne {
|
||||||
return (&AttachmentClient{config: a.config}).UpdateOne(a)
|
return NewAttachmentClient(a.config).UpdateOne(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unwrap unwraps the Attachment entity that was returned from a transaction after it was closed,
|
// Unwrap unwraps the Attachment entity that was returned from a transaction after it was closed,
|
||||||
@@ -189,9 +199,3 @@ func (a *Attachment) String() string {
|
|||||||
|
|
||||||
// Attachments is a parsable slice of Attachment.
|
// Attachments is a parsable slice of Attachment.
|
||||||
type Attachments []*Attachment
|
type Attachments []*Attachment
|
||||||
|
|
||||||
func (a Attachments) config(cfg config) {
|
|
||||||
for _i := range a {
|
|
||||||
a[_i].config = cfg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"entgo.io/ent/dialect/sql"
|
||||||
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -111,3 +113,54 @@ func TypeValidator(_type Type) error {
|
|||||||
return fmt.Errorf("attachment: invalid enum value for type field: %q", _type)
|
return fmt.Errorf("attachment: invalid enum value for type field: %q", _type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OrderOption defines the ordering options for the Attachment queries.
|
||||||
|
type OrderOption func(*sql.Selector)
|
||||||
|
|
||||||
|
// ByID orders the results by the id field.
|
||||||
|
func ByID(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldID, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByCreatedAt orders the results by the created_at field.
|
||||||
|
func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByUpdatedAt orders the results by the updated_at field.
|
||||||
|
func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByType orders the results by the type field.
|
||||||
|
func ByType(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldType, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByItemField orders the results by item field.
|
||||||
|
func ByItemField(field string, opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return func(s *sql.Selector) {
|
||||||
|
sqlgraph.OrderByNeighborTerms(s, newItemStep(), sql.OrderByField(field, opts...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByDocumentField orders the results by document field.
|
||||||
|
func ByDocumentField(field string, opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return func(s *sql.Selector) {
|
||||||
|
sqlgraph.OrderByNeighborTerms(s, newDocumentStep(), sql.OrderByField(field, opts...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func newItemStep() *sqlgraph.Step {
|
||||||
|
return sqlgraph.NewStep(
|
||||||
|
sqlgraph.From(Table, FieldID),
|
||||||
|
sqlgraph.To(ItemInverseTable, FieldID),
|
||||||
|
sqlgraph.Edge(sqlgraph.M2O, true, ItemTable, ItemColumn),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
func newDocumentStep() *sqlgraph.Step {
|
||||||
|
return sqlgraph.NewStep(
|
||||||
|
sqlgraph.From(Table, FieldID),
|
||||||
|
sqlgraph.To(DocumentInverseTable, FieldID),
|
||||||
|
sqlgraph.Edge(sqlgraph.M2O, true, DocumentTable, DocumentColumn),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,251 +13,157 @@ import (
|
|||||||
|
|
||||||
// ID filters vertices based on their ID field.
|
// ID filters vertices based on their ID field.
|
||||||
func ID(id uuid.UUID) predicate.Attachment {
|
func ID(id uuid.UUID) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldEQ(FieldID, id))
|
||||||
s.Where(sql.EQ(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDEQ applies the EQ predicate on the ID field.
|
// IDEQ applies the EQ predicate on the ID field.
|
||||||
func IDEQ(id uuid.UUID) predicate.Attachment {
|
func IDEQ(id uuid.UUID) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldEQ(FieldID, id))
|
||||||
s.Where(sql.EQ(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDNEQ applies the NEQ predicate on the ID field.
|
// IDNEQ applies the NEQ predicate on the ID field.
|
||||||
func IDNEQ(id uuid.UUID) predicate.Attachment {
|
func IDNEQ(id uuid.UUID) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldNEQ(FieldID, id))
|
||||||
s.Where(sql.NEQ(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDIn applies the In predicate on the ID field.
|
// IDIn applies the In predicate on the ID field.
|
||||||
func IDIn(ids ...uuid.UUID) predicate.Attachment {
|
func IDIn(ids ...uuid.UUID) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldIn(FieldID, ids...))
|
||||||
v := make([]any, len(ids))
|
|
||||||
for i := range v {
|
|
||||||
v[i] = ids[i]
|
|
||||||
}
|
|
||||||
s.Where(sql.In(s.C(FieldID), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDNotIn applies the NotIn predicate on the ID field.
|
// IDNotIn applies the NotIn predicate on the ID field.
|
||||||
func IDNotIn(ids ...uuid.UUID) predicate.Attachment {
|
func IDNotIn(ids ...uuid.UUID) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldNotIn(FieldID, ids...))
|
||||||
v := make([]any, len(ids))
|
|
||||||
for i := range v {
|
|
||||||
v[i] = ids[i]
|
|
||||||
}
|
|
||||||
s.Where(sql.NotIn(s.C(FieldID), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDGT applies the GT predicate on the ID field.
|
// IDGT applies the GT predicate on the ID field.
|
||||||
func IDGT(id uuid.UUID) predicate.Attachment {
|
func IDGT(id uuid.UUID) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldGT(FieldID, id))
|
||||||
s.Where(sql.GT(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDGTE applies the GTE predicate on the ID field.
|
// IDGTE applies the GTE predicate on the ID field.
|
||||||
func IDGTE(id uuid.UUID) predicate.Attachment {
|
func IDGTE(id uuid.UUID) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldGTE(FieldID, id))
|
||||||
s.Where(sql.GTE(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDLT applies the LT predicate on the ID field.
|
// IDLT applies the LT predicate on the ID field.
|
||||||
func IDLT(id uuid.UUID) predicate.Attachment {
|
func IDLT(id uuid.UUID) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldLT(FieldID, id))
|
||||||
s.Where(sql.LT(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDLTE applies the LTE predicate on the ID field.
|
// IDLTE applies the LTE predicate on the ID field.
|
||||||
func IDLTE(id uuid.UUID) predicate.Attachment {
|
func IDLTE(id uuid.UUID) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldLTE(FieldID, id))
|
||||||
s.Where(sql.LTE(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
|
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
|
||||||
func CreatedAt(v time.Time) predicate.Attachment {
|
func CreatedAt(v time.Time) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldEQ(FieldCreatedAt, v))
|
||||||
s.Where(sql.EQ(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ.
|
// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ.
|
||||||
func UpdatedAt(v time.Time) predicate.Attachment {
|
func UpdatedAt(v time.Time) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldEQ(FieldUpdatedAt, v))
|
||||||
s.Where(sql.EQ(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
||||||
func CreatedAtEQ(v time.Time) predicate.Attachment {
|
func CreatedAtEQ(v time.Time) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldEQ(FieldCreatedAt, v))
|
||||||
s.Where(sql.EQ(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
|
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
|
||||||
func CreatedAtNEQ(v time.Time) predicate.Attachment {
|
func CreatedAtNEQ(v time.Time) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldNEQ(FieldCreatedAt, v))
|
||||||
s.Where(sql.NEQ(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtIn applies the In predicate on the "created_at" field.
|
// CreatedAtIn applies the In predicate on the "created_at" field.
|
||||||
func CreatedAtIn(vs ...time.Time) predicate.Attachment {
|
func CreatedAtIn(vs ...time.Time) predicate.Attachment {
|
||||||
v := make([]any, len(vs))
|
return predicate.Attachment(sql.FieldIn(FieldCreatedAt, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.In(s.C(FieldCreatedAt), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
|
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
|
||||||
func CreatedAtNotIn(vs ...time.Time) predicate.Attachment {
|
func CreatedAtNotIn(vs ...time.Time) predicate.Attachment {
|
||||||
v := make([]any, len(vs))
|
return predicate.Attachment(sql.FieldNotIn(FieldCreatedAt, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.NotIn(s.C(FieldCreatedAt), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtGT applies the GT predicate on the "created_at" field.
|
// CreatedAtGT applies the GT predicate on the "created_at" field.
|
||||||
func CreatedAtGT(v time.Time) predicate.Attachment {
|
func CreatedAtGT(v time.Time) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldGT(FieldCreatedAt, v))
|
||||||
s.Where(sql.GT(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
|
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
|
||||||
func CreatedAtGTE(v time.Time) predicate.Attachment {
|
func CreatedAtGTE(v time.Time) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldGTE(FieldCreatedAt, v))
|
||||||
s.Where(sql.GTE(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtLT applies the LT predicate on the "created_at" field.
|
// CreatedAtLT applies the LT predicate on the "created_at" field.
|
||||||
func CreatedAtLT(v time.Time) predicate.Attachment {
|
func CreatedAtLT(v time.Time) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldLT(FieldCreatedAt, v))
|
||||||
s.Where(sql.LT(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
|
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
|
||||||
func CreatedAtLTE(v time.Time) predicate.Attachment {
|
func CreatedAtLTE(v time.Time) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldLTE(FieldCreatedAt, v))
|
||||||
s.Where(sql.LTE(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
|
// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
|
||||||
func UpdatedAtEQ(v time.Time) predicate.Attachment {
|
func UpdatedAtEQ(v time.Time) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldEQ(FieldUpdatedAt, v))
|
||||||
s.Where(sql.EQ(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
|
// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
|
||||||
func UpdatedAtNEQ(v time.Time) predicate.Attachment {
|
func UpdatedAtNEQ(v time.Time) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldNEQ(FieldUpdatedAt, v))
|
||||||
s.Where(sql.NEQ(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtIn applies the In predicate on the "updated_at" field.
|
// UpdatedAtIn applies the In predicate on the "updated_at" field.
|
||||||
func UpdatedAtIn(vs ...time.Time) predicate.Attachment {
|
func UpdatedAtIn(vs ...time.Time) predicate.Attachment {
|
||||||
v := make([]any, len(vs))
|
return predicate.Attachment(sql.FieldIn(FieldUpdatedAt, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.In(s.C(FieldUpdatedAt), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
|
// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
|
||||||
func UpdatedAtNotIn(vs ...time.Time) predicate.Attachment {
|
func UpdatedAtNotIn(vs ...time.Time) predicate.Attachment {
|
||||||
v := make([]any, len(vs))
|
return predicate.Attachment(sql.FieldNotIn(FieldUpdatedAt, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.NotIn(s.C(FieldUpdatedAt), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtGT applies the GT predicate on the "updated_at" field.
|
// UpdatedAtGT applies the GT predicate on the "updated_at" field.
|
||||||
func UpdatedAtGT(v time.Time) predicate.Attachment {
|
func UpdatedAtGT(v time.Time) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldGT(FieldUpdatedAt, v))
|
||||||
s.Where(sql.GT(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
|
// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
|
||||||
func UpdatedAtGTE(v time.Time) predicate.Attachment {
|
func UpdatedAtGTE(v time.Time) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldGTE(FieldUpdatedAt, v))
|
||||||
s.Where(sql.GTE(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtLT applies the LT predicate on the "updated_at" field.
|
// UpdatedAtLT applies the LT predicate on the "updated_at" field.
|
||||||
func UpdatedAtLT(v time.Time) predicate.Attachment {
|
func UpdatedAtLT(v time.Time) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldLT(FieldUpdatedAt, v))
|
||||||
s.Where(sql.LT(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
|
// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
|
||||||
func UpdatedAtLTE(v time.Time) predicate.Attachment {
|
func UpdatedAtLTE(v time.Time) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldLTE(FieldUpdatedAt, v))
|
||||||
s.Where(sql.LTE(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TypeEQ applies the EQ predicate on the "type" field.
|
// TypeEQ applies the EQ predicate on the "type" field.
|
||||||
func TypeEQ(v Type) predicate.Attachment {
|
func TypeEQ(v Type) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldEQ(FieldType, v))
|
||||||
s.Where(sql.EQ(s.C(FieldType), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TypeNEQ applies the NEQ predicate on the "type" field.
|
// TypeNEQ applies the NEQ predicate on the "type" field.
|
||||||
func TypeNEQ(v Type) predicate.Attachment {
|
func TypeNEQ(v Type) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(sql.FieldNEQ(FieldType, v))
|
||||||
s.Where(sql.NEQ(s.C(FieldType), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TypeIn applies the In predicate on the "type" field.
|
// TypeIn applies the In predicate on the "type" field.
|
||||||
func TypeIn(vs ...Type) predicate.Attachment {
|
func TypeIn(vs ...Type) predicate.Attachment {
|
||||||
v := make([]any, len(vs))
|
return predicate.Attachment(sql.FieldIn(FieldType, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.In(s.C(FieldType), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TypeNotIn applies the NotIn predicate on the "type" field.
|
// TypeNotIn applies the NotIn predicate on the "type" field.
|
||||||
func TypeNotIn(vs ...Type) predicate.Attachment {
|
func TypeNotIn(vs ...Type) predicate.Attachment {
|
||||||
v := make([]any, len(vs))
|
return predicate.Attachment(sql.FieldNotIn(FieldType, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.NotIn(s.C(FieldType), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasItem applies the HasEdge predicate on the "item" edge.
|
// HasItem applies the HasEdge predicate on the "item" edge.
|
||||||
@@ -265,7 +171,6 @@ func HasItem() predicate.Attachment {
|
|||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(func(s *sql.Selector) {
|
||||||
step := sqlgraph.NewStep(
|
step := sqlgraph.NewStep(
|
||||||
sqlgraph.From(Table, FieldID),
|
sqlgraph.From(Table, FieldID),
|
||||||
sqlgraph.To(ItemTable, FieldID),
|
|
||||||
sqlgraph.Edge(sqlgraph.M2O, true, ItemTable, ItemColumn),
|
sqlgraph.Edge(sqlgraph.M2O, true, ItemTable, ItemColumn),
|
||||||
)
|
)
|
||||||
sqlgraph.HasNeighbors(s, step)
|
sqlgraph.HasNeighbors(s, step)
|
||||||
@@ -275,11 +180,7 @@ func HasItem() predicate.Attachment {
|
|||||||
// HasItemWith applies the HasEdge predicate on the "item" edge with a given conditions (other predicates).
|
// HasItemWith applies the HasEdge predicate on the "item" edge with a given conditions (other predicates).
|
||||||
func HasItemWith(preds ...predicate.Item) predicate.Attachment {
|
func HasItemWith(preds ...predicate.Item) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(func(s *sql.Selector) {
|
||||||
step := sqlgraph.NewStep(
|
step := newItemStep()
|
||||||
sqlgraph.From(Table, FieldID),
|
|
||||||
sqlgraph.To(ItemInverseTable, FieldID),
|
|
||||||
sqlgraph.Edge(sqlgraph.M2O, true, ItemTable, ItemColumn),
|
|
||||||
)
|
|
||||||
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
||||||
for _, p := range preds {
|
for _, p := range preds {
|
||||||
p(s)
|
p(s)
|
||||||
@@ -293,7 +194,6 @@ func HasDocument() predicate.Attachment {
|
|||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(func(s *sql.Selector) {
|
||||||
step := sqlgraph.NewStep(
|
step := sqlgraph.NewStep(
|
||||||
sqlgraph.From(Table, FieldID),
|
sqlgraph.From(Table, FieldID),
|
||||||
sqlgraph.To(DocumentTable, FieldID),
|
|
||||||
sqlgraph.Edge(sqlgraph.M2O, true, DocumentTable, DocumentColumn),
|
sqlgraph.Edge(sqlgraph.M2O, true, DocumentTable, DocumentColumn),
|
||||||
)
|
)
|
||||||
sqlgraph.HasNeighbors(s, step)
|
sqlgraph.HasNeighbors(s, step)
|
||||||
@@ -303,11 +203,7 @@ func HasDocument() predicate.Attachment {
|
|||||||
// HasDocumentWith applies the HasEdge predicate on the "document" edge with a given conditions (other predicates).
|
// HasDocumentWith applies the HasEdge predicate on the "document" edge with a given conditions (other predicates).
|
||||||
func HasDocumentWith(preds ...predicate.Document) predicate.Attachment {
|
func HasDocumentWith(preds ...predicate.Document) predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(func(s *sql.Selector) {
|
||||||
step := sqlgraph.NewStep(
|
step := newDocumentStep()
|
||||||
sqlgraph.From(Table, FieldID),
|
|
||||||
sqlgraph.To(DocumentInverseTable, FieldID),
|
|
||||||
sqlgraph.Edge(sqlgraph.M2O, true, DocumentTable, DocumentColumn),
|
|
||||||
)
|
|
||||||
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
||||||
for _, p := range preds {
|
for _, p := range preds {
|
||||||
p(s)
|
p(s)
|
||||||
|
|||||||
@@ -108,50 +108,8 @@ func (ac *AttachmentCreate) Mutation() *AttachmentMutation {
|
|||||||
|
|
||||||
// Save creates the Attachment in the database.
|
// Save creates the Attachment in the database.
|
||||||
func (ac *AttachmentCreate) Save(ctx context.Context) (*Attachment, error) {
|
func (ac *AttachmentCreate) Save(ctx context.Context) (*Attachment, error) {
|
||||||
var (
|
|
||||||
err error
|
|
||||||
node *Attachment
|
|
||||||
)
|
|
||||||
ac.defaults()
|
ac.defaults()
|
||||||
if len(ac.hooks) == 0 {
|
return withHooks(ctx, ac.sqlSave, ac.mutation, ac.hooks)
|
||||||
if err = ac.check(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
node, err = ac.sqlSave(ctx)
|
|
||||||
} else {
|
|
||||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
|
||||||
mutation, ok := m.(*AttachmentMutation)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
|
||||||
}
|
|
||||||
if err = ac.check(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ac.mutation = mutation
|
|
||||||
if node, err = ac.sqlSave(ctx); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mutation.id = &node.ID
|
|
||||||
mutation.done = true
|
|
||||||
return node, err
|
|
||||||
})
|
|
||||||
for i := len(ac.hooks) - 1; i >= 0; i-- {
|
|
||||||
if ac.hooks[i] == nil {
|
|
||||||
return nil, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
|
||||||
}
|
|
||||||
mut = ac.hooks[i](mut)
|
|
||||||
}
|
|
||||||
v, err := mut.Mutate(ctx, ac.mutation)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
nv, ok := v.(*Attachment)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected node type %T returned from AttachmentMutation", v)
|
|
||||||
}
|
|
||||||
node = nv
|
|
||||||
}
|
|
||||||
return node, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveX calls Save and panics if Save returns an error.
|
// SaveX calls Save and panics if Save returns an error.
|
||||||
@@ -222,6 +180,9 @@ func (ac *AttachmentCreate) check() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ac *AttachmentCreate) sqlSave(ctx context.Context) (*Attachment, error) {
|
func (ac *AttachmentCreate) sqlSave(ctx context.Context) (*Attachment, error) {
|
||||||
|
if err := ac.check(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
_node, _spec := ac.createSpec()
|
_node, _spec := ac.createSpec()
|
||||||
if err := sqlgraph.CreateNode(ctx, ac.driver, _spec); err != nil {
|
if err := sqlgraph.CreateNode(ctx, ac.driver, _spec); err != nil {
|
||||||
if sqlgraph.IsConstraintError(err) {
|
if sqlgraph.IsConstraintError(err) {
|
||||||
@@ -236,46 +197,30 @@ func (ac *AttachmentCreate) sqlSave(ctx context.Context) (*Attachment, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ac.mutation.id = &_node.ID
|
||||||
|
ac.mutation.done = true
|
||||||
return _node, nil
|
return _node, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ac *AttachmentCreate) createSpec() (*Attachment, *sqlgraph.CreateSpec) {
|
func (ac *AttachmentCreate) createSpec() (*Attachment, *sqlgraph.CreateSpec) {
|
||||||
var (
|
var (
|
||||||
_node = &Attachment{config: ac.config}
|
_node = &Attachment{config: ac.config}
|
||||||
_spec = &sqlgraph.CreateSpec{
|
_spec = sqlgraph.NewCreateSpec(attachment.Table, sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID))
|
||||||
Table: attachment.Table,
|
|
||||||
ID: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: attachment.FieldID,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
if id, ok := ac.mutation.ID(); ok {
|
if id, ok := ac.mutation.ID(); ok {
|
||||||
_node.ID = id
|
_node.ID = id
|
||||||
_spec.ID.Value = &id
|
_spec.ID.Value = &id
|
||||||
}
|
}
|
||||||
if value, ok := ac.mutation.CreatedAt(); ok {
|
if value, ok := ac.mutation.CreatedAt(); ok {
|
||||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
_spec.SetField(attachment.FieldCreatedAt, field.TypeTime, value)
|
||||||
Type: field.TypeTime,
|
|
||||||
Value: value,
|
|
||||||
Column: attachment.FieldCreatedAt,
|
|
||||||
})
|
|
||||||
_node.CreatedAt = value
|
_node.CreatedAt = value
|
||||||
}
|
}
|
||||||
if value, ok := ac.mutation.UpdatedAt(); ok {
|
if value, ok := ac.mutation.UpdatedAt(); ok {
|
||||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
_spec.SetField(attachment.FieldUpdatedAt, field.TypeTime, value)
|
||||||
Type: field.TypeTime,
|
|
||||||
Value: value,
|
|
||||||
Column: attachment.FieldUpdatedAt,
|
|
||||||
})
|
|
||||||
_node.UpdatedAt = value
|
_node.UpdatedAt = value
|
||||||
}
|
}
|
||||||
if value, ok := ac.mutation.GetType(); ok {
|
if value, ok := ac.mutation.GetType(); ok {
|
||||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
_spec.SetField(attachment.FieldType, field.TypeEnum, value)
|
||||||
Type: field.TypeEnum,
|
|
||||||
Value: value,
|
|
||||||
Column: attachment.FieldType,
|
|
||||||
})
|
|
||||||
_node.Type = value
|
_node.Type = value
|
||||||
}
|
}
|
||||||
if nodes := ac.mutation.ItemIDs(); len(nodes) > 0 {
|
if nodes := ac.mutation.ItemIDs(); len(nodes) > 0 {
|
||||||
@@ -286,10 +231,7 @@ func (ac *AttachmentCreate) createSpec() (*Attachment, *sqlgraph.CreateSpec) {
|
|||||||
Columns: []string{attachment.ItemColumn},
|
Columns: []string{attachment.ItemColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(item.FieldID, field.TypeUUID),
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: item.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
@@ -306,10 +248,7 @@ func (ac *AttachmentCreate) createSpec() (*Attachment, *sqlgraph.CreateSpec) {
|
|||||||
Columns: []string{attachment.DocumentColumn},
|
Columns: []string{attachment.DocumentColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID),
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: document.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
@@ -345,8 +284,8 @@ func (acb *AttachmentCreateBulk) Save(ctx context.Context) ([]*Attachment, error
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
builder.mutation = mutation
|
builder.mutation = mutation
|
||||||
nodes[i], specs[i] = builder.createSpec()
|
|
||||||
var err error
|
var err error
|
||||||
|
nodes[i], specs[i] = builder.createSpec()
|
||||||
if i < len(mutators)-1 {
|
if i < len(mutators)-1 {
|
||||||
_, err = mutators[i+1].Mutate(root, acb.builders[i+1].mutation)
|
_, err = mutators[i+1].Mutate(root, acb.builders[i+1].mutation)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ package ent
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"entgo.io/ent/dialect/sql"
|
"entgo.io/ent/dialect/sql"
|
||||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
@@ -28,34 +27,7 @@ func (ad *AttachmentDelete) Where(ps ...predicate.Attachment) *AttachmentDelete
|
|||||||
|
|
||||||
// Exec executes the deletion query and returns how many vertices were deleted.
|
// Exec executes the deletion query and returns how many vertices were deleted.
|
||||||
func (ad *AttachmentDelete) Exec(ctx context.Context) (int, error) {
|
func (ad *AttachmentDelete) Exec(ctx context.Context) (int, error) {
|
||||||
var (
|
return withHooks(ctx, ad.sqlExec, ad.mutation, ad.hooks)
|
||||||
err error
|
|
||||||
affected int
|
|
||||||
)
|
|
||||||
if len(ad.hooks) == 0 {
|
|
||||||
affected, err = ad.sqlExec(ctx)
|
|
||||||
} else {
|
|
||||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
|
||||||
mutation, ok := m.(*AttachmentMutation)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
|
||||||
}
|
|
||||||
ad.mutation = mutation
|
|
||||||
affected, err = ad.sqlExec(ctx)
|
|
||||||
mutation.done = true
|
|
||||||
return affected, err
|
|
||||||
})
|
|
||||||
for i := len(ad.hooks) - 1; i >= 0; i-- {
|
|
||||||
if ad.hooks[i] == nil {
|
|
||||||
return 0, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
|
||||||
}
|
|
||||||
mut = ad.hooks[i](mut)
|
|
||||||
}
|
|
||||||
if _, err := mut.Mutate(ctx, ad.mutation); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return affected, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecX is like Exec, but panics if an error occurs.
|
// ExecX is like Exec, but panics if an error occurs.
|
||||||
@@ -68,15 +40,7 @@ func (ad *AttachmentDelete) ExecX(ctx context.Context) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ad *AttachmentDelete) sqlExec(ctx context.Context) (int, error) {
|
func (ad *AttachmentDelete) sqlExec(ctx context.Context) (int, error) {
|
||||||
_spec := &sqlgraph.DeleteSpec{
|
_spec := sqlgraph.NewDeleteSpec(attachment.Table, sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID))
|
||||||
Node: &sqlgraph.NodeSpec{
|
|
||||||
Table: attachment.Table,
|
|
||||||
ID: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: attachment.FieldID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if ps := ad.mutation.predicates; len(ps) > 0 {
|
if ps := ad.mutation.predicates; len(ps) > 0 {
|
||||||
_spec.Predicate = func(selector *sql.Selector) {
|
_spec.Predicate = func(selector *sql.Selector) {
|
||||||
for i := range ps {
|
for i := range ps {
|
||||||
@@ -88,6 +52,7 @@ func (ad *AttachmentDelete) sqlExec(ctx context.Context) (int, error) {
|
|||||||
if err != nil && sqlgraph.IsConstraintError(err) {
|
if err != nil && sqlgraph.IsConstraintError(err) {
|
||||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||||
}
|
}
|
||||||
|
ad.mutation.done = true
|
||||||
return affected, err
|
return affected, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,6 +61,12 @@ type AttachmentDeleteOne struct {
|
|||||||
ad *AttachmentDelete
|
ad *AttachmentDelete
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Where appends a list predicates to the AttachmentDelete builder.
|
||||||
|
func (ado *AttachmentDeleteOne) Where(ps ...predicate.Attachment) *AttachmentDeleteOne {
|
||||||
|
ado.ad.mutation.Where(ps...)
|
||||||
|
return ado
|
||||||
|
}
|
||||||
|
|
||||||
// Exec executes the deletion query.
|
// Exec executes the deletion query.
|
||||||
func (ado *AttachmentDeleteOne) Exec(ctx context.Context) error {
|
func (ado *AttachmentDeleteOne) Exec(ctx context.Context) error {
|
||||||
n, err := ado.ad.Exec(ctx)
|
n, err := ado.ad.Exec(ctx)
|
||||||
@@ -111,5 +82,7 @@ func (ado *AttachmentDeleteOne) Exec(ctx context.Context) error {
|
|||||||
|
|
||||||
// ExecX is like Exec, but panics if an error occurs.
|
// ExecX is like Exec, but panics if an error occurs.
|
||||||
func (ado *AttachmentDeleteOne) ExecX(ctx context.Context) {
|
func (ado *AttachmentDeleteOne) ExecX(ctx context.Context) {
|
||||||
ado.ad.ExecX(ctx)
|
if err := ado.Exec(ctx); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,9 @@ import (
|
|||||||
// AttachmentQuery is the builder for querying Attachment entities.
|
// AttachmentQuery is the builder for querying Attachment entities.
|
||||||
type AttachmentQuery struct {
|
type AttachmentQuery struct {
|
||||||
config
|
config
|
||||||
limit *int
|
ctx *QueryContext
|
||||||
offset *int
|
order []attachment.OrderOption
|
||||||
unique *bool
|
inters []Interceptor
|
||||||
order []OrderFunc
|
|
||||||
fields []string
|
|
||||||
predicates []predicate.Attachment
|
predicates []predicate.Attachment
|
||||||
withItem *ItemQuery
|
withItem *ItemQuery
|
||||||
withDocument *DocumentQuery
|
withDocument *DocumentQuery
|
||||||
@@ -40,34 +38,34 @@ func (aq *AttachmentQuery) Where(ps ...predicate.Attachment) *AttachmentQuery {
|
|||||||
return aq
|
return aq
|
||||||
}
|
}
|
||||||
|
|
||||||
// Limit adds a limit step to the query.
|
// Limit the number of records to be returned by this query.
|
||||||
func (aq *AttachmentQuery) Limit(limit int) *AttachmentQuery {
|
func (aq *AttachmentQuery) Limit(limit int) *AttachmentQuery {
|
||||||
aq.limit = &limit
|
aq.ctx.Limit = &limit
|
||||||
return aq
|
return aq
|
||||||
}
|
}
|
||||||
|
|
||||||
// Offset adds an offset step to the query.
|
// Offset to start from.
|
||||||
func (aq *AttachmentQuery) Offset(offset int) *AttachmentQuery {
|
func (aq *AttachmentQuery) Offset(offset int) *AttachmentQuery {
|
||||||
aq.offset = &offset
|
aq.ctx.Offset = &offset
|
||||||
return aq
|
return aq
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unique configures the query builder to filter duplicate records on query.
|
// 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.
|
// By default, unique is set to true, and can be disabled using this method.
|
||||||
func (aq *AttachmentQuery) Unique(unique bool) *AttachmentQuery {
|
func (aq *AttachmentQuery) Unique(unique bool) *AttachmentQuery {
|
||||||
aq.unique = &unique
|
aq.ctx.Unique = &unique
|
||||||
return aq
|
return aq
|
||||||
}
|
}
|
||||||
|
|
||||||
// Order adds an order step to the query.
|
// Order specifies how the records should be ordered.
|
||||||
func (aq *AttachmentQuery) Order(o ...OrderFunc) *AttachmentQuery {
|
func (aq *AttachmentQuery) Order(o ...attachment.OrderOption) *AttachmentQuery {
|
||||||
aq.order = append(aq.order, o...)
|
aq.order = append(aq.order, o...)
|
||||||
return aq
|
return aq
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryItem chains the current query on the "item" edge.
|
// QueryItem chains the current query on the "item" edge.
|
||||||
func (aq *AttachmentQuery) QueryItem() *ItemQuery {
|
func (aq *AttachmentQuery) QueryItem() *ItemQuery {
|
||||||
query := &ItemQuery{config: aq.config}
|
query := (&ItemClient{config: aq.config}).Query()
|
||||||
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
||||||
if err := aq.prepareQuery(ctx); err != nil {
|
if err := aq.prepareQuery(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -89,7 +87,7 @@ func (aq *AttachmentQuery) QueryItem() *ItemQuery {
|
|||||||
|
|
||||||
// QueryDocument chains the current query on the "document" edge.
|
// QueryDocument chains the current query on the "document" edge.
|
||||||
func (aq *AttachmentQuery) QueryDocument() *DocumentQuery {
|
func (aq *AttachmentQuery) QueryDocument() *DocumentQuery {
|
||||||
query := &DocumentQuery{config: aq.config}
|
query := (&DocumentClient{config: aq.config}).Query()
|
||||||
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
||||||
if err := aq.prepareQuery(ctx); err != nil {
|
if err := aq.prepareQuery(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -112,7 +110,7 @@ func (aq *AttachmentQuery) QueryDocument() *DocumentQuery {
|
|||||||
// First returns the first Attachment entity from the query.
|
// First returns the first Attachment entity from the query.
|
||||||
// Returns a *NotFoundError when no Attachment was found.
|
// Returns a *NotFoundError when no Attachment was found.
|
||||||
func (aq *AttachmentQuery) First(ctx context.Context) (*Attachment, error) {
|
func (aq *AttachmentQuery) First(ctx context.Context) (*Attachment, error) {
|
||||||
nodes, err := aq.Limit(1).All(ctx)
|
nodes, err := aq.Limit(1).All(setContextOp(ctx, aq.ctx, "First"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -135,7 +133,7 @@ func (aq *AttachmentQuery) FirstX(ctx context.Context) *Attachment {
|
|||||||
// Returns a *NotFoundError when no Attachment ID was found.
|
// Returns a *NotFoundError when no Attachment ID was found.
|
||||||
func (aq *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
|
var ids []uuid.UUID
|
||||||
if ids, err = aq.Limit(1).IDs(ctx); err != nil {
|
if ids, err = aq.Limit(1).IDs(setContextOp(ctx, aq.ctx, "FirstID")); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(ids) == 0 {
|
if len(ids) == 0 {
|
||||||
@@ -158,7 +156,7 @@ func (aq *AttachmentQuery) FirstIDX(ctx context.Context) uuid.UUID {
|
|||||||
// Returns a *NotSingularError when more than one Attachment entity is found.
|
// Returns a *NotSingularError when more than one Attachment entity is found.
|
||||||
// Returns a *NotFoundError when no Attachment entities are found.
|
// Returns a *NotFoundError when no Attachment entities are found.
|
||||||
func (aq *AttachmentQuery) Only(ctx context.Context) (*Attachment, error) {
|
func (aq *AttachmentQuery) Only(ctx context.Context) (*Attachment, error) {
|
||||||
nodes, err := aq.Limit(2).All(ctx)
|
nodes, err := aq.Limit(2).All(setContextOp(ctx, aq.ctx, "Only"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -186,7 +184,7 @@ func (aq *AttachmentQuery) OnlyX(ctx context.Context) *Attachment {
|
|||||||
// Returns a *NotFoundError when no entities are found.
|
// Returns a *NotFoundError when no entities are found.
|
||||||
func (aq *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
|
var ids []uuid.UUID
|
||||||
if ids, err = aq.Limit(2).IDs(ctx); err != nil {
|
if ids, err = aq.Limit(2).IDs(setContextOp(ctx, aq.ctx, "OnlyID")); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch len(ids) {
|
switch len(ids) {
|
||||||
@@ -211,10 +209,12 @@ func (aq *AttachmentQuery) OnlyIDX(ctx context.Context) uuid.UUID {
|
|||||||
|
|
||||||
// All executes the query and returns a list of Attachments.
|
// All executes the query and returns a list of Attachments.
|
||||||
func (aq *AttachmentQuery) All(ctx context.Context) ([]*Attachment, error) {
|
func (aq *AttachmentQuery) All(ctx context.Context) ([]*Attachment, error) {
|
||||||
|
ctx = setContextOp(ctx, aq.ctx, "All")
|
||||||
if err := aq.prepareQuery(ctx); err != nil {
|
if err := aq.prepareQuery(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return aq.sqlAll(ctx)
|
qr := querierAll[[]*Attachment, *AttachmentQuery]()
|
||||||
|
return withInterceptors[[]*Attachment](ctx, aq, qr, aq.inters)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllX is like All, but panics if an error occurs.
|
// AllX is like All, but panics if an error occurs.
|
||||||
@@ -227,9 +227,12 @@ func (aq *AttachmentQuery) AllX(ctx context.Context) []*Attachment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IDs executes the query and returns a list of Attachment IDs.
|
// IDs executes the query and returns a list of Attachment IDs.
|
||||||
func (aq *AttachmentQuery) IDs(ctx context.Context) ([]uuid.UUID, error) {
|
func (aq *AttachmentQuery) IDs(ctx context.Context) (ids []uuid.UUID, err error) {
|
||||||
var ids []uuid.UUID
|
if aq.ctx.Unique == nil && aq.path != nil {
|
||||||
if err := aq.Select(attachment.FieldID).Scan(ctx, &ids); err != nil {
|
aq.Unique(true)
|
||||||
|
}
|
||||||
|
ctx = setContextOp(ctx, aq.ctx, "IDs")
|
||||||
|
if err = aq.Select(attachment.FieldID).Scan(ctx, &ids); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return ids, nil
|
return ids, nil
|
||||||
@@ -246,10 +249,11 @@ func (aq *AttachmentQuery) IDsX(ctx context.Context) []uuid.UUID {
|
|||||||
|
|
||||||
// Count returns the count of the given query.
|
// Count returns the count of the given query.
|
||||||
func (aq *AttachmentQuery) Count(ctx context.Context) (int, error) {
|
func (aq *AttachmentQuery) Count(ctx context.Context) (int, error) {
|
||||||
|
ctx = setContextOp(ctx, aq.ctx, "Count")
|
||||||
if err := aq.prepareQuery(ctx); err != nil {
|
if err := aq.prepareQuery(ctx); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return aq.sqlCount(ctx)
|
return withInterceptors[int](ctx, aq, querierCount[*AttachmentQuery](), aq.inters)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CountX is like Count, but panics if an error occurs.
|
// CountX is like Count, but panics if an error occurs.
|
||||||
@@ -263,10 +267,15 @@ func (aq *AttachmentQuery) CountX(ctx context.Context) int {
|
|||||||
|
|
||||||
// Exist returns true if the query has elements in the graph.
|
// Exist returns true if the query has elements in the graph.
|
||||||
func (aq *AttachmentQuery) Exist(ctx context.Context) (bool, error) {
|
func (aq *AttachmentQuery) Exist(ctx context.Context) (bool, error) {
|
||||||
if err := aq.prepareQuery(ctx); err != nil {
|
ctx = setContextOp(ctx, aq.ctx, "Exist")
|
||||||
return false, err
|
switch _, err := aq.FirstID(ctx); {
|
||||||
|
case IsNotFound(err):
|
||||||
|
return false, nil
|
||||||
|
case err != nil:
|
||||||
|
return false, fmt.Errorf("ent: check existence: %w", err)
|
||||||
|
default:
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
return aq.sqlExist(ctx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExistX is like Exist, but panics if an error occurs.
|
// ExistX is like Exist, but panics if an error occurs.
|
||||||
@@ -286,23 +295,22 @@ func (aq *AttachmentQuery) Clone() *AttachmentQuery {
|
|||||||
}
|
}
|
||||||
return &AttachmentQuery{
|
return &AttachmentQuery{
|
||||||
config: aq.config,
|
config: aq.config,
|
||||||
limit: aq.limit,
|
ctx: aq.ctx.Clone(),
|
||||||
offset: aq.offset,
|
order: append([]attachment.OrderOption{}, aq.order...),
|
||||||
order: append([]OrderFunc{}, aq.order...),
|
inters: append([]Interceptor{}, aq.inters...),
|
||||||
predicates: append([]predicate.Attachment{}, aq.predicates...),
|
predicates: append([]predicate.Attachment{}, aq.predicates...),
|
||||||
withItem: aq.withItem.Clone(),
|
withItem: aq.withItem.Clone(),
|
||||||
withDocument: aq.withDocument.Clone(),
|
withDocument: aq.withDocument.Clone(),
|
||||||
// clone intermediate query.
|
// clone intermediate query.
|
||||||
sql: aq.sql.Clone(),
|
sql: aq.sql.Clone(),
|
||||||
path: aq.path,
|
path: aq.path,
|
||||||
unique: aq.unique,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithItem tells the query-builder to eager-load the nodes that are connected to
|
// 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.
|
// the "item" edge. The optional arguments are used to configure the query builder of the edge.
|
||||||
func (aq *AttachmentQuery) WithItem(opts ...func(*ItemQuery)) *AttachmentQuery {
|
func (aq *AttachmentQuery) WithItem(opts ...func(*ItemQuery)) *AttachmentQuery {
|
||||||
query := &ItemQuery{config: aq.config}
|
query := (&ItemClient{config: aq.config}).Query()
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(query)
|
opt(query)
|
||||||
}
|
}
|
||||||
@@ -313,7 +321,7 @@ func (aq *AttachmentQuery) WithItem(opts ...func(*ItemQuery)) *AttachmentQuery {
|
|||||||
// WithDocument tells the query-builder to eager-load the nodes that are connected to
|
// 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.
|
// the "document" edge. The optional arguments are used to configure the query builder of the edge.
|
||||||
func (aq *AttachmentQuery) WithDocument(opts ...func(*DocumentQuery)) *AttachmentQuery {
|
func (aq *AttachmentQuery) WithDocument(opts ...func(*DocumentQuery)) *AttachmentQuery {
|
||||||
query := &DocumentQuery{config: aq.config}
|
query := (&DocumentClient{config: aq.config}).Query()
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(query)
|
opt(query)
|
||||||
}
|
}
|
||||||
@@ -336,16 +344,11 @@ func (aq *AttachmentQuery) WithDocument(opts ...func(*DocumentQuery)) *Attachmen
|
|||||||
// Aggregate(ent.Count()).
|
// Aggregate(ent.Count()).
|
||||||
// Scan(ctx, &v)
|
// Scan(ctx, &v)
|
||||||
func (aq *AttachmentQuery) GroupBy(field string, fields ...string) *AttachmentGroupBy {
|
func (aq *AttachmentQuery) GroupBy(field string, fields ...string) *AttachmentGroupBy {
|
||||||
grbuild := &AttachmentGroupBy{config: aq.config}
|
aq.ctx.Fields = append([]string{field}, fields...)
|
||||||
grbuild.fields = append([]string{field}, fields...)
|
grbuild := &AttachmentGroupBy{build: aq}
|
||||||
grbuild.path = func(ctx context.Context) (prev *sql.Selector, err error) {
|
grbuild.flds = &aq.ctx.Fields
|
||||||
if err := aq.prepareQuery(ctx); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return aq.sqlQuery(ctx), nil
|
|
||||||
}
|
|
||||||
grbuild.label = attachment.Label
|
grbuild.label = attachment.Label
|
||||||
grbuild.flds, grbuild.scan = &grbuild.fields, grbuild.Scan
|
grbuild.scan = grbuild.Scan
|
||||||
return grbuild
|
return grbuild
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,15 +365,30 @@ func (aq *AttachmentQuery) GroupBy(field string, fields ...string) *AttachmentGr
|
|||||||
// Select(attachment.FieldCreatedAt).
|
// Select(attachment.FieldCreatedAt).
|
||||||
// Scan(ctx, &v)
|
// Scan(ctx, &v)
|
||||||
func (aq *AttachmentQuery) Select(fields ...string) *AttachmentSelect {
|
func (aq *AttachmentQuery) Select(fields ...string) *AttachmentSelect {
|
||||||
aq.fields = append(aq.fields, fields...)
|
aq.ctx.Fields = append(aq.ctx.Fields, fields...)
|
||||||
selbuild := &AttachmentSelect{AttachmentQuery: aq}
|
sbuild := &AttachmentSelect{AttachmentQuery: aq}
|
||||||
selbuild.label = attachment.Label
|
sbuild.label = attachment.Label
|
||||||
selbuild.flds, selbuild.scan = &aq.fields, selbuild.Scan
|
sbuild.flds, sbuild.scan = &aq.ctx.Fields, sbuild.Scan
|
||||||
return selbuild
|
return sbuild
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aggregate returns a AttachmentSelect configured with the given aggregations.
|
||||||
|
func (aq *AttachmentQuery) Aggregate(fns ...AggregateFunc) *AttachmentSelect {
|
||||||
|
return aq.Select().Aggregate(fns...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (aq *AttachmentQuery) prepareQuery(ctx context.Context) error {
|
func (aq *AttachmentQuery) prepareQuery(ctx context.Context) error {
|
||||||
for _, f := range aq.fields {
|
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, aq); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, f := range aq.ctx.Fields {
|
||||||
if !attachment.ValidColumn(f) {
|
if !attachment.ValidColumn(f) {
|
||||||
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
|
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
|
||||||
}
|
}
|
||||||
@@ -447,6 +465,9 @@ func (aq *AttachmentQuery) loadItem(ctx context.Context, query *ItemQuery, nodes
|
|||||||
}
|
}
|
||||||
nodeids[fk] = append(nodeids[fk], nodes[i])
|
nodeids[fk] = append(nodeids[fk], nodes[i])
|
||||||
}
|
}
|
||||||
|
if len(ids) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
query.Where(item.IDIn(ids...))
|
query.Where(item.IDIn(ids...))
|
||||||
neighbors, err := query.All(ctx)
|
neighbors, err := query.All(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -476,6 +497,9 @@ func (aq *AttachmentQuery) loadDocument(ctx context.Context, query *DocumentQuer
|
|||||||
}
|
}
|
||||||
nodeids[fk] = append(nodeids[fk], nodes[i])
|
nodeids[fk] = append(nodeids[fk], nodes[i])
|
||||||
}
|
}
|
||||||
|
if len(ids) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
query.Where(document.IDIn(ids...))
|
query.Where(document.IDIn(ids...))
|
||||||
neighbors, err := query.All(ctx)
|
neighbors, err := query.All(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -495,41 +519,22 @@ func (aq *AttachmentQuery) loadDocument(ctx context.Context, query *DocumentQuer
|
|||||||
|
|
||||||
func (aq *AttachmentQuery) sqlCount(ctx context.Context) (int, error) {
|
func (aq *AttachmentQuery) sqlCount(ctx context.Context) (int, error) {
|
||||||
_spec := aq.querySpec()
|
_spec := aq.querySpec()
|
||||||
_spec.Node.Columns = aq.fields
|
_spec.Node.Columns = aq.ctx.Fields
|
||||||
if len(aq.fields) > 0 {
|
if len(aq.ctx.Fields) > 0 {
|
||||||
_spec.Unique = aq.unique != nil && *aq.unique
|
_spec.Unique = aq.ctx.Unique != nil && *aq.ctx.Unique
|
||||||
}
|
}
|
||||||
return sqlgraph.CountNodes(ctx, aq.driver, _spec)
|
return sqlgraph.CountNodes(ctx, aq.driver, _spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (aq *AttachmentQuery) sqlExist(ctx context.Context) (bool, error) {
|
|
||||||
switch _, err := aq.FirstID(ctx); {
|
|
||||||
case IsNotFound(err):
|
|
||||||
return false, nil
|
|
||||||
case err != nil:
|
|
||||||
return false, fmt.Errorf("ent: check existence: %w", err)
|
|
||||||
default:
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (aq *AttachmentQuery) querySpec() *sqlgraph.QuerySpec {
|
func (aq *AttachmentQuery) querySpec() *sqlgraph.QuerySpec {
|
||||||
_spec := &sqlgraph.QuerySpec{
|
_spec := sqlgraph.NewQuerySpec(attachment.Table, attachment.Columns, sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID))
|
||||||
Node: &sqlgraph.NodeSpec{
|
_spec.From = aq.sql
|
||||||
Table: attachment.Table,
|
if unique := aq.ctx.Unique; unique != nil {
|
||||||
Columns: attachment.Columns,
|
|
||||||
ID: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: attachment.FieldID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
From: aq.sql,
|
|
||||||
Unique: true,
|
|
||||||
}
|
|
||||||
if unique := aq.unique; unique != nil {
|
|
||||||
_spec.Unique = *unique
|
_spec.Unique = *unique
|
||||||
|
} else if aq.path != nil {
|
||||||
|
_spec.Unique = true
|
||||||
}
|
}
|
||||||
if fields := aq.fields; len(fields) > 0 {
|
if fields := aq.ctx.Fields; len(fields) > 0 {
|
||||||
_spec.Node.Columns = make([]string, 0, len(fields))
|
_spec.Node.Columns = make([]string, 0, len(fields))
|
||||||
_spec.Node.Columns = append(_spec.Node.Columns, attachment.FieldID)
|
_spec.Node.Columns = append(_spec.Node.Columns, attachment.FieldID)
|
||||||
for i := range fields {
|
for i := range fields {
|
||||||
@@ -545,10 +550,10 @@ func (aq *AttachmentQuery) querySpec() *sqlgraph.QuerySpec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if limit := aq.limit; limit != nil {
|
if limit := aq.ctx.Limit; limit != nil {
|
||||||
_spec.Limit = *limit
|
_spec.Limit = *limit
|
||||||
}
|
}
|
||||||
if offset := aq.offset; offset != nil {
|
if offset := aq.ctx.Offset; offset != nil {
|
||||||
_spec.Offset = *offset
|
_spec.Offset = *offset
|
||||||
}
|
}
|
||||||
if ps := aq.order; len(ps) > 0 {
|
if ps := aq.order; len(ps) > 0 {
|
||||||
@@ -564,7 +569,7 @@ func (aq *AttachmentQuery) querySpec() *sqlgraph.QuerySpec {
|
|||||||
func (aq *AttachmentQuery) sqlQuery(ctx context.Context) *sql.Selector {
|
func (aq *AttachmentQuery) sqlQuery(ctx context.Context) *sql.Selector {
|
||||||
builder := sql.Dialect(aq.driver.Dialect())
|
builder := sql.Dialect(aq.driver.Dialect())
|
||||||
t1 := builder.Table(attachment.Table)
|
t1 := builder.Table(attachment.Table)
|
||||||
columns := aq.fields
|
columns := aq.ctx.Fields
|
||||||
if len(columns) == 0 {
|
if len(columns) == 0 {
|
||||||
columns = attachment.Columns
|
columns = attachment.Columns
|
||||||
}
|
}
|
||||||
@@ -573,7 +578,7 @@ func (aq *AttachmentQuery) sqlQuery(ctx context.Context) *sql.Selector {
|
|||||||
selector = aq.sql
|
selector = aq.sql
|
||||||
selector.Select(selector.Columns(columns...)...)
|
selector.Select(selector.Columns(columns...)...)
|
||||||
}
|
}
|
||||||
if aq.unique != nil && *aq.unique {
|
if aq.ctx.Unique != nil && *aq.ctx.Unique {
|
||||||
selector.Distinct()
|
selector.Distinct()
|
||||||
}
|
}
|
||||||
for _, p := range aq.predicates {
|
for _, p := range aq.predicates {
|
||||||
@@ -582,12 +587,12 @@ func (aq *AttachmentQuery) sqlQuery(ctx context.Context) *sql.Selector {
|
|||||||
for _, p := range aq.order {
|
for _, p := range aq.order {
|
||||||
p(selector)
|
p(selector)
|
||||||
}
|
}
|
||||||
if offset := aq.offset; offset != nil {
|
if offset := aq.ctx.Offset; offset != nil {
|
||||||
// limit is mandatory for offset clause. We start
|
// limit is mandatory for offset clause. We start
|
||||||
// with default value, and override it below if needed.
|
// with default value, and override it below if needed.
|
||||||
selector.Offset(*offset).Limit(math.MaxInt32)
|
selector.Offset(*offset).Limit(math.MaxInt32)
|
||||||
}
|
}
|
||||||
if limit := aq.limit; limit != nil {
|
if limit := aq.ctx.Limit; limit != nil {
|
||||||
selector.Limit(*limit)
|
selector.Limit(*limit)
|
||||||
}
|
}
|
||||||
return selector
|
return selector
|
||||||
@@ -595,13 +600,8 @@ func (aq *AttachmentQuery) sqlQuery(ctx context.Context) *sql.Selector {
|
|||||||
|
|
||||||
// AttachmentGroupBy is the group-by builder for Attachment entities.
|
// AttachmentGroupBy is the group-by builder for Attachment entities.
|
||||||
type AttachmentGroupBy struct {
|
type AttachmentGroupBy struct {
|
||||||
config
|
|
||||||
selector
|
selector
|
||||||
fields []string
|
build *AttachmentQuery
|
||||||
fns []AggregateFunc
|
|
||||||
// intermediate query (i.e. traversal path).
|
|
||||||
sql *sql.Selector
|
|
||||||
path func(context.Context) (*sql.Selector, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aggregate adds the given aggregation functions to the group-by query.
|
// Aggregate adds the given aggregation functions to the group-by query.
|
||||||
@@ -610,74 +610,77 @@ func (agb *AttachmentGroupBy) Aggregate(fns ...AggregateFunc) *AttachmentGroupBy
|
|||||||
return agb
|
return agb
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan applies the group-by query and scans the result into the given value.
|
// Scan applies the selector query and scans the result into the given value.
|
||||||
func (agb *AttachmentGroupBy) Scan(ctx context.Context, v any) error {
|
func (agb *AttachmentGroupBy) Scan(ctx context.Context, v any) error {
|
||||||
query, err := agb.path(ctx)
|
ctx = setContextOp(ctx, agb.build.ctx, "GroupBy")
|
||||||
if err != nil {
|
if err := agb.build.prepareQuery(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
agb.sql = query
|
return scanWithInterceptors[*AttachmentQuery, *AttachmentGroupBy](ctx, agb.build, agb, agb.build.inters, v)
|
||||||
return agb.sqlScan(ctx, v)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (agb *AttachmentGroupBy) sqlScan(ctx context.Context, v any) error {
|
func (agb *AttachmentGroupBy) sqlScan(ctx context.Context, root *AttachmentQuery, v any) error {
|
||||||
for _, f := range agb.fields {
|
selector := root.sqlQuery(ctx).Select()
|
||||||
if !attachment.ValidColumn(f) {
|
|
||||||
return &ValidationError{Name: f, err: fmt.Errorf("invalid field %q for group-by", f)}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
selector := agb.sqlQuery()
|
|
||||||
if err := selector.Err(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rows := &sql.Rows{}
|
|
||||||
query, args := selector.Query()
|
|
||||||
if err := agb.driver.Query(ctx, query, args, rows); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
return sql.ScanSlice(rows, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (agb *AttachmentGroupBy) sqlQuery() *sql.Selector {
|
|
||||||
selector := agb.sql.Select()
|
|
||||||
aggregation := make([]string, 0, len(agb.fns))
|
aggregation := make([]string, 0, len(agb.fns))
|
||||||
for _, fn := range agb.fns {
|
for _, fn := range agb.fns {
|
||||||
aggregation = append(aggregation, fn(selector))
|
aggregation = append(aggregation, fn(selector))
|
||||||
}
|
}
|
||||||
// If no columns were selected in a custom aggregation function, the default
|
|
||||||
// selection is the fields used for "group-by", and the aggregation functions.
|
|
||||||
if len(selector.SelectedColumns()) == 0 {
|
if len(selector.SelectedColumns()) == 0 {
|
||||||
columns := make([]string, 0, len(agb.fields)+len(agb.fns))
|
columns := make([]string, 0, len(*agb.flds)+len(agb.fns))
|
||||||
for _, f := range agb.fields {
|
for _, f := range *agb.flds {
|
||||||
columns = append(columns, selector.C(f))
|
columns = append(columns, selector.C(f))
|
||||||
}
|
}
|
||||||
columns = append(columns, aggregation...)
|
columns = append(columns, aggregation...)
|
||||||
selector.Select(columns...)
|
selector.Select(columns...)
|
||||||
}
|
}
|
||||||
return selector.GroupBy(selector.Columns(agb.fields...)...)
|
selector.GroupBy(selector.Columns(*agb.flds...)...)
|
||||||
|
if err := selector.Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rows := &sql.Rows{}
|
||||||
|
query, args := selector.Query()
|
||||||
|
if err := agb.build.driver.Query(ctx, query, args, rows); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
return sql.ScanSlice(rows, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AttachmentSelect is the builder for selecting fields of Attachment entities.
|
// AttachmentSelect is the builder for selecting fields of Attachment entities.
|
||||||
type AttachmentSelect struct {
|
type AttachmentSelect struct {
|
||||||
*AttachmentQuery
|
*AttachmentQuery
|
||||||
selector
|
selector
|
||||||
// intermediate query (i.e. traversal path).
|
}
|
||||||
sql *sql.Selector
|
|
||||||
|
// Aggregate adds the given aggregation functions to the selector query.
|
||||||
|
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.
|
// Scan applies the selector query and scans the result into the given value.
|
||||||
func (as *AttachmentSelect) Scan(ctx context.Context, v any) error {
|
func (as *AttachmentSelect) Scan(ctx context.Context, v any) error {
|
||||||
|
ctx = setContextOp(ctx, as.ctx, "Select")
|
||||||
if err := as.prepareQuery(ctx); err != nil {
|
if err := as.prepareQuery(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
as.sql = as.AttachmentQuery.sqlQuery(ctx)
|
return scanWithInterceptors[*AttachmentQuery, *AttachmentSelect](ctx, as.AttachmentQuery, as, as.inters, v)
|
||||||
return as.sqlScan(ctx, v)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (as *AttachmentSelect) sqlScan(ctx context.Context, v any) error {
|
func (as *AttachmentSelect) sqlScan(ctx context.Context, root *AttachmentQuery, v any) error {
|
||||||
|
selector := root.sqlQuery(ctx)
|
||||||
|
aggregation := make([]string, 0, len(as.fns))
|
||||||
|
for _, fn := range as.fns {
|
||||||
|
aggregation = append(aggregation, fn(selector))
|
||||||
|
}
|
||||||
|
switch n := len(*as.selector.flds); {
|
||||||
|
case n == 0 && len(aggregation) > 0:
|
||||||
|
selector.Select(aggregation...)
|
||||||
|
case n != 0 && len(aggregation) > 0:
|
||||||
|
selector.AppendSelect(aggregation...)
|
||||||
|
}
|
||||||
rows := &sql.Rows{}
|
rows := &sql.Rows{}
|
||||||
query, args := as.sql.Query()
|
query, args := selector.Query()
|
||||||
if err := as.driver.Query(ctx, query, args, rows); err != nil {
|
if err := as.driver.Query(ctx, query, args, rows); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,41 +92,8 @@ func (au *AttachmentUpdate) ClearDocument() *AttachmentUpdate {
|
|||||||
|
|
||||||
// Save executes the query and returns the number of nodes affected by the update operation.
|
// Save executes the query and returns the number of nodes affected by the update operation.
|
||||||
func (au *AttachmentUpdate) Save(ctx context.Context) (int, error) {
|
func (au *AttachmentUpdate) Save(ctx context.Context) (int, error) {
|
||||||
var (
|
|
||||||
err error
|
|
||||||
affected int
|
|
||||||
)
|
|
||||||
au.defaults()
|
au.defaults()
|
||||||
if len(au.hooks) == 0 {
|
return withHooks(ctx, au.sqlSave, au.mutation, au.hooks)
|
||||||
if err = au.check(); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
affected, err = au.sqlSave(ctx)
|
|
||||||
} else {
|
|
||||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
|
||||||
mutation, ok := m.(*AttachmentMutation)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
|
||||||
}
|
|
||||||
if err = au.check(); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
au.mutation = mutation
|
|
||||||
affected, err = au.sqlSave(ctx)
|
|
||||||
mutation.done = true
|
|
||||||
return affected, err
|
|
||||||
})
|
|
||||||
for i := len(au.hooks) - 1; i >= 0; i-- {
|
|
||||||
if au.hooks[i] == nil {
|
|
||||||
return 0, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
|
||||||
}
|
|
||||||
mut = au.hooks[i](mut)
|
|
||||||
}
|
|
||||||
if _, err := mut.Mutate(ctx, au.mutation); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return affected, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveX is like Save, but panics if an error occurs.
|
// SaveX is like Save, but panics if an error occurs.
|
||||||
@@ -176,16 +143,10 @@ func (au *AttachmentUpdate) check() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||||
_spec := &sqlgraph.UpdateSpec{
|
if err := au.check(); err != nil {
|
||||||
Node: &sqlgraph.NodeSpec{
|
return n, err
|
||||||
Table: attachment.Table,
|
|
||||||
Columns: attachment.Columns,
|
|
||||||
ID: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: attachment.FieldID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
_spec := sqlgraph.NewUpdateSpec(attachment.Table, attachment.Columns, sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID))
|
||||||
if ps := au.mutation.predicates; len(ps) > 0 {
|
if ps := au.mutation.predicates; len(ps) > 0 {
|
||||||
_spec.Predicate = func(selector *sql.Selector) {
|
_spec.Predicate = func(selector *sql.Selector) {
|
||||||
for i := range ps {
|
for i := range ps {
|
||||||
@@ -194,18 +155,10 @@ func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if value, ok := au.mutation.UpdatedAt(); ok {
|
if value, ok := au.mutation.UpdatedAt(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(attachment.FieldUpdatedAt, field.TypeTime, value)
|
||||||
Type: field.TypeTime,
|
|
||||||
Value: value,
|
|
||||||
Column: attachment.FieldUpdatedAt,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if value, ok := au.mutation.GetType(); ok {
|
if value, ok := au.mutation.GetType(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(attachment.FieldType, field.TypeEnum, value)
|
||||||
Type: field.TypeEnum,
|
|
||||||
Value: value,
|
|
||||||
Column: attachment.FieldType,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if au.mutation.ItemCleared() {
|
if au.mutation.ItemCleared() {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
@@ -215,10 +168,7 @@ func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
|||||||
Columns: []string{attachment.ItemColumn},
|
Columns: []string{attachment.ItemColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(item.FieldID, field.TypeUUID),
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: item.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||||
@@ -231,10 +181,7 @@ func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
|||||||
Columns: []string{attachment.ItemColumn},
|
Columns: []string{attachment.ItemColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(item.FieldID, field.TypeUUID),
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: item.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
@@ -250,10 +197,7 @@ func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
|||||||
Columns: []string{attachment.DocumentColumn},
|
Columns: []string{attachment.DocumentColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID),
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: document.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||||
@@ -266,10 +210,7 @@ func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
|||||||
Columns: []string{attachment.DocumentColumn},
|
Columns: []string{attachment.DocumentColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID),
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: document.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
@@ -285,6 +226,7 @@ func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
|||||||
}
|
}
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
au.mutation.done = true
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,6 +297,12 @@ func (auo *AttachmentUpdateOne) ClearDocument() *AttachmentUpdateOne {
|
|||||||
return auo
|
return auo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Where appends a list predicates to the AttachmentUpdate builder.
|
||||||
|
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.
|
// Select allows selecting one or more fields (columns) of the returned entity.
|
||||||
// The default is selecting all fields defined in the entity schema.
|
// The default is selecting all fields defined in the entity schema.
|
||||||
func (auo *AttachmentUpdateOne) Select(field string, fields ...string) *AttachmentUpdateOne {
|
func (auo *AttachmentUpdateOne) Select(field string, fields ...string) *AttachmentUpdateOne {
|
||||||
@@ -364,47 +312,8 @@ func (auo *AttachmentUpdateOne) Select(field string, fields ...string) *Attachme
|
|||||||
|
|
||||||
// Save executes the query and returns the updated Attachment entity.
|
// Save executes the query and returns the updated Attachment entity.
|
||||||
func (auo *AttachmentUpdateOne) Save(ctx context.Context) (*Attachment, error) {
|
func (auo *AttachmentUpdateOne) Save(ctx context.Context) (*Attachment, error) {
|
||||||
var (
|
|
||||||
err error
|
|
||||||
node *Attachment
|
|
||||||
)
|
|
||||||
auo.defaults()
|
auo.defaults()
|
||||||
if len(auo.hooks) == 0 {
|
return withHooks(ctx, auo.sqlSave, auo.mutation, auo.hooks)
|
||||||
if err = auo.check(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
node, err = auo.sqlSave(ctx)
|
|
||||||
} else {
|
|
||||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
|
||||||
mutation, ok := m.(*AttachmentMutation)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
|
||||||
}
|
|
||||||
if err = auo.check(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
auo.mutation = mutation
|
|
||||||
node, err = auo.sqlSave(ctx)
|
|
||||||
mutation.done = true
|
|
||||||
return node, err
|
|
||||||
})
|
|
||||||
for i := len(auo.hooks) - 1; i >= 0; i-- {
|
|
||||||
if auo.hooks[i] == nil {
|
|
||||||
return nil, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
|
||||||
}
|
|
||||||
mut = auo.hooks[i](mut)
|
|
||||||
}
|
|
||||||
v, err := mut.Mutate(ctx, auo.mutation)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
nv, ok := v.(*Attachment)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected node type %T returned from AttachmentMutation", v)
|
|
||||||
}
|
|
||||||
node = nv
|
|
||||||
}
|
|
||||||
return node, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveX is like Save, but panics if an error occurs.
|
// SaveX is like Save, but panics if an error occurs.
|
||||||
@@ -454,16 +363,10 @@ func (auo *AttachmentUpdateOne) check() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment, err error) {
|
func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment, err error) {
|
||||||
_spec := &sqlgraph.UpdateSpec{
|
if err := auo.check(); err != nil {
|
||||||
Node: &sqlgraph.NodeSpec{
|
return _node, err
|
||||||
Table: attachment.Table,
|
|
||||||
Columns: attachment.Columns,
|
|
||||||
ID: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: attachment.FieldID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
_spec := sqlgraph.NewUpdateSpec(attachment.Table, attachment.Columns, sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID))
|
||||||
id, ok := auo.mutation.ID()
|
id, ok := auo.mutation.ID()
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Attachment.id" for update`)}
|
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Attachment.id" for update`)}
|
||||||
@@ -489,18 +392,10 @@ func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if value, ok := auo.mutation.UpdatedAt(); ok {
|
if value, ok := auo.mutation.UpdatedAt(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(attachment.FieldUpdatedAt, field.TypeTime, value)
|
||||||
Type: field.TypeTime,
|
|
||||||
Value: value,
|
|
||||||
Column: attachment.FieldUpdatedAt,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if value, ok := auo.mutation.GetType(); ok {
|
if value, ok := auo.mutation.GetType(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(attachment.FieldType, field.TypeEnum, value)
|
||||||
Type: field.TypeEnum,
|
|
||||||
Value: value,
|
|
||||||
Column: attachment.FieldType,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if auo.mutation.ItemCleared() {
|
if auo.mutation.ItemCleared() {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
@@ -510,10 +405,7 @@ func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
|
|||||||
Columns: []string{attachment.ItemColumn},
|
Columns: []string{attachment.ItemColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(item.FieldID, field.TypeUUID),
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: item.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||||
@@ -526,10 +418,7 @@ func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
|
|||||||
Columns: []string{attachment.ItemColumn},
|
Columns: []string{attachment.ItemColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(item.FieldID, field.TypeUUID),
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: item.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
@@ -545,10 +434,7 @@ func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
|
|||||||
Columns: []string{attachment.DocumentColumn},
|
Columns: []string{attachment.DocumentColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID),
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: document.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||||
@@ -561,10 +447,7 @@ func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
|
|||||||
Columns: []string{attachment.DocumentColumn},
|
Columns: []string{attachment.DocumentColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID),
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: document.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
@@ -583,5 +466,6 @@ func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
|
|||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
auo.mutation.done = true
|
||||||
return _node, nil
|
return _node, nil
|
||||||
}
|
}
|
||||||
|
|||||||
145
backend/internal/data/ent/authroles.go
Normal file
145
backend/internal/data/ent/authroles.go
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
|
package ent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"entgo.io/ent"
|
||||||
|
"entgo.io/ent/dialect/sql"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AuthRoles is the model entity for the AuthRoles schema.
|
||||||
|
type AuthRoles struct {
|
||||||
|
config `json:"-"`
|
||||||
|
// ID of the ent.
|
||||||
|
ID int `json:"id,omitempty"`
|
||||||
|
// Role holds the value of the "role" field.
|
||||||
|
Role authroles.Role `json:"role,omitempty"`
|
||||||
|
// Edges holds the relations/edges for other nodes in the graph.
|
||||||
|
// The values are being populated by the AuthRolesQuery when eager-loading is set.
|
||||||
|
Edges AuthRolesEdges `json:"edges"`
|
||||||
|
auth_tokens_roles *uuid.UUID
|
||||||
|
selectValues sql.SelectValues
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthRolesEdges holds the relations/edges for other nodes in the graph.
|
||||||
|
type AuthRolesEdges struct {
|
||||||
|
// Token holds the value of the token edge.
|
||||||
|
Token *AuthTokens `json:"token,omitempty"`
|
||||||
|
// loadedTypes holds the information for reporting if a
|
||||||
|
// type was loaded (or requested) in eager-loading or not.
|
||||||
|
loadedTypes [1]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenOrErr returns the Token value or an error if the edge
|
||||||
|
// was not loaded in eager-loading, or loaded but was not found.
|
||||||
|
func (e AuthRolesEdges) TokenOrErr() (*AuthTokens, error) {
|
||||||
|
if e.loadedTypes[0] {
|
||||||
|
if e.Token == nil {
|
||||||
|
// Edge was loaded but was not found.
|
||||||
|
return nil, &NotFoundError{label: authtokens.Label}
|
||||||
|
}
|
||||||
|
return e.Token, nil
|
||||||
|
}
|
||||||
|
return nil, &NotLoadedError{edge: "token"}
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanValues returns the types for scanning values from sql.Rows.
|
||||||
|
func (*AuthRoles) scanValues(columns []string) ([]any, error) {
|
||||||
|
values := make([]any, len(columns))
|
||||||
|
for i := range columns {
|
||||||
|
switch columns[i] {
|
||||||
|
case authroles.FieldID:
|
||||||
|
values[i] = new(sql.NullInt64)
|
||||||
|
case authroles.FieldRole:
|
||||||
|
values[i] = new(sql.NullString)
|
||||||
|
case authroles.ForeignKeys[0]: // auth_tokens_roles
|
||||||
|
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 AuthRoles fields.
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
for i := range columns {
|
||||||
|
switch columns[i] {
|
||||||
|
case authroles.FieldID:
|
||||||
|
value, ok := values[i].(*sql.NullInt64)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected type %T for field id", value)
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
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 {
|
||||||
|
ar.auth_tokens_roles = new(uuid.UUID)
|
||||||
|
*ar.auth_tokens_roles = *value.S.(*uuid.UUID)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ar.selectValues.Set(columns[i], values[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns the ent.Value that was dynamically selected and assigned to the AuthRoles.
|
||||||
|
// This includes values selected through modifiers, order, etc.
|
||||||
|
func (ar *AuthRoles) Value(name string) (ent.Value, error) {
|
||||||
|
return ar.selectValues.Get(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryToken queries the "token" edge of the AuthRoles entity.
|
||||||
|
func (ar *AuthRoles) QueryToken() *AuthTokensQuery {
|
||||||
|
return NewAuthRolesClient(ar.config).QueryToken(ar)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (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 (ar *AuthRoles) Unwrap() *AuthRoles {
|
||||||
|
_tx, ok := ar.config.driver.(*txDriver)
|
||||||
|
if !ok {
|
||||||
|
panic("ent: AuthRoles is not a transactional entity")
|
||||||
|
}
|
||||||
|
ar.config.driver = _tx.drv
|
||||||
|
return ar
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements the fmt.Stringer.
|
||||||
|
func (ar *AuthRoles) String() string {
|
||||||
|
var builder strings.Builder
|
||||||
|
builder.WriteString("AuthRoles(")
|
||||||
|
builder.WriteString(fmt.Sprintf("id=%v, ", ar.ID))
|
||||||
|
builder.WriteString("role=")
|
||||||
|
builder.WriteString(fmt.Sprintf("%v", ar.Role))
|
||||||
|
builder.WriteByte(')')
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthRolesSlice is a parsable slice of AuthRoles.
|
||||||
|
type AuthRolesSlice []*AuthRoles
|
||||||
111
backend/internal/data/ent/authroles/authroles.go
Normal file
111
backend/internal/data/ent/authroles/authroles.go
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
|
package authroles
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"entgo.io/ent/dialect/sql"
|
||||||
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Label holds the string label denoting the authroles type in the database.
|
||||||
|
Label = "auth_roles"
|
||||||
|
// FieldID holds the string denoting the id field in the database.
|
||||||
|
FieldID = "id"
|
||||||
|
// FieldRole holds the string denoting the role field in the database.
|
||||||
|
FieldRole = "role"
|
||||||
|
// EdgeToken holds the string denoting the token edge name in mutations.
|
||||||
|
EdgeToken = "token"
|
||||||
|
// Table holds the table name of the authroles in the database.
|
||||||
|
Table = "auth_roles"
|
||||||
|
// TokenTable is the table that holds the token relation/edge.
|
||||||
|
TokenTable = "auth_roles"
|
||||||
|
// TokenInverseTable is the table name for the AuthTokens entity.
|
||||||
|
// It exists in this package in order to avoid circular dependency with the "authtokens" package.
|
||||||
|
TokenInverseTable = "auth_tokens"
|
||||||
|
// TokenColumn is the table column denoting the token relation/edge.
|
||||||
|
TokenColumn = "auth_tokens_roles"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Columns holds all SQL columns for authroles fields.
|
||||||
|
var Columns = []string{
|
||||||
|
FieldID,
|
||||||
|
FieldRole,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForeignKeys holds the SQL foreign-keys that are owned by the "auth_roles"
|
||||||
|
// table and are not defined as standalone fields in the schema.
|
||||||
|
var ForeignKeys = []string{
|
||||||
|
"auth_tokens_roles",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Role defines the type for the "role" enum field.
|
||||||
|
type Role string
|
||||||
|
|
||||||
|
// RoleUser is the default value of the Role enum.
|
||||||
|
const DefaultRole = RoleUser
|
||||||
|
|
||||||
|
// Role values.
|
||||||
|
const (
|
||||||
|
RoleAdmin Role = "admin"
|
||||||
|
RoleUser Role = "user"
|
||||||
|
RoleAttachments Role = "attachments"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r Role) String() string {
|
||||||
|
return string(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoleValidator is a validator for the "role" field enum values. It is called by the builders before save.
|
||||||
|
func RoleValidator(r Role) error {
|
||||||
|
switch r {
|
||||||
|
case RoleAdmin, RoleUser, RoleAttachments:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("authroles: invalid enum value for role field: %q", r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrderOption defines the ordering options for the AuthRoles queries.
|
||||||
|
type OrderOption func(*sql.Selector)
|
||||||
|
|
||||||
|
// ByID orders the results by the id field.
|
||||||
|
func ByID(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldID, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByRole orders the results by the role field.
|
||||||
|
func ByRole(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldRole, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByTokenField orders the results by token field.
|
||||||
|
func ByTokenField(field string, opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return func(s *sql.Selector) {
|
||||||
|
sqlgraph.OrderByNeighborTerms(s, newTokenStep(), sql.OrderByField(field, opts...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func newTokenStep() *sqlgraph.Step {
|
||||||
|
return sqlgraph.NewStep(
|
||||||
|
sqlgraph.From(Table, FieldID),
|
||||||
|
sqlgraph.To(TokenInverseTable, FieldID),
|
||||||
|
sqlgraph.Edge(sqlgraph.O2O, true, TokenTable, TokenColumn),
|
||||||
|
)
|
||||||
|
}
|
||||||
129
backend/internal/data/ent/authroles/where.go
Normal file
129
backend/internal/data/ent/authroles/where.go
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
|
package authroles
|
||||||
|
|
||||||
|
import (
|
||||||
|
"entgo.io/ent/dialect/sql"
|
||||||
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ID filters vertices based on their ID field.
|
||||||
|
func ID(id int) predicate.AuthRoles {
|
||||||
|
return predicate.AuthRoles(sql.FieldEQ(FieldID, id))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDEQ applies the EQ predicate on the ID field.
|
||||||
|
func IDEQ(id int) predicate.AuthRoles {
|
||||||
|
return predicate.AuthRoles(sql.FieldEQ(FieldID, id))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDNEQ applies the NEQ predicate on the ID field.
|
||||||
|
func IDNEQ(id int) predicate.AuthRoles {
|
||||||
|
return predicate.AuthRoles(sql.FieldNEQ(FieldID, id))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDIn applies the In predicate on the ID field.
|
||||||
|
func IDIn(ids ...int) predicate.AuthRoles {
|
||||||
|
return predicate.AuthRoles(sql.FieldIn(FieldID, ids...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDNotIn applies the NotIn predicate on the ID field.
|
||||||
|
func IDNotIn(ids ...int) predicate.AuthRoles {
|
||||||
|
return predicate.AuthRoles(sql.FieldNotIn(FieldID, ids...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDGT applies the GT predicate on the ID field.
|
||||||
|
func IDGT(id int) predicate.AuthRoles {
|
||||||
|
return predicate.AuthRoles(sql.FieldGT(FieldID, id))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDGTE applies the GTE predicate on the ID field.
|
||||||
|
func IDGTE(id int) predicate.AuthRoles {
|
||||||
|
return predicate.AuthRoles(sql.FieldGTE(FieldID, id))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDLT applies the LT predicate on the ID field.
|
||||||
|
func IDLT(id int) predicate.AuthRoles {
|
||||||
|
return predicate.AuthRoles(sql.FieldLT(FieldID, id))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDLTE applies the LTE predicate on the ID field.
|
||||||
|
func IDLTE(id int) predicate.AuthRoles {
|
||||||
|
return predicate.AuthRoles(sql.FieldLTE(FieldID, id))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoleEQ applies the EQ predicate on the "role" field.
|
||||||
|
func RoleEQ(v Role) predicate.AuthRoles {
|
||||||
|
return predicate.AuthRoles(sql.FieldEQ(FieldRole, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoleNEQ applies the NEQ predicate on the "role" field.
|
||||||
|
func RoleNEQ(v Role) predicate.AuthRoles {
|
||||||
|
return predicate.AuthRoles(sql.FieldNEQ(FieldRole, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoleIn applies the In predicate on the "role" field.
|
||||||
|
func RoleIn(vs ...Role) predicate.AuthRoles {
|
||||||
|
return predicate.AuthRoles(sql.FieldIn(FieldRole, vs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoleNotIn applies the NotIn predicate on the "role" field.
|
||||||
|
func RoleNotIn(vs ...Role) predicate.AuthRoles {
|
||||||
|
return predicate.AuthRoles(sql.FieldNotIn(FieldRole, vs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasToken applies the HasEdge predicate on the "token" edge.
|
||||||
|
func HasToken() predicate.AuthRoles {
|
||||||
|
return predicate.AuthRoles(func(s *sql.Selector) {
|
||||||
|
step := sqlgraph.NewStep(
|
||||||
|
sqlgraph.From(Table, FieldID),
|
||||||
|
sqlgraph.Edge(sqlgraph.O2O, true, TokenTable, TokenColumn),
|
||||||
|
)
|
||||||
|
sqlgraph.HasNeighbors(s, step)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasTokenWith applies the HasEdge predicate on the "token" edge with a given conditions (other predicates).
|
||||||
|
func HasTokenWith(preds ...predicate.AuthTokens) predicate.AuthRoles {
|
||||||
|
return predicate.AuthRoles(func(s *sql.Selector) {
|
||||||
|
step := newTokenStep()
|
||||||
|
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.AuthRoles) predicate.AuthRoles {
|
||||||
|
return predicate.AuthRoles(func(s *sql.Selector) {
|
||||||
|
s1 := s.Clone().SetP(nil)
|
||||||
|
for _, p := range predicates {
|
||||||
|
p(s1)
|
||||||
|
}
|
||||||
|
s.Where(s1.P())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Or groups predicates with the OR operator between them.
|
||||||
|
func Or(predicates ...predicate.AuthRoles) predicate.AuthRoles {
|
||||||
|
return predicate.AuthRoles(func(s *sql.Selector) {
|
||||||
|
s1 := s.Clone().SetP(nil)
|
||||||
|
for i, p := range predicates {
|
||||||
|
if i > 0 {
|
||||||
|
s1.Or()
|
||||||
|
}
|
||||||
|
p(s1)
|
||||||
|
}
|
||||||
|
s.Where(s1.P())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not applies the not operator on the given predicate.
|
||||||
|
func Not(p predicate.AuthRoles) predicate.AuthRoles {
|
||||||
|
return predicate.AuthRoles(func(s *sql.Selector) {
|
||||||
|
p(s.Not())
|
||||||
|
})
|
||||||
|
}
|
||||||
240
backend/internal/data/ent/authroles_create.go
Normal file
240
backend/internal/data/ent/authroles_create.go
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
|
package ent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
|
"entgo.io/ent/schema/field"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AuthRolesCreate is the builder for creating a AuthRoles entity.
|
||||||
|
type AuthRolesCreate struct {
|
||||||
|
config
|
||||||
|
mutation *AuthRolesMutation
|
||||||
|
hooks []Hook
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRole sets the "role" field.
|
||||||
|
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 (arc *AuthRolesCreate) SetNillableRole(a *authroles.Role) *AuthRolesCreate {
|
||||||
|
if a != nil {
|
||||||
|
arc.SetRole(*a)
|
||||||
|
}
|
||||||
|
return arc
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTokenID sets the "token" edge to the AuthTokens entity by ID.
|
||||||
|
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 (arc *AuthRolesCreate) SetNillableTokenID(id *uuid.UUID) *AuthRolesCreate {
|
||||||
|
if id != nil {
|
||||||
|
arc = arc.SetTokenID(*id)
|
||||||
|
}
|
||||||
|
return arc
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetToken sets the "token" edge to the AuthTokens entity.
|
||||||
|
func (arc *AuthRolesCreate) SetToken(a *AuthTokens) *AuthRolesCreate {
|
||||||
|
return arc.SetTokenID(a.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mutation returns the AuthRolesMutation object of the builder.
|
||||||
|
func (arc *AuthRolesCreate) Mutation() *AuthRolesMutation {
|
||||||
|
return arc.mutation
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save creates the AuthRoles in the database.
|
||||||
|
func (arc *AuthRolesCreate) Save(ctx context.Context) (*AuthRoles, error) {
|
||||||
|
arc.defaults()
|
||||||
|
return withHooks(ctx, arc.sqlSave, arc.mutation, arc.hooks)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveX calls Save and panics if Save returns an error.
|
||||||
|
func (arc *AuthRolesCreate) SaveX(ctx context.Context) *AuthRoles {
|
||||||
|
v, err := arc.Save(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exec executes the query.
|
||||||
|
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 (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 (arc *AuthRolesCreate) defaults() {
|
||||||
|
if _, ok := arc.mutation.Role(); !ok {
|
||||||
|
v := authroles.DefaultRole
|
||||||
|
arc.mutation.SetRole(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check runs all checks and user-defined validators on the builder.
|
||||||
|
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 := 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)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (arc *AuthRolesCreate) sqlSave(ctx context.Context) (*AuthRoles, error) {
|
||||||
|
if err := arc.check(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_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}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
id := _spec.ID.Value.(int64)
|
||||||
|
_node.ID = int(id)
|
||||||
|
arc.mutation.id = &_node.ID
|
||||||
|
arc.mutation.done = true
|
||||||
|
return _node, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (arc *AuthRolesCreate) createSpec() (*AuthRoles, *sqlgraph.CreateSpec) {
|
||||||
|
var (
|
||||||
|
_node = &AuthRoles{config: arc.config}
|
||||||
|
_spec = sqlgraph.NewCreateSpec(authroles.Table, sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt))
|
||||||
|
)
|
||||||
|
if value, ok := arc.mutation.Role(); ok {
|
||||||
|
_spec.SetField(authroles.FieldRole, field.TypeEnum, value)
|
||||||
|
_node.Role = value
|
||||||
|
}
|
||||||
|
if nodes := arc.mutation.TokenIDs(); len(nodes) > 0 {
|
||||||
|
edge := &sqlgraph.EdgeSpec{
|
||||||
|
Rel: sqlgraph.O2O,
|
||||||
|
Inverse: true,
|
||||||
|
Table: authroles.TokenTable,
|
||||||
|
Columns: []string{authroles.TokenColumn},
|
||||||
|
Bidi: false,
|
||||||
|
Target: &sqlgraph.EdgeTarget{
|
||||||
|
IDSpec: sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, k := range nodes {
|
||||||
|
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||||
|
}
|
||||||
|
_node.auth_tokens_roles = &nodes[0]
|
||||||
|
_spec.Edges = append(_spec.Edges, edge)
|
||||||
|
}
|
||||||
|
return _node, _spec
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthRolesCreateBulk is the builder for creating many AuthRoles entities in bulk.
|
||||||
|
type AuthRolesCreateBulk struct {
|
||||||
|
config
|
||||||
|
builders []*AuthRolesCreate
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save creates the AuthRoles entities in the database.
|
||||||
|
func (arcb *AuthRolesCreateBulk) Save(ctx context.Context) ([]*AuthRoles, error) {
|
||||||
|
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 := arcb.builders[i]
|
||||||
|
builder.defaults()
|
||||||
|
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
||||||
|
mutation, ok := m.(*AuthRolesMutation)
|
||||||
|
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, 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, arcb.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
|
||||||
|
if specs[i].ID.Value != nil {
|
||||||
|
id := specs[i].ID.Value.(int64)
|
||||||
|
nodes[i].ID = int(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, arcb.builders[0].mutation); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveX is like Save, but panics if an error occurs.
|
||||||
|
func (arcb *AuthRolesCreateBulk) SaveX(ctx context.Context) []*AuthRoles {
|
||||||
|
v, err := arcb.Save(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exec executes the query.
|
||||||
|
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 (arcb *AuthRolesCreateBulk) ExecX(ctx context.Context) {
|
||||||
|
if err := arcb.Exec(ctx); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
88
backend/internal/data/ent/authroles_delete.go
Normal file
88
backend/internal/data/ent/authroles_delete.go
Normal 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/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AuthRolesDelete is the builder for deleting a AuthRoles entity.
|
||||||
|
type AuthRolesDelete struct {
|
||||||
|
config
|
||||||
|
hooks []Hook
|
||||||
|
mutation *AuthRolesMutation
|
||||||
|
}
|
||||||
|
|
||||||
|
// Where appends a list predicates to the AuthRolesDelete builder.
|
||||||
|
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 (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 (ard *AuthRolesDelete) ExecX(ctx context.Context) int {
|
||||||
|
n, err := ard.Exec(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ard *AuthRolesDelete) sqlExec(ctx context.Context) (int, error) {
|
||||||
|
_spec := sqlgraph.NewDeleteSpec(authroles.Table, sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt))
|
||||||
|
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, ard.driver, _spec)
|
||||||
|
if err != nil && sqlgraph.IsConstraintError(err) {
|
||||||
|
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||||
|
}
|
||||||
|
ard.mutation.done = true
|
||||||
|
return affected, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthRolesDeleteOne is the builder for deleting a single AuthRoles entity.
|
||||||
|
type AuthRolesDeleteOne struct {
|
||||||
|
ard *AuthRolesDelete
|
||||||
|
}
|
||||||
|
|
||||||
|
// Where appends a list predicates to the AuthRolesDelete builder.
|
||||||
|
func (ardo *AuthRolesDeleteOne) Where(ps ...predicate.AuthRoles) *AuthRolesDeleteOne {
|
||||||
|
ardo.ard.mutation.Where(ps...)
|
||||||
|
return ardo
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exec executes the deletion query.
|
||||||
|
func (ardo *AuthRolesDeleteOne) Exec(ctx context.Context) error {
|
||||||
|
n, err := ardo.ard.Exec(ctx)
|
||||||
|
switch {
|
||||||
|
case err != nil:
|
||||||
|
return err
|
||||||
|
case n == 0:
|
||||||
|
return &NotFoundError{authroles.Label}
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecX is like Exec, but panics if an error occurs.
|
||||||
|
func (ardo *AuthRolesDeleteOne) ExecX(ctx context.Context) {
|
||||||
|
if err := ardo.Exec(ctx); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
614
backend/internal/data/ent/authroles_query.go
Normal file
614
backend/internal/data/ent/authroles_query.go
Normal file
@@ -0,0 +1,614 @@
|
|||||||
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
|
package ent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"entgo.io/ent/dialect/sql"
|
||||||
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
|
"entgo.io/ent/schema/field"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AuthRolesQuery is the builder for querying AuthRoles entities.
|
||||||
|
type AuthRolesQuery struct {
|
||||||
|
config
|
||||||
|
ctx *QueryContext
|
||||||
|
order []authroles.OrderOption
|
||||||
|
inters []Interceptor
|
||||||
|
predicates []predicate.AuthRoles
|
||||||
|
withToken *AuthTokensQuery
|
||||||
|
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 AuthRolesQuery builder.
|
||||||
|
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 (arq *AuthRolesQuery) Limit(limit int) *AuthRolesQuery {
|
||||||
|
arq.ctx.Limit = &limit
|
||||||
|
return arq
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offset to start from.
|
||||||
|
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 (arq *AuthRolesQuery) Unique(unique bool) *AuthRolesQuery {
|
||||||
|
arq.ctx.Unique = &unique
|
||||||
|
return arq
|
||||||
|
}
|
||||||
|
|
||||||
|
// Order specifies how the records should be ordered.
|
||||||
|
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 (arq *AuthRolesQuery) QueryToken() *AuthTokensQuery {
|
||||||
|
query := (&AuthTokensClient{config: arq.config}).Query()
|
||||||
|
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
||||||
|
if err := arq.prepareQuery(ctx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
selector := arq.sqlQuery(ctx)
|
||||||
|
if err := selector.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
step := sqlgraph.NewStep(
|
||||||
|
sqlgraph.From(authroles.Table, authroles.FieldID, selector),
|
||||||
|
sqlgraph.To(authtokens.Table, authtokens.FieldID),
|
||||||
|
sqlgraph.Edge(sqlgraph.O2O, true, authroles.TokenTable, authroles.TokenColumn),
|
||||||
|
)
|
||||||
|
fromU = sqlgraph.SetNeighbors(arq.driver.Dialect(), step)
|
||||||
|
return fromU, nil
|
||||||
|
}
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
|
||||||
|
// First returns the first AuthRoles entity from the query.
|
||||||
|
// Returns a *NotFoundError when no AuthRoles was found.
|
||||||
|
func (arq *AuthRolesQuery) First(ctx context.Context) (*AuthRoles, error) {
|
||||||
|
nodes, err := arq.Limit(1).All(setContextOp(ctx, arq.ctx, "First"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(nodes) == 0 {
|
||||||
|
return nil, &NotFoundError{authroles.Label}
|
||||||
|
}
|
||||||
|
return nodes[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FirstX is like First, but panics if an error occurs.
|
||||||
|
func (arq *AuthRolesQuery) FirstX(ctx context.Context) *AuthRoles {
|
||||||
|
node, err := arq.First(ctx)
|
||||||
|
if err != nil && !IsNotFound(err) {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
// FirstID returns the first AuthRoles ID from the query.
|
||||||
|
// Returns a *NotFoundError when no AuthRoles ID was found.
|
||||||
|
func (arq *AuthRolesQuery) FirstID(ctx context.Context) (id int, err error) {
|
||||||
|
var ids []int
|
||||||
|
if ids, err = arq.Limit(1).IDs(setContextOp(ctx, arq.ctx, "FirstID")); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(ids) == 0 {
|
||||||
|
err = &NotFoundError{authroles.Label}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return ids[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FirstIDX is like FirstID, but panics if an error occurs.
|
||||||
|
func (arq *AuthRolesQuery) FirstIDX(ctx context.Context) int {
|
||||||
|
id, err := arq.FirstID(ctx)
|
||||||
|
if err != nil && !IsNotFound(err) {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (arq *AuthRolesQuery) Only(ctx context.Context) (*AuthRoles, error) {
|
||||||
|
nodes, err := arq.Limit(2).All(setContextOp(ctx, arq.ctx, "Only"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
switch len(nodes) {
|
||||||
|
case 1:
|
||||||
|
return nodes[0], nil
|
||||||
|
case 0:
|
||||||
|
return nil, &NotFoundError{authroles.Label}
|
||||||
|
default:
|
||||||
|
return nil, &NotSingularError{authroles.Label}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnlyX is like Only, but panics if an error occurs.
|
||||||
|
func (arq *AuthRolesQuery) OnlyX(ctx context.Context) *AuthRoles {
|
||||||
|
node, err := arq.Only(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (arq *AuthRolesQuery) OnlyID(ctx context.Context) (id int, err error) {
|
||||||
|
var ids []int
|
||||||
|
if ids, err = arq.Limit(2).IDs(setContextOp(ctx, arq.ctx, "OnlyID")); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch len(ids) {
|
||||||
|
case 1:
|
||||||
|
id = ids[0]
|
||||||
|
case 0:
|
||||||
|
err = &NotFoundError{authroles.Label}
|
||||||
|
default:
|
||||||
|
err = &NotSingularError{authroles.Label}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnlyIDX is like OnlyID, but panics if an error occurs.
|
||||||
|
func (arq *AuthRolesQuery) OnlyIDX(ctx context.Context) int {
|
||||||
|
id, err := arq.OnlyID(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
// All executes the query and returns a list of AuthRolesSlice.
|
||||||
|
func (arq *AuthRolesQuery) All(ctx context.Context) ([]*AuthRoles, error) {
|
||||||
|
ctx = setContextOp(ctx, arq.ctx, "All")
|
||||||
|
if err := arq.prepareQuery(ctx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
qr := querierAll[[]*AuthRoles, *AuthRolesQuery]()
|
||||||
|
return withInterceptors[[]*AuthRoles](ctx, arq, qr, arq.inters)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllX is like All, but panics if an error occurs.
|
||||||
|
func (arq *AuthRolesQuery) AllX(ctx context.Context) []*AuthRoles {
|
||||||
|
nodes, err := arq.All(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDs executes the query and returns a list of AuthRoles IDs.
|
||||||
|
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, arq.ctx, "IDs")
|
||||||
|
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 (arq *AuthRolesQuery) IDsX(ctx context.Context) []int {
|
||||||
|
ids, err := arq.IDs(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return ids
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count returns the count of the given query.
|
||||||
|
func (arq *AuthRolesQuery) Count(ctx context.Context) (int, error) {
|
||||||
|
ctx = setContextOp(ctx, arq.ctx, "Count")
|
||||||
|
if err := arq.prepareQuery(ctx); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return withInterceptors[int](ctx, arq, querierCount[*AuthRolesQuery](), arq.inters)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountX is like Count, but panics if an error occurs.
|
||||||
|
func (arq *AuthRolesQuery) CountX(ctx context.Context) int {
|
||||||
|
count, err := arq.Count(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exist returns true if the query has elements in the graph.
|
||||||
|
func (arq *AuthRolesQuery) Exist(ctx context.Context) (bool, error) {
|
||||||
|
ctx = setContextOp(ctx, arq.ctx, "Exist")
|
||||||
|
switch _, err := arq.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 (arq *AuthRolesQuery) ExistX(ctx context.Context) bool {
|
||||||
|
exist, err := arq.Exist(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return exist
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (arq *AuthRolesQuery) Clone() *AuthRolesQuery {
|
||||||
|
if arq == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &AuthRolesQuery{
|
||||||
|
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: 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 (arq *AuthRolesQuery) WithToken(opts ...func(*AuthTokensQuery)) *AuthRolesQuery {
|
||||||
|
query := (&AuthTokensClient{config: arq.config}).Query()
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(query)
|
||||||
|
}
|
||||||
|
arq.withToken = query
|
||||||
|
return arq
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
// Role authroles.Role `json:"role,omitempty"`
|
||||||
|
// Count int `json:"count,omitempty"`
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// client.AuthRoles.Query().
|
||||||
|
// GroupBy(authroles.FieldRole).
|
||||||
|
// Aggregate(ent.Count()).
|
||||||
|
// Scan(ctx, &v)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
// Role authroles.Role `json:"role,omitempty"`
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// client.AuthRoles.Query().
|
||||||
|
// Select(authroles.FieldRole).
|
||||||
|
// Scan(ctx, &v)
|
||||||
|
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 = &arq.ctx.Fields, sbuild.Scan
|
||||||
|
return sbuild
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aggregate returns a AuthRolesSelect configured with the given aggregations.
|
||||||
|
func (arq *AuthRolesQuery) Aggregate(fns ...AggregateFunc) *AuthRolesSelect {
|
||||||
|
return arq.Select().Aggregate(fns...)
|
||||||
|
}
|
||||||
|
|
||||||
|
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, arq); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 arq.path != nil {
|
||||||
|
prev, err := arq.path(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
arq.sql = prev
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (arq *AuthRolesQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*AuthRoles, error) {
|
||||||
|
var (
|
||||||
|
nodes = []*AuthRoles{}
|
||||||
|
withFKs = arq.withFKs
|
||||||
|
_spec = arq.querySpec()
|
||||||
|
loadedTypes = [1]bool{
|
||||||
|
arq.withToken != nil,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if arq.withToken != nil {
|
||||||
|
withFKs = true
|
||||||
|
}
|
||||||
|
if withFKs {
|
||||||
|
_spec.Node.Columns = append(_spec.Node.Columns, authroles.ForeignKeys...)
|
||||||
|
}
|
||||||
|
_spec.ScanValues = func(columns []string) ([]any, error) {
|
||||||
|
return (*AuthRoles).scanValues(nil, columns)
|
||||||
|
}
|
||||||
|
_spec.Assign = func(columns []string, values []any) error {
|
||||||
|
node := &AuthRoles{config: arq.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, arq.driver, _spec); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(nodes) == 0 {
|
||||||
|
return 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
if nodes[i].auth_tokens_roles == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fk := *nodes[i].auth_tokens_roles
|
||||||
|
if _, ok := nodeids[fk]; !ok {
|
||||||
|
ids = append(ids, fk)
|
||||||
|
}
|
||||||
|
nodeids[fk] = append(nodeids[fk], nodes[i])
|
||||||
|
}
|
||||||
|
if len(ids) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
query.Where(authtokens.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 "auth_tokens_roles" returned %v`, n.ID)
|
||||||
|
}
|
||||||
|
for i := range nodes {
|
||||||
|
assign(nodes[i], n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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, arq.driver, _spec)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (arq *AuthRolesQuery) querySpec() *sqlgraph.QuerySpec {
|
||||||
|
_spec := sqlgraph.NewQuerySpec(authroles.Table, authroles.Columns, sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt))
|
||||||
|
_spec.From = arq.sql
|
||||||
|
if unique := arq.ctx.Unique; unique != nil {
|
||||||
|
_spec.Unique = *unique
|
||||||
|
} else if arq.path != nil {
|
||||||
|
_spec.Unique = true
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
if fields[i] != authroles.FieldID {
|
||||||
|
_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ps := arq.predicates; len(ps) > 0 {
|
||||||
|
_spec.Predicate = func(selector *sql.Selector) {
|
||||||
|
for i := range ps {
|
||||||
|
ps[i](selector)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if limit := arq.ctx.Limit; limit != nil {
|
||||||
|
_spec.Limit = *limit
|
||||||
|
}
|
||||||
|
if offset := arq.ctx.Offset; offset != nil {
|
||||||
|
_spec.Offset = *offset
|
||||||
|
}
|
||||||
|
if ps := arq.order; len(ps) > 0 {
|
||||||
|
_spec.Order = func(selector *sql.Selector) {
|
||||||
|
for i := range ps {
|
||||||
|
ps[i](selector)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _spec
|
||||||
|
}
|
||||||
|
|
||||||
|
func (arq *AuthRolesQuery) sqlQuery(ctx context.Context) *sql.Selector {
|
||||||
|
builder := sql.Dialect(arq.driver.Dialect())
|
||||||
|
t1 := builder.Table(authroles.Table)
|
||||||
|
columns := arq.ctx.Fields
|
||||||
|
if len(columns) == 0 {
|
||||||
|
columns = authroles.Columns
|
||||||
|
}
|
||||||
|
selector := builder.Select(t1.Columns(columns...)...).From(t1)
|
||||||
|
if arq.sql != nil {
|
||||||
|
selector = arq.sql
|
||||||
|
selector.Select(selector.Columns(columns...)...)
|
||||||
|
}
|
||||||
|
if arq.ctx.Unique != nil && *arq.ctx.Unique {
|
||||||
|
selector.Distinct()
|
||||||
|
}
|
||||||
|
for _, p := range arq.predicates {
|
||||||
|
p(selector)
|
||||||
|
}
|
||||||
|
for _, p := range arq.order {
|
||||||
|
p(selector)
|
||||||
|
}
|
||||||
|
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 := arq.ctx.Limit; limit != nil {
|
||||||
|
selector.Limit(*limit)
|
||||||
|
}
|
||||||
|
return selector
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthRolesGroupBy is the group-by builder for AuthRoles entities.
|
||||||
|
type AuthRolesGroupBy struct {
|
||||||
|
selector
|
||||||
|
build *AuthRolesQuery
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aggregate adds the given aggregation functions to the group-by query.
|
||||||
|
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 (argb *AuthRolesGroupBy) Scan(ctx context.Context, v any) error {
|
||||||
|
ctx = setContextOp(ctx, argb.build.ctx, "GroupBy")
|
||||||
|
if err := argb.build.prepareQuery(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return scanWithInterceptors[*AuthRolesQuery, *AuthRolesGroupBy](ctx, argb.build, argb, argb.build.inters, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (argb *AuthRolesGroupBy) sqlScan(ctx context.Context, root *AuthRolesQuery, v any) error {
|
||||||
|
selector := root.sqlQuery(ctx).Select()
|
||||||
|
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(*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(*argb.flds...)...)
|
||||||
|
if err := selector.Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rows := &sql.Rows{}
|
||||||
|
query, args := selector.Query()
|
||||||
|
if err := argb.build.driver.Query(ctx, query, args, rows); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
return sql.ScanSlice(rows, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthRolesSelect is the builder for selecting fields of AuthRoles entities.
|
||||||
|
type AuthRolesSelect struct {
|
||||||
|
*AuthRolesQuery
|
||||||
|
selector
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aggregate adds the given aggregation functions to the selector query.
|
||||||
|
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 (ars *AuthRolesSelect) Scan(ctx context.Context, v any) error {
|
||||||
|
ctx = setContextOp(ctx, ars.ctx, "Select")
|
||||||
|
if err := ars.prepareQuery(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return scanWithInterceptors[*AuthRolesQuery, *AuthRolesSelect](ctx, ars.AuthRolesQuery, ars, ars.inters, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ars *AuthRolesSelect) sqlScan(ctx context.Context, root *AuthRolesQuery, v any) error {
|
||||||
|
selector := root.sqlQuery(ctx)
|
||||||
|
aggregation := make([]string, 0, len(ars.fns))
|
||||||
|
for _, fn := range ars.fns {
|
||||||
|
aggregation = append(aggregation, fn(selector))
|
||||||
|
}
|
||||||
|
switch n := len(*ars.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 := ars.driver.Query(ctx, query, args, rows); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
return sql.ScanSlice(rows, v)
|
||||||
|
}
|
||||||
345
backend/internal/data/ent/authroles_update.go
Normal file
345
backend/internal/data/ent/authroles_update.go
Normal file
@@ -0,0 +1,345 @@
|
|||||||
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
|
package ent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"entgo.io/ent/dialect/sql"
|
||||||
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
|
"entgo.io/ent/schema/field"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AuthRolesUpdate is the builder for updating AuthRoles entities.
|
||||||
|
type AuthRolesUpdate struct {
|
||||||
|
config
|
||||||
|
hooks []Hook
|
||||||
|
mutation *AuthRolesMutation
|
||||||
|
}
|
||||||
|
|
||||||
|
// Where appends a list predicates to the AuthRolesUpdate builder.
|
||||||
|
func (aru *AuthRolesUpdate) Where(ps ...predicate.AuthRoles) *AuthRolesUpdate {
|
||||||
|
aru.mutation.Where(ps...)
|
||||||
|
return aru
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRole sets the "role" field.
|
||||||
|
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 (aru *AuthRolesUpdate) SetNillableRole(a *authroles.Role) *AuthRolesUpdate {
|
||||||
|
if a != nil {
|
||||||
|
aru.SetRole(*a)
|
||||||
|
}
|
||||||
|
return aru
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTokenID sets the "token" edge to the AuthTokens entity by ID.
|
||||||
|
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 (aru *AuthRolesUpdate) SetNillableTokenID(id *uuid.UUID) *AuthRolesUpdate {
|
||||||
|
if id != nil {
|
||||||
|
aru = aru.SetTokenID(*id)
|
||||||
|
}
|
||||||
|
return aru
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetToken sets the "token" edge to the AuthTokens entity.
|
||||||
|
func (aru *AuthRolesUpdate) SetToken(a *AuthTokens) *AuthRolesUpdate {
|
||||||
|
return aru.SetTokenID(a.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mutation returns the AuthRolesMutation object of the builder.
|
||||||
|
func (aru *AuthRolesUpdate) Mutation() *AuthRolesMutation {
|
||||||
|
return aru.mutation
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearToken clears the "token" edge to the AuthTokens entity.
|
||||||
|
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 (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 (aru *AuthRolesUpdate) SaveX(ctx context.Context) int {
|
||||||
|
affected, err := aru.Save(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exec executes the query.
|
||||||
|
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 (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 (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)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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 := aru.mutation.predicates; len(ps) > 0 {
|
||||||
|
_spec.Predicate = func(selector *sql.Selector) {
|
||||||
|
for i := range ps {
|
||||||
|
ps[i](selector)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if value, ok := aru.mutation.Role(); ok {
|
||||||
|
_spec.SetField(authroles.FieldRole, field.TypeEnum, value)
|
||||||
|
}
|
||||||
|
if aru.mutation.TokenCleared() {
|
||||||
|
edge := &sqlgraph.EdgeSpec{
|
||||||
|
Rel: sqlgraph.O2O,
|
||||||
|
Inverse: true,
|
||||||
|
Table: authroles.TokenTable,
|
||||||
|
Columns: []string{authroles.TokenColumn},
|
||||||
|
Bidi: false,
|
||||||
|
Target: &sqlgraph.EdgeTarget{
|
||||||
|
IDSpec: sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||||
|
}
|
||||||
|
if nodes := aru.mutation.TokenIDs(); len(nodes) > 0 {
|
||||||
|
edge := &sqlgraph.EdgeSpec{
|
||||||
|
Rel: sqlgraph.O2O,
|
||||||
|
Inverse: true,
|
||||||
|
Table: authroles.TokenTable,
|
||||||
|
Columns: []string{authroles.TokenColumn},
|
||||||
|
Bidi: false,
|
||||||
|
Target: &sqlgraph.EdgeTarget{
|
||||||
|
IDSpec: sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, k := range nodes {
|
||||||
|
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||||
|
}
|
||||||
|
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||||
|
}
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
aru.mutation.done = true
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthRolesUpdateOne is the builder for updating a single AuthRoles entity.
|
||||||
|
type AuthRolesUpdateOne struct {
|
||||||
|
config
|
||||||
|
fields []string
|
||||||
|
hooks []Hook
|
||||||
|
mutation *AuthRolesMutation
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRole sets the "role" field.
|
||||||
|
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 (aruo *AuthRolesUpdateOne) SetNillableRole(a *authroles.Role) *AuthRolesUpdateOne {
|
||||||
|
if a != nil {
|
||||||
|
aruo.SetRole(*a)
|
||||||
|
}
|
||||||
|
return aruo
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTokenID sets the "token" edge to the AuthTokens entity by ID.
|
||||||
|
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 (aruo *AuthRolesUpdateOne) SetNillableTokenID(id *uuid.UUID) *AuthRolesUpdateOne {
|
||||||
|
if id != nil {
|
||||||
|
aruo = aruo.SetTokenID(*id)
|
||||||
|
}
|
||||||
|
return aruo
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetToken sets the "token" edge to the AuthTokens entity.
|
||||||
|
func (aruo *AuthRolesUpdateOne) SetToken(a *AuthTokens) *AuthRolesUpdateOne {
|
||||||
|
return aruo.SetTokenID(a.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mutation returns the AuthRolesMutation object of the builder.
|
||||||
|
func (aruo *AuthRolesUpdateOne) Mutation() *AuthRolesMutation {
|
||||||
|
return aruo.mutation
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearToken clears the "token" edge to the AuthTokens entity.
|
||||||
|
func (aruo *AuthRolesUpdateOne) ClearToken() *AuthRolesUpdateOne {
|
||||||
|
aruo.mutation.ClearToken()
|
||||||
|
return aruo
|
||||||
|
}
|
||||||
|
|
||||||
|
// Where appends a list predicates to the AuthRolesUpdate builder.
|
||||||
|
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 (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 (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 (aruo *AuthRolesUpdateOne) SaveX(ctx context.Context) *AuthRoles {
|
||||||
|
node, err := aruo.Save(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exec executes the query on the entity.
|
||||||
|
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 (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 (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)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 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 := 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 := 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 {
|
||||||
|
if !authroles.ValidColumn(f) {
|
||||||
|
return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
|
||||||
|
}
|
||||||
|
if f != authroles.FieldID {
|
||||||
|
_spec.Node.Columns = append(_spec.Node.Columns, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ps := aruo.mutation.predicates; len(ps) > 0 {
|
||||||
|
_spec.Predicate = func(selector *sql.Selector) {
|
||||||
|
for i := range ps {
|
||||||
|
ps[i](selector)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if value, ok := aruo.mutation.Role(); ok {
|
||||||
|
_spec.SetField(authroles.FieldRole, field.TypeEnum, value)
|
||||||
|
}
|
||||||
|
if aruo.mutation.TokenCleared() {
|
||||||
|
edge := &sqlgraph.EdgeSpec{
|
||||||
|
Rel: sqlgraph.O2O,
|
||||||
|
Inverse: true,
|
||||||
|
Table: authroles.TokenTable,
|
||||||
|
Columns: []string{authroles.TokenColumn},
|
||||||
|
Bidi: false,
|
||||||
|
Target: &sqlgraph.EdgeTarget{
|
||||||
|
IDSpec: sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||||
|
}
|
||||||
|
if nodes := aruo.mutation.TokenIDs(); len(nodes) > 0 {
|
||||||
|
edge := &sqlgraph.EdgeSpec{
|
||||||
|
Rel: sqlgraph.O2O,
|
||||||
|
Inverse: true,
|
||||||
|
Table: authroles.TokenTable,
|
||||||
|
Columns: []string{authroles.TokenColumn},
|
||||||
|
Bidi: false,
|
||||||
|
Target: &sqlgraph.EdgeTarget{
|
||||||
|
IDSpec: sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, k := range nodes {
|
||||||
|
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||||
|
}
|
||||||
|
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
||||||
|
}
|
||||||
|
_node = &AuthRoles{config: aruo.config}
|
||||||
|
_spec.Assign = _node.assignValues
|
||||||
|
_spec.ScanValues = _node.scanValues
|
||||||
|
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) {
|
||||||
|
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
aruo.mutation.done = true
|
||||||
|
return _node, nil
|
||||||
|
}
|
||||||
@@ -7,8 +7,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"entgo.io/ent"
|
||||||
"entgo.io/ent/dialect/sql"
|
"entgo.io/ent/dialect/sql"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/user"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/user"
|
||||||
)
|
)
|
||||||
@@ -30,15 +32,18 @@ type AuthTokens struct {
|
|||||||
// The values are being populated by the AuthTokensQuery when eager-loading is set.
|
// The values are being populated by the AuthTokensQuery when eager-loading is set.
|
||||||
Edges AuthTokensEdges `json:"edges"`
|
Edges AuthTokensEdges `json:"edges"`
|
||||||
user_auth_tokens *uuid.UUID
|
user_auth_tokens *uuid.UUID
|
||||||
|
selectValues sql.SelectValues
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthTokensEdges holds the relations/edges for other nodes in the graph.
|
// AuthTokensEdges holds the relations/edges for other nodes in the graph.
|
||||||
type AuthTokensEdges struct {
|
type AuthTokensEdges struct {
|
||||||
// User holds the value of the user edge.
|
// User holds the value of the user edge.
|
||||||
User *User `json:"user,omitempty"`
|
User *User `json:"user,omitempty"`
|
||||||
|
// Roles holds the value of the roles edge.
|
||||||
|
Roles *AuthRoles `json:"roles,omitempty"`
|
||||||
// loadedTypes holds the information for reporting if a
|
// loadedTypes holds the information for reporting if a
|
||||||
// type was loaded (or requested) in eager-loading or not.
|
// type was loaded (or requested) in eager-loading or not.
|
||||||
loadedTypes [1]bool
|
loadedTypes [2]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserOrErr returns the User value or an error if the edge
|
// UserOrErr returns the User value or an error if the edge
|
||||||
@@ -54,6 +59,19 @@ func (e AuthTokensEdges) UserOrErr() (*User, error) {
|
|||||||
return nil, &NotLoadedError{edge: "user"}
|
return nil, &NotLoadedError{edge: "user"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RolesOrErr returns the Roles value or an error if the edge
|
||||||
|
// was not loaded in eager-loading, or loaded but was not found.
|
||||||
|
func (e AuthTokensEdges) RolesOrErr() (*AuthRoles, error) {
|
||||||
|
if e.loadedTypes[1] {
|
||||||
|
if e.Roles == nil {
|
||||||
|
// Edge was loaded but was not found.
|
||||||
|
return nil, &NotFoundError{label: authroles.Label}
|
||||||
|
}
|
||||||
|
return e.Roles, nil
|
||||||
|
}
|
||||||
|
return nil, &NotLoadedError{edge: "roles"}
|
||||||
|
}
|
||||||
|
|
||||||
// scanValues returns the types for scanning values from sql.Rows.
|
// scanValues returns the types for scanning values from sql.Rows.
|
||||||
func (*AuthTokens) scanValues(columns []string) ([]any, error) {
|
func (*AuthTokens) scanValues(columns []string) ([]any, error) {
|
||||||
values := make([]any, len(columns))
|
values := make([]any, len(columns))
|
||||||
@@ -68,7 +86,7 @@ func (*AuthTokens) scanValues(columns []string) ([]any, error) {
|
|||||||
case authtokens.ForeignKeys[0]: // user_auth_tokens
|
case authtokens.ForeignKeys[0]: // user_auth_tokens
|
||||||
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
|
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unexpected column %q for type AuthTokens", columns[i])
|
values[i] = new(sql.UnknownType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return values, nil
|
return values, nil
|
||||||
@@ -119,21 +137,34 @@ func (at *AuthTokens) assignValues(columns []string, values []any) error {
|
|||||||
at.user_auth_tokens = new(uuid.UUID)
|
at.user_auth_tokens = new(uuid.UUID)
|
||||||
*at.user_auth_tokens = *value.S.(*uuid.UUID)
|
*at.user_auth_tokens = *value.S.(*uuid.UUID)
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
at.selectValues.Set(columns[i], values[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Value returns the ent.Value that was dynamically selected and assigned to the AuthTokens.
|
||||||
|
// This includes values selected through modifiers, order, etc.
|
||||||
|
func (at *AuthTokens) Value(name string) (ent.Value, error) {
|
||||||
|
return at.selectValues.Get(name)
|
||||||
|
}
|
||||||
|
|
||||||
// QueryUser queries the "user" edge of the AuthTokens entity.
|
// QueryUser queries the "user" edge of the AuthTokens entity.
|
||||||
func (at *AuthTokens) QueryUser() *UserQuery {
|
func (at *AuthTokens) QueryUser() *UserQuery {
|
||||||
return (&AuthTokensClient{config: at.config}).QueryUser(at)
|
return NewAuthTokensClient(at.config).QueryUser(at)
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryRoles queries the "roles" edge of the AuthTokens entity.
|
||||||
|
func (at *AuthTokens) QueryRoles() *AuthRolesQuery {
|
||||||
|
return NewAuthTokensClient(at.config).QueryRoles(at)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update returns a builder for updating this AuthTokens.
|
// Update returns a builder for updating this AuthTokens.
|
||||||
// Note that you need to call AuthTokens.Unwrap() before calling this method if 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.
|
// was returned from a transaction, and the transaction was committed or rolled back.
|
||||||
func (at *AuthTokens) Update() *AuthTokensUpdateOne {
|
func (at *AuthTokens) Update() *AuthTokensUpdateOne {
|
||||||
return (&AuthTokensClient{config: at.config}).UpdateOne(at)
|
return NewAuthTokensClient(at.config).UpdateOne(at)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unwrap unwraps the AuthTokens entity that was returned from a transaction after it was closed,
|
// Unwrap unwraps the AuthTokens entity that was returned from a transaction after it was closed,
|
||||||
@@ -169,9 +200,3 @@ func (at *AuthTokens) String() string {
|
|||||||
|
|
||||||
// AuthTokensSlice is a parsable slice of AuthTokens.
|
// AuthTokensSlice is a parsable slice of AuthTokens.
|
||||||
type AuthTokensSlice []*AuthTokens
|
type AuthTokensSlice []*AuthTokens
|
||||||
|
|
||||||
func (at AuthTokensSlice) config(cfg config) {
|
|
||||||
for _i := range at {
|
|
||||||
at[_i].config = cfg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ package authtokens
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"entgo.io/ent/dialect/sql"
|
||||||
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,6 +25,8 @@ const (
|
|||||||
FieldExpiresAt = "expires_at"
|
FieldExpiresAt = "expires_at"
|
||||||
// EdgeUser holds the string denoting the user edge name in mutations.
|
// EdgeUser holds the string denoting the user edge name in mutations.
|
||||||
EdgeUser = "user"
|
EdgeUser = "user"
|
||||||
|
// EdgeRoles holds the string denoting the roles edge name in mutations.
|
||||||
|
EdgeRoles = "roles"
|
||||||
// Table holds the table name of the authtokens in the database.
|
// Table holds the table name of the authtokens in the database.
|
||||||
Table = "auth_tokens"
|
Table = "auth_tokens"
|
||||||
// UserTable is the table that holds the user relation/edge.
|
// UserTable is the table that holds the user relation/edge.
|
||||||
@@ -32,6 +36,13 @@ const (
|
|||||||
UserInverseTable = "users"
|
UserInverseTable = "users"
|
||||||
// UserColumn is the table column denoting the user relation/edge.
|
// UserColumn is the table column denoting the user relation/edge.
|
||||||
UserColumn = "user_auth_tokens"
|
UserColumn = "user_auth_tokens"
|
||||||
|
// RolesTable is the table that holds the roles relation/edge.
|
||||||
|
RolesTable = "auth_roles"
|
||||||
|
// RolesInverseTable is the table name for the AuthRoles entity.
|
||||||
|
// It exists in this package in order to avoid circular dependency with the "authroles" package.
|
||||||
|
RolesInverseTable = "auth_roles"
|
||||||
|
// RolesColumn is the table column denoting the roles relation/edge.
|
||||||
|
RolesColumn = "auth_tokens_roles"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Columns holds all SQL columns for authtokens fields.
|
// Columns holds all SQL columns for authtokens fields.
|
||||||
@@ -76,3 +87,54 @@ var (
|
|||||||
// DefaultID holds the default value on creation for the "id" field.
|
// DefaultID holds the default value on creation for the "id" field.
|
||||||
DefaultID func() uuid.UUID
|
DefaultID func() uuid.UUID
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// OrderOption defines the ordering options for the AuthTokens queries.
|
||||||
|
type OrderOption func(*sql.Selector)
|
||||||
|
|
||||||
|
// ByID orders the results by the id field.
|
||||||
|
func ByID(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldID, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByCreatedAt orders the results by the created_at field.
|
||||||
|
func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByUpdatedAt orders the results by the updated_at field.
|
||||||
|
func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByExpiresAt orders the results by the expires_at field.
|
||||||
|
func ByExpiresAt(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldExpiresAt, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByUserField orders the results by user field.
|
||||||
|
func ByUserField(field string, opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return func(s *sql.Selector) {
|
||||||
|
sqlgraph.OrderByNeighborTerms(s, newUserStep(), sql.OrderByField(field, opts...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByRolesField orders the results by roles field.
|
||||||
|
func ByRolesField(field string, opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return func(s *sql.Selector) {
|
||||||
|
sqlgraph.OrderByNeighborTerms(s, newRolesStep(), sql.OrderByField(field, opts...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func newUserStep() *sqlgraph.Step {
|
||||||
|
return sqlgraph.NewStep(
|
||||||
|
sqlgraph.From(Table, FieldID),
|
||||||
|
sqlgraph.To(UserInverseTable, FieldID),
|
||||||
|
sqlgraph.Edge(sqlgraph.M2O, true, UserTable, UserColumn),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
func newRolesStep() *sqlgraph.Step {
|
||||||
|
return sqlgraph.NewStep(
|
||||||
|
sqlgraph.From(Table, FieldID),
|
||||||
|
sqlgraph.To(RolesInverseTable, FieldID),
|
||||||
|
sqlgraph.Edge(sqlgraph.O2O, false, RolesTable, RolesColumn),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,357 +13,227 @@ import (
|
|||||||
|
|
||||||
// ID filters vertices based on their ID field.
|
// ID filters vertices based on their ID field.
|
||||||
func ID(id uuid.UUID) predicate.AuthTokens {
|
func ID(id uuid.UUID) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldEQ(FieldID, id))
|
||||||
s.Where(sql.EQ(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDEQ applies the EQ predicate on the ID field.
|
// IDEQ applies the EQ predicate on the ID field.
|
||||||
func IDEQ(id uuid.UUID) predicate.AuthTokens {
|
func IDEQ(id uuid.UUID) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldEQ(FieldID, id))
|
||||||
s.Where(sql.EQ(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDNEQ applies the NEQ predicate on the ID field.
|
// IDNEQ applies the NEQ predicate on the ID field.
|
||||||
func IDNEQ(id uuid.UUID) predicate.AuthTokens {
|
func IDNEQ(id uuid.UUID) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldNEQ(FieldID, id))
|
||||||
s.Where(sql.NEQ(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDIn applies the In predicate on the ID field.
|
// IDIn applies the In predicate on the ID field.
|
||||||
func IDIn(ids ...uuid.UUID) predicate.AuthTokens {
|
func IDIn(ids ...uuid.UUID) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldIn(FieldID, ids...))
|
||||||
v := make([]any, len(ids))
|
|
||||||
for i := range v {
|
|
||||||
v[i] = ids[i]
|
|
||||||
}
|
|
||||||
s.Where(sql.In(s.C(FieldID), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDNotIn applies the NotIn predicate on the ID field.
|
// IDNotIn applies the NotIn predicate on the ID field.
|
||||||
func IDNotIn(ids ...uuid.UUID) predicate.AuthTokens {
|
func IDNotIn(ids ...uuid.UUID) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldNotIn(FieldID, ids...))
|
||||||
v := make([]any, len(ids))
|
|
||||||
for i := range v {
|
|
||||||
v[i] = ids[i]
|
|
||||||
}
|
|
||||||
s.Where(sql.NotIn(s.C(FieldID), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDGT applies the GT predicate on the ID field.
|
// IDGT applies the GT predicate on the ID field.
|
||||||
func IDGT(id uuid.UUID) predicate.AuthTokens {
|
func IDGT(id uuid.UUID) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldGT(FieldID, id))
|
||||||
s.Where(sql.GT(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDGTE applies the GTE predicate on the ID field.
|
// IDGTE applies the GTE predicate on the ID field.
|
||||||
func IDGTE(id uuid.UUID) predicate.AuthTokens {
|
func IDGTE(id uuid.UUID) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldGTE(FieldID, id))
|
||||||
s.Where(sql.GTE(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDLT applies the LT predicate on the ID field.
|
// IDLT applies the LT predicate on the ID field.
|
||||||
func IDLT(id uuid.UUID) predicate.AuthTokens {
|
func IDLT(id uuid.UUID) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldLT(FieldID, id))
|
||||||
s.Where(sql.LT(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDLTE applies the LTE predicate on the ID field.
|
// IDLTE applies the LTE predicate on the ID field.
|
||||||
func IDLTE(id uuid.UUID) predicate.AuthTokens {
|
func IDLTE(id uuid.UUID) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldLTE(FieldID, id))
|
||||||
s.Where(sql.LTE(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
|
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
|
||||||
func CreatedAt(v time.Time) predicate.AuthTokens {
|
func CreatedAt(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldEQ(FieldCreatedAt, v))
|
||||||
s.Where(sql.EQ(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ.
|
// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ.
|
||||||
func UpdatedAt(v time.Time) predicate.AuthTokens {
|
func UpdatedAt(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldEQ(FieldUpdatedAt, v))
|
||||||
s.Where(sql.EQ(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Token applies equality check predicate on the "token" field. It's identical to TokenEQ.
|
// Token applies equality check predicate on the "token" field. It's identical to TokenEQ.
|
||||||
func Token(v []byte) predicate.AuthTokens {
|
func Token(v []byte) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldEQ(FieldToken, v))
|
||||||
s.Where(sql.EQ(s.C(FieldToken), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExpiresAt applies equality check predicate on the "expires_at" field. It's identical to ExpiresAtEQ.
|
// ExpiresAt applies equality check predicate on the "expires_at" field. It's identical to ExpiresAtEQ.
|
||||||
func ExpiresAt(v time.Time) predicate.AuthTokens {
|
func ExpiresAt(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldEQ(FieldExpiresAt, v))
|
||||||
s.Where(sql.EQ(s.C(FieldExpiresAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
||||||
func CreatedAtEQ(v time.Time) predicate.AuthTokens {
|
func CreatedAtEQ(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldEQ(FieldCreatedAt, v))
|
||||||
s.Where(sql.EQ(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
|
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
|
||||||
func CreatedAtNEQ(v time.Time) predicate.AuthTokens {
|
func CreatedAtNEQ(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldNEQ(FieldCreatedAt, v))
|
||||||
s.Where(sql.NEQ(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtIn applies the In predicate on the "created_at" field.
|
// CreatedAtIn applies the In predicate on the "created_at" field.
|
||||||
func CreatedAtIn(vs ...time.Time) predicate.AuthTokens {
|
func CreatedAtIn(vs ...time.Time) predicate.AuthTokens {
|
||||||
v := make([]any, len(vs))
|
return predicate.AuthTokens(sql.FieldIn(FieldCreatedAt, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.In(s.C(FieldCreatedAt), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
|
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
|
||||||
func CreatedAtNotIn(vs ...time.Time) predicate.AuthTokens {
|
func CreatedAtNotIn(vs ...time.Time) predicate.AuthTokens {
|
||||||
v := make([]any, len(vs))
|
return predicate.AuthTokens(sql.FieldNotIn(FieldCreatedAt, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.NotIn(s.C(FieldCreatedAt), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtGT applies the GT predicate on the "created_at" field.
|
// CreatedAtGT applies the GT predicate on the "created_at" field.
|
||||||
func CreatedAtGT(v time.Time) predicate.AuthTokens {
|
func CreatedAtGT(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldGT(FieldCreatedAt, v))
|
||||||
s.Where(sql.GT(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
|
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
|
||||||
func CreatedAtGTE(v time.Time) predicate.AuthTokens {
|
func CreatedAtGTE(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldGTE(FieldCreatedAt, v))
|
||||||
s.Where(sql.GTE(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtLT applies the LT predicate on the "created_at" field.
|
// CreatedAtLT applies the LT predicate on the "created_at" field.
|
||||||
func CreatedAtLT(v time.Time) predicate.AuthTokens {
|
func CreatedAtLT(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldLT(FieldCreatedAt, v))
|
||||||
s.Where(sql.LT(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
|
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
|
||||||
func CreatedAtLTE(v time.Time) predicate.AuthTokens {
|
func CreatedAtLTE(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldLTE(FieldCreatedAt, v))
|
||||||
s.Where(sql.LTE(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
|
// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
|
||||||
func UpdatedAtEQ(v time.Time) predicate.AuthTokens {
|
func UpdatedAtEQ(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldEQ(FieldUpdatedAt, v))
|
||||||
s.Where(sql.EQ(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
|
// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
|
||||||
func UpdatedAtNEQ(v time.Time) predicate.AuthTokens {
|
func UpdatedAtNEQ(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldNEQ(FieldUpdatedAt, v))
|
||||||
s.Where(sql.NEQ(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtIn applies the In predicate on the "updated_at" field.
|
// UpdatedAtIn applies the In predicate on the "updated_at" field.
|
||||||
func UpdatedAtIn(vs ...time.Time) predicate.AuthTokens {
|
func UpdatedAtIn(vs ...time.Time) predicate.AuthTokens {
|
||||||
v := make([]any, len(vs))
|
return predicate.AuthTokens(sql.FieldIn(FieldUpdatedAt, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.In(s.C(FieldUpdatedAt), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
|
// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
|
||||||
func UpdatedAtNotIn(vs ...time.Time) predicate.AuthTokens {
|
func UpdatedAtNotIn(vs ...time.Time) predicate.AuthTokens {
|
||||||
v := make([]any, len(vs))
|
return predicate.AuthTokens(sql.FieldNotIn(FieldUpdatedAt, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.NotIn(s.C(FieldUpdatedAt), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtGT applies the GT predicate on the "updated_at" field.
|
// UpdatedAtGT applies the GT predicate on the "updated_at" field.
|
||||||
func UpdatedAtGT(v time.Time) predicate.AuthTokens {
|
func UpdatedAtGT(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldGT(FieldUpdatedAt, v))
|
||||||
s.Where(sql.GT(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
|
// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
|
||||||
func UpdatedAtGTE(v time.Time) predicate.AuthTokens {
|
func UpdatedAtGTE(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldGTE(FieldUpdatedAt, v))
|
||||||
s.Where(sql.GTE(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtLT applies the LT predicate on the "updated_at" field.
|
// UpdatedAtLT applies the LT predicate on the "updated_at" field.
|
||||||
func UpdatedAtLT(v time.Time) predicate.AuthTokens {
|
func UpdatedAtLT(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldLT(FieldUpdatedAt, v))
|
||||||
s.Where(sql.LT(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
|
// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
|
||||||
func UpdatedAtLTE(v time.Time) predicate.AuthTokens {
|
func UpdatedAtLTE(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldLTE(FieldUpdatedAt, v))
|
||||||
s.Where(sql.LTE(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenEQ applies the EQ predicate on the "token" field.
|
// TokenEQ applies the EQ predicate on the "token" field.
|
||||||
func TokenEQ(v []byte) predicate.AuthTokens {
|
func TokenEQ(v []byte) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldEQ(FieldToken, v))
|
||||||
s.Where(sql.EQ(s.C(FieldToken), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenNEQ applies the NEQ predicate on the "token" field.
|
// TokenNEQ applies the NEQ predicate on the "token" field.
|
||||||
func TokenNEQ(v []byte) predicate.AuthTokens {
|
func TokenNEQ(v []byte) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldNEQ(FieldToken, v))
|
||||||
s.Where(sql.NEQ(s.C(FieldToken), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenIn applies the In predicate on the "token" field.
|
// TokenIn applies the In predicate on the "token" field.
|
||||||
func TokenIn(vs ...[]byte) predicate.AuthTokens {
|
func TokenIn(vs ...[]byte) predicate.AuthTokens {
|
||||||
v := make([]any, len(vs))
|
return predicate.AuthTokens(sql.FieldIn(FieldToken, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.In(s.C(FieldToken), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenNotIn applies the NotIn predicate on the "token" field.
|
// TokenNotIn applies the NotIn predicate on the "token" field.
|
||||||
func TokenNotIn(vs ...[]byte) predicate.AuthTokens {
|
func TokenNotIn(vs ...[]byte) predicate.AuthTokens {
|
||||||
v := make([]any, len(vs))
|
return predicate.AuthTokens(sql.FieldNotIn(FieldToken, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.NotIn(s.C(FieldToken), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenGT applies the GT predicate on the "token" field.
|
// TokenGT applies the GT predicate on the "token" field.
|
||||||
func TokenGT(v []byte) predicate.AuthTokens {
|
func TokenGT(v []byte) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldGT(FieldToken, v))
|
||||||
s.Where(sql.GT(s.C(FieldToken), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenGTE applies the GTE predicate on the "token" field.
|
// TokenGTE applies the GTE predicate on the "token" field.
|
||||||
func TokenGTE(v []byte) predicate.AuthTokens {
|
func TokenGTE(v []byte) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldGTE(FieldToken, v))
|
||||||
s.Where(sql.GTE(s.C(FieldToken), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenLT applies the LT predicate on the "token" field.
|
// TokenLT applies the LT predicate on the "token" field.
|
||||||
func TokenLT(v []byte) predicate.AuthTokens {
|
func TokenLT(v []byte) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldLT(FieldToken, v))
|
||||||
s.Where(sql.LT(s.C(FieldToken), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenLTE applies the LTE predicate on the "token" field.
|
// TokenLTE applies the LTE predicate on the "token" field.
|
||||||
func TokenLTE(v []byte) predicate.AuthTokens {
|
func TokenLTE(v []byte) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldLTE(FieldToken, v))
|
||||||
s.Where(sql.LTE(s.C(FieldToken), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExpiresAtEQ applies the EQ predicate on the "expires_at" field.
|
// ExpiresAtEQ applies the EQ predicate on the "expires_at" field.
|
||||||
func ExpiresAtEQ(v time.Time) predicate.AuthTokens {
|
func ExpiresAtEQ(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldEQ(FieldExpiresAt, v))
|
||||||
s.Where(sql.EQ(s.C(FieldExpiresAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExpiresAtNEQ applies the NEQ predicate on the "expires_at" field.
|
// ExpiresAtNEQ applies the NEQ predicate on the "expires_at" field.
|
||||||
func ExpiresAtNEQ(v time.Time) predicate.AuthTokens {
|
func ExpiresAtNEQ(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldNEQ(FieldExpiresAt, v))
|
||||||
s.Where(sql.NEQ(s.C(FieldExpiresAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExpiresAtIn applies the In predicate on the "expires_at" field.
|
// ExpiresAtIn applies the In predicate on the "expires_at" field.
|
||||||
func ExpiresAtIn(vs ...time.Time) predicate.AuthTokens {
|
func ExpiresAtIn(vs ...time.Time) predicate.AuthTokens {
|
||||||
v := make([]any, len(vs))
|
return predicate.AuthTokens(sql.FieldIn(FieldExpiresAt, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.In(s.C(FieldExpiresAt), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExpiresAtNotIn applies the NotIn predicate on the "expires_at" field.
|
// ExpiresAtNotIn applies the NotIn predicate on the "expires_at" field.
|
||||||
func ExpiresAtNotIn(vs ...time.Time) predicate.AuthTokens {
|
func ExpiresAtNotIn(vs ...time.Time) predicate.AuthTokens {
|
||||||
v := make([]any, len(vs))
|
return predicate.AuthTokens(sql.FieldNotIn(FieldExpiresAt, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.NotIn(s.C(FieldExpiresAt), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExpiresAtGT applies the GT predicate on the "expires_at" field.
|
// ExpiresAtGT applies the GT predicate on the "expires_at" field.
|
||||||
func ExpiresAtGT(v time.Time) predicate.AuthTokens {
|
func ExpiresAtGT(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldGT(FieldExpiresAt, v))
|
||||||
s.Where(sql.GT(s.C(FieldExpiresAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExpiresAtGTE applies the GTE predicate on the "expires_at" field.
|
// ExpiresAtGTE applies the GTE predicate on the "expires_at" field.
|
||||||
func ExpiresAtGTE(v time.Time) predicate.AuthTokens {
|
func ExpiresAtGTE(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldGTE(FieldExpiresAt, v))
|
||||||
s.Where(sql.GTE(s.C(FieldExpiresAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExpiresAtLT applies the LT predicate on the "expires_at" field.
|
// ExpiresAtLT applies the LT predicate on the "expires_at" field.
|
||||||
func ExpiresAtLT(v time.Time) predicate.AuthTokens {
|
func ExpiresAtLT(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldLT(FieldExpiresAt, v))
|
||||||
s.Where(sql.LT(s.C(FieldExpiresAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExpiresAtLTE applies the LTE predicate on the "expires_at" field.
|
// ExpiresAtLTE applies the LTE predicate on the "expires_at" field.
|
||||||
func ExpiresAtLTE(v time.Time) predicate.AuthTokens {
|
func ExpiresAtLTE(v time.Time) predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(sql.FieldLTE(FieldExpiresAt, v))
|
||||||
s.Where(sql.LTE(s.C(FieldExpiresAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasUser applies the HasEdge predicate on the "user" edge.
|
// HasUser applies the HasEdge predicate on the "user" edge.
|
||||||
@@ -371,7 +241,6 @@ func HasUser() predicate.AuthTokens {
|
|||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||||
step := sqlgraph.NewStep(
|
step := sqlgraph.NewStep(
|
||||||
sqlgraph.From(Table, FieldID),
|
sqlgraph.From(Table, FieldID),
|
||||||
sqlgraph.To(UserTable, FieldID),
|
|
||||||
sqlgraph.Edge(sqlgraph.M2O, true, UserTable, UserColumn),
|
sqlgraph.Edge(sqlgraph.M2O, true, UserTable, UserColumn),
|
||||||
)
|
)
|
||||||
sqlgraph.HasNeighbors(s, step)
|
sqlgraph.HasNeighbors(s, step)
|
||||||
@@ -380,12 +249,31 @@ func HasUser() predicate.AuthTokens {
|
|||||||
|
|
||||||
// HasUserWith applies the HasEdge predicate on the "user" edge with a given conditions (other predicates).
|
// HasUserWith applies the HasEdge predicate on the "user" edge with a given conditions (other predicates).
|
||||||
func HasUserWith(preds ...predicate.User) predicate.AuthTokens {
|
func HasUserWith(preds ...predicate.User) predicate.AuthTokens {
|
||||||
|
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||||
|
step := newUserStep()
|
||||||
|
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
||||||
|
for _, p := range preds {
|
||||||
|
p(s)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasRoles applies the HasEdge predicate on the "roles" edge.
|
||||||
|
func HasRoles() predicate.AuthTokens {
|
||||||
return predicate.AuthTokens(func(s *sql.Selector) {
|
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||||
step := sqlgraph.NewStep(
|
step := sqlgraph.NewStep(
|
||||||
sqlgraph.From(Table, FieldID),
|
sqlgraph.From(Table, FieldID),
|
||||||
sqlgraph.To(UserInverseTable, FieldID),
|
sqlgraph.Edge(sqlgraph.O2O, false, RolesTable, RolesColumn),
|
||||||
sqlgraph.Edge(sqlgraph.M2O, true, UserTable, UserColumn),
|
|
||||||
)
|
)
|
||||||
|
sqlgraph.HasNeighbors(s, step)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasRolesWith applies the HasEdge predicate on the "roles" edge with a given conditions (other predicates).
|
||||||
|
func HasRolesWith(preds ...predicate.AuthRoles) predicate.AuthTokens {
|
||||||
|
return predicate.AuthTokens(func(s *sql.Selector) {
|
||||||
|
step := newRolesStep()
|
||||||
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
||||||
for _, p := range preds {
|
for _, p := range preds {
|
||||||
p(s)
|
p(s)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
"entgo.io/ent/schema/field"
|
"entgo.io/ent/schema/field"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/user"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/user"
|
||||||
)
|
)
|
||||||
@@ -103,6 +104,25 @@ func (atc *AuthTokensCreate) SetUser(u *User) *AuthTokensCreate {
|
|||||||
return atc.SetUserID(u.ID)
|
return atc.SetUserID(u.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetRolesID sets the "roles" edge to the AuthRoles entity by ID.
|
||||||
|
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 (atc *AuthTokensCreate) SetNillableRolesID(id *int) *AuthTokensCreate {
|
||||||
|
if id != nil {
|
||||||
|
atc = atc.SetRolesID(*id)
|
||||||
|
}
|
||||||
|
return atc
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRoles sets the "roles" edge to the AuthRoles entity.
|
||||||
|
func (atc *AuthTokensCreate) SetRoles(a *AuthRoles) *AuthTokensCreate {
|
||||||
|
return atc.SetRolesID(a.ID)
|
||||||
|
}
|
||||||
|
|
||||||
// Mutation returns the AuthTokensMutation object of the builder.
|
// Mutation returns the AuthTokensMutation object of the builder.
|
||||||
func (atc *AuthTokensCreate) Mutation() *AuthTokensMutation {
|
func (atc *AuthTokensCreate) Mutation() *AuthTokensMutation {
|
||||||
return atc.mutation
|
return atc.mutation
|
||||||
@@ -110,50 +130,8 @@ func (atc *AuthTokensCreate) Mutation() *AuthTokensMutation {
|
|||||||
|
|
||||||
// Save creates the AuthTokens in the database.
|
// Save creates the AuthTokens in the database.
|
||||||
func (atc *AuthTokensCreate) Save(ctx context.Context) (*AuthTokens, error) {
|
func (atc *AuthTokensCreate) Save(ctx context.Context) (*AuthTokens, error) {
|
||||||
var (
|
|
||||||
err error
|
|
||||||
node *AuthTokens
|
|
||||||
)
|
|
||||||
atc.defaults()
|
atc.defaults()
|
||||||
if len(atc.hooks) == 0 {
|
return withHooks(ctx, atc.sqlSave, atc.mutation, atc.hooks)
|
||||||
if err = atc.check(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
node, err = atc.sqlSave(ctx)
|
|
||||||
} else {
|
|
||||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
|
||||||
mutation, ok := m.(*AuthTokensMutation)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
|
||||||
}
|
|
||||||
if err = atc.check(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
atc.mutation = mutation
|
|
||||||
if node, err = atc.sqlSave(ctx); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mutation.id = &node.ID
|
|
||||||
mutation.done = true
|
|
||||||
return node, err
|
|
||||||
})
|
|
||||||
for i := len(atc.hooks) - 1; i >= 0; i-- {
|
|
||||||
if atc.hooks[i] == nil {
|
|
||||||
return nil, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
|
||||||
}
|
|
||||||
mut = atc.hooks[i](mut)
|
|
||||||
}
|
|
||||||
v, err := mut.Mutate(ctx, atc.mutation)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
nv, ok := v.(*AuthTokens)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected node type %T returned from AuthTokensMutation", v)
|
|
||||||
}
|
|
||||||
node = nv
|
|
||||||
}
|
|
||||||
return node, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveX calls Save and panics if Save returns an error.
|
// SaveX calls Save and panics if Save returns an error.
|
||||||
@@ -216,6 +194,9 @@ func (atc *AuthTokensCreate) check() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (atc *AuthTokensCreate) sqlSave(ctx context.Context) (*AuthTokens, error) {
|
func (atc *AuthTokensCreate) sqlSave(ctx context.Context) (*AuthTokens, error) {
|
||||||
|
if err := atc.check(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
_node, _spec := atc.createSpec()
|
_node, _spec := atc.createSpec()
|
||||||
if err := sqlgraph.CreateNode(ctx, atc.driver, _spec); err != nil {
|
if err := sqlgraph.CreateNode(ctx, atc.driver, _spec); err != nil {
|
||||||
if sqlgraph.IsConstraintError(err) {
|
if sqlgraph.IsConstraintError(err) {
|
||||||
@@ -230,54 +211,34 @@ func (atc *AuthTokensCreate) sqlSave(ctx context.Context) (*AuthTokens, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
atc.mutation.id = &_node.ID
|
||||||
|
atc.mutation.done = true
|
||||||
return _node, nil
|
return _node, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (atc *AuthTokensCreate) createSpec() (*AuthTokens, *sqlgraph.CreateSpec) {
|
func (atc *AuthTokensCreate) createSpec() (*AuthTokens, *sqlgraph.CreateSpec) {
|
||||||
var (
|
var (
|
||||||
_node = &AuthTokens{config: atc.config}
|
_node = &AuthTokens{config: atc.config}
|
||||||
_spec = &sqlgraph.CreateSpec{
|
_spec = sqlgraph.NewCreateSpec(authtokens.Table, sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID))
|
||||||
Table: authtokens.Table,
|
|
||||||
ID: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: authtokens.FieldID,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
if id, ok := atc.mutation.ID(); ok {
|
if id, ok := atc.mutation.ID(); ok {
|
||||||
_node.ID = id
|
_node.ID = id
|
||||||
_spec.ID.Value = &id
|
_spec.ID.Value = &id
|
||||||
}
|
}
|
||||||
if value, ok := atc.mutation.CreatedAt(); ok {
|
if value, ok := atc.mutation.CreatedAt(); ok {
|
||||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
_spec.SetField(authtokens.FieldCreatedAt, field.TypeTime, value)
|
||||||
Type: field.TypeTime,
|
|
||||||
Value: value,
|
|
||||||
Column: authtokens.FieldCreatedAt,
|
|
||||||
})
|
|
||||||
_node.CreatedAt = value
|
_node.CreatedAt = value
|
||||||
}
|
}
|
||||||
if value, ok := atc.mutation.UpdatedAt(); ok {
|
if value, ok := atc.mutation.UpdatedAt(); ok {
|
||||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
_spec.SetField(authtokens.FieldUpdatedAt, field.TypeTime, value)
|
||||||
Type: field.TypeTime,
|
|
||||||
Value: value,
|
|
||||||
Column: authtokens.FieldUpdatedAt,
|
|
||||||
})
|
|
||||||
_node.UpdatedAt = value
|
_node.UpdatedAt = value
|
||||||
}
|
}
|
||||||
if value, ok := atc.mutation.Token(); ok {
|
if value, ok := atc.mutation.Token(); ok {
|
||||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
_spec.SetField(authtokens.FieldToken, field.TypeBytes, value)
|
||||||
Type: field.TypeBytes,
|
|
||||||
Value: value,
|
|
||||||
Column: authtokens.FieldToken,
|
|
||||||
})
|
|
||||||
_node.Token = value
|
_node.Token = value
|
||||||
}
|
}
|
||||||
if value, ok := atc.mutation.ExpiresAt(); ok {
|
if value, ok := atc.mutation.ExpiresAt(); ok {
|
||||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
_spec.SetField(authtokens.FieldExpiresAt, field.TypeTime, value)
|
||||||
Type: field.TypeTime,
|
|
||||||
Value: value,
|
|
||||||
Column: authtokens.FieldExpiresAt,
|
|
||||||
})
|
|
||||||
_node.ExpiresAt = value
|
_node.ExpiresAt = value
|
||||||
}
|
}
|
||||||
if nodes := atc.mutation.UserIDs(); len(nodes) > 0 {
|
if nodes := atc.mutation.UserIDs(); len(nodes) > 0 {
|
||||||
@@ -288,10 +249,7 @@ func (atc *AuthTokensCreate) createSpec() (*AuthTokens, *sqlgraph.CreateSpec) {
|
|||||||
Columns: []string{authtokens.UserColumn},
|
Columns: []string{authtokens.UserColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: user.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
@@ -300,6 +258,22 @@ func (atc *AuthTokensCreate) createSpec() (*AuthTokens, *sqlgraph.CreateSpec) {
|
|||||||
_node.user_auth_tokens = &nodes[0]
|
_node.user_auth_tokens = &nodes[0]
|
||||||
_spec.Edges = append(_spec.Edges, edge)
|
_spec.Edges = append(_spec.Edges, edge)
|
||||||
}
|
}
|
||||||
|
if nodes := atc.mutation.RolesIDs(); len(nodes) > 0 {
|
||||||
|
edge := &sqlgraph.EdgeSpec{
|
||||||
|
Rel: sqlgraph.O2O,
|
||||||
|
Inverse: false,
|
||||||
|
Table: authtokens.RolesTable,
|
||||||
|
Columns: []string{authtokens.RolesColumn},
|
||||||
|
Bidi: false,
|
||||||
|
Target: &sqlgraph.EdgeTarget{
|
||||||
|
IDSpec: sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, k := range nodes {
|
||||||
|
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||||
|
}
|
||||||
|
_spec.Edges = append(_spec.Edges, edge)
|
||||||
|
}
|
||||||
return _node, _spec
|
return _node, _spec
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,8 +301,8 @@ func (atcb *AuthTokensCreateBulk) Save(ctx context.Context) ([]*AuthTokens, erro
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
builder.mutation = mutation
|
builder.mutation = mutation
|
||||||
nodes[i], specs[i] = builder.createSpec()
|
|
||||||
var err error
|
var err error
|
||||||
|
nodes[i], specs[i] = builder.createSpec()
|
||||||
if i < len(mutators)-1 {
|
if i < len(mutators)-1 {
|
||||||
_, err = mutators[i+1].Mutate(root, atcb.builders[i+1].mutation)
|
_, err = mutators[i+1].Mutate(root, atcb.builders[i+1].mutation)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ package ent
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"entgo.io/ent/dialect/sql"
|
"entgo.io/ent/dialect/sql"
|
||||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
@@ -28,34 +27,7 @@ func (atd *AuthTokensDelete) Where(ps ...predicate.AuthTokens) *AuthTokensDelete
|
|||||||
|
|
||||||
// Exec executes the deletion query and returns how many vertices were deleted.
|
// Exec executes the deletion query and returns how many vertices were deleted.
|
||||||
func (atd *AuthTokensDelete) Exec(ctx context.Context) (int, error) {
|
func (atd *AuthTokensDelete) Exec(ctx context.Context) (int, error) {
|
||||||
var (
|
return withHooks(ctx, atd.sqlExec, atd.mutation, atd.hooks)
|
||||||
err error
|
|
||||||
affected int
|
|
||||||
)
|
|
||||||
if len(atd.hooks) == 0 {
|
|
||||||
affected, err = atd.sqlExec(ctx)
|
|
||||||
} else {
|
|
||||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
|
||||||
mutation, ok := m.(*AuthTokensMutation)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
|
||||||
}
|
|
||||||
atd.mutation = mutation
|
|
||||||
affected, err = atd.sqlExec(ctx)
|
|
||||||
mutation.done = true
|
|
||||||
return affected, err
|
|
||||||
})
|
|
||||||
for i := len(atd.hooks) - 1; i >= 0; i-- {
|
|
||||||
if atd.hooks[i] == nil {
|
|
||||||
return 0, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
|
||||||
}
|
|
||||||
mut = atd.hooks[i](mut)
|
|
||||||
}
|
|
||||||
if _, err := mut.Mutate(ctx, atd.mutation); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return affected, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecX is like Exec, but panics if an error occurs.
|
// ExecX is like Exec, but panics if an error occurs.
|
||||||
@@ -68,15 +40,7 @@ func (atd *AuthTokensDelete) ExecX(ctx context.Context) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (atd *AuthTokensDelete) sqlExec(ctx context.Context) (int, error) {
|
func (atd *AuthTokensDelete) sqlExec(ctx context.Context) (int, error) {
|
||||||
_spec := &sqlgraph.DeleteSpec{
|
_spec := sqlgraph.NewDeleteSpec(authtokens.Table, sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID))
|
||||||
Node: &sqlgraph.NodeSpec{
|
|
||||||
Table: authtokens.Table,
|
|
||||||
ID: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: authtokens.FieldID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if ps := atd.mutation.predicates; len(ps) > 0 {
|
if ps := atd.mutation.predicates; len(ps) > 0 {
|
||||||
_spec.Predicate = func(selector *sql.Selector) {
|
_spec.Predicate = func(selector *sql.Selector) {
|
||||||
for i := range ps {
|
for i := range ps {
|
||||||
@@ -88,6 +52,7 @@ func (atd *AuthTokensDelete) sqlExec(ctx context.Context) (int, error) {
|
|||||||
if err != nil && sqlgraph.IsConstraintError(err) {
|
if err != nil && sqlgraph.IsConstraintError(err) {
|
||||||
err = &ConstraintError{msg: err.Error(), wrap: err}
|
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||||
}
|
}
|
||||||
|
atd.mutation.done = true
|
||||||
return affected, err
|
return affected, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,6 +61,12 @@ type AuthTokensDeleteOne struct {
|
|||||||
atd *AuthTokensDelete
|
atd *AuthTokensDelete
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Where appends a list predicates to the AuthTokensDelete builder.
|
||||||
|
func (atdo *AuthTokensDeleteOne) Where(ps ...predicate.AuthTokens) *AuthTokensDeleteOne {
|
||||||
|
atdo.atd.mutation.Where(ps...)
|
||||||
|
return atdo
|
||||||
|
}
|
||||||
|
|
||||||
// Exec executes the deletion query.
|
// Exec executes the deletion query.
|
||||||
func (atdo *AuthTokensDeleteOne) Exec(ctx context.Context) error {
|
func (atdo *AuthTokensDeleteOne) Exec(ctx context.Context) error {
|
||||||
n, err := atdo.atd.Exec(ctx)
|
n, err := atdo.atd.Exec(ctx)
|
||||||
@@ -111,5 +82,7 @@ func (atdo *AuthTokensDeleteOne) Exec(ctx context.Context) error {
|
|||||||
|
|
||||||
// ExecX is like Exec, but panics if an error occurs.
|
// ExecX is like Exec, but panics if an error occurs.
|
||||||
func (atdo *AuthTokensDeleteOne) ExecX(ctx context.Context) {
|
func (atdo *AuthTokensDeleteOne) ExecX(ctx context.Context) {
|
||||||
atdo.atd.ExecX(ctx)
|
if err := atdo.Exec(ctx); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package ent
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql/driver"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
@@ -11,6 +12,7 @@ import (
|
|||||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
"entgo.io/ent/schema/field"
|
"entgo.io/ent/schema/field"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/user"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/user"
|
||||||
@@ -19,13 +21,12 @@ import (
|
|||||||
// AuthTokensQuery is the builder for querying AuthTokens entities.
|
// AuthTokensQuery is the builder for querying AuthTokens entities.
|
||||||
type AuthTokensQuery struct {
|
type AuthTokensQuery struct {
|
||||||
config
|
config
|
||||||
limit *int
|
ctx *QueryContext
|
||||||
offset *int
|
order []authtokens.OrderOption
|
||||||
unique *bool
|
inters []Interceptor
|
||||||
order []OrderFunc
|
|
||||||
fields []string
|
|
||||||
predicates []predicate.AuthTokens
|
predicates []predicate.AuthTokens
|
||||||
withUser *UserQuery
|
withUser *UserQuery
|
||||||
|
withRoles *AuthRolesQuery
|
||||||
withFKs bool
|
withFKs bool
|
||||||
// intermediate query (i.e. traversal path).
|
// intermediate query (i.e. traversal path).
|
||||||
sql *sql.Selector
|
sql *sql.Selector
|
||||||
@@ -38,34 +39,34 @@ func (atq *AuthTokensQuery) Where(ps ...predicate.AuthTokens) *AuthTokensQuery {
|
|||||||
return atq
|
return atq
|
||||||
}
|
}
|
||||||
|
|
||||||
// Limit adds a limit step to the query.
|
// Limit the number of records to be returned by this query.
|
||||||
func (atq *AuthTokensQuery) Limit(limit int) *AuthTokensQuery {
|
func (atq *AuthTokensQuery) Limit(limit int) *AuthTokensQuery {
|
||||||
atq.limit = &limit
|
atq.ctx.Limit = &limit
|
||||||
return atq
|
return atq
|
||||||
}
|
}
|
||||||
|
|
||||||
// Offset adds an offset step to the query.
|
// Offset to start from.
|
||||||
func (atq *AuthTokensQuery) Offset(offset int) *AuthTokensQuery {
|
func (atq *AuthTokensQuery) Offset(offset int) *AuthTokensQuery {
|
||||||
atq.offset = &offset
|
atq.ctx.Offset = &offset
|
||||||
return atq
|
return atq
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unique configures the query builder to filter duplicate records on query.
|
// 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.
|
// By default, unique is set to true, and can be disabled using this method.
|
||||||
func (atq *AuthTokensQuery) Unique(unique bool) *AuthTokensQuery {
|
func (atq *AuthTokensQuery) Unique(unique bool) *AuthTokensQuery {
|
||||||
atq.unique = &unique
|
atq.ctx.Unique = &unique
|
||||||
return atq
|
return atq
|
||||||
}
|
}
|
||||||
|
|
||||||
// Order adds an order step to the query.
|
// Order specifies how the records should be ordered.
|
||||||
func (atq *AuthTokensQuery) Order(o ...OrderFunc) *AuthTokensQuery {
|
func (atq *AuthTokensQuery) Order(o ...authtokens.OrderOption) *AuthTokensQuery {
|
||||||
atq.order = append(atq.order, o...)
|
atq.order = append(atq.order, o...)
|
||||||
return atq
|
return atq
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryUser chains the current query on the "user" edge.
|
// QueryUser chains the current query on the "user" edge.
|
||||||
func (atq *AuthTokensQuery) QueryUser() *UserQuery {
|
func (atq *AuthTokensQuery) QueryUser() *UserQuery {
|
||||||
query := &UserQuery{config: atq.config}
|
query := (&UserClient{config: atq.config}).Query()
|
||||||
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
||||||
if err := atq.prepareQuery(ctx); err != nil {
|
if err := atq.prepareQuery(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -85,10 +86,32 @@ func (atq *AuthTokensQuery) QueryUser() *UserQuery {
|
|||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueryRoles chains the current query on the "roles" edge.
|
||||||
|
func (atq *AuthTokensQuery) QueryRoles() *AuthRolesQuery {
|
||||||
|
query := (&AuthRolesClient{config: atq.config}).Query()
|
||||||
|
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
||||||
|
if err := atq.prepareQuery(ctx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
selector := atq.sqlQuery(ctx)
|
||||||
|
if err := selector.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
step := sqlgraph.NewStep(
|
||||||
|
sqlgraph.From(authtokens.Table, authtokens.FieldID, selector),
|
||||||
|
sqlgraph.To(authroles.Table, authroles.FieldID),
|
||||||
|
sqlgraph.Edge(sqlgraph.O2O, false, authtokens.RolesTable, authtokens.RolesColumn),
|
||||||
|
)
|
||||||
|
fromU = sqlgraph.SetNeighbors(atq.driver.Dialect(), step)
|
||||||
|
return fromU, nil
|
||||||
|
}
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
|
||||||
// First returns the first AuthTokens entity from the query.
|
// First returns the first AuthTokens entity from the query.
|
||||||
// Returns a *NotFoundError when no AuthTokens was found.
|
// Returns a *NotFoundError when no AuthTokens was found.
|
||||||
func (atq *AuthTokensQuery) First(ctx context.Context) (*AuthTokens, error) {
|
func (atq *AuthTokensQuery) First(ctx context.Context) (*AuthTokens, error) {
|
||||||
nodes, err := atq.Limit(1).All(ctx)
|
nodes, err := atq.Limit(1).All(setContextOp(ctx, atq.ctx, "First"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -111,7 +134,7 @@ func (atq *AuthTokensQuery) FirstX(ctx context.Context) *AuthTokens {
|
|||||||
// Returns a *NotFoundError when no AuthTokens ID was found.
|
// Returns a *NotFoundError when no AuthTokens ID was found.
|
||||||
func (atq *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
|
var ids []uuid.UUID
|
||||||
if ids, err = atq.Limit(1).IDs(ctx); err != nil {
|
if ids, err = atq.Limit(1).IDs(setContextOp(ctx, atq.ctx, "FirstID")); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(ids) == 0 {
|
if len(ids) == 0 {
|
||||||
@@ -134,7 +157,7 @@ func (atq *AuthTokensQuery) FirstIDX(ctx context.Context) uuid.UUID {
|
|||||||
// Returns a *NotSingularError when more than one AuthTokens entity is found.
|
// Returns a *NotSingularError when more than one AuthTokens entity is found.
|
||||||
// Returns a *NotFoundError when no AuthTokens entities are found.
|
// Returns a *NotFoundError when no AuthTokens entities are found.
|
||||||
func (atq *AuthTokensQuery) Only(ctx context.Context) (*AuthTokens, error) {
|
func (atq *AuthTokensQuery) Only(ctx context.Context) (*AuthTokens, error) {
|
||||||
nodes, err := atq.Limit(2).All(ctx)
|
nodes, err := atq.Limit(2).All(setContextOp(ctx, atq.ctx, "Only"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -162,7 +185,7 @@ func (atq *AuthTokensQuery) OnlyX(ctx context.Context) *AuthTokens {
|
|||||||
// Returns a *NotFoundError when no entities are found.
|
// Returns a *NotFoundError when no entities are found.
|
||||||
func (atq *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
|
var ids []uuid.UUID
|
||||||
if ids, err = atq.Limit(2).IDs(ctx); err != nil {
|
if ids, err = atq.Limit(2).IDs(setContextOp(ctx, atq.ctx, "OnlyID")); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch len(ids) {
|
switch len(ids) {
|
||||||
@@ -187,10 +210,12 @@ func (atq *AuthTokensQuery) OnlyIDX(ctx context.Context) uuid.UUID {
|
|||||||
|
|
||||||
// All executes the query and returns a list of AuthTokensSlice.
|
// All executes the query and returns a list of AuthTokensSlice.
|
||||||
func (atq *AuthTokensQuery) All(ctx context.Context) ([]*AuthTokens, error) {
|
func (atq *AuthTokensQuery) All(ctx context.Context) ([]*AuthTokens, error) {
|
||||||
|
ctx = setContextOp(ctx, atq.ctx, "All")
|
||||||
if err := atq.prepareQuery(ctx); err != nil {
|
if err := atq.prepareQuery(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return atq.sqlAll(ctx)
|
qr := querierAll[[]*AuthTokens, *AuthTokensQuery]()
|
||||||
|
return withInterceptors[[]*AuthTokens](ctx, atq, qr, atq.inters)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllX is like All, but panics if an error occurs.
|
// AllX is like All, but panics if an error occurs.
|
||||||
@@ -203,9 +228,12 @@ func (atq *AuthTokensQuery) AllX(ctx context.Context) []*AuthTokens {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IDs executes the query and returns a list of AuthTokens IDs.
|
// IDs executes the query and returns a list of AuthTokens IDs.
|
||||||
func (atq *AuthTokensQuery) IDs(ctx context.Context) ([]uuid.UUID, error) {
|
func (atq *AuthTokensQuery) IDs(ctx context.Context) (ids []uuid.UUID, err error) {
|
||||||
var ids []uuid.UUID
|
if atq.ctx.Unique == nil && atq.path != nil {
|
||||||
if err := atq.Select(authtokens.FieldID).Scan(ctx, &ids); err != nil {
|
atq.Unique(true)
|
||||||
|
}
|
||||||
|
ctx = setContextOp(ctx, atq.ctx, "IDs")
|
||||||
|
if err = atq.Select(authtokens.FieldID).Scan(ctx, &ids); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return ids, nil
|
return ids, nil
|
||||||
@@ -222,10 +250,11 @@ func (atq *AuthTokensQuery) IDsX(ctx context.Context) []uuid.UUID {
|
|||||||
|
|
||||||
// Count returns the count of the given query.
|
// Count returns the count of the given query.
|
||||||
func (atq *AuthTokensQuery) Count(ctx context.Context) (int, error) {
|
func (atq *AuthTokensQuery) Count(ctx context.Context) (int, error) {
|
||||||
|
ctx = setContextOp(ctx, atq.ctx, "Count")
|
||||||
if err := atq.prepareQuery(ctx); err != nil {
|
if err := atq.prepareQuery(ctx); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return atq.sqlCount(ctx)
|
return withInterceptors[int](ctx, atq, querierCount[*AuthTokensQuery](), atq.inters)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CountX is like Count, but panics if an error occurs.
|
// CountX is like Count, but panics if an error occurs.
|
||||||
@@ -239,10 +268,15 @@ func (atq *AuthTokensQuery) CountX(ctx context.Context) int {
|
|||||||
|
|
||||||
// Exist returns true if the query has elements in the graph.
|
// Exist returns true if the query has elements in the graph.
|
||||||
func (atq *AuthTokensQuery) Exist(ctx context.Context) (bool, error) {
|
func (atq *AuthTokensQuery) Exist(ctx context.Context) (bool, error) {
|
||||||
if err := atq.prepareQuery(ctx); err != nil {
|
ctx = setContextOp(ctx, atq.ctx, "Exist")
|
||||||
return false, err
|
switch _, err := atq.FirstID(ctx); {
|
||||||
|
case IsNotFound(err):
|
||||||
|
return false, nil
|
||||||
|
case err != nil:
|
||||||
|
return false, fmt.Errorf("ent: check existence: %w", err)
|
||||||
|
default:
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
return atq.sqlExist(ctx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExistX is like Exist, but panics if an error occurs.
|
// ExistX is like Exist, but panics if an error occurs.
|
||||||
@@ -262,22 +296,22 @@ func (atq *AuthTokensQuery) Clone() *AuthTokensQuery {
|
|||||||
}
|
}
|
||||||
return &AuthTokensQuery{
|
return &AuthTokensQuery{
|
||||||
config: atq.config,
|
config: atq.config,
|
||||||
limit: atq.limit,
|
ctx: atq.ctx.Clone(),
|
||||||
offset: atq.offset,
|
order: append([]authtokens.OrderOption{}, atq.order...),
|
||||||
order: append([]OrderFunc{}, atq.order...),
|
inters: append([]Interceptor{}, atq.inters...),
|
||||||
predicates: append([]predicate.AuthTokens{}, atq.predicates...),
|
predicates: append([]predicate.AuthTokens{}, atq.predicates...),
|
||||||
withUser: atq.withUser.Clone(),
|
withUser: atq.withUser.Clone(),
|
||||||
|
withRoles: atq.withRoles.Clone(),
|
||||||
// clone intermediate query.
|
// clone intermediate query.
|
||||||
sql: atq.sql.Clone(),
|
sql: atq.sql.Clone(),
|
||||||
path: atq.path,
|
path: atq.path,
|
||||||
unique: atq.unique,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithUser tells the query-builder to eager-load the nodes that are connected to
|
// 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.
|
// the "user" edge. The optional arguments are used to configure the query builder of the edge.
|
||||||
func (atq *AuthTokensQuery) WithUser(opts ...func(*UserQuery)) *AuthTokensQuery {
|
func (atq *AuthTokensQuery) WithUser(opts ...func(*UserQuery)) *AuthTokensQuery {
|
||||||
query := &UserQuery{config: atq.config}
|
query := (&UserClient{config: atq.config}).Query()
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(query)
|
opt(query)
|
||||||
}
|
}
|
||||||
@@ -285,6 +319,17 @@ func (atq *AuthTokensQuery) WithUser(opts ...func(*UserQuery)) *AuthTokensQuery
|
|||||||
return atq
|
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 (atq *AuthTokensQuery) WithRoles(opts ...func(*AuthRolesQuery)) *AuthTokensQuery {
|
||||||
|
query := (&AuthRolesClient{config: atq.config}).Query()
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(query)
|
||||||
|
}
|
||||||
|
atq.withRoles = query
|
||||||
|
return atq
|
||||||
|
}
|
||||||
|
|
||||||
// GroupBy is used to group vertices by one or more fields/columns.
|
// 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.
|
// It is often used with aggregate functions, like: count, max, mean, min, sum.
|
||||||
//
|
//
|
||||||
@@ -300,16 +345,11 @@ func (atq *AuthTokensQuery) WithUser(opts ...func(*UserQuery)) *AuthTokensQuery
|
|||||||
// Aggregate(ent.Count()).
|
// Aggregate(ent.Count()).
|
||||||
// Scan(ctx, &v)
|
// Scan(ctx, &v)
|
||||||
func (atq *AuthTokensQuery) GroupBy(field string, fields ...string) *AuthTokensGroupBy {
|
func (atq *AuthTokensQuery) GroupBy(field string, fields ...string) *AuthTokensGroupBy {
|
||||||
grbuild := &AuthTokensGroupBy{config: atq.config}
|
atq.ctx.Fields = append([]string{field}, fields...)
|
||||||
grbuild.fields = append([]string{field}, fields...)
|
grbuild := &AuthTokensGroupBy{build: atq}
|
||||||
grbuild.path = func(ctx context.Context) (prev *sql.Selector, err error) {
|
grbuild.flds = &atq.ctx.Fields
|
||||||
if err := atq.prepareQuery(ctx); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return atq.sqlQuery(ctx), nil
|
|
||||||
}
|
|
||||||
grbuild.label = authtokens.Label
|
grbuild.label = authtokens.Label
|
||||||
grbuild.flds, grbuild.scan = &grbuild.fields, grbuild.Scan
|
grbuild.scan = grbuild.Scan
|
||||||
return grbuild
|
return grbuild
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,15 +366,30 @@ func (atq *AuthTokensQuery) GroupBy(field string, fields ...string) *AuthTokensG
|
|||||||
// Select(authtokens.FieldCreatedAt).
|
// Select(authtokens.FieldCreatedAt).
|
||||||
// Scan(ctx, &v)
|
// Scan(ctx, &v)
|
||||||
func (atq *AuthTokensQuery) Select(fields ...string) *AuthTokensSelect {
|
func (atq *AuthTokensQuery) Select(fields ...string) *AuthTokensSelect {
|
||||||
atq.fields = append(atq.fields, fields...)
|
atq.ctx.Fields = append(atq.ctx.Fields, fields...)
|
||||||
selbuild := &AuthTokensSelect{AuthTokensQuery: atq}
|
sbuild := &AuthTokensSelect{AuthTokensQuery: atq}
|
||||||
selbuild.label = authtokens.Label
|
sbuild.label = authtokens.Label
|
||||||
selbuild.flds, selbuild.scan = &atq.fields, selbuild.Scan
|
sbuild.flds, sbuild.scan = &atq.ctx.Fields, sbuild.Scan
|
||||||
return selbuild
|
return sbuild
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aggregate returns a AuthTokensSelect configured with the given aggregations.
|
||||||
|
func (atq *AuthTokensQuery) Aggregate(fns ...AggregateFunc) *AuthTokensSelect {
|
||||||
|
return atq.Select().Aggregate(fns...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (atq *AuthTokensQuery) prepareQuery(ctx context.Context) error {
|
func (atq *AuthTokensQuery) prepareQuery(ctx context.Context) error {
|
||||||
for _, f := range atq.fields {
|
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, atq); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, f := range atq.ctx.Fields {
|
||||||
if !authtokens.ValidColumn(f) {
|
if !authtokens.ValidColumn(f) {
|
||||||
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
|
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
|
||||||
}
|
}
|
||||||
@@ -354,8 +409,9 @@ func (atq *AuthTokensQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*
|
|||||||
nodes = []*AuthTokens{}
|
nodes = []*AuthTokens{}
|
||||||
withFKs = atq.withFKs
|
withFKs = atq.withFKs
|
||||||
_spec = atq.querySpec()
|
_spec = atq.querySpec()
|
||||||
loadedTypes = [1]bool{
|
loadedTypes = [2]bool{
|
||||||
atq.withUser != nil,
|
atq.withUser != nil,
|
||||||
|
atq.withRoles != nil,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if atq.withUser != nil {
|
if atq.withUser != nil {
|
||||||
@@ -388,6 +444,12 @@ func (atq *AuthTokensQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
return nodes, nil
|
return nodes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,6 +466,9 @@ func (atq *AuthTokensQuery) loadUser(ctx context.Context, query *UserQuery, node
|
|||||||
}
|
}
|
||||||
nodeids[fk] = append(nodeids[fk], nodes[i])
|
nodeids[fk] = append(nodeids[fk], nodes[i])
|
||||||
}
|
}
|
||||||
|
if len(ids) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
query.Where(user.IDIn(ids...))
|
query.Where(user.IDIn(ids...))
|
||||||
neighbors, err := query.All(ctx)
|
neighbors, err := query.All(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -420,44 +485,53 @@ func (atq *AuthTokensQuery) loadUser(ctx context.Context, query *UserQuery, node
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
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 {
|
||||||
|
fks = append(fks, nodes[i].ID)
|
||||||
|
nodeids[nodes[i].ID] = nodes[i]
|
||||||
|
}
|
||||||
|
query.withFKs = true
|
||||||
|
query.Where(predicate.AuthRoles(func(s *sql.Selector) {
|
||||||
|
s.Where(sql.InValues(s.C(authtokens.RolesColumn), fks...))
|
||||||
|
}))
|
||||||
|
neighbors, err := query.All(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, n := range neighbors {
|
||||||
|
fk := n.auth_tokens_roles
|
||||||
|
if fk == nil {
|
||||||
|
return fmt.Errorf(`foreign-key "auth_tokens_roles" is nil for node %v`, n.ID)
|
||||||
|
}
|
||||||
|
node, ok := nodeids[*fk]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf(`unexpected referenced foreign-key "auth_tokens_roles" returned %v for node %v`, *fk, n.ID)
|
||||||
|
}
|
||||||
|
assign(node, n)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (atq *AuthTokensQuery) sqlCount(ctx context.Context) (int, error) {
|
func (atq *AuthTokensQuery) sqlCount(ctx context.Context) (int, error) {
|
||||||
_spec := atq.querySpec()
|
_spec := atq.querySpec()
|
||||||
_spec.Node.Columns = atq.fields
|
_spec.Node.Columns = atq.ctx.Fields
|
||||||
if len(atq.fields) > 0 {
|
if len(atq.ctx.Fields) > 0 {
|
||||||
_spec.Unique = atq.unique != nil && *atq.unique
|
_spec.Unique = atq.ctx.Unique != nil && *atq.ctx.Unique
|
||||||
}
|
}
|
||||||
return sqlgraph.CountNodes(ctx, atq.driver, _spec)
|
return sqlgraph.CountNodes(ctx, atq.driver, _spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (atq *AuthTokensQuery) sqlExist(ctx context.Context) (bool, error) {
|
|
||||||
switch _, err := atq.FirstID(ctx); {
|
|
||||||
case IsNotFound(err):
|
|
||||||
return false, nil
|
|
||||||
case err != nil:
|
|
||||||
return false, fmt.Errorf("ent: check existence: %w", err)
|
|
||||||
default:
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (atq *AuthTokensQuery) querySpec() *sqlgraph.QuerySpec {
|
func (atq *AuthTokensQuery) querySpec() *sqlgraph.QuerySpec {
|
||||||
_spec := &sqlgraph.QuerySpec{
|
_spec := sqlgraph.NewQuerySpec(authtokens.Table, authtokens.Columns, sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID))
|
||||||
Node: &sqlgraph.NodeSpec{
|
_spec.From = atq.sql
|
||||||
Table: authtokens.Table,
|
if unique := atq.ctx.Unique; unique != nil {
|
||||||
Columns: authtokens.Columns,
|
|
||||||
ID: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: authtokens.FieldID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
From: atq.sql,
|
|
||||||
Unique: true,
|
|
||||||
}
|
|
||||||
if unique := atq.unique; unique != nil {
|
|
||||||
_spec.Unique = *unique
|
_spec.Unique = *unique
|
||||||
|
} else if atq.path != nil {
|
||||||
|
_spec.Unique = true
|
||||||
}
|
}
|
||||||
if fields := atq.fields; len(fields) > 0 {
|
if fields := atq.ctx.Fields; len(fields) > 0 {
|
||||||
_spec.Node.Columns = make([]string, 0, len(fields))
|
_spec.Node.Columns = make([]string, 0, len(fields))
|
||||||
_spec.Node.Columns = append(_spec.Node.Columns, authtokens.FieldID)
|
_spec.Node.Columns = append(_spec.Node.Columns, authtokens.FieldID)
|
||||||
for i := range fields {
|
for i := range fields {
|
||||||
@@ -473,10 +547,10 @@ func (atq *AuthTokensQuery) querySpec() *sqlgraph.QuerySpec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if limit := atq.limit; limit != nil {
|
if limit := atq.ctx.Limit; limit != nil {
|
||||||
_spec.Limit = *limit
|
_spec.Limit = *limit
|
||||||
}
|
}
|
||||||
if offset := atq.offset; offset != nil {
|
if offset := atq.ctx.Offset; offset != nil {
|
||||||
_spec.Offset = *offset
|
_spec.Offset = *offset
|
||||||
}
|
}
|
||||||
if ps := atq.order; len(ps) > 0 {
|
if ps := atq.order; len(ps) > 0 {
|
||||||
@@ -492,7 +566,7 @@ func (atq *AuthTokensQuery) querySpec() *sqlgraph.QuerySpec {
|
|||||||
func (atq *AuthTokensQuery) sqlQuery(ctx context.Context) *sql.Selector {
|
func (atq *AuthTokensQuery) sqlQuery(ctx context.Context) *sql.Selector {
|
||||||
builder := sql.Dialect(atq.driver.Dialect())
|
builder := sql.Dialect(atq.driver.Dialect())
|
||||||
t1 := builder.Table(authtokens.Table)
|
t1 := builder.Table(authtokens.Table)
|
||||||
columns := atq.fields
|
columns := atq.ctx.Fields
|
||||||
if len(columns) == 0 {
|
if len(columns) == 0 {
|
||||||
columns = authtokens.Columns
|
columns = authtokens.Columns
|
||||||
}
|
}
|
||||||
@@ -501,7 +575,7 @@ func (atq *AuthTokensQuery) sqlQuery(ctx context.Context) *sql.Selector {
|
|||||||
selector = atq.sql
|
selector = atq.sql
|
||||||
selector.Select(selector.Columns(columns...)...)
|
selector.Select(selector.Columns(columns...)...)
|
||||||
}
|
}
|
||||||
if atq.unique != nil && *atq.unique {
|
if atq.ctx.Unique != nil && *atq.ctx.Unique {
|
||||||
selector.Distinct()
|
selector.Distinct()
|
||||||
}
|
}
|
||||||
for _, p := range atq.predicates {
|
for _, p := range atq.predicates {
|
||||||
@@ -510,12 +584,12 @@ func (atq *AuthTokensQuery) sqlQuery(ctx context.Context) *sql.Selector {
|
|||||||
for _, p := range atq.order {
|
for _, p := range atq.order {
|
||||||
p(selector)
|
p(selector)
|
||||||
}
|
}
|
||||||
if offset := atq.offset; offset != nil {
|
if offset := atq.ctx.Offset; offset != nil {
|
||||||
// limit is mandatory for offset clause. We start
|
// limit is mandatory for offset clause. We start
|
||||||
// with default value, and override it below if needed.
|
// with default value, and override it below if needed.
|
||||||
selector.Offset(*offset).Limit(math.MaxInt32)
|
selector.Offset(*offset).Limit(math.MaxInt32)
|
||||||
}
|
}
|
||||||
if limit := atq.limit; limit != nil {
|
if limit := atq.ctx.Limit; limit != nil {
|
||||||
selector.Limit(*limit)
|
selector.Limit(*limit)
|
||||||
}
|
}
|
||||||
return selector
|
return selector
|
||||||
@@ -523,13 +597,8 @@ func (atq *AuthTokensQuery) sqlQuery(ctx context.Context) *sql.Selector {
|
|||||||
|
|
||||||
// AuthTokensGroupBy is the group-by builder for AuthTokens entities.
|
// AuthTokensGroupBy is the group-by builder for AuthTokens entities.
|
||||||
type AuthTokensGroupBy struct {
|
type AuthTokensGroupBy struct {
|
||||||
config
|
|
||||||
selector
|
selector
|
||||||
fields []string
|
build *AuthTokensQuery
|
||||||
fns []AggregateFunc
|
|
||||||
// intermediate query (i.e. traversal path).
|
|
||||||
sql *sql.Selector
|
|
||||||
path func(context.Context) (*sql.Selector, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aggregate adds the given aggregation functions to the group-by query.
|
// Aggregate adds the given aggregation functions to the group-by query.
|
||||||
@@ -538,74 +607,77 @@ func (atgb *AuthTokensGroupBy) Aggregate(fns ...AggregateFunc) *AuthTokensGroupB
|
|||||||
return atgb
|
return atgb
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan applies the group-by query and scans the result into the given value.
|
// Scan applies the selector query and scans the result into the given value.
|
||||||
func (atgb *AuthTokensGroupBy) Scan(ctx context.Context, v any) error {
|
func (atgb *AuthTokensGroupBy) Scan(ctx context.Context, v any) error {
|
||||||
query, err := atgb.path(ctx)
|
ctx = setContextOp(ctx, atgb.build.ctx, "GroupBy")
|
||||||
if err != nil {
|
if err := atgb.build.prepareQuery(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
atgb.sql = query
|
return scanWithInterceptors[*AuthTokensQuery, *AuthTokensGroupBy](ctx, atgb.build, atgb, atgb.build.inters, v)
|
||||||
return atgb.sqlScan(ctx, v)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (atgb *AuthTokensGroupBy) sqlScan(ctx context.Context, v any) error {
|
func (atgb *AuthTokensGroupBy) sqlScan(ctx context.Context, root *AuthTokensQuery, v any) error {
|
||||||
for _, f := range atgb.fields {
|
selector := root.sqlQuery(ctx).Select()
|
||||||
if !authtokens.ValidColumn(f) {
|
|
||||||
return &ValidationError{Name: f, err: fmt.Errorf("invalid field %q for group-by", f)}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
selector := atgb.sqlQuery()
|
|
||||||
if err := selector.Err(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rows := &sql.Rows{}
|
|
||||||
query, args := selector.Query()
|
|
||||||
if err := atgb.driver.Query(ctx, query, args, rows); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
return sql.ScanSlice(rows, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (atgb *AuthTokensGroupBy) sqlQuery() *sql.Selector {
|
|
||||||
selector := atgb.sql.Select()
|
|
||||||
aggregation := make([]string, 0, len(atgb.fns))
|
aggregation := make([]string, 0, len(atgb.fns))
|
||||||
for _, fn := range atgb.fns {
|
for _, fn := range atgb.fns {
|
||||||
aggregation = append(aggregation, fn(selector))
|
aggregation = append(aggregation, fn(selector))
|
||||||
}
|
}
|
||||||
// If no columns were selected in a custom aggregation function, the default
|
|
||||||
// selection is the fields used for "group-by", and the aggregation functions.
|
|
||||||
if len(selector.SelectedColumns()) == 0 {
|
if len(selector.SelectedColumns()) == 0 {
|
||||||
columns := make([]string, 0, len(atgb.fields)+len(atgb.fns))
|
columns := make([]string, 0, len(*atgb.flds)+len(atgb.fns))
|
||||||
for _, f := range atgb.fields {
|
for _, f := range *atgb.flds {
|
||||||
columns = append(columns, selector.C(f))
|
columns = append(columns, selector.C(f))
|
||||||
}
|
}
|
||||||
columns = append(columns, aggregation...)
|
columns = append(columns, aggregation...)
|
||||||
selector.Select(columns...)
|
selector.Select(columns...)
|
||||||
}
|
}
|
||||||
return selector.GroupBy(selector.Columns(atgb.fields...)...)
|
selector.GroupBy(selector.Columns(*atgb.flds...)...)
|
||||||
|
if err := selector.Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rows := &sql.Rows{}
|
||||||
|
query, args := selector.Query()
|
||||||
|
if err := atgb.build.driver.Query(ctx, query, args, rows); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
return sql.ScanSlice(rows, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthTokensSelect is the builder for selecting fields of AuthTokens entities.
|
// AuthTokensSelect is the builder for selecting fields of AuthTokens entities.
|
||||||
type AuthTokensSelect struct {
|
type AuthTokensSelect struct {
|
||||||
*AuthTokensQuery
|
*AuthTokensQuery
|
||||||
selector
|
selector
|
||||||
// intermediate query (i.e. traversal path).
|
}
|
||||||
sql *sql.Selector
|
|
||||||
|
// Aggregate adds the given aggregation functions to the selector query.
|
||||||
|
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.
|
// Scan applies the selector query and scans the result into the given value.
|
||||||
func (ats *AuthTokensSelect) Scan(ctx context.Context, v any) error {
|
func (ats *AuthTokensSelect) Scan(ctx context.Context, v any) error {
|
||||||
|
ctx = setContextOp(ctx, ats.ctx, "Select")
|
||||||
if err := ats.prepareQuery(ctx); err != nil {
|
if err := ats.prepareQuery(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ats.sql = ats.AuthTokensQuery.sqlQuery(ctx)
|
return scanWithInterceptors[*AuthTokensQuery, *AuthTokensSelect](ctx, ats.AuthTokensQuery, ats, ats.inters, v)
|
||||||
return ats.sqlScan(ctx, v)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ats *AuthTokensSelect) sqlScan(ctx context.Context, v any) error {
|
func (ats *AuthTokensSelect) sqlScan(ctx context.Context, root *AuthTokensQuery, v any) error {
|
||||||
|
selector := root.sqlQuery(ctx)
|
||||||
|
aggregation := make([]string, 0, len(ats.fns))
|
||||||
|
for _, fn := range ats.fns {
|
||||||
|
aggregation = append(aggregation, fn(selector))
|
||||||
|
}
|
||||||
|
switch n := len(*ats.selector.flds); {
|
||||||
|
case n == 0 && len(aggregation) > 0:
|
||||||
|
selector.Select(aggregation...)
|
||||||
|
case n != 0 && len(aggregation) > 0:
|
||||||
|
selector.AppendSelect(aggregation...)
|
||||||
|
}
|
||||||
rows := &sql.Rows{}
|
rows := &sql.Rows{}
|
||||||
query, args := ats.sql.Query()
|
query, args := selector.Query()
|
||||||
if err := ats.driver.Query(ctx, query, args, rows); err != nil {
|
if err := ats.driver.Query(ctx, query, args, rows); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
"entgo.io/ent/schema/field"
|
"entgo.io/ent/schema/field"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/user"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/user"
|
||||||
@@ -75,6 +76,25 @@ func (atu *AuthTokensUpdate) SetUser(u *User) *AuthTokensUpdate {
|
|||||||
return atu.SetUserID(u.ID)
|
return atu.SetUserID(u.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetRolesID sets the "roles" edge to the AuthRoles entity by ID.
|
||||||
|
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 (atu *AuthTokensUpdate) SetNillableRolesID(id *int) *AuthTokensUpdate {
|
||||||
|
if id != nil {
|
||||||
|
atu = atu.SetRolesID(*id)
|
||||||
|
}
|
||||||
|
return atu
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRoles sets the "roles" edge to the AuthRoles entity.
|
||||||
|
func (atu *AuthTokensUpdate) SetRoles(a *AuthRoles) *AuthTokensUpdate {
|
||||||
|
return atu.SetRolesID(a.ID)
|
||||||
|
}
|
||||||
|
|
||||||
// Mutation returns the AuthTokensMutation object of the builder.
|
// Mutation returns the AuthTokensMutation object of the builder.
|
||||||
func (atu *AuthTokensUpdate) Mutation() *AuthTokensMutation {
|
func (atu *AuthTokensUpdate) Mutation() *AuthTokensMutation {
|
||||||
return atu.mutation
|
return atu.mutation
|
||||||
@@ -86,37 +106,16 @@ func (atu *AuthTokensUpdate) ClearUser() *AuthTokensUpdate {
|
|||||||
return atu
|
return atu
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClearRoles clears the "roles" edge to the AuthRoles entity.
|
||||||
|
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.
|
// Save executes the query and returns the number of nodes affected by the update operation.
|
||||||
func (atu *AuthTokensUpdate) Save(ctx context.Context) (int, error) {
|
func (atu *AuthTokensUpdate) Save(ctx context.Context) (int, error) {
|
||||||
var (
|
|
||||||
err error
|
|
||||||
affected int
|
|
||||||
)
|
|
||||||
atu.defaults()
|
atu.defaults()
|
||||||
if len(atu.hooks) == 0 {
|
return withHooks(ctx, atu.sqlSave, atu.mutation, atu.hooks)
|
||||||
affected, err = atu.sqlSave(ctx)
|
|
||||||
} else {
|
|
||||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
|
||||||
mutation, ok := m.(*AuthTokensMutation)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
|
||||||
}
|
|
||||||
atu.mutation = mutation
|
|
||||||
affected, err = atu.sqlSave(ctx)
|
|
||||||
mutation.done = true
|
|
||||||
return affected, err
|
|
||||||
})
|
|
||||||
for i := len(atu.hooks) - 1; i >= 0; i-- {
|
|
||||||
if atu.hooks[i] == nil {
|
|
||||||
return 0, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
|
||||||
}
|
|
||||||
mut = atu.hooks[i](mut)
|
|
||||||
}
|
|
||||||
if _, err := mut.Mutate(ctx, atu.mutation); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return affected, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveX is like Save, but panics if an error occurs.
|
// SaveX is like Save, but panics if an error occurs.
|
||||||
@@ -150,16 +149,7 @@ func (atu *AuthTokensUpdate) defaults() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (atu *AuthTokensUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
func (atu *AuthTokensUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||||
_spec := &sqlgraph.UpdateSpec{
|
_spec := sqlgraph.NewUpdateSpec(authtokens.Table, authtokens.Columns, sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID))
|
||||||
Node: &sqlgraph.NodeSpec{
|
|
||||||
Table: authtokens.Table,
|
|
||||||
Columns: authtokens.Columns,
|
|
||||||
ID: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: authtokens.FieldID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if ps := atu.mutation.predicates; len(ps) > 0 {
|
if ps := atu.mutation.predicates; len(ps) > 0 {
|
||||||
_spec.Predicate = func(selector *sql.Selector) {
|
_spec.Predicate = func(selector *sql.Selector) {
|
||||||
for i := range ps {
|
for i := range ps {
|
||||||
@@ -168,25 +158,13 @@ func (atu *AuthTokensUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if value, ok := atu.mutation.UpdatedAt(); ok {
|
if value, ok := atu.mutation.UpdatedAt(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(authtokens.FieldUpdatedAt, field.TypeTime, value)
|
||||||
Type: field.TypeTime,
|
|
||||||
Value: value,
|
|
||||||
Column: authtokens.FieldUpdatedAt,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if value, ok := atu.mutation.Token(); ok {
|
if value, ok := atu.mutation.Token(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(authtokens.FieldToken, field.TypeBytes, value)
|
||||||
Type: field.TypeBytes,
|
|
||||||
Value: value,
|
|
||||||
Column: authtokens.FieldToken,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if value, ok := atu.mutation.ExpiresAt(); ok {
|
if value, ok := atu.mutation.ExpiresAt(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(authtokens.FieldExpiresAt, field.TypeTime, value)
|
||||||
Type: field.TypeTime,
|
|
||||||
Value: value,
|
|
||||||
Column: authtokens.FieldExpiresAt,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if atu.mutation.UserCleared() {
|
if atu.mutation.UserCleared() {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
@@ -196,10 +174,7 @@ func (atu *AuthTokensUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
|||||||
Columns: []string{authtokens.UserColumn},
|
Columns: []string{authtokens.UserColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: user.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||||
@@ -212,10 +187,36 @@ func (atu *AuthTokensUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
|||||||
Columns: []string{authtokens.UserColumn},
|
Columns: []string{authtokens.UserColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
||||||
Type: field.TypeUUID,
|
},
|
||||||
Column: user.FieldID,
|
}
|
||||||
},
|
for _, k := range nodes {
|
||||||
|
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||||
|
}
|
||||||
|
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
||||||
|
}
|
||||||
|
if atu.mutation.RolesCleared() {
|
||||||
|
edge := &sqlgraph.EdgeSpec{
|
||||||
|
Rel: sqlgraph.O2O,
|
||||||
|
Inverse: false,
|
||||||
|
Table: authtokens.RolesTable,
|
||||||
|
Columns: []string{authtokens.RolesColumn},
|
||||||
|
Bidi: false,
|
||||||
|
Target: &sqlgraph.EdgeTarget{
|
||||||
|
IDSpec: sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||||
|
}
|
||||||
|
if nodes := atu.mutation.RolesIDs(); len(nodes) > 0 {
|
||||||
|
edge := &sqlgraph.EdgeSpec{
|
||||||
|
Rel: sqlgraph.O2O,
|
||||||
|
Inverse: false,
|
||||||
|
Table: authtokens.RolesTable,
|
||||||
|
Columns: []string{authtokens.RolesColumn},
|
||||||
|
Bidi: false,
|
||||||
|
Target: &sqlgraph.EdgeTarget{
|
||||||
|
IDSpec: sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
@@ -231,6 +232,7 @@ func (atu *AuthTokensUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
|||||||
}
|
}
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
atu.mutation.done = true
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,6 +289,25 @@ func (atuo *AuthTokensUpdateOne) SetUser(u *User) *AuthTokensUpdateOne {
|
|||||||
return atuo.SetUserID(u.ID)
|
return atuo.SetUserID(u.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetRolesID sets the "roles" edge to the AuthRoles entity by ID.
|
||||||
|
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 (atuo *AuthTokensUpdateOne) SetNillableRolesID(id *int) *AuthTokensUpdateOne {
|
||||||
|
if id != nil {
|
||||||
|
atuo = atuo.SetRolesID(*id)
|
||||||
|
}
|
||||||
|
return atuo
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRoles sets the "roles" edge to the AuthRoles entity.
|
||||||
|
func (atuo *AuthTokensUpdateOne) SetRoles(a *AuthRoles) *AuthTokensUpdateOne {
|
||||||
|
return atuo.SetRolesID(a.ID)
|
||||||
|
}
|
||||||
|
|
||||||
// Mutation returns the AuthTokensMutation object of the builder.
|
// Mutation returns the AuthTokensMutation object of the builder.
|
||||||
func (atuo *AuthTokensUpdateOne) Mutation() *AuthTokensMutation {
|
func (atuo *AuthTokensUpdateOne) Mutation() *AuthTokensMutation {
|
||||||
return atuo.mutation
|
return atuo.mutation
|
||||||
@@ -298,6 +319,18 @@ func (atuo *AuthTokensUpdateOne) ClearUser() *AuthTokensUpdateOne {
|
|||||||
return atuo
|
return atuo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClearRoles clears the "roles" edge to the AuthRoles entity.
|
||||||
|
func (atuo *AuthTokensUpdateOne) ClearRoles() *AuthTokensUpdateOne {
|
||||||
|
atuo.mutation.ClearRoles()
|
||||||
|
return atuo
|
||||||
|
}
|
||||||
|
|
||||||
|
// Where appends a list predicates to the AuthTokensUpdate builder.
|
||||||
|
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.
|
// Select allows selecting one or more fields (columns) of the returned entity.
|
||||||
// The default is selecting all fields defined in the entity schema.
|
// The default is selecting all fields defined in the entity schema.
|
||||||
func (atuo *AuthTokensUpdateOne) Select(field string, fields ...string) *AuthTokensUpdateOne {
|
func (atuo *AuthTokensUpdateOne) Select(field string, fields ...string) *AuthTokensUpdateOne {
|
||||||
@@ -307,41 +340,8 @@ func (atuo *AuthTokensUpdateOne) Select(field string, fields ...string) *AuthTok
|
|||||||
|
|
||||||
// Save executes the query and returns the updated AuthTokens entity.
|
// Save executes the query and returns the updated AuthTokens entity.
|
||||||
func (atuo *AuthTokensUpdateOne) Save(ctx context.Context) (*AuthTokens, error) {
|
func (atuo *AuthTokensUpdateOne) Save(ctx context.Context) (*AuthTokens, error) {
|
||||||
var (
|
|
||||||
err error
|
|
||||||
node *AuthTokens
|
|
||||||
)
|
|
||||||
atuo.defaults()
|
atuo.defaults()
|
||||||
if len(atuo.hooks) == 0 {
|
return withHooks(ctx, atuo.sqlSave, atuo.mutation, atuo.hooks)
|
||||||
node, err = atuo.sqlSave(ctx)
|
|
||||||
} else {
|
|
||||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
|
||||||
mutation, ok := m.(*AuthTokensMutation)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
|
||||||
}
|
|
||||||
atuo.mutation = mutation
|
|
||||||
node, err = atuo.sqlSave(ctx)
|
|
||||||
mutation.done = true
|
|
||||||
return node, err
|
|
||||||
})
|
|
||||||
for i := len(atuo.hooks) - 1; i >= 0; i-- {
|
|
||||||
if atuo.hooks[i] == nil {
|
|
||||||
return nil, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
|
||||||
}
|
|
||||||
mut = atuo.hooks[i](mut)
|
|
||||||
}
|
|
||||||
v, err := mut.Mutate(ctx, atuo.mutation)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
nv, ok := v.(*AuthTokens)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected node type %T returned from AuthTokensMutation", v)
|
|
||||||
}
|
|
||||||
node = nv
|
|
||||||
}
|
|
||||||
return node, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveX is like Save, but panics if an error occurs.
|
// SaveX is like Save, but panics if an error occurs.
|
||||||
@@ -375,16 +375,7 @@ func (atuo *AuthTokensUpdateOne) defaults() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (atuo *AuthTokensUpdateOne) sqlSave(ctx context.Context) (_node *AuthTokens, err error) {
|
func (atuo *AuthTokensUpdateOne) sqlSave(ctx context.Context) (_node *AuthTokens, err error) {
|
||||||
_spec := &sqlgraph.UpdateSpec{
|
_spec := sqlgraph.NewUpdateSpec(authtokens.Table, authtokens.Columns, sqlgraph.NewFieldSpec(authtokens.FieldID, field.TypeUUID))
|
||||||
Node: &sqlgraph.NodeSpec{
|
|
||||||
Table: authtokens.Table,
|
|
||||||
Columns: authtokens.Columns,
|
|
||||||
ID: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: authtokens.FieldID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
id, ok := atuo.mutation.ID()
|
id, ok := atuo.mutation.ID()
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "AuthTokens.id" for update`)}
|
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "AuthTokens.id" for update`)}
|
||||||
@@ -410,25 +401,13 @@ func (atuo *AuthTokensUpdateOne) sqlSave(ctx context.Context) (_node *AuthTokens
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if value, ok := atuo.mutation.UpdatedAt(); ok {
|
if value, ok := atuo.mutation.UpdatedAt(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(authtokens.FieldUpdatedAt, field.TypeTime, value)
|
||||||
Type: field.TypeTime,
|
|
||||||
Value: value,
|
|
||||||
Column: authtokens.FieldUpdatedAt,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if value, ok := atuo.mutation.Token(); ok {
|
if value, ok := atuo.mutation.Token(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(authtokens.FieldToken, field.TypeBytes, value)
|
||||||
Type: field.TypeBytes,
|
|
||||||
Value: value,
|
|
||||||
Column: authtokens.FieldToken,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if value, ok := atuo.mutation.ExpiresAt(); ok {
|
if value, ok := atuo.mutation.ExpiresAt(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(authtokens.FieldExpiresAt, field.TypeTime, value)
|
||||||
Type: field.TypeTime,
|
|
||||||
Value: value,
|
|
||||||
Column: authtokens.FieldExpiresAt,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if atuo.mutation.UserCleared() {
|
if atuo.mutation.UserCleared() {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
@@ -438,10 +417,7 @@ func (atuo *AuthTokensUpdateOne) sqlSave(ctx context.Context) (_node *AuthTokens
|
|||||||
Columns: []string{authtokens.UserColumn},
|
Columns: []string{authtokens.UserColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: user.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||||
@@ -454,10 +430,36 @@ func (atuo *AuthTokensUpdateOne) sqlSave(ctx context.Context) (_node *AuthTokens
|
|||||||
Columns: []string{authtokens.UserColumn},
|
Columns: []string{authtokens.UserColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
||||||
Type: field.TypeUUID,
|
},
|
||||||
Column: user.FieldID,
|
}
|
||||||
},
|
for _, k := range nodes {
|
||||||
|
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||||
|
}
|
||||||
|
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
||||||
|
}
|
||||||
|
if atuo.mutation.RolesCleared() {
|
||||||
|
edge := &sqlgraph.EdgeSpec{
|
||||||
|
Rel: sqlgraph.O2O,
|
||||||
|
Inverse: false,
|
||||||
|
Table: authtokens.RolesTable,
|
||||||
|
Columns: []string{authtokens.RolesColumn},
|
||||||
|
Bidi: false,
|
||||||
|
Target: &sqlgraph.EdgeTarget{
|
||||||
|
IDSpec: sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||||
|
}
|
||||||
|
if nodes := atuo.mutation.RolesIDs(); len(nodes) > 0 {
|
||||||
|
edge := &sqlgraph.EdgeSpec{
|
||||||
|
Rel: sqlgraph.O2O,
|
||||||
|
Inverse: false,
|
||||||
|
Table: authtokens.RolesTable,
|
||||||
|
Columns: []string{authtokens.RolesColumn},
|
||||||
|
Bidi: false,
|
||||||
|
Target: &sqlgraph.EdgeTarget{
|
||||||
|
IDSpec: sqlgraph.NewFieldSpec(authroles.FieldID, field.TypeInt),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
@@ -476,5 +478,6 @@ func (atuo *AuthTokensUpdateOne) sqlSave(ctx context.Context) (_node *AuthTokens
|
|||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
atuo.mutation.done = true
|
||||||
return _node, nil
|
return _node, nil
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,69 +0,0 @@
|
|||||||
// Code generated by ent, DO NOT EDIT.
|
|
||||||
|
|
||||||
package ent
|
|
||||||
|
|
||||||
import (
|
|
||||||
"entgo.io/ent"
|
|
||||||
"entgo.io/ent/dialect"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Option function to configure the client.
|
|
||||||
type Option func(*config)
|
|
||||||
|
|
||||||
// Config is the configuration for the client and its builder.
|
|
||||||
type config struct {
|
|
||||||
// driver used for executing database requests.
|
|
||||||
driver dialect.Driver
|
|
||||||
// debug enable a debug logging.
|
|
||||||
debug bool
|
|
||||||
// log used for logging on debug mode.
|
|
||||||
log func(...any)
|
|
||||||
// hooks to execute on mutations.
|
|
||||||
hooks *hooks
|
|
||||||
}
|
|
||||||
|
|
||||||
// hooks per client, for fast access.
|
|
||||||
type hooks struct {
|
|
||||||
Attachment []ent.Hook
|
|
||||||
AuthTokens []ent.Hook
|
|
||||||
Document []ent.Hook
|
|
||||||
DocumentToken []ent.Hook
|
|
||||||
Group []ent.Hook
|
|
||||||
GroupInvitationToken []ent.Hook
|
|
||||||
Item []ent.Hook
|
|
||||||
ItemField []ent.Hook
|
|
||||||
Label []ent.Hook
|
|
||||||
Location []ent.Hook
|
|
||||||
User []ent.Hook
|
|
||||||
}
|
|
||||||
|
|
||||||
// Options applies the options on the config object.
|
|
||||||
func (c *config) options(opts ...Option) {
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(c)
|
|
||||||
}
|
|
||||||
if c.debug {
|
|
||||||
c.driver = dialect.Debug(c.driver, c.log)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug enables debug logging on the ent.Driver.
|
|
||||||
func Debug() Option {
|
|
||||||
return func(c *config) {
|
|
||||||
c.debug = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log sets the logging function for debug mode.
|
|
||||||
func Log(fn func(...any)) Option {
|
|
||||||
return func(c *config) {
|
|
||||||
c.log = fn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Driver configures the client driver.
|
|
||||||
func Driver(driver dialect.Driver) Option {
|
|
||||||
return func(c *config) {
|
|
||||||
c.driver = driver
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
// Code generated by ent, DO NOT EDIT.
|
|
||||||
|
|
||||||
package ent
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
)
|
|
||||||
|
|
||||||
type clientCtxKey struct{}
|
|
||||||
|
|
||||||
// FromContext returns a Client stored inside a context, or nil if there isn't one.
|
|
||||||
func FromContext(ctx context.Context) *Client {
|
|
||||||
c, _ := ctx.Value(clientCtxKey{}).(*Client)
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewContext returns a new context with the given Client attached.
|
|
||||||
func NewContext(parent context.Context, c *Client) context.Context {
|
|
||||||
return context.WithValue(parent, clientCtxKey{}, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
type txCtxKey struct{}
|
|
||||||
|
|
||||||
// TxFromContext returns a Tx stored inside a context, or nil if there isn't one.
|
|
||||||
func TxFromContext(ctx context.Context) *Tx {
|
|
||||||
tx, _ := ctx.Value(txCtxKey{}).(*Tx)
|
|
||||||
return tx
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTxContext returns a new context with the given Tx attached.
|
|
||||||
func NewTxContext(parent context.Context, tx *Tx) context.Context {
|
|
||||||
return context.WithValue(parent, txCtxKey{}, tx)
|
|
||||||
}
|
|
||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"entgo.io/ent"
|
||||||
"entgo.io/ent/dialect/sql"
|
"entgo.io/ent/dialect/sql"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/document"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/document"
|
||||||
@@ -30,19 +31,18 @@ type Document struct {
|
|||||||
// The values are being populated by the DocumentQuery when eager-loading is set.
|
// The values are being populated by the DocumentQuery when eager-loading is set.
|
||||||
Edges DocumentEdges `json:"edges"`
|
Edges DocumentEdges `json:"edges"`
|
||||||
group_documents *uuid.UUID
|
group_documents *uuid.UUID
|
||||||
|
selectValues sql.SelectValues
|
||||||
}
|
}
|
||||||
|
|
||||||
// DocumentEdges holds the relations/edges for other nodes in the graph.
|
// DocumentEdges holds the relations/edges for other nodes in the graph.
|
||||||
type DocumentEdges struct {
|
type DocumentEdges struct {
|
||||||
// Group holds the value of the group edge.
|
// Group holds the value of the group edge.
|
||||||
Group *Group `json:"group,omitempty"`
|
Group *Group `json:"group,omitempty"`
|
||||||
// DocumentTokens holds the value of the document_tokens edge.
|
|
||||||
DocumentTokens []*DocumentToken `json:"document_tokens,omitempty"`
|
|
||||||
// Attachments holds the value of the attachments edge.
|
// Attachments holds the value of the attachments edge.
|
||||||
Attachments []*Attachment `json:"attachments,omitempty"`
|
Attachments []*Attachment `json:"attachments,omitempty"`
|
||||||
// loadedTypes holds the information for reporting if a
|
// loadedTypes holds the information for reporting if a
|
||||||
// type was loaded (or requested) in eager-loading or not.
|
// type was loaded (or requested) in eager-loading or not.
|
||||||
loadedTypes [3]bool
|
loadedTypes [2]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// GroupOrErr returns the Group value or an error if the edge
|
// GroupOrErr returns the Group value or an error if the edge
|
||||||
@@ -58,19 +58,10 @@ func (e DocumentEdges) GroupOrErr() (*Group, error) {
|
|||||||
return nil, &NotLoadedError{edge: "group"}
|
return nil, &NotLoadedError{edge: "group"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DocumentTokensOrErr returns the DocumentTokens value or an error if the edge
|
|
||||||
// was not loaded in eager-loading.
|
|
||||||
func (e DocumentEdges) DocumentTokensOrErr() ([]*DocumentToken, error) {
|
|
||||||
if e.loadedTypes[1] {
|
|
||||||
return e.DocumentTokens, nil
|
|
||||||
}
|
|
||||||
return nil, &NotLoadedError{edge: "document_tokens"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AttachmentsOrErr returns the Attachments value or an error if the edge
|
// AttachmentsOrErr returns the Attachments value or an error if the edge
|
||||||
// was not loaded in eager-loading.
|
// was not loaded in eager-loading.
|
||||||
func (e DocumentEdges) AttachmentsOrErr() ([]*Attachment, error) {
|
func (e DocumentEdges) AttachmentsOrErr() ([]*Attachment, error) {
|
||||||
if e.loadedTypes[2] {
|
if e.loadedTypes[1] {
|
||||||
return e.Attachments, nil
|
return e.Attachments, nil
|
||||||
}
|
}
|
||||||
return nil, &NotLoadedError{edge: "attachments"}
|
return nil, &NotLoadedError{edge: "attachments"}
|
||||||
@@ -90,7 +81,7 @@ func (*Document) scanValues(columns []string) ([]any, error) {
|
|||||||
case document.ForeignKeys[0]: // group_documents
|
case document.ForeignKeys[0]: // group_documents
|
||||||
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
|
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unexpected column %q for type Document", columns[i])
|
values[i] = new(sql.UnknownType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return values, nil
|
return values, nil
|
||||||
@@ -141,31 +132,34 @@ func (d *Document) assignValues(columns []string, values []any) error {
|
|||||||
d.group_documents = new(uuid.UUID)
|
d.group_documents = new(uuid.UUID)
|
||||||
*d.group_documents = *value.S.(*uuid.UUID)
|
*d.group_documents = *value.S.(*uuid.UUID)
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
d.selectValues.Set(columns[i], values[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryGroup queries the "group" edge of the Document entity.
|
// Value returns the ent.Value that was dynamically selected and assigned to the Document.
|
||||||
func (d *Document) QueryGroup() *GroupQuery {
|
// This includes values selected through modifiers, order, etc.
|
||||||
return (&DocumentClient{config: d.config}).QueryGroup(d)
|
func (d *Document) Value(name string) (ent.Value, error) {
|
||||||
|
return d.selectValues.Get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryDocumentTokens queries the "document_tokens" edge of the Document entity.
|
// QueryGroup queries the "group" edge of the Document entity.
|
||||||
func (d *Document) QueryDocumentTokens() *DocumentTokenQuery {
|
func (d *Document) QueryGroup() *GroupQuery {
|
||||||
return (&DocumentClient{config: d.config}).QueryDocumentTokens(d)
|
return NewDocumentClient(d.config).QueryGroup(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryAttachments queries the "attachments" edge of the Document entity.
|
// QueryAttachments queries the "attachments" edge of the Document entity.
|
||||||
func (d *Document) QueryAttachments() *AttachmentQuery {
|
func (d *Document) QueryAttachments() *AttachmentQuery {
|
||||||
return (&DocumentClient{config: d.config}).QueryAttachments(d)
|
return NewDocumentClient(d.config).QueryAttachments(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update returns a builder for updating this Document.
|
// Update returns a builder for updating this Document.
|
||||||
// Note that you need to call Document.Unwrap() before calling this method if 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.
|
// was returned from a transaction, and the transaction was committed or rolled back.
|
||||||
func (d *Document) Update() *DocumentUpdateOne {
|
func (d *Document) Update() *DocumentUpdateOne {
|
||||||
return (&DocumentClient{config: d.config}).UpdateOne(d)
|
return NewDocumentClient(d.config).UpdateOne(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unwrap unwraps the Document entity that was returned from a transaction after it was closed,
|
// Unwrap unwraps the Document entity that was returned from a transaction after it was closed,
|
||||||
@@ -201,9 +195,3 @@ func (d *Document) String() string {
|
|||||||
|
|
||||||
// Documents is a parsable slice of Document.
|
// Documents is a parsable slice of Document.
|
||||||
type Documents []*Document
|
type Documents []*Document
|
||||||
|
|
||||||
func (d Documents) config(cfg config) {
|
|
||||||
for _i := range d {
|
|
||||||
d[_i].config = cfg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ package document
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"entgo.io/ent/dialect/sql"
|
||||||
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,8 +25,6 @@ const (
|
|||||||
FieldPath = "path"
|
FieldPath = "path"
|
||||||
// EdgeGroup holds the string denoting the group edge name in mutations.
|
// EdgeGroup holds the string denoting the group edge name in mutations.
|
||||||
EdgeGroup = "group"
|
EdgeGroup = "group"
|
||||||
// EdgeDocumentTokens holds the string denoting the document_tokens edge name in mutations.
|
|
||||||
EdgeDocumentTokens = "document_tokens"
|
|
||||||
// EdgeAttachments holds the string denoting the attachments edge name in mutations.
|
// EdgeAttachments holds the string denoting the attachments edge name in mutations.
|
||||||
EdgeAttachments = "attachments"
|
EdgeAttachments = "attachments"
|
||||||
// Table holds the table name of the document in the database.
|
// Table holds the table name of the document in the database.
|
||||||
@@ -36,13 +36,6 @@ const (
|
|||||||
GroupInverseTable = "groups"
|
GroupInverseTable = "groups"
|
||||||
// GroupColumn is the table column denoting the group relation/edge.
|
// GroupColumn is the table column denoting the group relation/edge.
|
||||||
GroupColumn = "group_documents"
|
GroupColumn = "group_documents"
|
||||||
// DocumentTokensTable is the table that holds the document_tokens relation/edge.
|
|
||||||
DocumentTokensTable = "document_tokens"
|
|
||||||
// DocumentTokensInverseTable is the table name for the DocumentToken entity.
|
|
||||||
// It exists in this package in order to avoid circular dependency with the "documenttoken" package.
|
|
||||||
DocumentTokensInverseTable = "document_tokens"
|
|
||||||
// DocumentTokensColumn is the table column denoting the document_tokens relation/edge.
|
|
||||||
DocumentTokensColumn = "document_document_tokens"
|
|
||||||
// AttachmentsTable is the table that holds the attachments relation/edge.
|
// AttachmentsTable is the table that holds the attachments relation/edge.
|
||||||
AttachmentsTable = "attachments"
|
AttachmentsTable = "attachments"
|
||||||
// AttachmentsInverseTable is the table name for the Attachment entity.
|
// AttachmentsInverseTable is the table name for the Attachment entity.
|
||||||
@@ -96,3 +89,66 @@ var (
|
|||||||
// DefaultID holds the default value on creation for the "id" field.
|
// DefaultID holds the default value on creation for the "id" field.
|
||||||
DefaultID func() uuid.UUID
|
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),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,427 +13,277 @@ import (
|
|||||||
|
|
||||||
// ID filters vertices based on their ID field.
|
// ID filters vertices based on their ID field.
|
||||||
func ID(id uuid.UUID) predicate.Document {
|
func ID(id uuid.UUID) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldEQ(FieldID, id))
|
||||||
s.Where(sql.EQ(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDEQ applies the EQ predicate on the ID field.
|
// IDEQ applies the EQ predicate on the ID field.
|
||||||
func IDEQ(id uuid.UUID) predicate.Document {
|
func IDEQ(id uuid.UUID) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldEQ(FieldID, id))
|
||||||
s.Where(sql.EQ(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDNEQ applies the NEQ predicate on the ID field.
|
// IDNEQ applies the NEQ predicate on the ID field.
|
||||||
func IDNEQ(id uuid.UUID) predicate.Document {
|
func IDNEQ(id uuid.UUID) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldNEQ(FieldID, id))
|
||||||
s.Where(sql.NEQ(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDIn applies the In predicate on the ID field.
|
// IDIn applies the In predicate on the ID field.
|
||||||
func IDIn(ids ...uuid.UUID) predicate.Document {
|
func IDIn(ids ...uuid.UUID) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldIn(FieldID, ids...))
|
||||||
v := make([]any, len(ids))
|
|
||||||
for i := range v {
|
|
||||||
v[i] = ids[i]
|
|
||||||
}
|
|
||||||
s.Where(sql.In(s.C(FieldID), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDNotIn applies the NotIn predicate on the ID field.
|
// IDNotIn applies the NotIn predicate on the ID field.
|
||||||
func IDNotIn(ids ...uuid.UUID) predicate.Document {
|
func IDNotIn(ids ...uuid.UUID) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldNotIn(FieldID, ids...))
|
||||||
v := make([]any, len(ids))
|
|
||||||
for i := range v {
|
|
||||||
v[i] = ids[i]
|
|
||||||
}
|
|
||||||
s.Where(sql.NotIn(s.C(FieldID), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDGT applies the GT predicate on the ID field.
|
// IDGT applies the GT predicate on the ID field.
|
||||||
func IDGT(id uuid.UUID) predicate.Document {
|
func IDGT(id uuid.UUID) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldGT(FieldID, id))
|
||||||
s.Where(sql.GT(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDGTE applies the GTE predicate on the ID field.
|
// IDGTE applies the GTE predicate on the ID field.
|
||||||
func IDGTE(id uuid.UUID) predicate.Document {
|
func IDGTE(id uuid.UUID) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldGTE(FieldID, id))
|
||||||
s.Where(sql.GTE(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDLT applies the LT predicate on the ID field.
|
// IDLT applies the LT predicate on the ID field.
|
||||||
func IDLT(id uuid.UUID) predicate.Document {
|
func IDLT(id uuid.UUID) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldLT(FieldID, id))
|
||||||
s.Where(sql.LT(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDLTE applies the LTE predicate on the ID field.
|
// IDLTE applies the LTE predicate on the ID field.
|
||||||
func IDLTE(id uuid.UUID) predicate.Document {
|
func IDLTE(id uuid.UUID) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldLTE(FieldID, id))
|
||||||
s.Where(sql.LTE(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
|
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
|
||||||
func CreatedAt(v time.Time) predicate.Document {
|
func CreatedAt(v time.Time) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldEQ(FieldCreatedAt, v))
|
||||||
s.Where(sql.EQ(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ.
|
// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ.
|
||||||
func UpdatedAt(v time.Time) predicate.Document {
|
func UpdatedAt(v time.Time) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldEQ(FieldUpdatedAt, v))
|
||||||
s.Where(sql.EQ(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Title applies equality check predicate on the "title" field. It's identical to TitleEQ.
|
// Title applies equality check predicate on the "title" field. It's identical to TitleEQ.
|
||||||
func Title(v string) predicate.Document {
|
func Title(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldEQ(FieldTitle, v))
|
||||||
s.Where(sql.EQ(s.C(FieldTitle), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path applies equality check predicate on the "path" field. It's identical to PathEQ.
|
// Path applies equality check predicate on the "path" field. It's identical to PathEQ.
|
||||||
func Path(v string) predicate.Document {
|
func Path(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldEQ(FieldPath, v))
|
||||||
s.Where(sql.EQ(s.C(FieldPath), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
||||||
func CreatedAtEQ(v time.Time) predicate.Document {
|
func CreatedAtEQ(v time.Time) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldEQ(FieldCreatedAt, v))
|
||||||
s.Where(sql.EQ(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
|
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
|
||||||
func CreatedAtNEQ(v time.Time) predicate.Document {
|
func CreatedAtNEQ(v time.Time) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldNEQ(FieldCreatedAt, v))
|
||||||
s.Where(sql.NEQ(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtIn applies the In predicate on the "created_at" field.
|
// CreatedAtIn applies the In predicate on the "created_at" field.
|
||||||
func CreatedAtIn(vs ...time.Time) predicate.Document {
|
func CreatedAtIn(vs ...time.Time) predicate.Document {
|
||||||
v := make([]any, len(vs))
|
return predicate.Document(sql.FieldIn(FieldCreatedAt, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.In(s.C(FieldCreatedAt), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
|
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
|
||||||
func CreatedAtNotIn(vs ...time.Time) predicate.Document {
|
func CreatedAtNotIn(vs ...time.Time) predicate.Document {
|
||||||
v := make([]any, len(vs))
|
return predicate.Document(sql.FieldNotIn(FieldCreatedAt, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.NotIn(s.C(FieldCreatedAt), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtGT applies the GT predicate on the "created_at" field.
|
// CreatedAtGT applies the GT predicate on the "created_at" field.
|
||||||
func CreatedAtGT(v time.Time) predicate.Document {
|
func CreatedAtGT(v time.Time) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldGT(FieldCreatedAt, v))
|
||||||
s.Where(sql.GT(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
|
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
|
||||||
func CreatedAtGTE(v time.Time) predicate.Document {
|
func CreatedAtGTE(v time.Time) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldGTE(FieldCreatedAt, v))
|
||||||
s.Where(sql.GTE(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtLT applies the LT predicate on the "created_at" field.
|
// CreatedAtLT applies the LT predicate on the "created_at" field.
|
||||||
func CreatedAtLT(v time.Time) predicate.Document {
|
func CreatedAtLT(v time.Time) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldLT(FieldCreatedAt, v))
|
||||||
s.Where(sql.LT(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
|
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
|
||||||
func CreatedAtLTE(v time.Time) predicate.Document {
|
func CreatedAtLTE(v time.Time) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldLTE(FieldCreatedAt, v))
|
||||||
s.Where(sql.LTE(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
|
// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
|
||||||
func UpdatedAtEQ(v time.Time) predicate.Document {
|
func UpdatedAtEQ(v time.Time) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldEQ(FieldUpdatedAt, v))
|
||||||
s.Where(sql.EQ(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
|
// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
|
||||||
func UpdatedAtNEQ(v time.Time) predicate.Document {
|
func UpdatedAtNEQ(v time.Time) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldNEQ(FieldUpdatedAt, v))
|
||||||
s.Where(sql.NEQ(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtIn applies the In predicate on the "updated_at" field.
|
// UpdatedAtIn applies the In predicate on the "updated_at" field.
|
||||||
func UpdatedAtIn(vs ...time.Time) predicate.Document {
|
func UpdatedAtIn(vs ...time.Time) predicate.Document {
|
||||||
v := make([]any, len(vs))
|
return predicate.Document(sql.FieldIn(FieldUpdatedAt, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.In(s.C(FieldUpdatedAt), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
|
// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
|
||||||
func UpdatedAtNotIn(vs ...time.Time) predicate.Document {
|
func UpdatedAtNotIn(vs ...time.Time) predicate.Document {
|
||||||
v := make([]any, len(vs))
|
return predicate.Document(sql.FieldNotIn(FieldUpdatedAt, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.NotIn(s.C(FieldUpdatedAt), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtGT applies the GT predicate on the "updated_at" field.
|
// UpdatedAtGT applies the GT predicate on the "updated_at" field.
|
||||||
func UpdatedAtGT(v time.Time) predicate.Document {
|
func UpdatedAtGT(v time.Time) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldGT(FieldUpdatedAt, v))
|
||||||
s.Where(sql.GT(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
|
// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
|
||||||
func UpdatedAtGTE(v time.Time) predicate.Document {
|
func UpdatedAtGTE(v time.Time) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldGTE(FieldUpdatedAt, v))
|
||||||
s.Where(sql.GTE(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtLT applies the LT predicate on the "updated_at" field.
|
// UpdatedAtLT applies the LT predicate on the "updated_at" field.
|
||||||
func UpdatedAtLT(v time.Time) predicate.Document {
|
func UpdatedAtLT(v time.Time) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldLT(FieldUpdatedAt, v))
|
||||||
s.Where(sql.LT(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
|
// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
|
||||||
func UpdatedAtLTE(v time.Time) predicate.Document {
|
func UpdatedAtLTE(v time.Time) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldLTE(FieldUpdatedAt, v))
|
||||||
s.Where(sql.LTE(s.C(FieldUpdatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TitleEQ applies the EQ predicate on the "title" field.
|
// TitleEQ applies the EQ predicate on the "title" field.
|
||||||
func TitleEQ(v string) predicate.Document {
|
func TitleEQ(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldEQ(FieldTitle, v))
|
||||||
s.Where(sql.EQ(s.C(FieldTitle), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TitleNEQ applies the NEQ predicate on the "title" field.
|
// TitleNEQ applies the NEQ predicate on the "title" field.
|
||||||
func TitleNEQ(v string) predicate.Document {
|
func TitleNEQ(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldNEQ(FieldTitle, v))
|
||||||
s.Where(sql.NEQ(s.C(FieldTitle), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TitleIn applies the In predicate on the "title" field.
|
// TitleIn applies the In predicate on the "title" field.
|
||||||
func TitleIn(vs ...string) predicate.Document {
|
func TitleIn(vs ...string) predicate.Document {
|
||||||
v := make([]any, len(vs))
|
return predicate.Document(sql.FieldIn(FieldTitle, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.In(s.C(FieldTitle), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TitleNotIn applies the NotIn predicate on the "title" field.
|
// TitleNotIn applies the NotIn predicate on the "title" field.
|
||||||
func TitleNotIn(vs ...string) predicate.Document {
|
func TitleNotIn(vs ...string) predicate.Document {
|
||||||
v := make([]any, len(vs))
|
return predicate.Document(sql.FieldNotIn(FieldTitle, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.NotIn(s.C(FieldTitle), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TitleGT applies the GT predicate on the "title" field.
|
// TitleGT applies the GT predicate on the "title" field.
|
||||||
func TitleGT(v string) predicate.Document {
|
func TitleGT(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldGT(FieldTitle, v))
|
||||||
s.Where(sql.GT(s.C(FieldTitle), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TitleGTE applies the GTE predicate on the "title" field.
|
// TitleGTE applies the GTE predicate on the "title" field.
|
||||||
func TitleGTE(v string) predicate.Document {
|
func TitleGTE(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldGTE(FieldTitle, v))
|
||||||
s.Where(sql.GTE(s.C(FieldTitle), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TitleLT applies the LT predicate on the "title" field.
|
// TitleLT applies the LT predicate on the "title" field.
|
||||||
func TitleLT(v string) predicate.Document {
|
func TitleLT(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldLT(FieldTitle, v))
|
||||||
s.Where(sql.LT(s.C(FieldTitle), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TitleLTE applies the LTE predicate on the "title" field.
|
// TitleLTE applies the LTE predicate on the "title" field.
|
||||||
func TitleLTE(v string) predicate.Document {
|
func TitleLTE(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldLTE(FieldTitle, v))
|
||||||
s.Where(sql.LTE(s.C(FieldTitle), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TitleContains applies the Contains predicate on the "title" field.
|
// TitleContains applies the Contains predicate on the "title" field.
|
||||||
func TitleContains(v string) predicate.Document {
|
func TitleContains(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldContains(FieldTitle, v))
|
||||||
s.Where(sql.Contains(s.C(FieldTitle), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TitleHasPrefix applies the HasPrefix predicate on the "title" field.
|
// TitleHasPrefix applies the HasPrefix predicate on the "title" field.
|
||||||
func TitleHasPrefix(v string) predicate.Document {
|
func TitleHasPrefix(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldHasPrefix(FieldTitle, v))
|
||||||
s.Where(sql.HasPrefix(s.C(FieldTitle), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TitleHasSuffix applies the HasSuffix predicate on the "title" field.
|
// TitleHasSuffix applies the HasSuffix predicate on the "title" field.
|
||||||
func TitleHasSuffix(v string) predicate.Document {
|
func TitleHasSuffix(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldHasSuffix(FieldTitle, v))
|
||||||
s.Where(sql.HasSuffix(s.C(FieldTitle), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TitleEqualFold applies the EqualFold predicate on the "title" field.
|
// TitleEqualFold applies the EqualFold predicate on the "title" field.
|
||||||
func TitleEqualFold(v string) predicate.Document {
|
func TitleEqualFold(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldEqualFold(FieldTitle, v))
|
||||||
s.Where(sql.EqualFold(s.C(FieldTitle), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TitleContainsFold applies the ContainsFold predicate on the "title" field.
|
// TitleContainsFold applies the ContainsFold predicate on the "title" field.
|
||||||
func TitleContainsFold(v string) predicate.Document {
|
func TitleContainsFold(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldContainsFold(FieldTitle, v))
|
||||||
s.Where(sql.ContainsFold(s.C(FieldTitle), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PathEQ applies the EQ predicate on the "path" field.
|
// PathEQ applies the EQ predicate on the "path" field.
|
||||||
func PathEQ(v string) predicate.Document {
|
func PathEQ(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldEQ(FieldPath, v))
|
||||||
s.Where(sql.EQ(s.C(FieldPath), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PathNEQ applies the NEQ predicate on the "path" field.
|
// PathNEQ applies the NEQ predicate on the "path" field.
|
||||||
func PathNEQ(v string) predicate.Document {
|
func PathNEQ(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldNEQ(FieldPath, v))
|
||||||
s.Where(sql.NEQ(s.C(FieldPath), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PathIn applies the In predicate on the "path" field.
|
// PathIn applies the In predicate on the "path" field.
|
||||||
func PathIn(vs ...string) predicate.Document {
|
func PathIn(vs ...string) predicate.Document {
|
||||||
v := make([]any, len(vs))
|
return predicate.Document(sql.FieldIn(FieldPath, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.In(s.C(FieldPath), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PathNotIn applies the NotIn predicate on the "path" field.
|
// PathNotIn applies the NotIn predicate on the "path" field.
|
||||||
func PathNotIn(vs ...string) predicate.Document {
|
func PathNotIn(vs ...string) predicate.Document {
|
||||||
v := make([]any, len(vs))
|
return predicate.Document(sql.FieldNotIn(FieldPath, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
|
||||||
s.Where(sql.NotIn(s.C(FieldPath), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PathGT applies the GT predicate on the "path" field.
|
// PathGT applies the GT predicate on the "path" field.
|
||||||
func PathGT(v string) predicate.Document {
|
func PathGT(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldGT(FieldPath, v))
|
||||||
s.Where(sql.GT(s.C(FieldPath), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PathGTE applies the GTE predicate on the "path" field.
|
// PathGTE applies the GTE predicate on the "path" field.
|
||||||
func PathGTE(v string) predicate.Document {
|
func PathGTE(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldGTE(FieldPath, v))
|
||||||
s.Where(sql.GTE(s.C(FieldPath), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PathLT applies the LT predicate on the "path" field.
|
// PathLT applies the LT predicate on the "path" field.
|
||||||
func PathLT(v string) predicate.Document {
|
func PathLT(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldLT(FieldPath, v))
|
||||||
s.Where(sql.LT(s.C(FieldPath), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PathLTE applies the LTE predicate on the "path" field.
|
// PathLTE applies the LTE predicate on the "path" field.
|
||||||
func PathLTE(v string) predicate.Document {
|
func PathLTE(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldLTE(FieldPath, v))
|
||||||
s.Where(sql.LTE(s.C(FieldPath), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PathContains applies the Contains predicate on the "path" field.
|
// PathContains applies the Contains predicate on the "path" field.
|
||||||
func PathContains(v string) predicate.Document {
|
func PathContains(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldContains(FieldPath, v))
|
||||||
s.Where(sql.Contains(s.C(FieldPath), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PathHasPrefix applies the HasPrefix predicate on the "path" field.
|
// PathHasPrefix applies the HasPrefix predicate on the "path" field.
|
||||||
func PathHasPrefix(v string) predicate.Document {
|
func PathHasPrefix(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldHasPrefix(FieldPath, v))
|
||||||
s.Where(sql.HasPrefix(s.C(FieldPath), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PathHasSuffix applies the HasSuffix predicate on the "path" field.
|
// PathHasSuffix applies the HasSuffix predicate on the "path" field.
|
||||||
func PathHasSuffix(v string) predicate.Document {
|
func PathHasSuffix(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldHasSuffix(FieldPath, v))
|
||||||
s.Where(sql.HasSuffix(s.C(FieldPath), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PathEqualFold applies the EqualFold predicate on the "path" field.
|
// PathEqualFold applies the EqualFold predicate on the "path" field.
|
||||||
func PathEqualFold(v string) predicate.Document {
|
func PathEqualFold(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldEqualFold(FieldPath, v))
|
||||||
s.Where(sql.EqualFold(s.C(FieldPath), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PathContainsFold applies the ContainsFold predicate on the "path" field.
|
// PathContainsFold applies the ContainsFold predicate on the "path" field.
|
||||||
func PathContainsFold(v string) predicate.Document {
|
func PathContainsFold(v string) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(sql.FieldContainsFold(FieldPath, v))
|
||||||
s.Where(sql.ContainsFold(s.C(FieldPath), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasGroup applies the HasEdge predicate on the "group" edge.
|
// HasGroup applies the HasEdge predicate on the "group" edge.
|
||||||
@@ -441,7 +291,6 @@ func HasGroup() predicate.Document {
|
|||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(func(s *sql.Selector) {
|
||||||
step := sqlgraph.NewStep(
|
step := sqlgraph.NewStep(
|
||||||
sqlgraph.From(Table, FieldID),
|
sqlgraph.From(Table, FieldID),
|
||||||
sqlgraph.To(GroupTable, FieldID),
|
|
||||||
sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn),
|
sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn),
|
||||||
)
|
)
|
||||||
sqlgraph.HasNeighbors(s, step)
|
sqlgraph.HasNeighbors(s, step)
|
||||||
@@ -451,39 +300,7 @@ func HasGroup() predicate.Document {
|
|||||||
// HasGroupWith applies the HasEdge predicate on the "group" edge with a given conditions (other predicates).
|
// HasGroupWith applies the HasEdge predicate on the "group" edge with a given conditions (other predicates).
|
||||||
func HasGroupWith(preds ...predicate.Group) predicate.Document {
|
func HasGroupWith(preds ...predicate.Group) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(func(s *sql.Selector) {
|
||||||
step := sqlgraph.NewStep(
|
step := newGroupStep()
|
||||||
sqlgraph.From(Table, FieldID),
|
|
||||||
sqlgraph.To(GroupInverseTable, FieldID),
|
|
||||||
sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn),
|
|
||||||
)
|
|
||||||
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
|
||||||
for _, p := range preds {
|
|
||||||
p(s)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasDocumentTokens applies the HasEdge predicate on the "document_tokens" edge.
|
|
||||||
func HasDocumentTokens() predicate.Document {
|
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
|
||||||
step := sqlgraph.NewStep(
|
|
||||||
sqlgraph.From(Table, FieldID),
|
|
||||||
sqlgraph.To(DocumentTokensTable, FieldID),
|
|
||||||
sqlgraph.Edge(sqlgraph.O2M, false, DocumentTokensTable, DocumentTokensColumn),
|
|
||||||
)
|
|
||||||
sqlgraph.HasNeighbors(s, step)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasDocumentTokensWith applies the HasEdge predicate on the "document_tokens" edge with a given conditions (other predicates).
|
|
||||||
func HasDocumentTokensWith(preds ...predicate.DocumentToken) predicate.Document {
|
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
|
||||||
step := sqlgraph.NewStep(
|
|
||||||
sqlgraph.From(Table, FieldID),
|
|
||||||
sqlgraph.To(DocumentTokensInverseTable, FieldID),
|
|
||||||
sqlgraph.Edge(sqlgraph.O2M, false, DocumentTokensTable, DocumentTokensColumn),
|
|
||||||
)
|
|
||||||
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
||||||
for _, p := range preds {
|
for _, p := range preds {
|
||||||
p(s)
|
p(s)
|
||||||
@@ -497,7 +314,6 @@ func HasAttachments() predicate.Document {
|
|||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(func(s *sql.Selector) {
|
||||||
step := sqlgraph.NewStep(
|
step := sqlgraph.NewStep(
|
||||||
sqlgraph.From(Table, FieldID),
|
sqlgraph.From(Table, FieldID),
|
||||||
sqlgraph.To(AttachmentsTable, FieldID),
|
|
||||||
sqlgraph.Edge(sqlgraph.O2M, false, AttachmentsTable, AttachmentsColumn),
|
sqlgraph.Edge(sqlgraph.O2M, false, AttachmentsTable, AttachmentsColumn),
|
||||||
)
|
)
|
||||||
sqlgraph.HasNeighbors(s, step)
|
sqlgraph.HasNeighbors(s, step)
|
||||||
@@ -507,11 +323,7 @@ func HasAttachments() predicate.Document {
|
|||||||
// HasAttachmentsWith applies the HasEdge predicate on the "attachments" edge with a given conditions (other predicates).
|
// HasAttachmentsWith applies the HasEdge predicate on the "attachments" edge with a given conditions (other predicates).
|
||||||
func HasAttachmentsWith(preds ...predicate.Attachment) predicate.Document {
|
func HasAttachmentsWith(preds ...predicate.Attachment) predicate.Document {
|
||||||
return predicate.Document(func(s *sql.Selector) {
|
return predicate.Document(func(s *sql.Selector) {
|
||||||
step := sqlgraph.NewStep(
|
step := newAttachmentsStep()
|
||||||
sqlgraph.From(Table, FieldID),
|
|
||||||
sqlgraph.To(AttachmentsInverseTable, FieldID),
|
|
||||||
sqlgraph.Edge(sqlgraph.O2M, false, AttachmentsTable, AttachmentsColumn),
|
|
||||||
)
|
|
||||||
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
||||||
for _, p := range preds {
|
for _, p := range preds {
|
||||||
p(s)
|
p(s)
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/document"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/document"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/documenttoken"
|
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/group"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/group"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -89,21 +88,6 @@ func (dc *DocumentCreate) SetGroup(g *Group) *DocumentCreate {
|
|||||||
return dc.SetGroupID(g.ID)
|
return dc.SetGroupID(g.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddDocumentTokenIDs adds the "document_tokens" edge to the DocumentToken entity by IDs.
|
|
||||||
func (dc *DocumentCreate) AddDocumentTokenIDs(ids ...uuid.UUID) *DocumentCreate {
|
|
||||||
dc.mutation.AddDocumentTokenIDs(ids...)
|
|
||||||
return dc
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddDocumentTokens adds the "document_tokens" edges to the DocumentToken entity.
|
|
||||||
func (dc *DocumentCreate) AddDocumentTokens(d ...*DocumentToken) *DocumentCreate {
|
|
||||||
ids := make([]uuid.UUID, len(d))
|
|
||||||
for i := range d {
|
|
||||||
ids[i] = d[i].ID
|
|
||||||
}
|
|
||||||
return dc.AddDocumentTokenIDs(ids...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddAttachmentIDs adds the "attachments" edge to the Attachment entity by IDs.
|
// AddAttachmentIDs adds the "attachments" edge to the Attachment entity by IDs.
|
||||||
func (dc *DocumentCreate) AddAttachmentIDs(ids ...uuid.UUID) *DocumentCreate {
|
func (dc *DocumentCreate) AddAttachmentIDs(ids ...uuid.UUID) *DocumentCreate {
|
||||||
dc.mutation.AddAttachmentIDs(ids...)
|
dc.mutation.AddAttachmentIDs(ids...)
|
||||||
@@ -126,50 +110,8 @@ func (dc *DocumentCreate) Mutation() *DocumentMutation {
|
|||||||
|
|
||||||
// Save creates the Document in the database.
|
// Save creates the Document in the database.
|
||||||
func (dc *DocumentCreate) Save(ctx context.Context) (*Document, error) {
|
func (dc *DocumentCreate) Save(ctx context.Context) (*Document, error) {
|
||||||
var (
|
|
||||||
err error
|
|
||||||
node *Document
|
|
||||||
)
|
|
||||||
dc.defaults()
|
dc.defaults()
|
||||||
if len(dc.hooks) == 0 {
|
return withHooks(ctx, dc.sqlSave, dc.mutation, dc.hooks)
|
||||||
if err = dc.check(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
node, err = dc.sqlSave(ctx)
|
|
||||||
} else {
|
|
||||||
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 = dc.check(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
dc.mutation = mutation
|
|
||||||
if node, err = dc.sqlSave(ctx); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mutation.id = &node.ID
|
|
||||||
mutation.done = true
|
|
||||||
return node, err
|
|
||||||
})
|
|
||||||
for i := len(dc.hooks) - 1; i >= 0; i-- {
|
|
||||||
if dc.hooks[i] == nil {
|
|
||||||
return nil, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
|
||||||
}
|
|
||||||
mut = dc.hooks[i](mut)
|
|
||||||
}
|
|
||||||
v, err := mut.Mutate(ctx, dc.mutation)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
nv, ok := v.(*Document)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected node type %T returned from DocumentMutation", v)
|
|
||||||
}
|
|
||||||
node = nv
|
|
||||||
}
|
|
||||||
return node, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveX calls Save and panics if Save returns an error.
|
// SaveX calls Save and panics if Save returns an error.
|
||||||
@@ -241,6 +183,9 @@ func (dc *DocumentCreate) check() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (dc *DocumentCreate) sqlSave(ctx context.Context) (*Document, error) {
|
func (dc *DocumentCreate) sqlSave(ctx context.Context) (*Document, error) {
|
||||||
|
if err := dc.check(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
_node, _spec := dc.createSpec()
|
_node, _spec := dc.createSpec()
|
||||||
if err := sqlgraph.CreateNode(ctx, dc.driver, _spec); err != nil {
|
if err := sqlgraph.CreateNode(ctx, dc.driver, _spec); err != nil {
|
||||||
if sqlgraph.IsConstraintError(err) {
|
if sqlgraph.IsConstraintError(err) {
|
||||||
@@ -255,54 +200,34 @@ func (dc *DocumentCreate) sqlSave(ctx context.Context) (*Document, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
dc.mutation.id = &_node.ID
|
||||||
|
dc.mutation.done = true
|
||||||
return _node, nil
|
return _node, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *DocumentCreate) createSpec() (*Document, *sqlgraph.CreateSpec) {
|
func (dc *DocumentCreate) createSpec() (*Document, *sqlgraph.CreateSpec) {
|
||||||
var (
|
var (
|
||||||
_node = &Document{config: dc.config}
|
_node = &Document{config: dc.config}
|
||||||
_spec = &sqlgraph.CreateSpec{
|
_spec = sqlgraph.NewCreateSpec(document.Table, sqlgraph.NewFieldSpec(document.FieldID, field.TypeUUID))
|
||||||
Table: document.Table,
|
|
||||||
ID: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: document.FieldID,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
if id, ok := dc.mutation.ID(); ok {
|
if id, ok := dc.mutation.ID(); ok {
|
||||||
_node.ID = id
|
_node.ID = id
|
||||||
_spec.ID.Value = &id
|
_spec.ID.Value = &id
|
||||||
}
|
}
|
||||||
if value, ok := dc.mutation.CreatedAt(); ok {
|
if value, ok := dc.mutation.CreatedAt(); ok {
|
||||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
_spec.SetField(document.FieldCreatedAt, field.TypeTime, value)
|
||||||
Type: field.TypeTime,
|
|
||||||
Value: value,
|
|
||||||
Column: document.FieldCreatedAt,
|
|
||||||
})
|
|
||||||
_node.CreatedAt = value
|
_node.CreatedAt = value
|
||||||
}
|
}
|
||||||
if value, ok := dc.mutation.UpdatedAt(); ok {
|
if value, ok := dc.mutation.UpdatedAt(); ok {
|
||||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
_spec.SetField(document.FieldUpdatedAt, field.TypeTime, value)
|
||||||
Type: field.TypeTime,
|
|
||||||
Value: value,
|
|
||||||
Column: document.FieldUpdatedAt,
|
|
||||||
})
|
|
||||||
_node.UpdatedAt = value
|
_node.UpdatedAt = value
|
||||||
}
|
}
|
||||||
if value, ok := dc.mutation.Title(); ok {
|
if value, ok := dc.mutation.Title(); ok {
|
||||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
_spec.SetField(document.FieldTitle, field.TypeString, value)
|
||||||
Type: field.TypeString,
|
|
||||||
Value: value,
|
|
||||||
Column: document.FieldTitle,
|
|
||||||
})
|
|
||||||
_node.Title = value
|
_node.Title = value
|
||||||
}
|
}
|
||||||
if value, ok := dc.mutation.Path(); ok {
|
if value, ok := dc.mutation.Path(); ok {
|
||||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
_spec.SetField(document.FieldPath, field.TypeString, value)
|
||||||
Type: field.TypeString,
|
|
||||||
Value: value,
|
|
||||||
Column: document.FieldPath,
|
|
||||||
})
|
|
||||||
_node.Path = value
|
_node.Path = value
|
||||||
}
|
}
|
||||||
if nodes := dc.mutation.GroupIDs(); len(nodes) > 0 {
|
if nodes := dc.mutation.GroupIDs(); len(nodes) > 0 {
|
||||||
@@ -313,10 +238,7 @@ func (dc *DocumentCreate) createSpec() (*Document, *sqlgraph.CreateSpec) {
|
|||||||
Columns: []string{document.GroupColumn},
|
Columns: []string{document.GroupColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: group.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
@@ -325,25 +247,6 @@ func (dc *DocumentCreate) createSpec() (*Document, *sqlgraph.CreateSpec) {
|
|||||||
_node.group_documents = &nodes[0]
|
_node.group_documents = &nodes[0]
|
||||||
_spec.Edges = append(_spec.Edges, edge)
|
_spec.Edges = append(_spec.Edges, edge)
|
||||||
}
|
}
|
||||||
if nodes := dc.mutation.DocumentTokensIDs(); len(nodes) > 0 {
|
|
||||||
edge := &sqlgraph.EdgeSpec{
|
|
||||||
Rel: sqlgraph.O2M,
|
|
||||||
Inverse: false,
|
|
||||||
Table: document.DocumentTokensTable,
|
|
||||||
Columns: []string{document.DocumentTokensColumn},
|
|
||||||
Bidi: false,
|
|
||||||
Target: &sqlgraph.EdgeTarget{
|
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: documenttoken.FieldID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, k := range nodes {
|
|
||||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
|
||||||
}
|
|
||||||
_spec.Edges = append(_spec.Edges, edge)
|
|
||||||
}
|
|
||||||
if nodes := dc.mutation.AttachmentsIDs(); len(nodes) > 0 {
|
if nodes := dc.mutation.AttachmentsIDs(); len(nodes) > 0 {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.O2M,
|
Rel: sqlgraph.O2M,
|
||||||
@@ -352,10 +255,7 @@ func (dc *DocumentCreate) createSpec() (*Document, *sqlgraph.CreateSpec) {
|
|||||||
Columns: []string{document.AttachmentsColumn},
|
Columns: []string{document.AttachmentsColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(attachment.FieldID, field.TypeUUID),
|
||||||
Type: field.TypeUUID,
|
|
||||||
Column: attachment.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
@@ -390,8 +290,8 @@ func (dcb *DocumentCreateBulk) Save(ctx context.Context) ([]*Document, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
builder.mutation = mutation
|
builder.mutation = mutation
|
||||||
nodes[i], specs[i] = builder.createSpec()
|
|
||||||
var err error
|
var err error
|
||||||
|
nodes[i], specs[i] = builder.createSpec()
|
||||||
if i < len(mutators)-1 {
|
if i < len(mutators)-1 {
|
||||||
_, err = mutators[i+1].Mutate(root, dcb.builders[i+1].mutation)
|
_, err = mutators[i+1].Mutate(root, dcb.builders[i+1].mutation)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user