Compare commits

..

22 commits

Author SHA1 Message Date
Hayden
2cd107b8bd
explicity dependency 2023-08-24 09:20:53 -05:00
Hayden
a3cce59a2a
fix https connection 2023-08-23 12:27:34 -05:00
Hayden
9fa17bec90
update lock file 2023-08-09 21:49:32 -05:00
Cheng Gu
b5987f2e8d
feat: set cookies' expires attribute and fix remember me (#530) 2023-08-09 18:48:39 -08:00
Hayden
2cbcc8bb1d
feat: WebSocket based implementation of server sent events for cache busting (#527)
* rough implementation of WS based event system for server side notifications of mutation

* fix test construction

* fix deadlock on event bus

* disable linter error

* add item mutation events

* remove old event bus code

* refactor event system to use composables

* refresh items table when new item is added

* fix create form errors

* cleanup unnecessary calls

* fix importer erorrs + limit fn calls on import
2023-08-02 13:00:57 -08:00
Hayden
cceec06148
specify h3 dependency 2023-08-02 09:05:07 -05:00
Hayden
2e2eed143d
try node 18 2023-08-02 09:01:47 -05:00
renovate[bot]
272cc5a370
chore(deps): update dependency vitest to ^0.34.0 (#529)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-02 05:59:31 -08:00
Hayden
275e106d72
build nightly rootless 2023-08-02 08:47:53 -05:00
Hayden
3f0e65a2ad
include rootless dockerfile 2023-08-02 08:45:22 -05:00
Hayden
22bbaae08f
feat: add support for create + add more for all create modals and support k… (#526)
* add support for create + add more for all create modals and support keyboard bindings

* listen for esc to close modals
2023-07-31 09:53:26 -08:00
Hayden
8c7d91ea52
fix: prevent resetting dialog state on error (#524) 2023-07-31 08:22:08 -08:00
Hayden
5a219f6a9c
feat: support cmd+s / ctrl+s and rework button display on edit (#523) 2023-07-31 06:57:42 -08:00
Hayden
895017b28e
fix: label prop not being passed to password input (#522) 2023-07-31 06:08:35 -08:00
Hayden
02ce52dbe3
fix: assert/asserts (#521) 2023-07-31 06:05:37 -08:00
Hayden
c5ae6b17f9
feat: more currency support (#520)
* add multiple new currencies

* add multiple new currencies

* remove duplicate yen
2023-07-31 05:59:36 -08:00
renovate[bot]
371fc0a6af
chore(deps): update dependency mkdocs-material to v9.1.21 (#512)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-29 09:54:55 -08:00
Hayden
016780920d
ui: rework location/labels pages (#475)
* formatting

* slimdown locations page

* update location/labels

* fix dependency issues

* fix type generator

* cleanup unused variables
2023-07-27 13:21:28 -08:00
db8200
06eb6c1f91
fix 3 places where API URLs were not constructed by function route (#451)
* Fixed 3 places where API URLs were not constructed by function route(path, params).

* autofix

---------

Co-authored-by: Hayden <64056131+hay-kot@users.noreply.github.com>
2023-07-22 20:11:29 -08:00
renovate[bot]
27dad0e118
fix(deps): update module github.com/swaggo/http-swagger to v2 (#508)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-22 20:10:52 -08:00
renovate[bot]
dc9446516a
fix(deps): update module github.com/swaggo/http-swagger to v2 (#506)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-22 20:09:43 -08:00
Hayden
a042496c71
chore: bump all go deps (#507)
* bump all deps

* run code-gen
2023-07-22 19:57:51 -08:00
243 changed files with 10478 additions and 20818 deletions

View file

@ -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.21" "golang": "1.20"
} }
} }

View file

@ -7,12 +7,12 @@ jobs:
Go: Go:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v4
with: with:
go-version: "1.21" go-version: "1.20"
- name: Install Task - name: Install Task
uses: arduino/setup-task@v1 uses: arduino/setup-task@v1
@ -20,7 +20,7 @@ jobs:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@v4 uses: golangci/golangci-lint-action@v3
with: with:
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
version: latest version: latest

View file

@ -9,11 +9,11 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
- uses: pnpm/action-setup@v3.0.0 - uses: pnpm/action-setup@v2.2.4
with: with:
version: 6.0.2 version: 6.0.2
@ -34,7 +34,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
@ -44,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@v5 uses: actions/setup-go@v4
with: with:
go-version: "1.21" go-version: "1.20"
- uses: actions/setup-node@v4 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 18
- uses: pnpm/action-setup@v3.0.0 - uses: pnpm/action-setup@v2.2.4
with: with:
version: 6.0.2 version: 6.0.2

View file

@ -20,22 +20,22 @@ jobs:
name: "Publish Homebox" name: "Publish Homebox"
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v4
with: with:
go-version: "1.20" go-version: "1.20"
- name: Set up QEMU - name: Set up QEMU
id: qemu id: qemu
uses: docker/setup-qemu-action@v3 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@v3 uses: docker/setup-buildx-action@v2
with: with:
install: true install: true

View file

@ -13,7 +13,7 @@ jobs:
name: "Deploy Nightly to Fly.io" name: "Deploy Nightly to Fly.io"
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - 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

View file

@ -22,12 +22,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v4
- uses: pnpm/action-setup@v2 - uses: pnpm/action-setup@v2
with: with:
@ -41,7 +41,7 @@ jobs:
cp -r ./.output/public ../backend/app/api/static/ cp -r ./.output/public ../backend/app/api/static/
- name: Run GoReleaser - name: Run GoReleaser
uses: goreleaser/goreleaser-action@v5 uses: goreleaser/goreleaser-action@v4
with: with:
workdir: "backend" workdir: "backend"
distribution: goreleaser distribution: goreleaser
@ -67,7 +67,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout main - name: Checkout main
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Deploy docs - name: Deploy docs
uses: mhausenblas/mkdocs-deploy-gh-pages@master uses: mhausenblas/mkdocs-deploy-gh-pages@master

1
.gitignore vendored
View file

@ -54,4 +54,3 @@ dist/
# Nuxt Publish Dir # Nuxt Publish Dir
backend/app/api/static/public/* backend/app/api/static/public/*
!backend/app/api/static/public/.gitkeep !backend/app/api/static/public/.gitkeep
backend/api

View file

@ -16,7 +16,7 @@
"editor.formatOnSave": false, "editor.formatOnSave": false,
"editor.defaultFormatter": "dbaeumer.vscode-eslint", "editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit" "source.fixAll.eslint": true
}, },
"[typescript]": { "[typescript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint" "editor.defaultFormatter": "dbaeumer.vscode-eslint"

View file

@ -1,16 +1,16 @@
# Contributing # Contributing
## We Develop with GitHub ## We Develop with Github
We use GitHub to host code, to track issues and feature requests, as well as accept pull requests. We use github to host code, to track issues and feature requests, as well as accept pull requests.
## Branch Flow ## Branch Flow
We use the `main` branch as the development branch. All PRs should be made to the `main` branch from a feature branch. To create a pull request, you can use the following steps: We use the `main` branch as the development branch. All PRs should be made to the `main` branch from a feature branch. To create a pull request you can use the following steps:
1. Fork the repository and create a new branch from `main`. 1. Fork the repository and create a new branch from `main`.
2. If you've added code that should be tested, add tests. 2. If you've added code that should be tested, add tests.
3. If you've changed APIs, update the documentation. 3. If you've changed API's, update the documentation.
4. Ensure that the test suite and linters pass 4. Ensure that the test suite and linters pass
5. Issue your pull request 5. Issue your pull request
@ -18,7 +18,7 @@ We use the `main` branch as the development branch. All PRs should be made to th
### Prerequisites ### Prerequisites
There is a devcontainer available for this project. If you are using VSCode, you can use the devcontainer to get started. If you are not using VSCode, you need to ensure that you have the following tools installed: There is a devcontainer available for this project. If you are using VSCode, you can use the devcontainer to get started. If you are not using VSCode, you can need to ensure that you have the following tools installed:
- [Go 1.19+](https://golang.org/doc/install) - [Go 1.19+](https://golang.org/doc/install)
- [Swaggo](https://github.com/swaggo/swag) - [Swaggo](https://github.com/swaggo/swag)
@ -31,27 +31,27 @@ If you're using `taskfile` you can run `task --list-all` for a list of all comma
### Setup ### Setup
If you're using the taskfile, you can use the `task setup` command to run the required setup commands. Otherwise, you can review the commands required in the `Taskfile.yml` file. If you're using the taskfile you can use the `task setup` command to run the required setup commands. Otherwise you can review the commands required in the `Taskfile.yml` file.
Note that when installing dependencies with pnpm you must use the `--shamefully-hoist` flag. If you don't use this flag, you will get an error when running the frontend server. Note that when installing dependencies with pnpm you must use the `--shamefully-hoist` flag. If you don't use this flag you will get an error when running the the frontend server.
### API Development Notes ### API Development Notes
start command `task go:run` start command `task go:run`
1. API Server does not auto reload. You'll need to restart the server after making changes. 1. API Server does not auto reload. You'll need to restart the server after making changes.
2. Unit tests should be written in Go, however, end-to-end or user story tests should be written in TypeScript using the client library in the frontend directory. 2. Unit tests should be written in Go, however end-to-end or user story tests should be written in TypeScript using the client library in the frontend directory.
### Frontend Development Notes ### Frontend Development Notes
start command `task: ui:dev` 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 ## Publishing Release
Create a new tag in GitHub with the version number vX.X.X. This will trigger a new release to be created. Create a new tag in github with the version number vX.X.X. This will trigger a new release to be created.
Test -> Goreleaser -> Publish Release -> Trigger Docker Builds -> Deploy Docs + Fly.io Demo Test -> Goreleaser -> Publish Release -> Trigger Docker Builds -> Deploy Docs + Fly.io Demo

View file

@ -1,20 +1,21 @@
# Build Nuxt # Build Nuxt
FROM r.batts.cloud/nodejs:18 as frontend-builder FROM node:18-alpine as frontend-builder
WORKDIR /app WORKDIR /app
RUN npm install -g pnpm@latest-9 RUN npm install -g pnpm
COPY frontend/package.json frontend/pnpm-lock.yaml ./ COPY frontend/package.json frontend/pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile --shamefully-hoist RUN pnpm install --frozen-lockfile --shamefully-hoist
COPY frontend . COPY frontend .
RUN pnpm build RUN pnpm build
# Build API # Build API
FROM r.batts.cloud/golang:1.24 AS builder FROM golang:alpine AS builder
ARG BUILD_TIME ARG BUILD_TIME
ARG COMMIT ARG COMMIT
ARG VERSION ARG VERSION
RUN apt update && \ RUN apk update && \
apt install -y git build-essential gcc g++ apk upgrade && \
apk add --update git build-base gcc g++
WORKDIR /go/src/app WORKDIR /go/src/app
COPY ./backend . COPY ./backend .
@ -27,12 +28,13 @@ RUN CGO_ENABLED=0 GOOS=linux go build \
-v ./app/api/*.go -v ./app/api/*.go
# Production Stage # Production Stage
FROM r.batts.cloud/debian:trixie FROM alpine:latest
ENV HBOX_MODE=production ENV HBOX_MODE=production
ENV HBOX_STORAGE_DATA=/data/ ENV HBOX_STORAGE_DATA=/data/
ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_pragma=busy_timeout=2000&_pragma=journal_mode=WAL&_fk=1 ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_fk=1
RUN apk --no-cache add ca-certificates
RUN mkdir /app RUN mkdir /app
COPY --from=builder /go/bin/api /app COPY --from=builder /go/bin/api /app

View file

@ -30,14 +30,6 @@ docker run -d \
# ghcr.io/hay-kot/homebox:latest-rootless # ghcr.io/hay-kot/homebox:latest-rootless
``` ```
<!-- CONTRIBUTING -->
## Contributing
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
If you are not a coder, you can still contribute financially. Financial contributions help me prioritize working on this project over others and helps me know that there is a real demand for project development.
<a href="https://www.buymeacoffee.com/haykot" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-green.png" alt="Buy Me A Coffee" style="height: 30px !important;width: 107px !important;" ></a>
## Credits ## Credits
- Logo by [@lakotelman](https://github.com/lakotelman) - Logo by [@lakotelman](https://github.com/lakotelman)

View file

@ -1,7 +1,6 @@
version: "3" version: "3"
env: env:
HBOX_LOG_LEVEL: debug
HBOX_STORAGE_SQLITE_URL: .data/homebox.db?_pragma=busy_timeout=1000&_pragma=journal_mode=WAL&_fk=1 HBOX_STORAGE_SQLITE_URL: .data/homebox.db?_pragma=busy_timeout=1000&_pragma=journal_mode=WAL&_fk=1
HBOX_OPTIONS_ALLOW_REGISTRATION: true HBOX_OPTIONS_ALLOW_REGISTRATION: true
UNSAFE_DISABLE_PASSWORD_PROJECTION: "yes_i_am_sure" UNSAFE_DISABLE_PASSWORD_PROJECTION: "yes_i_am_sure"
@ -13,25 +12,15 @@ tasks:
- cd backend && go mod tidy - cd backend && go mod tidy
- cd frontend && pnpm install --shamefully-hoist - cd frontend && pnpm install --shamefully-hoist
swag: generate:
desc: Generate swagger docs desc: |
dir: backend/app/api/static/ Generates collateral files from the backend project
vars: including swagger docs and typescripts type for the frontend
API: "../" deps:
INTERNAL: "../../../internal" - db:generate
PKGS: "../../../pkgs"
cmds:
- swag fmt --dir={{ .API }}
- swag init --dir={{ .API }},{{ .INTERNAL }}/core/services,{{ .INTERNAL }}/data/repo --parseDependency
sources:
- "./backend/app/api/**/*"
- "./backend/internal/data/**"
- "./backend/internal/core/services/**/*"
- "./backend/app/tools/typegen/main.go"
typescript-types:
desc: Generates typescript types from swagger definition
cmds: cmds:
- cd backend/app/api/static && swag fmt --dir=../
- cd backend/app/api/static && swag init --dir=../,../../../internal,../../../pkgs
- | - |
npx swagger-typescript-api \ npx swagger-typescript-api \
--no-client \ --no-client \
@ -39,17 +28,12 @@ tasks:
--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
- go run ./backend/app/tools/typegen/main.go ./frontend/lib/api/types/data-contracts.ts - go run ./backend/app/tools/typegen/main.go ./frontend/lib/api/types/data-contracts.ts
sources:
- ./backend/app/tools/typegen/main.go
- ./backend/app/api/static/docs/swagger.json
generate:
deps:
- db:generate
cmds:
- task: swag
- task: typescript-types
- cp ./backend/app/api/static/docs/swagger.json docs/docs/api/openapi-2.0.json - cp ./backend/app/api/static/docs/swagger.json docs/docs/api/openapi-2.0.json
sources:
- "./backend/app/api/**/*"
- "./backend/internal/data/**"
- "./backend/internal/core/services/**/*"
- "./backend/app/tools/typegen/main.go"
go:run: go:run:
desc: Starts the backend api server (depends on generate task) desc: Starts the backend api server (depends on generate task)
@ -103,7 +87,8 @@ tasks:
dir: backend/internal/ dir: backend/internal/
cmds: cmds:
- | - |
go generate ./... go generate ./... \
--template=./data/ent/schema/templates/has_id.tmpl
sources: sources:
- "./backend/internal/data/ent/schema/**/*" - "./backend/internal/data/ent/schema/**/*"

View file

@ -1,74 +0,0 @@
run:
timeout: 10m
skip-dirs:
- internal/data/ent.*
linters-settings:
goconst:
min-len: 5
min-occurrences: 5
exhaustive:
default-signifies-exhaustive: true
revive:
ignore-generated-header: false
severity: warning
confidence: 3
depguard:
rules:
main:
deny:
- pkg: io/util
desc: |
Deprecated: As of Go 1.16, the same functionality is now provided by
package io or package os, and those implementations should be
preferred in new code. See the specific function documentation for
details.
gocritic:
enabled-checks:
- ruleguard
testifylint:
enable-all: true
tagalign:
order:
- json
- schema
- yaml
- yml
- toml
- validate
linters:
disable-all: true
enable:
- asciicheck
- bodyclose
- depguard
- dogsled
- errcheck
- errorlint
- exhaustive
- exportloopref
- gochecknoinits
- goconst
- gocritic
- gocyclo
- gofmt
- goprintffuncname
- gosimple
- govet
- ineffassign
- misspell
- nakedret
- revive
- staticcheck
- stylecheck
- tagalign
- testifylint
- typecheck
- typecheck
- unconvert
- unused
- whitespace
- zerologlint
- sqlclosecheck
issues:
exclude-use-default: false
fix: true

BIN
backend/api Executable file

Binary file not shown.

View file

@ -1,18 +1,22 @@
package main package main
import ( import (
"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/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/httpkit/server"
) )
type app struct { type app struct {
conf *config.Config conf *config.Config
mailer mailer.Mailer mailer mailer.Mailer
db *ent.Client db *ent.Client
server *server.Server
repos *repo.AllRepos repos *repo.AllRepos
services *services.AllServices services *services.AllServices
bus *eventbus.EventBus bus *eventbus.EventBus
@ -33,3 +37,13 @@ func new(conf *config.Config) *app {
return s return s
} }
func (a *app) startBgTask(t time.Duration, fn func()) {
timer := time.NewTimer(t)
for {
timer.Reset(t)
a.server.Background(fn)
<-timer.C
}
}

View file

@ -1,37 +0,0 @@
package main
import (
"context"
"time"
)
type BackgroundTask struct {
name string
Interval time.Duration
Fn func(context.Context)
}
func (tsk *BackgroundTask) Name() string {
return tsk.name
}
func NewTask(name string, interval time.Duration, fn func(context.Context)) *BackgroundTask {
return &BackgroundTask{
Interval: interval,
Fn: fn,
}
}
func (tsk *BackgroundTask) Start(ctx context.Context) error {
timer := time.NewTimer(tsk.Interval)
for {
select {
case <-ctx.Done():
return nil
case <-timer.C:
timer.Reset(tsk.Interval)
tsk.Fn(ctx)
}
}
}

View file

@ -3,7 +3,6 @@ package main
import ( import (
"context" "context"
"strings" "strings"
"time"
"github.com/hay-kot/homebox/backend/internal/core/services" "github.com/hay-kot/homebox/backend/internal/core/services"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
@ -16,12 +15,9 @@ func (a *app) SetupDemo() {
,Office,IOT;Home Assistant; Z-Wave,1,Zooz 110v Power Switch,"Zooz Z-Wave Plus Power Switch ZEN15 for 110V AC Units, Sump Pumps, Humidifiers, and More",,,ZEN15,Zooz,,Amazon,39.95,10/13/2021,,,,,,, ,Office,IOT;Home Assistant; Z-Wave,1,Zooz 110v Power Switch,"Zooz Z-Wave Plus Power Switch ZEN15 for 110V AC Units, Sump Pumps, Humidifiers, and More",,,ZEN15,Zooz,,Amazon,39.95,10/13/2021,,,,,,,
,Downstairs,IOT;Home Assistant; Z-Wave,1,Ecolink Z-Wave PIR Motion Sensor,"Ecolink Z-Wave PIR Motion Detector Pet Immune, White (PIRZWAVE2.5-ECO)",,,PIRZWAVE2.5-ECO,Ecolink,,Amazon,35.58,10/21/2020,,,,,,, ,Downstairs,IOT;Home Assistant; Z-Wave,1,Ecolink Z-Wave PIR Motion Sensor,"Ecolink Z-Wave PIR Motion Detector Pet Immune, White (PIRZWAVE2.5-ECO)",,,PIRZWAVE2.5-ECO,Ecolink,,Amazon,35.58,10/21/2020,,,,,,,
,Entry,IOT;Home Assistant; Z-Wave,1,Yale Security Touchscreen Deadbolt,"Yale Security YRD226-ZW2-619 YRD226ZW2619 Touchscreen Deadbolt, Satin Nickel",,,YRD226ZW2619,Yale,,Amazon,120.39,10/14/2020,,,,,,, ,Entry,IOT;Home Assistant; Z-Wave,1,Yale Security Touchscreen Deadbolt,"Yale Security YRD226-ZW2-619 YRD226ZW2619 Touchscreen Deadbolt, Satin Nickel",,,YRD226ZW2619,Yale,,Amazon,120.39,10/14/2020,,,,,,,
,Kitchen,IOT;Home Assistant; Z-Wave,1,Smart Rocker Light Dimmer,"UltraPro Z-Wave Smart Rocker Light Dimmer with QuickFit and SimpleWire, 3-Way Ready, Compatible with Alexa, Google Assistant, ZWave Hub Required, Repeater/Range Extender, White Paddle Only, 39351",,,39351,Honeywell,,Amazon,65.98,09/30/0202,,,,,,, ,Kitchen,IOT;Home Assistant; Z-Wave,1,Smart Rocker Light Dimmer,"UltraPro Z-Wave Smart Rocker Light Dimmer with QuickFit and SimpleWire, 3-Way Ready, Compatible with Alexa, Google Assistant, ZWave Hub Required, Repeater/Range Extender, White Paddle Only, 39351",,,39351,Honeywell,,Amazon,65.98,09/30/0202,,,,,,,
` `
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
registration := services.UserRegistration{ registration := services.UserRegistration{
Email: "demo@example.com", Email: "demo@example.com",
Name: "Demo", Name: "Demo",
@ -29,34 +25,21 @@ func (a *app) SetupDemo() {
} }
// 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
log.Debug().Msg("Checking if demo user already exists") _, err := a.services.User.Login(context.Background(), registration.Email, registration.Password, false)
_, err := a.services.User.Login(ctx, registration.Email, registration.Password, false)
if err == nil { if err == nil {
log.Info().Msg("Demo user already exists, skipping setup")
return return
} }
log.Debug().Msg("Demo user does not exist, setting up demo") _, err = a.services.User.RegisterUser(context.Background(), registration)
_, err = a.services.User.RegisterUser(ctx, registration)
if err != nil { if err != nil {
log.Err(err).Msg("Failed to register demo user") log.Err(err).Msg("Failed to register demo user")
log.Fatal().Msg("Failed to setup demo") log.Fatal().Msg("Failed to setup demo")
} }
token, err := a.services.User.Login(ctx, registration.Email, registration.Password, false) token, _ := a.services.User.Login(context.Background(), registration.Email, registration.Password, false)
if err != nil { self, _ := a.services.User.GetSelf(context.Background(), token.Raw)
log.Err(err).Msg("Failed to login demo user")
log.Fatal().Msg("Failed to setup demo")
return
}
self, err := a.services.User.GetSelf(ctx, token.Raw)
if err != nil {
log.Err(err).Msg("Failed to get self")
log.Fatal().Msg("Failed to setup demo")
return
}
_, err = a.services.Items.CsvImport(ctx, self.GroupID, strings.NewReader(csvText)) _, err = a.services.Items.CsvImport(context.Background(), self.GroupID, strings.NewReader(csvText))
if err != nil { 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")

View file

@ -1,4 +1,3 @@
// Package debughandlers provides handlers for debugging.
package debughandlers package debughandlers
import ( import (

View file

@ -1,10 +1,8 @@
// Package v1 provides the API handlers for version 1 of the API.
package v1 package v1
import ( import (
"encoding/json" "fmt"
"net/http" "net/http"
"time"
"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"
@ -51,14 +49,7 @@ func WithRegistration(allowRegistration bool) func(*V1Controller) {
} }
} }
func WithSecureCookies(secure bool) func(*V1Controller) {
return func(ctrl *V1Controller) {
ctrl.cookieSecure = secure
}
}
type V1Controller struct { type V1Controller struct {
cookieSecure bool
repo *repo.AllRepos repo *repo.AllRepos
svc *services.AllServices svc *services.AllServices
maxUploadSize int64 maxUploadSize int64
@ -76,7 +67,7 @@ type (
BuildTime string `json:"buildTime"` BuildTime string `json:"buildTime"`
} }
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"`
@ -87,7 +78,7 @@ type (
} }
) )
func BaseURLFunc(prefix string) func(s string) string { func BaseUrlFunc(prefix string) func(s string) string {
return func(s string) string { return func(s string) string {
return prefix + "/v1" + s return prefix + "/v1" + s
} }
@ -113,11 +104,11 @@ func NewControllerV1(svc *services.AllServices, repos *repo.AllRepos, bus *event
// @Summary Application Info // @Summary Application Info
// @Tags Base // @Tags Base
// @Produce json // @Produce json
// @Success 200 {object} APISummary // @Success 200 {object} ApiSummary
// @Router /v1/status [GET] // @Router /v1/status [GET]
func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) errchain.HandlerFunc { 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.JSON(w, http.StatusOK, APISummary{ return server.JSON(w, http.StatusOK, ApiSummary{
Healthy: ready(), Healthy: ready(),
Title: "Homebox", Title: "Homebox",
Message: "Track, Manage, and Organize your Things", Message: "Track, Manage, and Organize your Things",
@ -128,27 +119,7 @@ func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) errchain.Hand
} }
} }
// HandleCurrency godoc
//
// @Summary Currency
// @Tags Base
// @Produce json
// @Success 200 {object} currencies.Currency
// @Router /v1/currency [GET]
func (ctrl *V1Controller) HandleCurrency() errchain.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
// Set Cache for 10 Minutes
w.Header().Set("Cache-Control", "max-age=600")
return server.JSON(w, http.StatusOK, ctrl.svc.Currencies.Slice())
}
}
func (ctrl *V1Controller) HandleCacheWS() errchain.HandlerFunc { func (ctrl *V1Controller) HandleCacheWS() errchain.HandlerFunc {
type eventMsg struct {
Event string `json:"event"`
}
m := melody.New() m := melody.New()
m.HandleConnect(func(s *melody.Session) { m.HandleConnect(func(s *melody.Session) {
@ -164,15 +135,9 @@ func (ctrl *V1Controller) HandleCacheWS() errchain.HandlerFunc {
return return
} }
msg := &eventMsg{Event: e} jsonStr := fmt.Sprintf(`{"event": "%s"}`, e)
jsonBytes, err := json.Marshal(msg) _ = m.BroadcastFilter([]byte(jsonStr), func(s *melody.Session) bool {
if err != nil {
log.Log().Msgf("error marshling event data %v: %v", data, err)
return
}
_ = m.BroadcastFilter(jsonBytes, func(s *melody.Session) bool {
groupIDStr, ok := s.Get("gid") groupIDStr, ok := s.Get("gid")
if !ok { if !ok {
return false return false
@ -188,25 +153,6 @@ func (ctrl *V1Controller) HandleCacheWS() errchain.HandlerFunc {
ctrl.bus.Subscribe(eventbus.EventLocationMutation, factory("location.mutation")) ctrl.bus.Subscribe(eventbus.EventLocationMutation, factory("location.mutation"))
ctrl.bus.Subscribe(eventbus.EventItemMutation, factory("item.mutation")) ctrl.bus.Subscribe(eventbus.EventItemMutation, factory("item.mutation"))
// Persistent asynchronous ticker that keeps all websocket connections alive with periodic pings.
go func() {
const interval = 10 * time.Second
ping := time.NewTicker(interval)
defer ping.Stop()
for range ping.C {
msg := &eventMsg{Event: "ping"}
pingBytes, err := json.Marshal(msg)
if err != nil {
log.Log().Msgf("error marshaling ping: %v", err)
} else {
_ = m.Broadcast(pingBytes)
}
}
}()
return func(w http.ResponseWriter, r *http.Request) error { return func(w http.ResponseWriter, r *http.Request) error {
return m.HandleRequest(w, r) return m.HandleRequest(w, r)
} }

View file

@ -68,16 +68,3 @@ func (ctrl *V1Controller) HandleEnsureImportRefs() errchain.HandlerFunc {
func (ctrl *V1Controller) HandleItemDateZeroOut() errchain.HandlerFunc { func (ctrl *V1Controller) HandleItemDateZeroOut() errchain.HandlerFunc {
return actionHandlerFactory("zero out date time", ctrl.repo.Items.ZeroOutTimeFields) return actionHandlerFactory("zero out date time", ctrl.repo.Items.ZeroOutTimeFields)
} }
// HandleSetPrimaryPhotos godoc
//
// @Summary Set Primary Photos
// @Description Sets the first photo of each item as the primary photo
// @Tags Actions
// @Produce json
// @Success 200 {object} ActionAmountResult
// @Router /v1/actions/set-primary-photos [Post]
// @Security Bearer
func (ctrl *V1Controller) HandleSetPrimaryPhotos() errchain.HandlerFunc {
return actionHandlerFactory("ensure asset IDs", ctrl.repo.Items.SetPrimaryPhotos)
}

View file

@ -27,10 +27,10 @@ import (
func (ctrl *V1Controller) HandleAssetGet() errchain.HandlerFunc { func (ctrl *V1Controller) HandleAssetGet() errchain.HandlerFunc {
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())
assetIDParam := chi.URLParam(r, "id") assetIdParam := chi.URLParam(r, "id")
assetIDParam = strings.ReplaceAll(assetIDParam, "-", "") // Remove dashes assetIdParam = strings.ReplaceAll(assetIdParam, "-", "") // Remove dashes
// Convert the asset ID to an int64 // Convert the asset ID to an int64
assetID, err := strconv.ParseInt(assetIDParam, 10, 64) assetId, err := strconv.ParseInt(assetIdParam, 10, 64)
if err != nil { if err != nil {
return err return err
} }
@ -52,7 +52,7 @@ func (ctrl *V1Controller) HandleAssetGet() errchain.HandlerFunc {
} }
} }
items, err := ctrl.repo.Items.QueryByAssetID(r.Context(), ctx.GID, repo.AssetID(assetID), int(page), int(pageSize)) items, err := ctrl.repo.Items.QueryByAssetID(r.Context(), ctx.GID, repo.AssetID(assetId), int(page), int(pageSize))
if err != nil { if err != nil {
log.Err(err).Msg("failed to get item") log.Err(err).Msg("failed to get item")
return validate.NewRequestError(err, http.StatusInternalServerError) return validate.NewRequestError(err, http.StatusInternalServerError)

View file

@ -3,7 +3,6 @@ package v1
import ( import (
"errors" "errors"
"net/http" "net/http"
"strconv"
"strings" "strings"
"time" "time"
@ -14,12 +13,6 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
const (
cookieNameToken = "hb.auth.token"
cookieNameRemember = "hb.auth.remember"
cookieNameSession = "hb.auth.session"
)
type ( type (
TokenResponse struct { TokenResponse struct {
Token string `json:"token"` Token string `json:"token"`
@ -34,49 +27,6 @@ type (
} }
) )
type CookieContents struct {
Token string
ExpiresAt time.Time
Remember bool
}
func GetCookies(r *http.Request) (*CookieContents, error) {
cookie, err := r.Cookie(cookieNameToken)
if err != nil {
return nil, errors.New("authorization cookie is required")
}
rememberCookie, err := r.Cookie(cookieNameRemember)
if err != nil {
return nil, errors.New("remember cookie is required")
}
return &CookieContents{
Token: cookie.Value,
ExpiresAt: cookie.Expires,
Remember: rememberCookie.Value == "true",
}, nil
}
// AuthProvider is an interface that can be implemented by any authentication provider.
// to extend authentication methods for the API.
type AuthProvider interface {
// Name returns the name of the authentication provider. This should be a unique name.
// that is URL friendly.
//
// Example: "local", "ldap"
Name() string
// Authenticate is called when a user attempts to login to the API. The implementation
// should return an error if the user cannot be authenticated. If an error is returned
// the API controller will return a vague error message to the user.
//
// Authenticate should do the following:
//
// 1. Ensure that the user exists within the database (either create, or get)
// 2. On successful authentication, they must set the user cookies.
Authenticate(w http.ResponseWriter, r *http.Request) (services.UserAuthTokenDetail, error)
}
// HandleAuthLogin godoc // HandleAuthLogin godoc
// //
// @Summary User Login // @Summary User Login
@ -85,42 +35,52 @@ type AuthProvider interface {
// @Accept application/json // @Accept application/json
// @Param username formData string false "string" example(admin@admin.com) // @Param username formData string false "string" example(admin@admin.com)
// @Param password formData string false "string" example(admin) // @Param password formData string false "string" example(admin)
// @Param payload body LoginForm true "Login Data" // @Param payload body LoginForm true "Login Data"
// @Param provider query string false "auth provider"
// @Produce json // @Produce json
// @Success 200 {object} TokenResponse // @Success 200 {object} TokenResponse
// @Router /v1/users/login [POST] // @Router /v1/users/login [POST]
func (ctrl *V1Controller) HandleAuthLogin(ps ...AuthProvider) errchain.HandlerFunc { func (ctrl *V1Controller) HandleAuthLogin() errchain.HandlerFunc {
if len(ps) == 0 {
panic("no auth providers provided")
}
providers := make(map[string]AuthProvider)
for _, p := range ps {
log.Info().Str("name", p.Name()).Msg("registering auth provider")
providers[p.Name()] = p
}
return func(w http.ResponseWriter, r *http.Request) error { return func(w http.ResponseWriter, r *http.Request) error {
// Extract provider query loginForm := &LoginForm{}
provider := r.URL.Query().Get("provider")
if provider == "" { switch r.Header.Get("Content-Type") {
provider = "local" case "application/x-www-form-urlencoded":
err := r.ParseForm()
if err != nil {
return errors.New("failed to parse form")
}
loginForm.Username = r.PostFormValue("username")
loginForm.Password = r.PostFormValue("password")
loginForm.StayLoggedIn = r.PostFormValue("stayLoggedIn") == "true"
case "application/json":
err := server.Decode(r, loginForm)
if err != nil {
log.Err(err).Msg("failed to decode login form")
return errors.New("failed to decode login form")
}
default:
return server.JSON(w, http.StatusBadRequest, errors.New("invalid content type"))
} }
// Get the provider if loginForm.Username == "" || loginForm.Password == "" {
p, ok := providers[provider] return validate.NewFieldErrors(
if !ok { validate.FieldError{
return validate.NewRequestError(errors.New("invalid auth provider"), http.StatusBadRequest) Field: "username",
Error: "username or password is empty",
},
validate.FieldError{
Field: "password",
Error: "username or password is empty",
},
)
} }
newToken, err := p.Authenticate(w, r) newToken, err := ctrl.svc.User.Login(r.Context(), strings.ToLower(loginForm.Username), loginForm.Password, loginForm.StayLoggedIn)
if err != nil { if err != nil {
log.Err(err).Msg("failed to authenticate") return validate.NewRequestError(errors.New("authentication failed"), http.StatusInternalServerError)
return server.JSON(w, http.StatusInternalServerError, err.Error())
} }
ctrl.setCookies(w, noPort(r.Host), newToken.Raw, newToken.ExpiresAt, true)
return server.JSON(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,
@ -148,12 +108,11 @@ func (ctrl *V1Controller) HandleAuthLogout() errchain.HandlerFunc {
return validate.NewRequestError(err, http.StatusInternalServerError) return validate.NewRequestError(err, http.StatusInternalServerError)
} }
ctrl.unsetCookies(w, noPort(r.Host))
return server.JSON(w, http.StatusNoContent, nil) return server.JSON(w, http.StatusNoContent, nil)
} }
} }
// HandleAuthRefresh godoc // HandleAuthLogout godoc
// //
// @Summary User Token Refresh // @Summary User Token Refresh
// @Description handleAuthRefresh returns a handler that will issue a new token from an existing token. // @Description handleAuthRefresh returns a handler that will issue a new token from an existing token.
@ -174,78 +133,6 @@ func (ctrl *V1Controller) HandleAuthRefresh() errchain.HandlerFunc {
return validate.NewUnauthorizedError() return validate.NewUnauthorizedError()
} }
ctrl.setCookies(w, noPort(r.Host), newToken.Raw, newToken.ExpiresAt, false)
return server.JSON(w, http.StatusOK, newToken) return server.JSON(w, http.StatusOK, newToken)
} }
} }
func noPort(host string) string {
return strings.Split(host, ":")[0]
}
func (ctrl *V1Controller) setCookies(w http.ResponseWriter, domain, token string, expires time.Time, remember bool) {
http.SetCookie(w, &http.Cookie{
Name: cookieNameRemember,
Value: strconv.FormatBool(remember),
Expires: expires,
Domain: domain,
Secure: ctrl.cookieSecure,
HttpOnly: true,
Path: "/",
})
// Set HTTP only cookie
http.SetCookie(w, &http.Cookie{
Name: cookieNameToken,
Value: token,
Expires: expires,
Domain: domain,
Secure: ctrl.cookieSecure,
HttpOnly: true,
Path: "/",
})
// Set Fake Session cookie
http.SetCookie(w, &http.Cookie{
Name: cookieNameSession,
Value: "true",
Expires: expires,
Domain: domain,
Secure: ctrl.cookieSecure,
HttpOnly: false,
Path: "/",
})
}
func (ctrl *V1Controller) unsetCookies(w http.ResponseWriter, domain string) {
http.SetCookie(w, &http.Cookie{
Name: cookieNameToken,
Value: "",
Expires: time.Unix(0, 0),
Domain: domain,
Secure: ctrl.cookieSecure,
HttpOnly: true,
Path: "/",
})
http.SetCookie(w, &http.Cookie{
Name: cookieNameRemember,
Value: "false",
Expires: time.Unix(0, 0),
Domain: domain,
Secure: ctrl.cookieSecure,
HttpOnly: true,
Path: "/",
})
// Set Fake Session cookie
http.SetCookie(w, &http.Cookie{
Name: cookieNameSession,
Value: "false",
Expires: time.Unix(0, 0),
Domain: domain,
Secure: ctrl.cookieSecure,
HttpOnly: false,
Path: "/",
})
}

View file

@ -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/internal/web/adapters"
"github.com/hay-kot/httpkit/errchain" "github.com/hay-kot/httpkit/errchain"
) )
type ( type (
GroupInvitationCreate struct { GroupInvitationCreate struct {
Uses int `json:"uses" validate:"required,min=1,max=100"` Uses int `json:"uses" validate:"required,min=1,max=100"`
ExpiresAt time.Time `json:"expiresAt"` ExpiresAt time.Time `json:"expiresAt"`
} }
@ -53,14 +52,6 @@ func (ctrl *V1Controller) HandleGroupGet() errchain.HandlerFunc {
func (ctrl *V1Controller) HandleGroupUpdate() errchain.HandlerFunc { func (ctrl *V1Controller) HandleGroupUpdate() errchain.HandlerFunc {
fn := func(r *http.Request, body repo.GroupUpdate) (repo.Group, error) { fn := func(r *http.Request, body repo.GroupUpdate) (repo.Group, error) {
auth := services.NewContext(r.Context()) auth := services.NewContext(r.Context())
ok := ctrl.svc.Currencies.IsSupported(body.Currency)
if !ok {
return repo.Group{}, validate.NewFieldErrors(
validate.NewFieldError("currency", "currency '"+body.Currency+"' is not supported"),
)
}
return ctrl.svc.Group.UpdateGroup(auth, body) return ctrl.svc.Group.UpdateGroup(auth, body)
} }

View file

@ -27,7 +27,6 @@ import (
// @Param pageSize query int false "items per page" // @Param pageSize query int false "items per page"
// @Param labels query []string false "label Ids" collectionFormat(multi) // @Param labels query []string false "label Ids" collectionFormat(multi)
// @Param locations query []string false "location Ids" collectionFormat(multi) // @Param locations query []string false "location Ids" collectionFormat(multi)
// @Param parentIds query []string false "parent Ids" collectionFormat(multi)
// @Success 200 {object} repo.PaginationResult[repo.ItemSummary]{} // @Success 200 {object} repo.PaginationResult[repo.ItemSummary]{}
// @Router /v1/items [GET] // @Router /v1/items [GET]
// @Security Bearer // @Security Bearer
@ -57,7 +56,6 @@ func (ctrl *V1Controller) HandleItemsGetAll() errchain.HandlerFunc {
Search: params.Get("q"), Search: params.Get("q"),
LocationIDs: queryUUIDList(params, "locations"), LocationIDs: queryUUIDList(params, "locations"),
LabelIDs: queryUUIDList(params, "labels"), LabelIDs: queryUUIDList(params, "labels"),
ParentItemIDs: queryUUIDList(params, "parentIds"),
IncludeArchived: queryBool(params.Get("includeArchived")), IncludeArchived: queryBool(params.Get("includeArchived")),
Fields: filterFieldItems(params["fields"]), Fields: filterFieldItems(params["fields"]),
OrderBy: params.Get("orderBy"), OrderBy: params.Get("orderBy"),
@ -93,48 +91,6 @@ func (ctrl *V1Controller) HandleItemsGetAll() errchain.HandlerFunc {
} }
} }
// HandleItemFullPath godoc
//
// @Summary Get the full path of an item
// @Tags Items
// @Produce json
// @Param id path string true "Item ID"
// @Success 200 {object} []repo.ItemPath
// @Router /v1/items/{id}/path [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleItemFullPath() errchain.HandlerFunc {
fn := func(r *http.Request, ID uuid.UUID) ([]repo.ItemPath, error) {
auth := services.NewContext(r.Context())
item, err := ctrl.repo.Items.GetOneByGroup(auth, auth.GID, ID)
if err != nil {
return nil, err
}
paths, err := ctrl.repo.Locations.PathForLoc(auth, auth.GID, item.Location.ID)
if err != nil {
return nil, err
}
if item.Parent != nil {
paths = append(paths, repo.ItemPath{
Type: repo.ItemTypeItem,
ID: item.Parent.ID,
Name: item.Parent.Name,
})
}
paths = append(paths, repo.ItemPath{
Type: repo.ItemTypeItem,
ID: item.ID,
Name: item.Name,
})
return paths, nil
}
return adapters.CommandID("id", fn, http.StatusOK)
}
// HandleItemsCreate godoc // HandleItemsCreate godoc
// //
// @Summary Create Item // @Summary Create Item
@ -211,6 +167,7 @@ func (ctrl *V1Controller) HandleItemUpdate() errchain.HandlerFunc {
return adapters.ActionID("id", fn, http.StatusOK) return adapters.ActionID("id", fn, http.StatusOK)
} }
// HandleItemPatch godocs // HandleItemPatch godocs
// //
// @Summary Update Item // @Summary Update Item
@ -226,12 +183,12 @@ func (ctrl *V1Controller) HandleItemPatch() errchain.HandlerFunc {
auth := services.NewContext(r.Context()) auth := services.NewContext(r.Context())
body.ID = ID body.ID = ID
err := ctrl.repo.Items.Patch(auth, auth.GID, ID, body) err := ctrl.repo.Items.Patch(auth, auth.GID, ID, body)
if err != nil { if err != nil {
return repo.ItemOut{}, err return repo.ItemOut{}, err
} }
return ctrl.repo.Items.GetOneByGroup(auth, auth.GID, ID) return ctrl.repo.Items.GetOneByGroup(auth, auth.GID, ID)
} }
return adapters.ActionID("id", fn, http.StatusOK) return adapters.ActionID("id", fn, http.StatusOK)
@ -274,7 +231,8 @@ func (ctrl *V1Controller) HandleGetAllCustomFieldValues() errchain.HandlerFunc {
return ctrl.repo.Items.GetAllCustomFieldValues(auth, auth.GID, q.Field) return ctrl.repo.Items.GetAllCustomFieldValues(auth, auth.GID, q.Field)
} }
return adapters.Query(fn, http.StatusOK) return adapters.Action(fn, http.StatusOK)
} }
// HandleItemsImport godocs // HandleItemsImport godocs

View file

@ -3,8 +3,6 @@ package v1
import ( import (
"errors" "errors"
"net/http" "net/http"
"path/filepath"
"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/data/ent/attachment" "github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
@ -40,6 +38,7 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() errchain.HandlerFunc {
if err != nil { if err != nil {
log.Err(err).Msg("failed to parse multipart form") log.Err(err).Msg("failed to parse multipart form")
return validate.NewRequestError(errors.New("failed to parse multipart form"), http.StatusBadRequest) return validate.NewRequestError(errors.New("failed to parse multipart form"), http.StatusBadRequest)
} }
errs := validate.NewFieldErrors() errs := validate.NewFieldErrors()
@ -68,15 +67,7 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() errchain.HandlerFunc {
attachmentType := r.FormValue("type") attachmentType := r.FormValue("type")
if attachmentType == "" { if attachmentType == "" {
// Attempt to auto-detect the type of the file attachmentType = attachment.TypeAttachment.String()
ext := filepath.Ext(attachmentName)
switch strings.ToLower(ext) {
case ".jpg", ".jpeg", ".png", ".webp", ".gif", ".bmp", ".tiff":
attachmentType = attachment.TypePhoto.String()
default:
attachmentType = attachment.TypeAttachment.String()
}
} }
id, err := ctrl.routeID(r) id, err := ctrl.routeID(r)

View file

@ -10,7 +10,7 @@ import (
"github.com/hay-kot/httpkit/errchain" "github.com/hay-kot/httpkit/errchain"
) )
// HandleLocationTreeQuery godoc // HandleLocationTreeQuery
// //
// @Summary Get Locations Tree // @Summary Get Locations Tree
// @Tags Locations // @Tags Locations
@ -28,7 +28,7 @@ func (ctrl *V1Controller) HandleLocationTreeQuery() errchain.HandlerFunc {
return adapters.Query(fn, http.StatusOK) return adapters.Query(fn, http.StatusOK)
} }
// HandleLocationGetAll godoc // HandleLocationGetAll
// //
// @Summary Get All Locations // @Summary Get All Locations
// @Tags Locations // @Tags Locations
@ -46,7 +46,7 @@ func (ctrl *V1Controller) HandleLocationGetAll() errchain.HandlerFunc {
return adapters.Query(fn, http.StatusOK) return adapters.Query(fn, http.StatusOK)
} }
// HandleLocationCreate godoc // HandleLocationCreate
// //
// @Summary Create Location // @Summary Create Location
// @Tags Locations // @Tags Locations
@ -64,7 +64,7 @@ func (ctrl *V1Controller) HandleLocationCreate() errchain.HandlerFunc {
return adapters.Action(fn, http.StatusCreated) return adapters.Action(fn, http.StatusCreated)
} }
// HandleLocationDelete godoc // HandleLocationDelete
// //
// @Summary Delete Location // @Summary Delete Location
// @Tags Locations // @Tags Locations
@ -83,7 +83,7 @@ func (ctrl *V1Controller) HandleLocationDelete() errchain.HandlerFunc {
return adapters.CommandID("id", fn, http.StatusNoContent) return adapters.CommandID("id", fn, http.StatusNoContent)
} }
// HandleLocationGet godoc // HandleLocationGet
// //
// @Summary Get Location // @Summary Get Location
// @Tags Locations // @Tags Locations
@ -101,7 +101,7 @@ func (ctrl *V1Controller) HandleLocationGet() errchain.HandlerFunc {
return adapters.CommandID("id", fn, http.StatusOK) return adapters.CommandID("id", fn, http.StatusOK)
} }
// HandleLocationUpdate godoc // HandleLocationUpdate
// //
// @Summary Update Location // @Summary Update Location
// @Tags Locations // @Tags Locations

View file

@ -10,7 +10,7 @@ import (
"github.com/hay-kot/httpkit/errchain" "github.com/hay-kot/httpkit/errchain"
) )
// HandleMaintenanceLogGet godoc // HandleMaintenanceGetLog godoc
// //
// @Summary Get Maintenance Log // @Summary Get Maintenance Log
// @Tags Maintenance // @Tags Maintenance

View file

@ -5,7 +5,6 @@ import (
"image/png" "image/png"
"io" "io"
"net/http" "net/http"
"net/url"
"github.com/hay-kot/homebox/backend/internal/web/adapters" "github.com/hay-kot/homebox/backend/internal/web/adapters"
"github.com/hay-kot/httpkit/errchain" "github.com/hay-kot/httpkit/errchain"
@ -44,12 +43,7 @@ func (ctrl *V1Controller) HandleGenerateQRCode() errchain.HandlerFunc {
panic(err) panic(err)
} }
decodedStr, err := url.QueryUnescape(q.Data) qrc, err := qrcode.New(q.Data)
if err != nil {
return err
}
qrc, err := qrcode.New(decodedStr)
if err != nil { if err != nil {
return err return err
} }

View file

@ -12,7 +12,7 @@ import (
"github.com/hay-kot/httpkit/server" "github.com/hay-kot/httpkit/server"
) )
// HandleGroupStatisticsLocations godoc // HandleGroupGet godoc
// //
// @Summary Get Location Statistics // @Summary Get Location Statistics
// @Tags Statistics // @Tags Statistics

View file

@ -2,6 +2,7 @@ package main
import ( import (
"os" "os"
"strings"
"github.com/hay-kot/homebox/backend/internal/sys/config" "github.com/hay-kot/homebox/backend/internal/sys/config"
"github.com/rs/zerolog" "github.com/rs/zerolog"
@ -17,8 +18,24 @@ func (a *app) setupLogger() {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).With().Caller().Logger() log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).With().Caller().Logger()
} }
level, err := zerolog.ParseLevel(a.conf.Log.Level) log.Level(getLevel(a.conf.Log.Level))
if err == nil { }
zerolog.SetGlobalLevel(level)
func getLevel(l string) zerolog.Level {
switch strings.ToLower(l) {
case "debug":
return zerolog.DebugLevel
case "info":
return zerolog.InfoLevel
case "warn":
return zerolog.WarnLevel
case "error":
return zerolog.ErrorLevel
case "fatal":
return zerolog.FatalLevel
case "panic":
return zerolog.PanicLevel
default:
return zerolog.InfoLevel
} }
} }

View file

@ -1,7 +1,6 @@
package main package main
import ( import (
"bytes"
"context" "context"
"fmt" "fmt"
"net/http" "net/http"
@ -14,7 +13,6 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware" "github.com/go-chi/chi/v5/middleware"
"github.com/hay-kot/homebox/backend/internal/core/currencies"
"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/core/services/reporting/eventbus"
"github.com/hay-kot/homebox/backend/internal/data/ent" "github.com/hay-kot/homebox/backend/internal/data/ent"
@ -23,7 +21,7 @@ import (
"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/httpkit/errchain" "github.com/hay-kot/httpkit/errchain"
"github.com/hay-kot/httpkit/graceful" "github.com/hay-kot/httpkit/server"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/rs/zerolog/pkgerrors" "github.com/rs/zerolog/pkgerrors"
@ -37,15 +35,6 @@ var (
buildTime = "now" buildTime = "now"
) )
func build() string {
short := commit
if len(short) > 7 {
short = short[:7]
}
return fmt.Sprintf("%s, commit %s, built at %s", version, short, buildTime)
}
// @title Homebox API // @title Homebox API
// @version 1.0 // @version 1.0
// @description Track, Manage, and Organize your Things. // @description Track, Manage, and Organize your Things.
@ -58,7 +47,7 @@ func build() string {
func main() { func main() {
zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack
cfg, err := config.New(build(), "Homebox inventory management system") cfg, err := config.New()
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -80,12 +69,12 @@ func run(cfg *config.Config) error {
log.Fatal().Err(err).Msg("failed to create data directory") log.Fatal().Err(err).Msg("failed to create data directory")
} }
c, err := ent.Open("sqlite3", cfg.Storage.SqliteURL) c, err := ent.Open("sqlite3", cfg.Storage.SqliteUrl)
if err != nil { if err != nil {
log.Fatal(). log.Fatal().
Err(err). Err(err).
Str("driver", "sqlite"). Str("driver", "sqlite").
Str("url", cfg.Storage.SqliteURL). Str("url", cfg.Storage.SqliteUrl).
Msg("failed opening connection to sqlite") Msg("failed opening connection to sqlite")
} }
defer func(c *ent.Client) { defer func(c *ent.Client) {
@ -118,7 +107,7 @@ func run(cfg *config.Config) error {
log.Fatal(). log.Fatal().
Err(err). Err(err).
Str("driver", "sqlite"). Str("driver", "sqlite").
Str("url", cfg.Storage.SqliteURL). Str("url", cfg.Storage.SqliteUrl).
Msg("failed creating schema resources") Msg("failed creating schema resources")
} }
@ -128,40 +117,12 @@ func run(cfg *config.Config) error {
return err return err
} }
collectFuncs := []currencies.CollectorFunc{
currencies.CollectDefaults(),
}
if cfg.Options.CurrencyConfig != "" {
log.Info().
Str("path", cfg.Options.CurrencyConfig).
Msg("loading currency config file")
content, err := os.ReadFile(cfg.Options.CurrencyConfig)
if err != nil {
log.Fatal().
Err(err).
Str("path", cfg.Options.CurrencyConfig).
Msg("failed to read currency config file")
}
collectFuncs = append(collectFuncs, currencies.CollectJSON(bytes.NewReader(content)))
}
currencies, err := currencies.CollectionCurrencies(collectFuncs...)
if err != nil {
log.Fatal().
Err(err).
Msg("failed to collect currencies")
}
app.bus = eventbus.New() app.bus = eventbus.New()
app.db = c app.db = c
app.repos = repo.New(c, app.bus, cfg.Storage.Data) app.repos = repo.New(c, app.bus, cfg.Storage.Data)
app.services = services.New( app.services = services.New(
app.repos, app.repos,
services.WithAutoIncrementAssetID(cfg.Options.AutoIncrementAssetID), services.WithAutoIncrementAssetID(cfg.Options.AutoIncrementAssetID),
services.WithCurrencies(currencies),
) )
// ========================================================================= // =========================================================================
@ -178,63 +139,38 @@ func run(cfg *config.Config) error {
middleware.StripSlashes, middleware.StripSlashes,
) )
chain := errchain.New(mid.Errors(logger)) chain := errchain.New(mid.Errors(app.server, logger))
app.mountRoutes(router, chain, app.repos) app.mountRoutes(router, chain, app.repos)
runner := graceful.NewRunner() app.server = server.NewServer(
server.WithHost(app.conf.Web.Host),
runner.AddFunc("server", func(ctx context.Context) error { server.WithPort(app.conf.Web.Port),
httpserver := http.Server{ )
Addr: fmt.Sprintf("%s:%s", cfg.Web.Host, cfg.Web.Port), log.Info().Msgf("Starting HTTP Server on %s:%s", app.server.Host, app.server.Port)
Handler: router,
ReadTimeout: cfg.Web.ReadTimeout,
WriteTimeout: cfg.Web.WriteTimeout,
IdleTimeout: cfg.Web.IdleTimeout,
}
go func() {
<-ctx.Done()
_ = httpserver.Shutdown(context.Background())
}()
log.Info().Msgf("Server is running on %s:%s", cfg.Web.Host, cfg.Web.Port)
return httpserver.ListenAndServe()
})
// ========================================================================= // =========================================================================
// Start Reoccurring Tasks // Start Reoccurring Tasks
runner.AddFunc("eventbus", app.bus.Run) go app.bus.Run()
runner.AddFunc("seed_database", func(ctx context.Context) error { go app.startBgTask(time.Duration(24)*time.Hour, func() {
// TODO: Remove through external API that does setup _, err := app.repos.AuthTokens.PurgeExpiredTokens(context.Background())
if cfg.Demo {
log.Info().Msg("Running in demo mode, creating demo data")
app.SetupDemo()
}
return nil
})
runner.AddPlugin(NewTask("purge-tokens", time.Duration(24)*time.Hour, func(ctx context.Context) {
_, err := app.repos.AuthTokens.PurgeExpiredTokens(ctx)
if err != nil { if err != nil {
log.Error(). log.Error().
Err(err). Err(err).
Msg("failed to purge expired tokens") Msg("failed to purge expired tokens")
} }
})) })
go app.startBgTask(time.Duration(24)*time.Hour, func() {
runner.AddPlugin(NewTask("purge-invitations", time.Duration(24)*time.Hour, func(ctx context.Context) { _, err := app.repos.Groups.InvitationPurge(context.Background())
_, err := app.repos.Groups.InvitationPurge(ctx)
if err != nil { if err != nil {
log.Error(). log.Error().
Err(err). Err(err).
Msg("failed to purge expired invitations") Msg("failed to purge expired invitations")
} }
})) })
go app.startBgTask(time.Duration(1)*time.Hour, func() {
runner.AddPlugin(NewTask("send-notifications", time.Duration(1)*time.Hour, func(ctx context.Context) {
now := time.Now() now := time.Now()
if now.Hour() == 8 { if now.Hour() == 8 {
@ -246,27 +182,22 @@ func run(cfg *config.Config) error {
Msg("failed to send notifiers") Msg("failed to send notifiers")
} }
} }
})) })
if cfg.Debug.Enabled { // TODO: Remove through external API that does setup
runner.AddFunc("debug", func(ctx context.Context) error { if cfg.Demo {
debugserver := http.Server{ log.Info().Msg("Running in demo mode, creating demo data")
Addr: fmt.Sprintf("%s:%s", cfg.Web.Host, cfg.Debug.Port), app.SetupDemo()
Handler: app.debugRouter(),
ReadTimeout: cfg.Web.ReadTimeout,
WriteTimeout: cfg.Web.WriteTimeout,
IdleTimeout: cfg.Web.IdleTimeout,
}
go func() {
<-ctx.Done()
_ = debugserver.Shutdown(context.Background())
}()
log.Info().Msgf("Debug server is running on %s:%s", cfg.Web.Host, cfg.Debug.Port)
return debugserver.ListenAndServe()
})
} }
return runner.Start(context.Background()) if cfg.Debug.Enabled {
debugrouter := app.debugRouter()
go func() {
if err := http.ListenAndServe(":"+cfg.Debug.Port, debugrouter); err != nil {
log.Fatal().Err(err).Msg("failed to start debug server")
}
}()
}
return app.server.Start(router)
} }

View file

@ -7,9 +7,7 @@ import (
"net/url" "net/url"
"strings" "strings"
v1 "github.com/hay-kot/homebox/backend/app/api/handlers/v1"
"github.com/hay-kot/homebox/backend/internal/core/services" "github.com/hay-kot/homebox/backend/internal/core/services"
"github.com/hay-kot/homebox/backend/internal/data/ent"
"github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/internal/sys/validate"
"github.com/hay-kot/httpkit/errchain" "github.com/hay-kot/httpkit/errchain"
) )
@ -96,6 +94,20 @@ func getQuery(r *http.Request) (string, error) {
return token, nil 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's user to the request context, or return an appropriate error. // and attach it's user to the request context, or return an appropriate error.
// Authorization support is by token via Headers or Query Parameter // Authorization support is by token via Headers or Query Parameter
@ -103,35 +115,26 @@ func getQuery(r *http.Request) (string, error) {
// Example: // Example:
// - header = "Bearer 1234567890" // - header = "Bearer 1234567890"
// - query = "?access_token=1234567890" // - query = "?access_token=1234567890"
// - cookie = hb.auth.token = 1234567890
func (a *app) mwAuthToken(next errchain.Handler) errchain.Handler { func (a *app) mwAuthToken(next errchain.Handler) errchain.Handler {
return errchain.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error { return errchain.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
keyFuncs := [...]KeyFunc{
getBearer,
getCookie,
getQuery,
}
var requestToken string var requestToken string
for _, keyFunc := range keyFuncs {
// We ignore the error to allow the next strategy to be attempted token, err := keyFunc(r)
{ if err == nil {
cookies, _ := v1.GetCookies(r) requestToken = token
if cookies != nil { break
requestToken = cookies.Token
} }
} }
if requestToken == "" { if requestToken == "" {
keyFuncs := [...]KeyFunc{ return validate.NewRequestError(errors.New("Authorization header or query is required"), http.StatusUnauthorized)
getBearer,
getQuery,
}
for _, keyFunc := range keyFuncs {
token, err := keyFunc(r)
if err == nil {
requestToken = token
break
}
}
}
if requestToken == "" {
return validate.NewRequestError(errors.New("authorization header or query is required"), http.StatusUnauthorized)
} }
requestToken = strings.TrimPrefix(requestToken, "Bearer ") requestToken = strings.TrimPrefix(requestToken, "Bearer ")
@ -141,11 +144,7 @@ func (a *app) mwAuthToken(next errchain.Handler) errchain.Handler {
usr, err := a.services.User.GetSelf(r.Context(), requestToken) 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 {
if ent.IsNotFound(err) { return validate.NewRequestError(errors.New("valid authorization header is required"), http.StatusUnauthorized)
return validate.NewRequestError(errors.New("valid authorization token is required"), http.StatusUnauthorized)
}
return err
} }
r = r.WithContext(services.SetUserCtx(r.Context(), &usr, requestToken)) r = r.WithContext(services.SetUserCtx(r.Context(), &usr, requestToken))

View file

@ -1,2 +0,0 @@
// Package providers provides a authentication abstraction for the backend.
package providers

View file

@ -1,55 +0,0 @@
package providers
import (
"errors"
"net/http"
"github.com/hay-kot/homebox/backend/internal/sys/validate"
"github.com/hay-kot/httpkit/server"
"github.com/rs/zerolog/log"
)
type LoginForm struct {
Username string `json:"username"`
Password string `json:"password"`
StayLoggedIn bool `json:"stayLoggedIn"`
}
func getLoginForm(r *http.Request) (LoginForm, error) {
loginForm := LoginForm{}
switch r.Header.Get("Content-Type") {
case "application/x-www-form-urlencoded":
err := r.ParseForm()
if err != nil {
return loginForm, errors.New("failed to parse form")
}
loginForm.Username = r.PostFormValue("username")
loginForm.Password = r.PostFormValue("password")
loginForm.StayLoggedIn = r.PostFormValue("stayLoggedIn") == "true"
case "application/json":
err := server.Decode(r, &loginForm)
if err != nil {
log.Err(err).Msg("failed to decode login form")
return loginForm, errors.New("failed to decode login form")
}
default:
return loginForm, errors.New("invalid content type")
}
if loginForm.Username == "" || loginForm.Password == "" {
return loginForm, validate.NewFieldErrors(
validate.FieldError{
Field: "username",
Error: "username or password is empty",
},
validate.FieldError{
Field: "password",
Error: "username or password is empty",
},
)
}
return loginForm, nil
}

View file

@ -1,30 +0,0 @@
package providers
import (
"net/http"
"github.com/hay-kot/homebox/backend/internal/core/services"
)
type LocalProvider struct {
service *services.UserService
}
func NewLocalProvider(service *services.UserService) *LocalProvider {
return &LocalProvider{
service: service,
}
}
func (p *LocalProvider) Name() string {
return "local"
}
func (p *LocalProvider) Authenticate(w http.ResponseWriter, r *http.Request) (services.UserAuthTokenDetail, error) {
loginForm, err := getLoginForm(r)
if err != nil {
return services.UserAuthTokenDetail{}, err
}
return p.service.Login(r.Context(), loginForm.Username, loginForm.Password, loginForm.StayLoggedIn)
}

View file

@ -12,12 +12,11 @@ import (
"github.com/go-chi/chi/v5" "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/providers"
_ "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/ent/authroles"
"github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/data/repo"
"github.com/hay-kot/httpkit/errchain" "github.com/hay-kot/httpkit/errchain"
httpSwagger "github.com/swaggo/http-swagger/v2" // http-swagger middleware httpSwagger "github.com/swaggo/http-swagger" // http-swagger middleware
) )
const prefix = "/api" const prefix = "/api"
@ -47,12 +46,12 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
// ========================================================================= // =========================================================================
// API Version 1 // API Version 1
v1Base := v1.BaseURLFunc(prefix) v1Base := v1.BaseUrlFunc(prefix)
v1Ctrl := v1.NewControllerV1( v1Ctrl := v1.NewControllerV1(
a.services, a.services,
a.repos, a.repos,
a.bus, a.bus,
v1.WithMaxUploadSize(a.conf.Web.MaxUploadSize), v1.WithMaxUploadSize(a.conf.Web.MaxUploadSize),
v1.WithRegistration(a.conf.Options.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
@ -64,14 +63,8 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
BuildTime: buildTime, BuildTime: buildTime,
}))) })))
r.Get(v1Base("/currencies"), chain.ToHandlerFunc(v1Ctrl.HandleCurrency()))
providers := []v1.AuthProvider{
providers.NewLocalProvider(a.services.User),
}
r.Post(v1Base("/users/register"), chain.ToHandlerFunc(v1Ctrl.HandleUserRegistration())) r.Post(v1Base("/users/register"), chain.ToHandlerFunc(v1Ctrl.HandleUserRegistration()))
r.Post(v1Base("/users/login"), chain.ToHandlerFunc(v1Ctrl.HandleAuthLogin(providers...))) r.Post(v1Base("/users/login"), chain.ToHandlerFunc(v1Ctrl.HandleAuthLogin()))
userMW := []errchain.Middleware{ userMW := []errchain.Middleware{
a.mwAuthToken, a.mwAuthToken,
@ -99,7 +92,6 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
r.Post(v1Base("/actions/ensure-asset-ids"), chain.ToHandlerFunc(v1Ctrl.HandleEnsureAssetID(), userMW...)) r.Post(v1Base("/actions/ensure-asset-ids"), chain.ToHandlerFunc(v1Ctrl.HandleEnsureAssetID(), userMW...))
r.Post(v1Base("/actions/zero-item-time-fields"), chain.ToHandlerFunc(v1Ctrl.HandleItemDateZeroOut(), userMW...)) r.Post(v1Base("/actions/zero-item-time-fields"), chain.ToHandlerFunc(v1Ctrl.HandleItemDateZeroOut(), userMW...))
r.Post(v1Base("/actions/ensure-import-refs"), chain.ToHandlerFunc(v1Ctrl.HandleEnsureImportRefs(), userMW...)) r.Post(v1Base("/actions/ensure-import-refs"), chain.ToHandlerFunc(v1Ctrl.HandleEnsureImportRefs(), userMW...))
r.Post(v1Base("/actions/set-primary-photos"), chain.ToHandlerFunc(v1Ctrl.HandleSetPrimaryPhotos(), userMW...))
r.Get(v1Base("/locations"), chain.ToHandlerFunc(v1Ctrl.HandleLocationGetAll(), userMW...)) r.Get(v1Base("/locations"), chain.ToHandlerFunc(v1Ctrl.HandleLocationGetAll(), userMW...))
r.Post(v1Base("/locations"), chain.ToHandlerFunc(v1Ctrl.HandleLocationCreate(), userMW...)) r.Post(v1Base("/locations"), chain.ToHandlerFunc(v1Ctrl.HandleLocationCreate(), userMW...))
@ -122,7 +114,6 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
r.Get(v1Base("/items/fields/values"), chain.ToHandlerFunc(v1Ctrl.HandleGetAllCustomFieldValues(), userMW...)) r.Get(v1Base("/items/fields/values"), chain.ToHandlerFunc(v1Ctrl.HandleGetAllCustomFieldValues(), userMW...))
r.Get(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemGet(), userMW...)) r.Get(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemGet(), userMW...))
r.Get(v1Base("/items/{id}/path"), chain.ToHandlerFunc(v1Ctrl.HandleItemFullPath(), userMW...))
r.Put(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemUpdate(), userMW...)) r.Put(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemUpdate(), userMW...))
r.Patch(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemPatch(), userMW...)) r.Patch(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemPatch(), userMW...))
r.Delete(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemDelete(), userMW...)) r.Delete(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemDelete(), userMW...))
@ -186,7 +177,7 @@ func notFoundHandler() errchain.HandlerFunc {
if err != nil { if err != nil {
return err return err
} }
defer func() { _ = f.Close() }() defer f.Close()
stat, _ := f.Stat() stat, _ := f.Stat()
if stat.IsDir() { if stat.IsDir() {

View file

@ -1,4 +1,5 @@
// Package docs Code generated by swaggo/swag. DO NOT EDIT // Package docs GENERATED BY SWAG; DO NOT EDIT
// This file was generated by swaggo/swag
package docs package docs
import "github.com/swaggo/swag" import "github.com/swaggo/swag"
@ -67,31 +68,6 @@ const docTemplate = `{
} }
} }
}, },
"/v1/actions/set-primary-photos": {
"post": {
"security": [
{
"Bearer": []
}
],
"description": "Sets the first photo of each item as the primary photo",
"produces": [
"application/json"
],
"tags": [
"Actions"
],
"summary": "Set Primary Photos",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/v1.ActionAmountResult"
}
}
}
}
},
"/v1/actions/zero-item-time-fields": { "/v1/actions/zero-item-time-fields": {
"post": { "post": {
"security": [ "security": [
@ -150,25 +126,6 @@ const docTemplate = `{
} }
} }
}, },
"/v1/currency": {
"get": {
"produces": [
"application/json"
],
"tags": [
"Base"
],
"summary": "Currency",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/currencies.Currency"
}
}
}
}
},
"/v1/groups": { "/v1/groups": {
"get": { "get": {
"security": [ "security": [
@ -429,16 +386,6 @@ const docTemplate = `{
"description": "location Ids", "description": "location Ids",
"name": "locations", "name": "locations",
"in": "query" "in": "query"
},
{
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi",
"description": "parent Ids",
"name": "parentIds",
"in": "query"
} }
], ],
"responses": { "responses": {
@ -1017,42 +964,6 @@ const docTemplate = `{
} }
} }
}, },
"/v1/items/{id}/path": {
"get": {
"security": [
{
"Bearer": []
}
],
"produces": [
"application/json"
],
"tags": [
"Items"
],
"summary": "Get the full path of an item",
"parameters": [
{
"type": "string",
"description": "Item ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemPath"
}
}
}
}
}
},
"/v1/labels": { "/v1/labels": {
"get": { "get": {
"security": [ "security": [
@ -1639,7 +1550,7 @@ const docTemplate = `{
"200": { "200": {
"description": "OK", "description": "OK",
"schema": { "schema": {
"$ref": "#/definitions/v1.APISummary" "$ref": "#/definitions/v1.ApiSummary"
} }
} }
} }
@ -1710,12 +1621,6 @@ const docTemplate = `{
"schema": { "schema": {
"$ref": "#/definitions/v1.LoginForm" "$ref": "#/definitions/v1.LoginForm"
} }
},
{
"type": "string",
"description": "auth provider",
"name": "provider",
"in": "query"
} }
], ],
"responses": { "responses": {
@ -1894,23 +1799,6 @@ const docTemplate = `{
} }
}, },
"definitions": { "definitions": {
"currencies.Currency": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"local": {
"type": "string"
},
"name": {
"type": "string"
},
"symbol": {
"type": "string"
}
}
},
"repo.DocumentOut": { "repo.DocumentOut": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -1991,9 +1879,6 @@ const docTemplate = `{
"id": { "id": {
"type": "string" "type": "string"
}, },
"primary": {
"type": "boolean"
},
"type": { "type": {
"type": "string" "type": "string"
}, },
@ -2005,9 +1890,6 @@ const docTemplate = `{
"repo.ItemAttachmentUpdate": { "repo.ItemAttachmentUpdate": {
"type": "object", "type": "object",
"properties": { "properties": {
"primary": {
"type": "boolean"
},
"title": { "title": {
"type": "string" "type": "string"
}, },
@ -2086,6 +1968,12 @@ const docTemplate = `{
"$ref": "#/definitions/repo.ItemAttachment" "$ref": "#/definitions/repo.ItemAttachment"
} }
}, },
"children": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemSummary"
}
},
"createdAt": { "createdAt": {
"type": "string" "type": "string"
}, },
@ -2101,9 +1989,6 @@ const docTemplate = `{
"id": { "id": {
"type": "string" "type": "string"
}, },
"imageId": {
"type": "string"
},
"insured": { "insured": {
"type": "boolean" "type": "boolean"
}, },
@ -2119,13 +2004,9 @@ const docTemplate = `{
}, },
"location": { "location": {
"description": "Edges", "description": "Edges",
"allOf": [
{
"$ref": "#/definitions/repo.LocationSummary"
}
],
"x-nullable": true, "x-nullable": true,
"x-omitempty": true "x-omitempty": true,
"$ref": "#/definitions/repo.LocationSummary"
}, },
"manufacturer": { "manufacturer": {
"type": "string" "type": "string"
@ -2141,13 +2022,9 @@ const docTemplate = `{
"type": "string" "type": "string"
}, },
"parent": { "parent": {
"allOf": [
{
"$ref": "#/definitions/repo.ItemSummary"
}
],
"x-nullable": true, "x-nullable": true,
"x-omitempty": true "x-omitempty": true,
"$ref": "#/definitions/repo.ItemSummary"
}, },
"purchaseFrom": { "purchaseFrom": {
"type": "string" "type": "string"
@ -2204,20 +2081,6 @@ const docTemplate = `{
} }
} }
}, },
"repo.ItemPath": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"type": {
"$ref": "#/definitions/repo.ItemType"
}
}
},
"repo.ItemSummary": { "repo.ItemSummary": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -2233,9 +2096,6 @@ const docTemplate = `{
"id": { "id": {
"type": "string" "type": "string"
}, },
"imageId": {
"type": "string"
},
"insured": { "insured": {
"type": "boolean" "type": "boolean"
}, },
@ -2247,13 +2107,9 @@ const docTemplate = `{
}, },
"location": { "location": {
"description": "Edges", "description": "Edges",
"allOf": [
{
"$ref": "#/definitions/repo.LocationSummary"
}
],
"x-nullable": true, "x-nullable": true,
"x-omitempty": true "x-omitempty": true,
"$ref": "#/definitions/repo.LocationSummary"
}, },
"name": { "name": {
"type": "string" "type": "string"
@ -2270,17 +2126,6 @@ const docTemplate = `{
} }
} }
}, },
"repo.ItemType": {
"type": "string",
"enum": [
"location",
"item"
],
"x-enum-varnames": [
"ItemTypeLocation",
"ItemTypeItem"
]
},
"repo.ItemUpdate": { "repo.ItemUpdate": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -2373,6 +2218,7 @@ const docTemplate = `{
"type": "string" "type": "string"
}, },
"warrantyExpires": { "warrantyExpires": {
"description": "Sold",
"type": "string" "type": "string"
} }
} }
@ -2409,6 +2255,12 @@ const docTemplate = `{
"id": { "id": {
"type": "string" "type": "string"
}, },
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemSummary"
}
},
"name": { "name": {
"type": "string" "type": "string"
}, },
@ -2470,6 +2322,12 @@ const docTemplate = `{
"id": { "id": {
"type": "string" "type": "string"
}, },
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemSummary"
}
},
"name": { "name": {
"type": "string" "type": "string"
}, },
@ -2546,6 +2404,7 @@ const docTemplate = `{
"type": "object", "type": "object",
"properties": { "properties": {
"completedDate": { "completedDate": {
"description": "Sold",
"type": "string" "type": "string"
}, },
"cost": { "cost": {
@ -2562,6 +2421,7 @@ const docTemplate = `{
"type": "string" "type": "string"
}, },
"scheduledDate": { "scheduledDate": {
"description": "Sold",
"type": "string" "type": "string"
} }
} }
@ -2573,6 +2433,7 @@ const docTemplate = `{
], ],
"properties": { "properties": {
"completedDate": { "completedDate": {
"description": "Sold",
"type": "string" "type": "string"
}, },
"cost": { "cost": {
@ -2586,6 +2447,7 @@ const docTemplate = `{
"type": "string" "type": "string"
}, },
"scheduledDate": { "scheduledDate": {
"description": "Sold",
"type": "string" "type": "string"
} }
} }
@ -2594,6 +2456,7 @@ const docTemplate = `{
"type": "object", "type": "object",
"properties": { "properties": {
"completedDate": { "completedDate": {
"description": "Sold",
"type": "string" "type": "string"
}, },
"cost": { "cost": {
@ -2607,6 +2470,7 @@ const docTemplate = `{
"type": "string" "type": "string"
}, },
"scheduledDate": { "scheduledDate": {
"description": "Sold",
"type": "string" "type": "string"
} }
} }
@ -2842,7 +2706,15 @@ const docTemplate = `{
} }
} }
}, },
"v1.APISummary": { "v1.ActionAmountResult": {
"type": "object",
"properties": {
"completed": {
"type": "integer"
}
}
},
"v1.ApiSummary": {
"type": "object", "type": "object",
"properties": { "properties": {
"allowRegistration": { "allowRegistration": {
@ -2871,14 +2743,6 @@ const docTemplate = `{
} }
} }
}, },
"v1.ActionAmountResult": {
"type": "object",
"properties": {
"completed": {
"type": "integer"
}
}
},
"v1.Build": { "v1.Build": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -3008,8 +2872,6 @@ var SwaggerInfo = &swag.Spec{
Description: "Track, Manage, and Organize your Things.", Description: "Track, Manage, and Organize your Things.",
InfoInstanceName: "swagger", InfoInstanceName: "swagger",
SwaggerTemplate: docTemplate, SwaggerTemplate: docTemplate,
LeftDelim: "{{",
RightDelim: "}}",
} }
func init() { func init() {

View file

@ -60,31 +60,6 @@
} }
} }
}, },
"/v1/actions/set-primary-photos": {
"post": {
"security": [
{
"Bearer": []
}
],
"description": "Sets the first photo of each item as the primary photo",
"produces": [
"application/json"
],
"tags": [
"Actions"
],
"summary": "Set Primary Photos",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/v1.ActionAmountResult"
}
}
}
}
},
"/v1/actions/zero-item-time-fields": { "/v1/actions/zero-item-time-fields": {
"post": { "post": {
"security": [ "security": [
@ -143,25 +118,6 @@
} }
} }
}, },
"/v1/currency": {
"get": {
"produces": [
"application/json"
],
"tags": [
"Base"
],
"summary": "Currency",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/currencies.Currency"
}
}
}
}
},
"/v1/groups": { "/v1/groups": {
"get": { "get": {
"security": [ "security": [
@ -422,16 +378,6 @@
"description": "location Ids", "description": "location Ids",
"name": "locations", "name": "locations",
"in": "query" "in": "query"
},
{
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi",
"description": "parent Ids",
"name": "parentIds",
"in": "query"
} }
], ],
"responses": { "responses": {
@ -1010,42 +956,6 @@
} }
} }
}, },
"/v1/items/{id}/path": {
"get": {
"security": [
{
"Bearer": []
}
],
"produces": [
"application/json"
],
"tags": [
"Items"
],
"summary": "Get the full path of an item",
"parameters": [
{
"type": "string",
"description": "Item ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemPath"
}
}
}
}
}
},
"/v1/labels": { "/v1/labels": {
"get": { "get": {
"security": [ "security": [
@ -1632,7 +1542,7 @@
"200": { "200": {
"description": "OK", "description": "OK",
"schema": { "schema": {
"$ref": "#/definitions/v1.APISummary" "$ref": "#/definitions/v1.ApiSummary"
} }
} }
} }
@ -1703,12 +1613,6 @@
"schema": { "schema": {
"$ref": "#/definitions/v1.LoginForm" "$ref": "#/definitions/v1.LoginForm"
} }
},
{
"type": "string",
"description": "auth provider",
"name": "provider",
"in": "query"
} }
], ],
"responses": { "responses": {
@ -1887,23 +1791,6 @@
} }
}, },
"definitions": { "definitions": {
"currencies.Currency": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"local": {
"type": "string"
},
"name": {
"type": "string"
},
"symbol": {
"type": "string"
}
}
},
"repo.DocumentOut": { "repo.DocumentOut": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -1984,9 +1871,6 @@
"id": { "id": {
"type": "string" "type": "string"
}, },
"primary": {
"type": "boolean"
},
"type": { "type": {
"type": "string" "type": "string"
}, },
@ -1998,9 +1882,6 @@
"repo.ItemAttachmentUpdate": { "repo.ItemAttachmentUpdate": {
"type": "object", "type": "object",
"properties": { "properties": {
"primary": {
"type": "boolean"
},
"title": { "title": {
"type": "string" "type": "string"
}, },
@ -2079,6 +1960,12 @@
"$ref": "#/definitions/repo.ItemAttachment" "$ref": "#/definitions/repo.ItemAttachment"
} }
}, },
"children": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemSummary"
}
},
"createdAt": { "createdAt": {
"type": "string" "type": "string"
}, },
@ -2094,9 +1981,6 @@
"id": { "id": {
"type": "string" "type": "string"
}, },
"imageId": {
"type": "string"
},
"insured": { "insured": {
"type": "boolean" "type": "boolean"
}, },
@ -2112,13 +1996,9 @@
}, },
"location": { "location": {
"description": "Edges", "description": "Edges",
"allOf": [
{
"$ref": "#/definitions/repo.LocationSummary"
}
],
"x-nullable": true, "x-nullable": true,
"x-omitempty": true "x-omitempty": true,
"$ref": "#/definitions/repo.LocationSummary"
}, },
"manufacturer": { "manufacturer": {
"type": "string" "type": "string"
@ -2134,13 +2014,9 @@
"type": "string" "type": "string"
}, },
"parent": { "parent": {
"allOf": [
{
"$ref": "#/definitions/repo.ItemSummary"
}
],
"x-nullable": true, "x-nullable": true,
"x-omitempty": true "x-omitempty": true,
"$ref": "#/definitions/repo.ItemSummary"
}, },
"purchaseFrom": { "purchaseFrom": {
"type": "string" "type": "string"
@ -2197,20 +2073,6 @@
} }
} }
}, },
"repo.ItemPath": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"type": {
"$ref": "#/definitions/repo.ItemType"
}
}
},
"repo.ItemSummary": { "repo.ItemSummary": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -2226,9 +2088,6 @@
"id": { "id": {
"type": "string" "type": "string"
}, },
"imageId": {
"type": "string"
},
"insured": { "insured": {
"type": "boolean" "type": "boolean"
}, },
@ -2240,13 +2099,9 @@
}, },
"location": { "location": {
"description": "Edges", "description": "Edges",
"allOf": [
{
"$ref": "#/definitions/repo.LocationSummary"
}
],
"x-nullable": true, "x-nullable": true,
"x-omitempty": true "x-omitempty": true,
"$ref": "#/definitions/repo.LocationSummary"
}, },
"name": { "name": {
"type": "string" "type": "string"
@ -2263,17 +2118,6 @@
} }
} }
}, },
"repo.ItemType": {
"type": "string",
"enum": [
"location",
"item"
],
"x-enum-varnames": [
"ItemTypeLocation",
"ItemTypeItem"
]
},
"repo.ItemUpdate": { "repo.ItemUpdate": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -2366,6 +2210,7 @@
"type": "string" "type": "string"
}, },
"warrantyExpires": { "warrantyExpires": {
"description": "Sold",
"type": "string" "type": "string"
} }
} }
@ -2402,6 +2247,12 @@
"id": { "id": {
"type": "string" "type": "string"
}, },
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemSummary"
}
},
"name": { "name": {
"type": "string" "type": "string"
}, },
@ -2463,6 +2314,12 @@
"id": { "id": {
"type": "string" "type": "string"
}, },
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemSummary"
}
},
"name": { "name": {
"type": "string" "type": "string"
}, },
@ -2539,6 +2396,7 @@
"type": "object", "type": "object",
"properties": { "properties": {
"completedDate": { "completedDate": {
"description": "Sold",
"type": "string" "type": "string"
}, },
"cost": { "cost": {
@ -2555,6 +2413,7 @@
"type": "string" "type": "string"
}, },
"scheduledDate": { "scheduledDate": {
"description": "Sold",
"type": "string" "type": "string"
} }
} }
@ -2566,6 +2425,7 @@
], ],
"properties": { "properties": {
"completedDate": { "completedDate": {
"description": "Sold",
"type": "string" "type": "string"
}, },
"cost": { "cost": {
@ -2579,6 +2439,7 @@
"type": "string" "type": "string"
}, },
"scheduledDate": { "scheduledDate": {
"description": "Sold",
"type": "string" "type": "string"
} }
} }
@ -2587,6 +2448,7 @@
"type": "object", "type": "object",
"properties": { "properties": {
"completedDate": { "completedDate": {
"description": "Sold",
"type": "string" "type": "string"
}, },
"cost": { "cost": {
@ -2600,6 +2462,7 @@
"type": "string" "type": "string"
}, },
"scheduledDate": { "scheduledDate": {
"description": "Sold",
"type": "string" "type": "string"
} }
} }
@ -2835,7 +2698,15 @@
} }
} }
}, },
"v1.APISummary": { "v1.ActionAmountResult": {
"type": "object",
"properties": {
"completed": {
"type": "integer"
}
}
},
"v1.ApiSummary": {
"type": "object", "type": "object",
"properties": { "properties": {
"allowRegistration": { "allowRegistration": {
@ -2864,14 +2735,6 @@
} }
} }
}, },
"v1.ActionAmountResult": {
"type": "object",
"properties": {
"completed": {
"type": "integer"
}
}
},
"v1.Build": { "v1.Build": {
"type": "object", "type": "object",
"properties": { "properties": {

View file

@ -1,16 +1,5 @@
basePath: /api basePath: /api
definitions: definitions:
currencies.Currency:
properties:
code:
type: string
local:
type: string
name:
type: string
symbol:
type: string
type: object
repo.DocumentOut: repo.DocumentOut:
properties: properties:
id: id:
@ -63,8 +52,6 @@ definitions:
$ref: '#/definitions/repo.DocumentOut' $ref: '#/definitions/repo.DocumentOut'
id: id:
type: string type: string
primary:
type: boolean
type: type:
type: string type: string
updatedAt: updatedAt:
@ -72,8 +59,6 @@ definitions:
type: object type: object
repo.ItemAttachmentUpdate: repo.ItemAttachmentUpdate:
properties: properties:
primary:
type: boolean
title: title:
type: string type: string
type: type:
@ -127,6 +112,10 @@ definitions:
items: items:
$ref: '#/definitions/repo.ItemAttachment' $ref: '#/definitions/repo.ItemAttachment'
type: array type: array
children:
items:
$ref: '#/definitions/repo.ItemSummary'
type: array
createdAt: createdAt:
type: string type: string
description: description:
@ -137,8 +126,6 @@ definitions:
type: array type: array
id: id:
type: string type: string
imageId:
type: string
insured: insured:
type: boolean type: boolean
labels: labels:
@ -149,8 +136,7 @@ definitions:
description: Warranty description: Warranty
type: boolean type: boolean
location: location:
allOf: $ref: '#/definitions/repo.LocationSummary'
- $ref: '#/definitions/repo.LocationSummary'
description: Edges description: Edges
x-nullable: true x-nullable: true
x-omitempty: true x-omitempty: true
@ -164,8 +150,7 @@ definitions:
description: Extras description: Extras
type: string type: string
parent: parent:
allOf: $ref: '#/definitions/repo.ItemSummary'
- $ref: '#/definitions/repo.ItemSummary'
x-nullable: true x-nullable: true
x-omitempty: true x-omitempty: true
purchaseFrom: purchaseFrom:
@ -206,15 +191,6 @@ definitions:
x-nullable: true x-nullable: true
x-omitempty: true x-omitempty: true
type: object type: object
repo.ItemPath:
properties:
id:
type: string
name:
type: string
type:
$ref: '#/definitions/repo.ItemType'
type: object
repo.ItemSummary: repo.ItemSummary:
properties: properties:
archived: archived:
@ -225,8 +201,6 @@ definitions:
type: string type: string
id: id:
type: string type: string
imageId:
type: string
insured: insured:
type: boolean type: boolean
labels: labels:
@ -234,8 +208,7 @@ definitions:
$ref: '#/definitions/repo.LabelSummary' $ref: '#/definitions/repo.LabelSummary'
type: array type: array
location: location:
allOf: $ref: '#/definitions/repo.LocationSummary'
- $ref: '#/definitions/repo.LocationSummary'
description: Edges description: Edges
x-nullable: true x-nullable: true
x-omitempty: true x-omitempty: true
@ -249,14 +222,6 @@ definitions:
updatedAt: updatedAt:
type: string type: string
type: object type: object
repo.ItemType:
enum:
- location
- item
type: string
x-enum-varnames:
- ItemTypeLocation
- ItemTypeItem
repo.ItemUpdate: repo.ItemUpdate:
properties: properties:
archived: archived:
@ -322,6 +287,7 @@ definitions:
warrantyDetails: warrantyDetails:
type: string type: string
warrantyExpires: warrantyExpires:
description: Sold
type: string type: string
type: object type: object
repo.LabelCreate: repo.LabelCreate:
@ -346,6 +312,10 @@ definitions:
type: string type: string
id: id:
type: string type: string
items:
items:
$ref: '#/definitions/repo.ItemSummary'
type: array
name: name:
type: string type: string
updatedAt: updatedAt:
@ -386,6 +356,10 @@ definitions:
type: string type: string
id: id:
type: string type: string
items:
items:
$ref: '#/definitions/repo.ItemSummary'
type: array
name: name:
type: string type: string
parent: parent:
@ -436,6 +410,7 @@ definitions:
repo.MaintenanceEntry: repo.MaintenanceEntry:
properties: properties:
completedDate: completedDate:
description: Sold
type: string type: string
cost: cost:
example: "0" example: "0"
@ -447,11 +422,13 @@ definitions:
name: name:
type: string type: string
scheduledDate: scheduledDate:
description: Sold
type: string type: string
type: object type: object
repo.MaintenanceEntryCreate: repo.MaintenanceEntryCreate:
properties: properties:
completedDate: completedDate:
description: Sold
type: string type: string
cost: cost:
example: "0" example: "0"
@ -461,6 +438,7 @@ definitions:
name: name:
type: string type: string
scheduledDate: scheduledDate:
description: Sold
type: string type: string
required: required:
- name - name
@ -468,6 +446,7 @@ definitions:
repo.MaintenanceEntryUpdate: repo.MaintenanceEntryUpdate:
properties: properties:
completedDate: completedDate:
description: Sold
type: string type: string
cost: cost:
example: "0" example: "0"
@ -477,6 +456,7 @@ definitions:
name: name:
type: string type: string
scheduledDate: scheduledDate:
description: Sold
type: string type: string
type: object type: object
repo.MaintenanceLog: repo.MaintenanceLog:
@ -631,7 +611,12 @@ definitions:
token: token:
type: string type: string
type: object type: object
v1.APISummary: v1.ActionAmountResult:
properties:
completed:
type: integer
type: object
v1.ApiSummary:
properties: properties:
allowRegistration: allowRegistration:
type: boolean type: boolean
@ -650,11 +635,6 @@ definitions:
type: string type: string
type: array type: array
type: object type: object
v1.ActionAmountResult:
properties:
completed:
type: integer
type: object
v1.Build: v1.Build:
properties: properties:
buildTime: buildTime:
@ -762,21 +742,6 @@ paths:
summary: Ensures Import Refs summary: Ensures Import Refs
tags: tags:
- Actions - Actions
/v1/actions/set-primary-photos:
post:
description: Sets the first photo of each item as the primary photo
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/v1.ActionAmountResult'
security:
- Bearer: []
summary: Set Primary Photos
tags:
- Actions
/v1/actions/zero-item-time-fields: /v1/actions/zero-item-time-fields:
post: post:
description: Resets all item date fields to the beginning of the day description: Resets all item date fields to the beginning of the day
@ -812,18 +777,6 @@ paths:
summary: Get Item by Asset ID summary: Get Item by Asset ID
tags: tags:
- Items - Items
/v1/currency:
get:
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/currencies.Currency'
summary: Currency
tags:
- Base
/v1/groups: /v1/groups:
get: get:
produces: produces:
@ -977,13 +930,6 @@ paths:
type: string type: string
name: locations name: locations
type: array type: array
- collectionFormat: multi
description: parent Ids
in: query
items:
type: string
name: parentIds
type: array
produces: produces:
- application/json - application/json
responses: responses:
@ -1281,28 +1227,6 @@ paths:
summary: Update Maintenance Entry summary: Update Maintenance Entry
tags: tags:
- Maintenance - Maintenance
/v1/items/{id}/path:
get:
parameters:
- description: Item ID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/repo.ItemPath'
type: array
security:
- Bearer: []
summary: Get the full path of an item
tags:
- Items
/v1/items/export: /v1/items/export:
get: get:
responses: responses:
@ -1720,7 +1644,7 @@ paths:
"200": "200":
description: OK description: OK
schema: schema:
$ref: '#/definitions/v1.APISummary' $ref: '#/definitions/v1.ApiSummary'
summary: Application Info summary: Application Info
tags: tags:
- Base - Base
@ -1763,10 +1687,6 @@ paths:
required: true required: true
schema: schema:
$ref: '#/definitions/v1.LoginForm' $ref: '#/definitions/v1.LoginForm'
- description: auth provider
in: query
name: provider
type: string
produces: produces:
- application/json - application/json
responses: responses:

View file

@ -1,77 +1,77 @@
module github.com/hay-kot/homebox/backend module github.com/hay-kot/homebox/backend
go 1.23.0 go 1.20
toolchain go1.24.2
require ( require (
ariga.io/atlas v0.32.0 ariga.io/atlas v0.12.0
entgo.io/ent v0.14.4 entgo.io/ent v0.12.3
github.com/ardanlabs/conf/v3 v3.7.1 github.com/ardanlabs/conf/v3 v3.1.6
github.com/containrrr/shoutrrr v0.8.0 github.com/containrrr/shoutrrr v0.7.1
github.com/go-chi/chi/v5 v5.2.1 github.com/go-chi/chi/v5 v5.0.10
github.com/go-playground/validator/v10 v10.26.0 github.com/go-playground/validator/v10 v10.14.1
github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d
github.com/google/uuid v1.6.0 github.com/google/uuid v1.3.0
github.com/gorilla/schema v1.4.1 github.com/gorilla/schema v1.2.0
github.com/hay-kot/httpkit v0.0.11 github.com/hay-kot/httpkit v0.0.3
github.com/mattn/go-sqlite3 v1.14.27 github.com/mattn/go-sqlite3 v1.14.17
github.com/olahol/melody v1.2.1 github.com/olahol/melody v1.1.4
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/rs/zerolog v1.34.0 github.com/rs/zerolog v1.29.1
github.com/stretchr/testify v1.10.0 github.com/stretchr/testify v1.8.4
github.com/swaggo/http-swagger/v2 v2.0.2 github.com/swaggo/http-swagger v1.3.4
github.com/swaggo/swag v1.16.4 github.com/swaggo/swag v1.16.1
github.com/yeqown/go-qrcode/v2 v2.2.5 github.com/yeqown/go-qrcode/v2 v2.2.2
github.com/yeqown/go-qrcode/writer/standard v1.2.5 github.com/yeqown/go-qrcode/writer/standard v1.2.1
golang.org/x/crypto v0.37.0 golang.org/x/crypto v0.11.0
modernc.org/sqlite v1.37.0 modernc.org/sqlite v1.24.0
) )
require ( require (
github.com/KyleBanks/depth v1.2.1 // indirect github.com/KyleBanks/depth v1.2.1 // indirect
github.com/agext/levenshtein v1.2.3 // indirect github.com/agext/levenshtein v1.2.3 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
github.com/bmatcuk/doublestar v1.3.4 // 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/dustin/go-humanize v1.0.1 // indirect
github.com/fatih/color v1.18.0 // indirect github.com/fatih/color v1.15.0 // indirect
github.com/fogleman/gg v1.3.0 // indirect github.com/fogleman/gg v1.3.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/go-openapi/inflect v0.21.2 // indirect github.com/go-openapi/inflect v0.19.0 // indirect
github.com/go-openapi/jsonpointer v0.21.1 // indirect github.com/go-openapi/jsonpointer v0.20.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/spec v0.21.0 // indirect github.com/go-openapi/spec v0.20.9 // indirect
github.com/go-openapi/swag v0.23.1 // indirect github.com/go-openapi/swag v0.22.4 // indirect
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-cmp v0.5.9 // indirect
github.com/gorilla/websocket v1.5.3 // indirect github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/hcl/v2 v2.23.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.4.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/mailru/easyjson v0.9.0 // indirect github.com/leodido/go-urn v1.2.4 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-colorable v0.1.13 // 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/ncruces/go-strftime v0.1.9 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/swaggo/files/v2 v2.0.2 // indirect github.com/swaggo/files v1.0.1 // indirect
github.com/yeqown/reedsolomon v1.0.0 // indirect github.com/yeqown/reedsolomon v1.0.0 // indirect
github.com/zclconf/go-cty v1.16.2 // indirect github.com/zclconf/go-cty v1.13.2 // indirect
github.com/zclconf/go-cty-yaml v1.1.0 // indirect golang.org/x/image v0.9.0 // indirect
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect golang.org/x/mod v0.12.0 // indirect
golang.org/x/image v0.26.0 // indirect golang.org/x/net v0.12.0 // indirect
golang.org/x/mod v0.24.0 // indirect golang.org/x/sys v0.10.0 // indirect
golang.org/x/net v0.39.0 // indirect golang.org/x/text v0.11.0 // indirect
golang.org/x/sync v0.13.0 // indirect golang.org/x/tools v0.11.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/text v0.24.0 // indirect
golang.org/x/tools v0.32.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/libc v1.62.1 // indirect lukechampine.com/uint128 v1.3.0 // indirect
modernc.org/mathutil v1.7.1 // indirect modernc.org/cc/v3 v3.41.0 // indirect
modernc.org/memory v1.9.1 // 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
) )

File diff suppressed because it is too large Load diff

View file

@ -1,104 +0,0 @@
// Package currencies provides a shared definition of currencies. This uses a global
// variable to hold the currencies.
package currencies
import (
"bytes"
_ "embed"
"encoding/json"
"io"
"slices"
"strings"
"sync"
)
//go:embed currencies.json
var defaults []byte
type CollectorFunc func() ([]Currency, error)
func CollectJSON(reader io.Reader) CollectorFunc {
return func() ([]Currency, error) {
var currencies []Currency
err := json.NewDecoder(reader).Decode(&currencies)
if err != nil {
return nil, err
}
return currencies, nil
}
}
func CollectDefaults() CollectorFunc {
return CollectJSON(bytes.NewReader(defaults))
}
func CollectionCurrencies(collectors ...CollectorFunc) ([]Currency, error) {
out := make([]Currency, 0, len(collectors))
for i := range collectors {
c, err := collectors[i]()
if err != nil {
return nil, err
}
out = append(out, c...)
}
return out, nil
}
type Currency struct {
Name string `json:"name"`
Code string `json:"code"`
Local string `json:"local"`
Symbol string `json:"symbol"`
}
type CurrencyRegistry struct {
mu sync.RWMutex
registry map[string]Currency
}
func NewCurrencyService(currencies []Currency) *CurrencyRegistry {
registry := make(map[string]Currency, len(currencies))
for i := range currencies {
registry[currencies[i].Code] = currencies[i]
}
return &CurrencyRegistry{
registry: registry,
}
}
func (cs *CurrencyRegistry) Slice() []Currency {
cs.mu.RLock()
defer cs.mu.RUnlock()
out := make([]Currency, 0, len(cs.registry))
for key := range cs.registry {
out = append(out, cs.registry[key])
}
slices.SortFunc(out, func(a, b Currency) int {
if a.Name < b.Name {
return -1
}
if a.Name > b.Name {
return 1
}
return 0
})
return out
}
func (cs *CurrencyRegistry) IsSupported(code string) bool {
upper := strings.ToUpper(code)
cs.mu.RLock()
defer cs.mu.RUnlock()
_, ok := cs.registry[upper]
return ok
}

View file

@ -1,638 +0,0 @@
[
{
"code": "USD",
"local": "United States",
"symbol": "$",
"name": "United States Dollar"
},
{
"code": "AED",
"local": "United Arab Emirates",
"symbol": "د.إ",
"name": "United Arab Emirates Dirham"
},
{
"code": "AFN",
"local": "Afghanistan",
"symbol": "؋",
"name": "Afghan Afghani"
},
{
"code": "ALL",
"local": "Albania",
"symbol": "L",
"name": "Albanian Lek"
},
{
"code": "AMD",
"local": "Armenia",
"symbol": "֏",
"name": "Armenian Dram"
},
{
"code": "ANG",
"local": "Netherlands Antilles",
"symbol": "ƒ",
"name": "Netherlands Antillean Guilder"
},
{
"code": "AOA",
"local": "Angola",
"symbol": "Kz",
"name": "Angolan Kwanza"
},
{
"code": "ARS",
"local": "Argentina",
"symbol": "$",
"name": "Argentine Peso"
},
{
"code": "AUD",
"local": "Australia",
"symbol": "A$",
"name": "Australian Dollar"
},
{
"code": "AWG",
"local": "Aruba",
"symbol": "ƒ",
"name": "Aruban Florin"
},
{
"code": "AZN",
"local": "Azerbaijan",
"symbol": "₼",
"name": "Azerbaijani Manat"
},
{
"code": "BAM",
"local": "Bosnia and Herzegovina",
"symbol": "KM",
"name": "Bosnia and Herzegovina Convertible Mark"
},
{
"code": "BBD",
"local": "Barbados",
"symbol": "Bds$",
"name": "Barbadian Dollar"
},
{
"code": "BDT",
"local": "Bangladesh",
"symbol": "৳",
"name": "Bangladeshi Taka"
},
{
"code": "BGN",
"local": "Bulgaria",
"symbol": "лв",
"name": "Bulgarian lev"
},
{
"code": "BHD",
"local": "Bahrain",
"symbol": "ب.د",
"name": "Bahraini Dinar"
},
{
"code": "BIF",
"local": "Burundi",
"symbol": "FBu",
"name": "Burundian Franc"
},
{
"code": "BMD",
"local": "Bermuda",
"symbol": "BD$",
"name": "Bermudian Dollar"
},
{
"code": "BND",
"local": "Brunei",
"symbol": "B$",
"name": "Brunei Dollar"
},
{
"code": "BOB",
"local": "Bolivia",
"symbol": "Bs.",
"name": "Bolivian Boliviano"
},
{
"code": "BRL",
"local": "Brazil",
"symbol": "R$",
"name": "Brazilian Real"
},
{
"code": "BSD",
"local": "Bahamas",
"symbol": "B$",
"name": "Bahamian Dollar"
},
{
"code": "BTN",
"local": "Bhutan",
"symbol": "Nu.",
"name": "Bhutanese Ngultrum"
},
{
"code": "BWP",
"local": "Botswana",
"symbol": "P",
"name": "Botswana Pula"
},
{
"code": "BYN",
"local": "Belarus",
"symbol": "Br",
"name": "Belarusian Ruble"
},
{
"code": "BZD",
"local": "Belize",
"symbol": "BZ$",
"name": "Belize Dollar"
},
{
"code": "CAD",
"local": "Canada",
"symbol": "C$",
"name": "Canadian Dollar"
},
{
"code": "CDF",
"local": "Democratic Republic of the Congo",
"symbol": "FC",
"name": "Congolese Franc"
},
{
"code": "CHF",
"local": "Switzerland",
"symbol": "CHF",
"name": "Swiss Franc"
},
{
"code": "CLP",
"local": "Chile",
"symbol": "CL$",
"name": "Chilean Peso"
},
{
"code": "CNY",
"local": "China",
"symbol": "¥",
"name": "Chinese Yuan"
},
{
"code": "COP",
"local": "Colombia",
"symbol": "COL$",
"name": "Colombian Peso"
},
{
"code": "CRC",
"local": "Costa Rica",
"symbol": "₡",
"name": "Costa Rican Colón"
},
{
"code": "CUP",
"local": "Cuba",
"symbol": "₱",
"name": "Cuban Peso"
},
{
"code": "CVE",
"local": "Cape Verde",
"symbol": "$",
"name": "Cape Verdean Escudo"
},
{
"code": "CZK",
"local": "Czech Republic",
"symbol": "Kč",
"name": "Czech Koruna"
},
{
"code": "DJF",
"local": "Djibouti",
"symbol": "Fdj",
"name": "Djiboutian Franc"
},
{
"code": "DKK",
"local": "Denmark",
"symbol": "kr",
"name": "Danish Krone"
},
{
"code": "DOP",
"local": "Dominican Republic",
"symbol": "RD$",
"name": "Dominican Peso"
},
{
"code": "DZD",
"local": "Algeria",
"symbol": "د.ج",
"name": "Algerian Dinar"
},
{
"code": "EGP",
"local": "Egypt",
"symbol": "£",
"name": "Egyptian Pound"
},
{
"code": "ERN",
"local": "Eritrea",
"symbol": "Nfk",
"name": "Eritrean Nakfa"
},
{
"code": "ETB",
"local": "Ethiopia",
"symbol": "Br",
"name": "Ethiopian Birr"
},
{
"code": "EUR",
"local": "Eurozone",
"symbol": "€",
"name": "Euro"
},
{
"code": "FJD",
"local": "Fiji",
"symbol": "FJ$",
"name": "Fijian Dollar"
},
{
"code": "FKP",
"local": "Falkland Islands",
"symbol": "£",
"name": "Falkland Islands Pound"
},
{
"code": "FOK",
"local": "Faroe Islands",
"symbol": "kr",
"name": "Faroese Króna"
},
{
"code": "GBP",
"local": "United Kingdom",
"symbol": "£",
"name": "British Pound Sterling"
},
{
"code": "GEL",
"local": "Georgia",
"symbol": "₾",
"name": "Georgian Lari"
},
{
"code": "GGP",
"local": "Guernsey",
"symbol": "£",
"name": "Guernsey Pound"
},
{
"code": "GHS",
"local": "Ghana",
"symbol": "GH₵",
"name": "Ghanaian Cedi"
},
{
"code": "GIP",
"local": "Gibraltar",
"symbol": "£",
"name": "Gibraltar Pound"
},
{
"code": "GMD",
"local": "Gambia",
"symbol": "D",
"name": "Gambian Dalasi"
},
{
"code": "GNF",
"local": "Guinea",
"symbol": "FG",
"name": "Guinean Franc"
},
{
"code": "GTQ",
"local": "Guatemala",
"symbol": "Q",
"name": "Guatemalan Quetzal"
},
{
"code": "GYD",
"local": "Guyana",
"symbol": "GY$",
"name": "Guyanese Dollar"
},
{
"code": "HKD",
"local": "Hong Kong",
"symbol": "HK$",
"name": "Hong Kong Dollar"
},
{
"code": "HNL",
"local": "Honduras",
"symbol": "L",
"name": "Honduran Lempira"
},
{
"code": "HRK",
"local": "Croatia",
"symbol": "kn",
"name": "Croatian Kuna"
},
{
"code": "HTG",
"local": "Haiti",
"symbol": "G",
"name": "Haitian Gourde"
},
{
"code": "HUF",
"local": "Hungary",
"symbol": "Ft",
"name": "Hungarian Forint"
},
{
"code": "IDR",
"local": "Indonesia",
"symbol": "Rp",
"name": "Indonesian Rupiah"
},
{
"code": "ILS",
"local": "Israel",
"symbol": "₪",
"name": "Israeli New Shekel"
},
{
"code": "IMP",
"local": "Isle of Man",
"symbol": "£",
"name": "Manx Pound"
},
{
"code": "INR",
"local": "India",
"symbol": "₹",
"name": "Indian Rupee"
},
{
"code": "IQD",
"local": "Iraq",
"symbol": "ع.د",
"name": "Iraqi Dinar"
},
{
"code": "IRR",
"local": "Iran",
"symbol": "﷼",
"name": "Iranian Rial"
},
{
"code": "ISK",
"local": "Iceland",
"symbol": "kr",
"name": "Icelandic Króna"
},
{
"code": "JEP",
"local": "Jersey",
"symbol": "£",
"name": "Jersey Pound"
},
{
"code": "JMD",
"local": "Jamaica",
"symbol": "J$",
"name": "Jamaican Dollar"
},
{
"code": "JOD",
"local": "Jordan",
"symbol": "د.ا",
"name": "Jordanian Dinar"
},
{
"code": "JPY",
"local": "Japan",
"symbol": "¥",
"name": "Japanese Yen"
},
{
"code": "KES",
"local": "Kenya",
"symbol": "KSh",
"name": "Kenyan Shilling"
},
{
"code": "KGS",
"local": "Kyrgyzstan",
"symbol": "с",
"name": "Kyrgyzstani Som"
},
{
"code": "KHR",
"local": "Cambodia",
"symbol": "៛",
"name": "Cambodian Riel"
},
{
"code": "KID",
"local": "Kiribati",
"symbol": "$",
"name": "Kiribati Dollar"
},
{
"code": "KMF",
"local": "Comoros",
"symbol": "CF",
"name": "Comorian Franc"
},
{
"code": "KRW",
"local": "South Korea",
"symbol": "₩",
"name": "South Korean Won"
},
{
"code": "KWD",
"local": "Kuwait",
"symbol": "د.ك",
"name": "Kuwaiti Dinar"
},
{
"code": "KYD",
"local": "Cayman Islands",
"symbol": "CI$",
"name": "Cayman Islands Dollar"
},
{
"code": "KZT",
"local": "Kazakhstan",
"symbol": "₸",
"name": "Kazakhstani Tenge"
},
{
"code": "LAK",
"local": "Laos",
"symbol": "₭",
"name": "Lao Kip"
},
{
"code": "LBP",
"local": "Lebanon",
"symbol": "ل.ل",
"name": "Lebanese Pound"
},
{
"code": "LKR",
"local": "Sri Lanka",
"symbol": "₨",
"name": "Sri Lankan Rupee"
},
{
"code": "LRD",
"local": "Liberia",
"symbol": "L$",
"name": "Liberian Dollar"
},
{
"code": "LSL",
"local": "Lesotho",
"symbol": "M",
"name": "Lesotho Loti"
},
{
"code": "LYD",
"local": "Libya",
"symbol": "ل.د",
"name": "Libyan Dinar"
},
{
"code": "MAD",
"local": "Morocco",
"symbol": "د.م.",
"name": "Moroccan Dirham"
},
{
"code": "MDL",
"local": "Moldova",
"symbol": "lei",
"name": "Moldovan Leu"
},
{
"code": "MGA",
"local": "Madagascar",
"symbol": "Ar",
"name": "Malagasy Ariary"
},
{
"code": "MKD",
"local": "North Macedonia",
"symbol": "ден",
"name": "Macedonian Denar"
},
{
"code": "MMK",
"local": "Myanmar",
"symbol": "K",
"name": "Myanmar Kyat"
},
{
"code": "MNT",
"local": "Mongolia",
"symbol": "₮",
"name": "Mongolian Tugrik"
},
{
"code": "MOP",
"local": "Macau",
"symbol": "MOP$",
"name": "Macanese Pataca"
},
{
"code": "MRU",
"local": "Mauritania",
"symbol": "UM",
"name": "Mauritanian Ouguiya"
},
{
"code": "MUR",
"local": "Mauritius",
"symbol": "₨",
"name": "Mauritian Rupee"
},
{
"code": "MVR",
"local": "Maldives",
"symbol": "Rf",
"name": "Maldivian Rufiyaa"
},
{
"code": "MWK",
"local": "Malawi",
"symbol": "MK",
"name": "Malawian Kwacha"
},
{
"code": "MXN",
"local": "Mexico",
"symbol": "Mex$",
"name": "Mexican Peso"
},
{
"code": "MYR",
"local": "Malaysia",
"symbol": "RM",
"name": "Malaysian Ringgit"
},
{
"code": "MZN",
"local": "Mozambique",
"symbol": "MT",
"name": "Mozambican Metical"
},
{
"code": "NAD",
"local": "Namibia",
"symbol": "N$",
"name": "Namibian Dollar"
},
{
"code": "NGN",
"local": "Nigeria",
"symbol": "₦",
"name": "Nigerian Naira"
},
{
"code": "NIO",
"local": "Nicaragua",
"symbol": "C$",
"name": "Nicaraguan Córdoba"
},
{
"code": "NOK",
"local": "Norway",
"symbol": "kr",
"name": "Norwegian Krone"
},
{
"code": "UAH",
"local": "Ukraine",
"symbol": "₴",
"name": "Ukrainian Hryvnia"
}
]

View file

@ -1,8 +1,6 @@
// Package services provides the core business logic for the application.
package services package services
import ( import (
"github.com/hay-kot/homebox/backend/internal/core/currencies"
"github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/data/repo"
) )
@ -11,14 +9,12 @@ type AllServices struct {
Group *GroupService Group *GroupService
Items *ItemService Items *ItemService
BackgroundService *BackgroundService BackgroundService *BackgroundService
Currencies *currencies.CurrencyRegistry
} }
type OptionsFunc func(*options) type OptionsFunc func(*options)
type options struct { type options struct {
autoIncrementAssetID bool autoIncrementAssetID bool
currencies []currencies.Currency
} }
func WithAutoIncrementAssetID(v bool) func(*options) { func WithAutoIncrementAssetID(v bool) func(*options) {
@ -27,27 +23,13 @@ func WithAutoIncrementAssetID(v bool) func(*options) {
} }
} }
func WithCurrencies(v []currencies.Currency) func(*options) {
return func(o *options) {
o.currencies = v
}
}
func New(repos *repo.AllRepos, opts ...OptionsFunc) *AllServices { func New(repos *repo.AllRepos, opts ...OptionsFunc) *AllServices {
if repos == nil { if repos == nil {
panic("repos cannot be nil") panic("repos cannot be nil")
} }
defaultCurrencies, err := currencies.CollectionCurrencies(
currencies.CollectDefaults(),
)
if err != nil {
panic("failed to collect default currencies")
}
options := &options{ options := &options{
autoIncrementAssetID: true, autoIncrementAssetID: true,
currencies: defaultCurrencies,
} }
for _, opt := range opts { for _, opt := range opts {
@ -62,6 +44,5 @@ func New(repos *repo.AllRepos, opts ...OptionsFunc) *AllServices {
autoIncrementAssetID: options.autoIncrementAssetID, autoIncrementAssetID: options.autoIncrementAssetID,
}, },
BackgroundService: &BackgroundService{repos}, BackgroundService: &BackgroundService{repos},
Currencies: currencies.NewCurrencyService(options.currencies),
} }
} }

View file

@ -6,7 +6,6 @@ import (
"os" "os"
"testing" "testing"
"github.com/hay-kot/homebox/backend/internal/core/currencies"
"github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus" "github.com/hay-kot/homebox/backend/internal/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"
@ -62,13 +61,8 @@ func TestMain(m *testing.M) {
tClient = client tClient = client
tRepos = repo.New(tClient, tbus, os.TempDir()+"/homebox") tRepos = repo.New(tClient, tbus, os.TempDir()+"/homebox")
tSvc = New(tRepos)
defaults, _ := currencies.CollectionCurrencies( defer client.Close()
currencies.CollectDefaults(),
)
tSvc = New(tRepos, WithCurrencies(defaults))
defer func() { _ = client.Close() }()
bootstrap() bootstrap()
tCtx = Context{ tCtx = Context{

View file

@ -1,8 +1,7 @@
// Package eventbus provides an interface for event bus. // / Package eventbus provides an interface for event bus.
package eventbus package eventbus
import ( import (
"context"
"sync" "sync"
"github.com/google/uuid" "github.com/google/uuid"
@ -35,38 +34,33 @@ type EventBus struct {
func New() *EventBus { func New() *EventBus {
return &EventBus{ return &EventBus{
ch: make(chan eventData, 100), ch: make(chan eventData, 10),
subscribers: map[Event][]func(any){ subscribers: map[Event][]func(any){
EventLabelMutation: {}, EventLabelMutation: {},
EventLocationMutation: {}, EventLocationMutation: {},
EventItemMutation: {}, EventItemMutation: {},
}, },
} }
} }
func (e *EventBus) Run(ctx context.Context) error { func (e *EventBus) Run() {
if e.started { if e.started {
panic("event bus already started") panic("event bus already started")
} }
e.started = true e.started = true
for { for event := range e.ch {
select { e.mu.RLock()
case <-ctx.Done(): arr, ok := e.subscribers[event.event]
return nil e.mu.RUnlock()
case event := <-e.ch:
e.mu.RLock()
arr, ok := e.subscribers[event.event]
e.mu.RUnlock()
if !ok { if !ok {
continue continue
} }
for _, fn := range arr { for _, fn := range arr {
fn(event.data) fn(event.data)
}
} }
} }
} }

View file

@ -1,4 +1,3 @@
// Package reporting provides a way to import CSV files into the database.
package reporting package reporting
import ( import (

View file

@ -84,7 +84,7 @@ func (csf LocationString) String() string {
return strings.Join(csf, " / ") return strings.Join(csf, " / ")
} }
func fromPathSlice(s []repo.ItemPath) LocationString { func fromPathSlice(s []repo.LocationPath) LocationString {
v := make(LocationString, len(s)) v := make(LocationString, len(s))
for i := range s { for i := range s {

View file

@ -152,7 +152,7 @@ func (s *IOSheet) Read(data io.Reader) error {
return nil return nil
} }
// ReadItems writes the sheet to a writer. // Write writes the sheet to a writer.
func (s *IOSheet) ReadItems(ctx context.Context, items []repo.ItemOut, GID uuid.UUID, repos *repo.AllRepos) error { func (s *IOSheet) ReadItems(ctx context.Context, items []repo.ItemOut, GID uuid.UUID, repos *repo.AllRepos) error {
s.Rows = make([]ExportTSVRow, len(items)) s.Rows = make([]ExportTSVRow, len(items))
@ -162,9 +162,9 @@ func (s *IOSheet) ReadItems(ctx context.Context, items []repo.ItemOut, GID uuid.
item := items[i] item := items[i]
// TODO: Support fetching nested locations // TODO: Support fetching nested locations
locID := item.Location.ID locId := item.Location.ID
locPaths, err := repos.Locations.PathForLoc(context.Background(), GID, locID) locPaths, err := repos.Locations.PathForLoc(context.Background(), GID, locId)
if err != nil { if err != nil {
log.Error().Err(err).Msg("could not get location path") log.Error().Err(err).Msg("could not get location path")
return err return err
@ -252,7 +252,7 @@ func (s *IOSheet) ReadItems(ctx context.Context, items []repo.ItemOut, GID uuid.
return nil return nil
} }
// TSV writes the current sheet to a writer in TSV format. // Writes the current sheet to a writer in TSV format.
func (s *IOSheet) TSV() ([][]string, error) { func (s *IOSheet) TSV() ([][]string, error) {
memcsv := make([][]string, len(s.Rows)+1) memcsv := make([][]string, len(s.Rows)+1)

View file

@ -9,7 +9,6 @@ import (
"github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/data/repo"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
var ( var (
@ -104,9 +103,9 @@ func TestSheet_Read(t *testing.T) {
switch { switch {
case tt.wantErr: case tt.wantErr:
require.Error(t, err) assert.Error(t, err)
default: default:
require.NoError(t, err) assert.NoError(t, err)
assert.ElementsMatch(t, tt.want, sheet.Rows) assert.ElementsMatch(t, tt.want, sheet.Rows)
} }
}) })

View file

@ -32,7 +32,7 @@ func (svc *ItemService) Create(ctx Context, item repo.ItemCreate) (repo.ItemOut,
return repo.ItemOut{}, err return repo.ItemOut{}, err
} }
item.AssetID = highest + 1 item.AssetID = repo.AssetID(highest + 1)
} }
return svc.repo.Items.Create(ctx, ctx.GID, item) return svc.repo.Items.Create(ctx, ctx.GID, item)
@ -53,7 +53,7 @@ func (svc *ItemService) EnsureAssetID(ctx context.Context, GID uuid.UUID) (int,
for _, item := range items { for _, item := range items {
highest++ highest++
err = svc.repo.Items.SetAssetID(ctx, GID, item.ID, highest) err = svc.repo.Items.SetAssetID(ctx, GID, item.ID, repo.AssetID(highest))
if err != nil { if err != nil {
return 0, err return 0, err
} }

View file

@ -12,8 +12,8 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
func (svc *ItemService) AttachmentPath(ctx context.Context, attachmentID uuid.UUID) (*ent.Document, error) { func (svc *ItemService) AttachmentPath(ctx context.Context, attachmentId uuid.UUID) (*ent.Document, error) {
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
} }
@ -21,9 +21,9 @@ func (svc *ItemService) AttachmentPath(ctx context.Context, attachmentID uuid.UU
return attachment.Edges.Document, nil return attachment.Edges.Document, nil
} }
func (svc *ItemService) AttachmentUpdate(ctx Context, itemID uuid.UUID, data *repo.ItemAttachmentUpdate) (repo.ItemOut, error) { func (svc *ItemService) AttachmentUpdate(ctx Context, itemId uuid.UUID, data *repo.ItemAttachmentUpdate) (repo.ItemOut, error) {
// Update Attachment // Update Attachment
attachment, err := svc.repo.Attachments.Update(ctx, data.ID, data) attachment, err := svc.repo.Attachments.Update(ctx, data.ID, attachment.Type(data.Type))
if err != nil { if err != nil {
return repo.ItemOut{}, err return repo.ItemOut{}, err
} }
@ -35,15 +35,15 @@ func (svc *ItemService) AttachmentUpdate(ctx Context, itemID uuid.UUID, data *re
return repo.ItemOut{}, err return repo.ItemOut{}, err
} }
return svc.repo.Items.GetOneByGroup(ctx, ctx.GID, itemID) return svc.repo.Items.GetOneByGroup(ctx, ctx.GID, itemId)
} }
// AttachmentAdd adds an attachment to an item by creating an entry in the Documents table and linking it to the Attachment // AttachmentAdd adds an attachment to an item by creating an entry in the Documents table and linking it to the Attachment
// Table and Items table. The file provided via the reader is stored on the file system based on the provided // Table and Items table. The file provided via the reader is stored on the file system based on the provided
// relative path during construction of the service. // relative path during construction of the service.
func (svc *ItemService) AttachmentAdd(ctx Context, itemID uuid.UUID, filename string, attachmentType attachment.Type, file io.Reader) (repo.ItemOut, error) { func (svc *ItemService) AttachmentAdd(ctx Context, itemId uuid.UUID, filename string, attachmentType attachment.Type, file io.Reader) (repo.ItemOut, error) {
// Get the Item // Get the Item
_, err := svc.repo.Items.GetOneByGroup(ctx, ctx.GID, itemID) _, err := svc.repo.Items.GetOneByGroup(ctx, ctx.GID, itemId)
if err != nil { if err != nil {
return repo.ItemOut{}, err return repo.ItemOut{}, err
} }
@ -56,29 +56,29 @@ func (svc *ItemService) AttachmentAdd(ctx Context, itemID uuid.UUID, filename st
} }
// Create the attachment // Create the attachment
_, err = svc.repo.Attachments.Create(ctx, itemID, doc.ID, attachmentType) _, err = svc.repo.Attachments.Create(ctx, itemId, doc.ID, attachmentType)
if err != nil { if err != nil {
log.Err(err).Msg("failed to create attachment") log.Err(err).Msg("failed to create attachment")
return repo.ItemOut{}, err return repo.ItemOut{}, err
} }
return svc.repo.Items.GetOneByGroup(ctx, ctx.GID, itemID) return svc.repo.Items.GetOneByGroup(ctx, ctx.GID, itemId)
} }
func (svc *ItemService) AttachmentDelete(ctx context.Context, gid, itemID, attachmentID uuid.UUID) error { func (svc *ItemService) AttachmentDelete(ctx context.Context, gid, itemId, attachmentId uuid.UUID) error {
// Get the Item // Get the Item
_, err := svc.repo.Items.GetOneByGroup(ctx, gid, itemID) _, err := svc.repo.Items.GetOneByGroup(ctx, gid, itemId)
if err != nil { if err != nil {
return err return err
} }
attachment, err := svc.repo.Attachments.Get(ctx, attachmentID) attachment, err := svc.repo.Attachments.Get(ctx, attachmentId)
if err != nil { if err != nil {
return err return err
} }
// Delete the attachment // Delete the attachment
err = svc.repo.Attachments.Delete(ctx, attachmentID) err = svc.repo.Attachments.Delete(ctx, attachmentId)
if err != nil { if err != nil {
return err return err
} }

View file

@ -9,7 +9,6 @@ import (
"github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/data/repo"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestItemService_AddAttachment(t *testing.T) { func TestItemService_AddAttachment(t *testing.T) {
@ -24,7 +23,7 @@ func TestItemService_AddAttachment(t *testing.T) {
Description: "test", Description: "test",
Name: "test", Name: "test",
}) })
require.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, loc) assert.NotNil(t, loc)
itmC := repo.ItemCreate{ itmC := repo.ItemCreate{
@ -34,11 +33,11 @@ func TestItemService_AddAttachment(t *testing.T) {
} }
itm, err := svc.repo.Items.Create(context.Background(), tGroup.ID, itmC) itm, err := svc.repo.Items.Create(context.Background(), tGroup.ID, itmC)
require.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, itm) assert.NotNil(t, itm)
t.Cleanup(func() { t.Cleanup(func() {
err := svc.repo.Items.Delete(context.Background(), itm.ID) err := svc.repo.Items.Delete(context.Background(), itm.ID)
require.NoError(t, err) assert.NoError(t, err)
}) })
contents := fk.Str(1000) contents := fk.Str(1000)
@ -46,7 +45,7 @@ func TestItemService_AddAttachment(t *testing.T) {
// Setup // Setup
afterAttachment, err := svc.AttachmentAdd(tCtx, itm.ID, "testfile.txt", "attachment", reader) afterAttachment, err := svc.AttachmentAdd(tCtx, itm.ID, "testfile.txt", "attachment", reader)
require.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, afterAttachment) assert.NotNil(t, afterAttachment)
// Check that the file exists // Check that the file exists
@ -57,6 +56,6 @@ func TestItemService_AddAttachment(t *testing.T) {
// Check that the file contents are correct // Check that the file contents are correct
bts, err := os.ReadFile(storedPath) bts, err := os.ReadFile(storedPath)
require.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, contents, string(bts)) assert.Equal(t, contents, string(bts))
} }

View file

@ -16,7 +16,7 @@ var (
oneWeek = time.Hour * 24 * 7 oneWeek = time.Hour * 24 * 7
ErrorInvalidLogin = errors.New("invalid username or password") ErrorInvalidLogin = errors.New("invalid username or password")
ErrorInvalidToken = errors.New("invalid token") ErrorInvalidToken = errors.New("invalid token")
ErrorTokenIDMismatch = errors.New("token id mismatch") ErrorTokenIdMismatch = errors.New("token id mismatch")
) )
type UserService struct { type UserService struct {
@ -92,11 +92,9 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
if err != nil { if err != nil {
return repo.UserOut{}, err return repo.UserOut{}, err
} }
log.Debug().Msg("user created")
// Create the default labels and locations for the group. // Create the default labels and locations for the group.
if creatingGroup { if creatingGroup {
log.Debug().Msg("creating default labels")
for _, label := range defaultLabels() { for _, label := range defaultLabels() {
_, err := svc.repos.Labels.Create(ctx, usr.GroupID, label) _, err := svc.repos.Labels.Create(ctx, usr.GroupID, label)
if err != nil { if err != nil {
@ -104,7 +102,6 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
} }
} }
log.Debug().Msg("creating default locations")
for _, location := range defaultLocations() { for _, location := range defaultLocations() {
_, err := svc.repos.Locations.Create(ctx, usr.GroupID, location) _, err := svc.repos.Locations.Create(ctx, usr.GroupID, location)
if err != nil { if err != nil {
@ -115,7 +112,6 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
// Decrement the invitation token if it was used. // Decrement the invitation token if it was used.
if token.ID != uuid.Nil { if token.ID != uuid.Nil {
log.Debug().Msg("decrementing invitation token")
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 {
log.Err(err).Msg("Failed to update invitation token") log.Err(err).Msg("Failed to update invitation token")
@ -138,13 +134,13 @@ func (svc *UserService) UpdateSelf(ctx context.Context, ID uuid.UUID, data repo.
return repo.UserOut{}, err return repo.UserOut{}, err
} }
return svc.repos.Users.GetOneID(ctx, ID) return svc.repos.Users.GetOneId(ctx, ID)
} }
// ============================================================================ // ============================================================================
// User Authentication // User Authentication
func (svc *UserService) createSessionToken(ctx context.Context, userID uuid.UUID, extendedSession bool) (UserAuthTokenDetail, error) { func (svc *UserService) createSessionToken(ctx context.Context, userId uuid.UUID, extendedSession bool) (UserAuthTokenDetail, error) {
attachmentToken := hasher.GenerateToken() attachmentToken := hasher.GenerateToken()
expiresAt := time.Now().Add(oneWeek) expiresAt := time.Now().Add(oneWeek)
@ -153,7 +149,7 @@ func (svc *UserService) createSessionToken(ctx context.Context, userID uuid.UUID
} }
attachmentData := repo.UserAuthTokenCreate{ attachmentData := repo.UserAuthTokenCreate{
UserID: userID, UserID: userId,
TokenHash: attachmentToken.Hash, TokenHash: attachmentToken.Hash,
ExpiresAt: expiresAt, ExpiresAt: expiresAt,
} }
@ -165,7 +161,7 @@ func (svc *UserService) createSessionToken(ctx context.Context, userID uuid.UUID
userToken := hasher.GenerateToken() userToken := hasher.GenerateToken()
data := repo.UserAuthTokenCreate{ data := repo.UserAuthTokenCreate{
UserID: userID, UserID: userId,
TokenHash: userToken.Hash, TokenHash: userToken.Hash,
ExpiresAt: expiresAt, ExpiresAt: expiresAt,
} }
@ -222,7 +218,7 @@ func (svc *UserService) DeleteSelf(ctx context.Context, ID uuid.UUID) error {
} }
func (svc *UserService) ChangePassword(ctx Context, current string, new string) (ok bool) { func (svc *UserService) ChangePassword(ctx Context, current string, new string) (ok bool) {
usr, err := svc.repos.Users.GetOneID(ctx, ctx.UID) usr, err := svc.repos.Users.GetOneId(ctx, ctx.UID)
if err != nil { if err != nil {
return false return false
} }

View file

@ -26,8 +26,6 @@ type Attachment struct {
UpdatedAt time.Time `json:"updated_at,omitempty"` UpdatedAt time.Time `json:"updated_at,omitempty"`
// Type holds the value of the "type" field. // Type holds the value of the "type" field.
Type attachment.Type `json:"type,omitempty"` Type attachment.Type `json:"type,omitempty"`
// Primary holds the value of the "primary" field.
Primary bool `json:"primary,omitempty"`
// Edges holds the relations/edges for other nodes in the graph. // Edges holds the relations/edges for other nodes in the graph.
// The values are being populated by the AttachmentQuery when eager-loading is set. // The values are being populated by the AttachmentQuery when eager-loading is set.
Edges AttachmentEdges `json:"edges"` Edges AttachmentEdges `json:"edges"`
@ -78,8 +76,6 @@ func (*Attachment) scanValues(columns []string) ([]any, error) {
values := make([]any, len(columns)) values := make([]any, len(columns))
for i := range columns { for i := range columns {
switch columns[i] { switch columns[i] {
case attachment.FieldPrimary:
values[i] = new(sql.NullBool)
case attachment.FieldType: case attachment.FieldType:
values[i] = new(sql.NullString) values[i] = new(sql.NullString)
case attachment.FieldCreatedAt, attachment.FieldUpdatedAt: case attachment.FieldCreatedAt, attachment.FieldUpdatedAt:
@ -129,12 +125,6 @@ func (a *Attachment) assignValues(columns []string, values []any) error {
} else if value.Valid { } else if value.Valid {
a.Type = attachment.Type(value.String) a.Type = attachment.Type(value.String)
} }
case attachment.FieldPrimary:
if value, ok := values[i].(*sql.NullBool); !ok {
return fmt.Errorf("unexpected type %T for field primary", values[i])
} else if value.Valid {
a.Primary = value.Bool
}
case attachment.ForeignKeys[0]: case attachment.ForeignKeys[0]:
if value, ok := values[i].(*sql.NullScanner); !ok { if value, ok := values[i].(*sql.NullScanner); !ok {
return fmt.Errorf("unexpected type %T for field document_attachments", values[i]) return fmt.Errorf("unexpected type %T for field document_attachments", values[i])
@ -203,9 +193,6 @@ func (a *Attachment) String() string {
builder.WriteString(", ") builder.WriteString(", ")
builder.WriteString("type=") builder.WriteString("type=")
builder.WriteString(fmt.Sprintf("%v", a.Type)) builder.WriteString(fmt.Sprintf("%v", a.Type))
builder.WriteString(", ")
builder.WriteString("primary=")
builder.WriteString(fmt.Sprintf("%v", a.Primary))
builder.WriteByte(')') builder.WriteByte(')')
return builder.String() return builder.String()
} }

View file

@ -22,8 +22,6 @@ const (
FieldUpdatedAt = "updated_at" FieldUpdatedAt = "updated_at"
// FieldType holds the string denoting the type field in the database. // FieldType holds the string denoting the type field in the database.
FieldType = "type" FieldType = "type"
// FieldPrimary holds the string denoting the primary field in the database.
FieldPrimary = "primary"
// EdgeItem holds the string denoting the item edge name in mutations. // EdgeItem holds the string denoting the item edge name in mutations.
EdgeItem = "item" EdgeItem = "item"
// EdgeDocument holds the string denoting the document edge name in mutations. // EdgeDocument holds the string denoting the document edge name in mutations.
@ -52,7 +50,6 @@ var Columns = []string{
FieldCreatedAt, FieldCreatedAt,
FieldUpdatedAt, FieldUpdatedAt,
FieldType, FieldType,
FieldPrimary,
} }
// ForeignKeys holds the SQL foreign-keys that are owned by the "attachments" // ForeignKeys holds the SQL foreign-keys that are owned by the "attachments"
@ -84,8 +81,6 @@ var (
DefaultUpdatedAt func() time.Time DefaultUpdatedAt func() time.Time
// UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field. // UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field.
UpdateDefaultUpdatedAt func() time.Time UpdateDefaultUpdatedAt func() time.Time
// DefaultPrimary holds the default value on creation for the "primary" field.
DefaultPrimary bool
// DefaultID holds the default value on creation for the "id" field. // DefaultID holds the default value on creation for the "id" field.
DefaultID func() uuid.UUID DefaultID func() uuid.UUID
) )
@ -142,11 +137,6 @@ func ByType(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldType, opts...).ToFunc() return sql.OrderByField(FieldType, opts...).ToFunc()
} }
// ByPrimary orders the results by the primary field.
func ByPrimary(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldPrimary, opts...).ToFunc()
}
// ByItemField orders the results by item field. // ByItemField orders the results by item field.
func ByItemField(field string, opts ...sql.OrderTermOption) OrderOption { func ByItemField(field string, opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) { return func(s *sql.Selector) {

View file

@ -66,11 +66,6 @@ func UpdatedAt(v time.Time) predicate.Attachment {
return predicate.Attachment(sql.FieldEQ(FieldUpdatedAt, v)) return predicate.Attachment(sql.FieldEQ(FieldUpdatedAt, v))
} }
// Primary applies equality check predicate on the "primary" field. It's identical to PrimaryEQ.
func Primary(v bool) predicate.Attachment {
return predicate.Attachment(sql.FieldEQ(FieldPrimary, v))
}
// CreatedAtEQ applies the EQ predicate on the "created_at" field. // 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(sql.FieldEQ(FieldCreatedAt, v)) return predicate.Attachment(sql.FieldEQ(FieldCreatedAt, v))
@ -171,16 +166,6 @@ func TypeNotIn(vs ...Type) predicate.Attachment {
return predicate.Attachment(sql.FieldNotIn(FieldType, vs...)) return predicate.Attachment(sql.FieldNotIn(FieldType, vs...))
} }
// PrimaryEQ applies the EQ predicate on the "primary" field.
func PrimaryEQ(v bool) predicate.Attachment {
return predicate.Attachment(sql.FieldEQ(FieldPrimary, v))
}
// PrimaryNEQ applies the NEQ predicate on the "primary" field.
func PrimaryNEQ(v bool) predicate.Attachment {
return predicate.Attachment(sql.FieldNEQ(FieldPrimary, v))
}
// HasItem applies the HasEdge predicate on the "item" edge. // HasItem applies the HasEdge predicate on the "item" edge.
func HasItem() predicate.Attachment { func HasItem() predicate.Attachment {
return predicate.Attachment(func(s *sql.Selector) { return predicate.Attachment(func(s *sql.Selector) {
@ -229,15 +214,32 @@ func HasDocumentWith(preds ...predicate.Document) predicate.Attachment {
// And groups predicates with the AND operator between them. // And groups predicates with the AND operator between them.
func And(predicates ...predicate.Attachment) predicate.Attachment { func And(predicates ...predicate.Attachment) predicate.Attachment {
return predicate.Attachment(sql.AndPredicates(predicates...)) return predicate.Attachment(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for _, p := range predicates {
p(s1)
}
s.Where(s1.P())
})
} }
// Or groups predicates with the OR operator between them. // Or groups predicates with the OR operator between them.
func Or(predicates ...predicate.Attachment) predicate.Attachment { func Or(predicates ...predicate.Attachment) predicate.Attachment {
return predicate.Attachment(sql.OrPredicates(predicates...)) return predicate.Attachment(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for i, p := range predicates {
if i > 0 {
s1.Or()
}
p(s1)
}
s.Where(s1.P())
})
} }
// Not applies the not operator on the given predicate. // Not applies the not operator on the given predicate.
func Not(p predicate.Attachment) predicate.Attachment { func Not(p predicate.Attachment) predicate.Attachment {
return predicate.Attachment(sql.NotPredicates(p)) return predicate.Attachment(func(s *sql.Selector) {
p(s.Not())
})
} }

View file

@ -65,20 +65,6 @@ func (ac *AttachmentCreate) SetNillableType(a *attachment.Type) *AttachmentCreat
return ac return ac
} }
// SetPrimary sets the "primary" field.
func (ac *AttachmentCreate) SetPrimary(b bool) *AttachmentCreate {
ac.mutation.SetPrimary(b)
return ac
}
// SetNillablePrimary sets the "primary" field if the given value is not nil.
func (ac *AttachmentCreate) SetNillablePrimary(b *bool) *AttachmentCreate {
if b != nil {
ac.SetPrimary(*b)
}
return ac
}
// SetID sets the "id" field. // SetID sets the "id" field.
func (ac *AttachmentCreate) SetID(u uuid.UUID) *AttachmentCreate { func (ac *AttachmentCreate) SetID(u uuid.UUID) *AttachmentCreate {
ac.mutation.SetID(u) ac.mutation.SetID(u)
@ -162,10 +148,6 @@ func (ac *AttachmentCreate) defaults() {
v := attachment.DefaultType v := attachment.DefaultType
ac.mutation.SetType(v) ac.mutation.SetType(v)
} }
if _, ok := ac.mutation.Primary(); !ok {
v := attachment.DefaultPrimary
ac.mutation.SetPrimary(v)
}
if _, ok := ac.mutation.ID(); !ok { if _, ok := ac.mutation.ID(); !ok {
v := attachment.DefaultID() v := attachment.DefaultID()
ac.mutation.SetID(v) ac.mutation.SetID(v)
@ -188,9 +170,6 @@ func (ac *AttachmentCreate) check() error {
return &ValidationError{Name: "type", err: fmt.Errorf(`ent: validator failed for field "Attachment.type": %w`, err)} return &ValidationError{Name: "type", err: fmt.Errorf(`ent: validator failed for field "Attachment.type": %w`, err)}
} }
} }
if _, ok := ac.mutation.Primary(); !ok {
return &ValidationError{Name: "primary", err: errors.New(`ent: missing required field "Attachment.primary"`)}
}
if _, ok := ac.mutation.ItemID(); !ok { if _, ok := ac.mutation.ItemID(); !ok {
return &ValidationError{Name: "item", err: errors.New(`ent: missing required edge "Attachment.item"`)} return &ValidationError{Name: "item", err: errors.New(`ent: missing required edge "Attachment.item"`)}
} }
@ -244,10 +223,6 @@ func (ac *AttachmentCreate) createSpec() (*Attachment, *sqlgraph.CreateSpec) {
_spec.SetField(attachment.FieldType, field.TypeEnum, value) _spec.SetField(attachment.FieldType, field.TypeEnum, value)
_node.Type = value _node.Type = value
} }
if value, ok := ac.mutation.Primary(); ok {
_spec.SetField(attachment.FieldPrimary, field.TypeBool, value)
_node.Primary = value
}
if nodes := ac.mutation.ItemIDs(); len(nodes) > 0 { if nodes := ac.mutation.ItemIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{ edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O, Rel: sqlgraph.M2O,
@ -288,15 +263,11 @@ func (ac *AttachmentCreate) createSpec() (*Attachment, *sqlgraph.CreateSpec) {
// AttachmentCreateBulk is the builder for creating many Attachment entities in bulk. // AttachmentCreateBulk is the builder for creating many Attachment entities in bulk.
type AttachmentCreateBulk struct { type AttachmentCreateBulk struct {
config config
err error
builders []*AttachmentCreate builders []*AttachmentCreate
} }
// Save creates the Attachment entities in the database. // Save creates the Attachment entities in the database.
func (acb *AttachmentCreateBulk) Save(ctx context.Context) ([]*Attachment, error) { func (acb *AttachmentCreateBulk) Save(ctx context.Context) ([]*Attachment, error) {
if acb.err != nil {
return nil, acb.err
}
specs := make([]*sqlgraph.CreateSpec, len(acb.builders)) specs := make([]*sqlgraph.CreateSpec, len(acb.builders))
nodes := make([]*Attachment, len(acb.builders)) nodes := make([]*Attachment, len(acb.builders))
mutators := make([]Mutator, len(acb.builders)) mutators := make([]Mutator, len(acb.builders))

View file

@ -51,20 +51,6 @@ func (au *AttachmentUpdate) SetNillableType(a *attachment.Type) *AttachmentUpdat
return au return au
} }
// SetPrimary sets the "primary" field.
func (au *AttachmentUpdate) SetPrimary(b bool) *AttachmentUpdate {
au.mutation.SetPrimary(b)
return au
}
// SetNillablePrimary sets the "primary" field if the given value is not nil.
func (au *AttachmentUpdate) SetNillablePrimary(b *bool) *AttachmentUpdate {
if b != nil {
au.SetPrimary(*b)
}
return au
}
// SetItemID sets the "item" edge to the Item entity by ID. // SetItemID sets the "item" edge to the Item entity by ID.
func (au *AttachmentUpdate) SetItemID(id uuid.UUID) *AttachmentUpdate { func (au *AttachmentUpdate) SetItemID(id uuid.UUID) *AttachmentUpdate {
au.mutation.SetItemID(id) au.mutation.SetItemID(id)
@ -174,9 +160,6 @@ func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) {
if value, ok := au.mutation.GetType(); ok { if value, ok := au.mutation.GetType(); ok {
_spec.SetField(attachment.FieldType, field.TypeEnum, value) _spec.SetField(attachment.FieldType, field.TypeEnum, value)
} }
if value, ok := au.mutation.Primary(); ok {
_spec.SetField(attachment.FieldPrimary, field.TypeBool, value)
}
if au.mutation.ItemCleared() { if au.mutation.ItemCleared() {
edge := &sqlgraph.EdgeSpec{ edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O, Rel: sqlgraph.M2O,
@ -275,20 +258,6 @@ func (auo *AttachmentUpdateOne) SetNillableType(a *attachment.Type) *AttachmentU
return auo return auo
} }
// SetPrimary sets the "primary" field.
func (auo *AttachmentUpdateOne) SetPrimary(b bool) *AttachmentUpdateOne {
auo.mutation.SetPrimary(b)
return auo
}
// SetNillablePrimary sets the "primary" field if the given value is not nil.
func (auo *AttachmentUpdateOne) SetNillablePrimary(b *bool) *AttachmentUpdateOne {
if b != nil {
auo.SetPrimary(*b)
}
return auo
}
// SetItemID sets the "item" edge to the Item entity by ID. // SetItemID sets the "item" edge to the Item entity by ID.
func (auo *AttachmentUpdateOne) SetItemID(id uuid.UUID) *AttachmentUpdateOne { func (auo *AttachmentUpdateOne) SetItemID(id uuid.UUID) *AttachmentUpdateOne {
auo.mutation.SetItemID(id) auo.mutation.SetItemID(id)
@ -428,9 +397,6 @@ func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
if value, ok := auo.mutation.GetType(); ok { if value, ok := auo.mutation.GetType(); ok {
_spec.SetField(attachment.FieldType, field.TypeEnum, value) _spec.SetField(attachment.FieldType, field.TypeEnum, value)
} }
if value, ok := auo.mutation.Primary(); ok {
_spec.SetField(attachment.FieldPrimary, field.TypeBool, value)
}
if auo.mutation.ItemCleared() { if auo.mutation.ItemCleared() {
edge := &sqlgraph.EdgeSpec{ edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O, Rel: sqlgraph.M2O,

View file

@ -98,15 +98,32 @@ func HasTokenWith(preds ...predicate.AuthTokens) predicate.AuthRoles {
// And groups predicates with the AND operator between them. // And groups predicates with the AND operator between them.
func And(predicates ...predicate.AuthRoles) predicate.AuthRoles { func And(predicates ...predicate.AuthRoles) predicate.AuthRoles {
return predicate.AuthRoles(sql.AndPredicates(predicates...)) return predicate.AuthRoles(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for _, p := range predicates {
p(s1)
}
s.Where(s1.P())
})
} }
// Or groups predicates with the OR operator between them. // Or groups predicates with the OR operator between them.
func Or(predicates ...predicate.AuthRoles) predicate.AuthRoles { func Or(predicates ...predicate.AuthRoles) predicate.AuthRoles {
return predicate.AuthRoles(sql.OrPredicates(predicates...)) return predicate.AuthRoles(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for i, p := range predicates {
if i > 0 {
s1.Or()
}
p(s1)
}
s.Where(s1.P())
})
} }
// Not applies the not operator on the given predicate. // Not applies the not operator on the given predicate.
func Not(p predicate.AuthRoles) predicate.AuthRoles { func Not(p predicate.AuthRoles) predicate.AuthRoles {
return predicate.AuthRoles(sql.NotPredicates(p)) return predicate.AuthRoles(func(s *sql.Selector) {
p(s.Not())
})
} }

View file

@ -158,15 +158,11 @@ func (arc *AuthRolesCreate) createSpec() (*AuthRoles, *sqlgraph.CreateSpec) {
// AuthRolesCreateBulk is the builder for creating many AuthRoles entities in bulk. // AuthRolesCreateBulk is the builder for creating many AuthRoles entities in bulk.
type AuthRolesCreateBulk struct { type AuthRolesCreateBulk struct {
config config
err error
builders []*AuthRolesCreate builders []*AuthRolesCreate
} }
// Save creates the AuthRoles entities in the database. // Save creates the AuthRoles entities in the database.
func (arcb *AuthRolesCreateBulk) Save(ctx context.Context) ([]*AuthRoles, error) { func (arcb *AuthRolesCreateBulk) Save(ctx context.Context) ([]*AuthRoles, error) {
if arcb.err != nil {
return nil, arcb.err
}
specs := make([]*sqlgraph.CreateSpec, len(arcb.builders)) specs := make([]*sqlgraph.CreateSpec, len(arcb.builders))
nodes := make([]*AuthRoles, len(arcb.builders)) nodes := make([]*AuthRoles, len(arcb.builders))
mutators := make([]Mutator, len(arcb.builders)) mutators := make([]Mutator, len(arcb.builders))

View file

@ -284,15 +284,32 @@ func HasRolesWith(preds ...predicate.AuthRoles) predicate.AuthTokens {
// And groups predicates with the AND operator between them. // And groups predicates with the AND operator between them.
func And(predicates ...predicate.AuthTokens) predicate.AuthTokens { func And(predicates ...predicate.AuthTokens) predicate.AuthTokens {
return predicate.AuthTokens(sql.AndPredicates(predicates...)) return predicate.AuthTokens(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for _, p := range predicates {
p(s1)
}
s.Where(s1.P())
})
} }
// Or groups predicates with the OR operator between them. // Or groups predicates with the OR operator between them.
func Or(predicates ...predicate.AuthTokens) predicate.AuthTokens { func Or(predicates ...predicate.AuthTokens) predicate.AuthTokens {
return predicate.AuthTokens(sql.OrPredicates(predicates...)) return predicate.AuthTokens(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for i, p := range predicates {
if i > 0 {
s1.Or()
}
p(s1)
}
s.Where(s1.P())
})
} }
// Not applies the not operator on the given predicate. // Not applies the not operator on the given predicate.
func Not(p predicate.AuthTokens) predicate.AuthTokens { func Not(p predicate.AuthTokens) predicate.AuthTokens {
return predicate.AuthTokens(sql.NotPredicates(p)) return predicate.AuthTokens(func(s *sql.Selector) {
p(s.Not())
})
} }

View file

@ -280,15 +280,11 @@ func (atc *AuthTokensCreate) createSpec() (*AuthTokens, *sqlgraph.CreateSpec) {
// AuthTokensCreateBulk is the builder for creating many AuthTokens entities in bulk. // AuthTokensCreateBulk is the builder for creating many AuthTokens entities in bulk.
type AuthTokensCreateBulk struct { type AuthTokensCreateBulk struct {
config config
err error
builders []*AuthTokensCreate builders []*AuthTokensCreate
} }
// Save creates the AuthTokens entities in the database. // Save creates the AuthTokens entities in the database.
func (atcb *AuthTokensCreateBulk) Save(ctx context.Context) ([]*AuthTokens, error) { func (atcb *AuthTokensCreateBulk) Save(ctx context.Context) ([]*AuthTokens, error) {
if atcb.err != nil {
return nil, atcb.err
}
specs := make([]*sqlgraph.CreateSpec, len(atcb.builders)) specs := make([]*sqlgraph.CreateSpec, len(atcb.builders))
nodes := make([]*AuthTokens, len(atcb.builders)) nodes := make([]*AuthTokens, len(atcb.builders))
mutators := make([]Mutator, len(atcb.builders)) mutators := make([]Mutator, len(atcb.builders))

View file

@ -7,7 +7,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"log" "log"
"reflect"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/data/ent/migrate" "github.com/hay-kot/homebox/backend/internal/data/ent/migrate"
@ -66,7 +65,9 @@ type Client struct {
// NewClient creates a new client configured with the given options. // NewClient creates a new client configured with the given options.
func NewClient(opts ...Option) *Client { func NewClient(opts ...Option) *Client {
client := &Client{config: newConfig(opts...)} cfg := config{log: log.Println, hooks: &hooks{}, inters: &inters{}}
cfg.options(opts...)
client := &Client{config: cfg}
client.init() client.init()
return client return client
} }
@ -106,13 +107,6 @@ type (
Option func(*config) Option func(*config)
) )
// newConfig creates a new config for the client.
func newConfig(opts ...Option) config {
cfg := config{log: log.Println, hooks: &hooks{}, inters: &inters{}}
cfg.options(opts...)
return cfg
}
// options applies the options on the config object. // options applies the options on the config object.
func (c *config) options(opts ...Option) { func (c *config) options(opts ...Option) {
for _, opt := range opts { for _, opt := range opts {
@ -160,14 +154,11 @@ func Open(driverName, dataSourceName string, options ...Option) (*Client, error)
} }
} }
// ErrTxStarted is returned when trying to start a new transaction from a transactional client.
var ErrTxStarted = errors.New("ent: cannot start a transaction within a transaction")
// Tx returns a new transactional client. The provided context // Tx returns a new transactional client. The provided context
// is used until the transaction is committed or rolled back. // is used until the transaction is committed or rolled back.
func (c *Client) Tx(ctx context.Context) (*Tx, error) { func (c *Client) Tx(ctx context.Context) (*Tx, error) {
if _, ok := c.driver.(*txDriver); ok { if _, ok := c.driver.(*txDriver); ok {
return nil, ErrTxStarted return nil, errors.New("ent: cannot start a transaction within a transaction")
} }
tx, err := newTx(ctx, c.driver) tx, err := newTx(ctx, c.driver)
if err != nil { if err != nil {
@ -339,21 +330,6 @@ func (c *AttachmentClient) CreateBulk(builders ...*AttachmentCreate) *Attachment
return &AttachmentCreateBulk{config: c.config, builders: builders} return &AttachmentCreateBulk{config: c.config, builders: builders}
} }
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
// a builder and applies setFunc on it.
func (c *AttachmentClient) MapCreateBulk(slice any, setFunc func(*AttachmentCreate, int)) *AttachmentCreateBulk {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice {
return &AttachmentCreateBulk{err: fmt.Errorf("calling to AttachmentClient.MapCreateBulk with wrong type %T, need slice", slice)}
}
builders := make([]*AttachmentCreate, rv.Len())
for i := 0; i < rv.Len(); i++ {
builders[i] = c.Create()
setFunc(builders[i], i)
}
return &AttachmentCreateBulk{config: c.config, builders: builders}
}
// Update returns an update builder for Attachment. // Update returns an update builder for Attachment.
func (c *AttachmentClient) Update() *AttachmentUpdate { func (c *AttachmentClient) Update() *AttachmentUpdate {
mutation := newAttachmentMutation(c.config, OpUpdate) mutation := newAttachmentMutation(c.config, OpUpdate)
@ -504,21 +480,6 @@ func (c *AuthRolesClient) CreateBulk(builders ...*AuthRolesCreate) *AuthRolesCre
return &AuthRolesCreateBulk{config: c.config, builders: builders} return &AuthRolesCreateBulk{config: c.config, builders: builders}
} }
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
// a builder and applies setFunc on it.
func (c *AuthRolesClient) MapCreateBulk(slice any, setFunc func(*AuthRolesCreate, int)) *AuthRolesCreateBulk {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice {
return &AuthRolesCreateBulk{err: fmt.Errorf("calling to AuthRolesClient.MapCreateBulk with wrong type %T, need slice", slice)}
}
builders := make([]*AuthRolesCreate, rv.Len())
for i := 0; i < rv.Len(); i++ {
builders[i] = c.Create()
setFunc(builders[i], i)
}
return &AuthRolesCreateBulk{config: c.config, builders: builders}
}
// Update returns an update builder for AuthRoles. // Update returns an update builder for AuthRoles.
func (c *AuthRolesClient) Update() *AuthRolesUpdate { func (c *AuthRolesClient) Update() *AuthRolesUpdate {
mutation := newAuthRolesMutation(c.config, OpUpdate) mutation := newAuthRolesMutation(c.config, OpUpdate)
@ -653,21 +614,6 @@ func (c *AuthTokensClient) CreateBulk(builders ...*AuthTokensCreate) *AuthTokens
return &AuthTokensCreateBulk{config: c.config, builders: builders} return &AuthTokensCreateBulk{config: c.config, builders: builders}
} }
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
// a builder and applies setFunc on it.
func (c *AuthTokensClient) MapCreateBulk(slice any, setFunc func(*AuthTokensCreate, int)) *AuthTokensCreateBulk {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice {
return &AuthTokensCreateBulk{err: fmt.Errorf("calling to AuthTokensClient.MapCreateBulk with wrong type %T, need slice", slice)}
}
builders := make([]*AuthTokensCreate, rv.Len())
for i := 0; i < rv.Len(); i++ {
builders[i] = c.Create()
setFunc(builders[i], i)
}
return &AuthTokensCreateBulk{config: c.config, builders: builders}
}
// Update returns an update builder for AuthTokens. // Update returns an update builder for AuthTokens.
func (c *AuthTokensClient) Update() *AuthTokensUpdate { func (c *AuthTokensClient) Update() *AuthTokensUpdate {
mutation := newAuthTokensMutation(c.config, OpUpdate) mutation := newAuthTokensMutation(c.config, OpUpdate)
@ -818,21 +764,6 @@ func (c *DocumentClient) CreateBulk(builders ...*DocumentCreate) *DocumentCreate
return &DocumentCreateBulk{config: c.config, builders: builders} return &DocumentCreateBulk{config: c.config, builders: builders}
} }
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
// a builder and applies setFunc on it.
func (c *DocumentClient) MapCreateBulk(slice any, setFunc func(*DocumentCreate, int)) *DocumentCreateBulk {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice {
return &DocumentCreateBulk{err: fmt.Errorf("calling to DocumentClient.MapCreateBulk with wrong type %T, need slice", slice)}
}
builders := make([]*DocumentCreate, rv.Len())
for i := 0; i < rv.Len(); i++ {
builders[i] = c.Create()
setFunc(builders[i], i)
}
return &DocumentCreateBulk{config: c.config, builders: builders}
}
// Update returns an update builder for Document. // Update returns an update builder for Document.
func (c *DocumentClient) Update() *DocumentUpdate { func (c *DocumentClient) Update() *DocumentUpdate {
mutation := newDocumentMutation(c.config, OpUpdate) mutation := newDocumentMutation(c.config, OpUpdate)
@ -983,21 +914,6 @@ func (c *GroupClient) CreateBulk(builders ...*GroupCreate) *GroupCreateBulk {
return &GroupCreateBulk{config: c.config, builders: builders} return &GroupCreateBulk{config: c.config, builders: builders}
} }
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
// a builder and applies setFunc on it.
func (c *GroupClient) MapCreateBulk(slice any, setFunc func(*GroupCreate, int)) *GroupCreateBulk {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice {
return &GroupCreateBulk{err: fmt.Errorf("calling to GroupClient.MapCreateBulk with wrong type %T, need slice", slice)}
}
builders := make([]*GroupCreate, rv.Len())
for i := 0; i < rv.Len(); i++ {
builders[i] = c.Create()
setFunc(builders[i], i)
}
return &GroupCreateBulk{config: c.config, builders: builders}
}
// Update returns an update builder for Group. // Update returns an update builder for Group.
func (c *GroupClient) Update() *GroupUpdate { func (c *GroupClient) Update() *GroupUpdate {
mutation := newGroupMutation(c.config, OpUpdate) mutation := newGroupMutation(c.config, OpUpdate)
@ -1228,21 +1144,6 @@ func (c *GroupInvitationTokenClient) CreateBulk(builders ...*GroupInvitationToke
return &GroupInvitationTokenCreateBulk{config: c.config, builders: builders} return &GroupInvitationTokenCreateBulk{config: c.config, builders: builders}
} }
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
// a builder and applies setFunc on it.
func (c *GroupInvitationTokenClient) MapCreateBulk(slice any, setFunc func(*GroupInvitationTokenCreate, int)) *GroupInvitationTokenCreateBulk {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice {
return &GroupInvitationTokenCreateBulk{err: fmt.Errorf("calling to GroupInvitationTokenClient.MapCreateBulk with wrong type %T, need slice", slice)}
}
builders := make([]*GroupInvitationTokenCreate, rv.Len())
for i := 0; i < rv.Len(); i++ {
builders[i] = c.Create()
setFunc(builders[i], i)
}
return &GroupInvitationTokenCreateBulk{config: c.config, builders: builders}
}
// Update returns an update builder for GroupInvitationToken. // Update returns an update builder for GroupInvitationToken.
func (c *GroupInvitationTokenClient) Update() *GroupInvitationTokenUpdate { func (c *GroupInvitationTokenClient) Update() *GroupInvitationTokenUpdate {
mutation := newGroupInvitationTokenMutation(c.config, OpUpdate) mutation := newGroupInvitationTokenMutation(c.config, OpUpdate)
@ -1377,21 +1278,6 @@ func (c *ItemClient) CreateBulk(builders ...*ItemCreate) *ItemCreateBulk {
return &ItemCreateBulk{config: c.config, builders: builders} return &ItemCreateBulk{config: c.config, builders: builders}
} }
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
// a builder and applies setFunc on it.
func (c *ItemClient) MapCreateBulk(slice any, setFunc func(*ItemCreate, int)) *ItemCreateBulk {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice {
return &ItemCreateBulk{err: fmt.Errorf("calling to ItemClient.MapCreateBulk with wrong type %T, need slice", slice)}
}
builders := make([]*ItemCreate, rv.Len())
for i := 0; i < rv.Len(); i++ {
builders[i] = c.Create()
setFunc(builders[i], i)
}
return &ItemCreateBulk{config: c.config, builders: builders}
}
// Update returns an update builder for Item. // Update returns an update builder for Item.
func (c *ItemClient) Update() *ItemUpdate { func (c *ItemClient) Update() *ItemUpdate {
mutation := newItemMutation(c.config, OpUpdate) mutation := newItemMutation(c.config, OpUpdate)
@ -1638,21 +1524,6 @@ func (c *ItemFieldClient) CreateBulk(builders ...*ItemFieldCreate) *ItemFieldCre
return &ItemFieldCreateBulk{config: c.config, builders: builders} return &ItemFieldCreateBulk{config: c.config, builders: builders}
} }
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
// a builder and applies setFunc on it.
func (c *ItemFieldClient) MapCreateBulk(slice any, setFunc func(*ItemFieldCreate, int)) *ItemFieldCreateBulk {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice {
return &ItemFieldCreateBulk{err: fmt.Errorf("calling to ItemFieldClient.MapCreateBulk with wrong type %T, need slice", slice)}
}
builders := make([]*ItemFieldCreate, rv.Len())
for i := 0; i < rv.Len(); i++ {
builders[i] = c.Create()
setFunc(builders[i], i)
}
return &ItemFieldCreateBulk{config: c.config, builders: builders}
}
// Update returns an update builder for ItemField. // Update returns an update builder for ItemField.
func (c *ItemFieldClient) Update() *ItemFieldUpdate { func (c *ItemFieldClient) Update() *ItemFieldUpdate {
mutation := newItemFieldMutation(c.config, OpUpdate) mutation := newItemFieldMutation(c.config, OpUpdate)
@ -1787,21 +1658,6 @@ func (c *LabelClient) CreateBulk(builders ...*LabelCreate) *LabelCreateBulk {
return &LabelCreateBulk{config: c.config, builders: builders} return &LabelCreateBulk{config: c.config, builders: builders}
} }
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
// a builder and applies setFunc on it.
func (c *LabelClient) MapCreateBulk(slice any, setFunc func(*LabelCreate, int)) *LabelCreateBulk {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice {
return &LabelCreateBulk{err: fmt.Errorf("calling to LabelClient.MapCreateBulk with wrong type %T, need slice", slice)}
}
builders := make([]*LabelCreate, rv.Len())
for i := 0; i < rv.Len(); i++ {
builders[i] = c.Create()
setFunc(builders[i], i)
}
return &LabelCreateBulk{config: c.config, builders: builders}
}
// Update returns an update builder for Label. // Update returns an update builder for Label.
func (c *LabelClient) Update() *LabelUpdate { func (c *LabelClient) Update() *LabelUpdate {
mutation := newLabelMutation(c.config, OpUpdate) mutation := newLabelMutation(c.config, OpUpdate)
@ -1952,21 +1808,6 @@ func (c *LocationClient) CreateBulk(builders ...*LocationCreate) *LocationCreate
return &LocationCreateBulk{config: c.config, builders: builders} return &LocationCreateBulk{config: c.config, builders: builders}
} }
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
// a builder and applies setFunc on it.
func (c *LocationClient) MapCreateBulk(slice any, setFunc func(*LocationCreate, int)) *LocationCreateBulk {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice {
return &LocationCreateBulk{err: fmt.Errorf("calling to LocationClient.MapCreateBulk with wrong type %T, need slice", slice)}
}
builders := make([]*LocationCreate, rv.Len())
for i := 0; i < rv.Len(); i++ {
builders[i] = c.Create()
setFunc(builders[i], i)
}
return &LocationCreateBulk{config: c.config, builders: builders}
}
// Update returns an update builder for Location. // Update returns an update builder for Location.
func (c *LocationClient) Update() *LocationUpdate { func (c *LocationClient) Update() *LocationUpdate {
mutation := newLocationMutation(c.config, OpUpdate) mutation := newLocationMutation(c.config, OpUpdate)
@ -2149,21 +1990,6 @@ func (c *MaintenanceEntryClient) CreateBulk(builders ...*MaintenanceEntryCreate)
return &MaintenanceEntryCreateBulk{config: c.config, builders: builders} return &MaintenanceEntryCreateBulk{config: c.config, builders: builders}
} }
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
// a builder and applies setFunc on it.
func (c *MaintenanceEntryClient) MapCreateBulk(slice any, setFunc func(*MaintenanceEntryCreate, int)) *MaintenanceEntryCreateBulk {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice {
return &MaintenanceEntryCreateBulk{err: fmt.Errorf("calling to MaintenanceEntryClient.MapCreateBulk with wrong type %T, need slice", slice)}
}
builders := make([]*MaintenanceEntryCreate, rv.Len())
for i := 0; i < rv.Len(); i++ {
builders[i] = c.Create()
setFunc(builders[i], i)
}
return &MaintenanceEntryCreateBulk{config: c.config, builders: builders}
}
// Update returns an update builder for MaintenanceEntry. // Update returns an update builder for MaintenanceEntry.
func (c *MaintenanceEntryClient) Update() *MaintenanceEntryUpdate { func (c *MaintenanceEntryClient) Update() *MaintenanceEntryUpdate {
mutation := newMaintenanceEntryMutation(c.config, OpUpdate) mutation := newMaintenanceEntryMutation(c.config, OpUpdate)
@ -2298,21 +2124,6 @@ func (c *NotifierClient) CreateBulk(builders ...*NotifierCreate) *NotifierCreate
return &NotifierCreateBulk{config: c.config, builders: builders} return &NotifierCreateBulk{config: c.config, builders: builders}
} }
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
// a builder and applies setFunc on it.
func (c *NotifierClient) MapCreateBulk(slice any, setFunc func(*NotifierCreate, int)) *NotifierCreateBulk {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice {
return &NotifierCreateBulk{err: fmt.Errorf("calling to NotifierClient.MapCreateBulk with wrong type %T, need slice", slice)}
}
builders := make([]*NotifierCreate, rv.Len())
for i := 0; i < rv.Len(); i++ {
builders[i] = c.Create()
setFunc(builders[i], i)
}
return &NotifierCreateBulk{config: c.config, builders: builders}
}
// Update returns an update builder for Notifier. // Update returns an update builder for Notifier.
func (c *NotifierClient) Update() *NotifierUpdate { func (c *NotifierClient) Update() *NotifierUpdate {
mutation := newNotifierMutation(c.config, OpUpdate) mutation := newNotifierMutation(c.config, OpUpdate)
@ -2463,21 +2274,6 @@ func (c *UserClient) CreateBulk(builders ...*UserCreate) *UserCreateBulk {
return &UserCreateBulk{config: c.config, builders: builders} return &UserCreateBulk{config: c.config, builders: builders}
} }
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
// a builder and applies setFunc on it.
func (c *UserClient) MapCreateBulk(slice any, setFunc func(*UserCreate, int)) *UserCreateBulk {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice {
return &UserCreateBulk{err: fmt.Errorf("calling to UserClient.MapCreateBulk with wrong type %T, need slice", slice)}
}
builders := make([]*UserCreate, rv.Len())
for i := 0; i < rv.Len(); i++ {
builders[i] = c.Create()
setFunc(builders[i], i)
}
return &UserCreateBulk{config: c.config, builders: builders}
}
// Update returns an update builder for User. // Update returns an update builder for User.
func (c *UserClient) Update() *UserUpdate { func (c *UserClient) Update() *UserUpdate {
mutation := newUserMutation(c.config, OpUpdate) mutation := newUserMutation(c.config, OpUpdate)

View file

@ -334,15 +334,32 @@ func HasAttachmentsWith(preds ...predicate.Attachment) predicate.Document {
// And groups predicates with the AND operator between them. // And groups predicates with the AND operator between them.
func And(predicates ...predicate.Document) predicate.Document { func And(predicates ...predicate.Document) predicate.Document {
return predicate.Document(sql.AndPredicates(predicates...)) return predicate.Document(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for _, p := range predicates {
p(s1)
}
s.Where(s1.P())
})
} }
// Or groups predicates with the OR operator between them. // Or groups predicates with the OR operator between them.
func Or(predicates ...predicate.Document) predicate.Document { func Or(predicates ...predicate.Document) predicate.Document {
return predicate.Document(sql.OrPredicates(predicates...)) return predicate.Document(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for i, p := range predicates {
if i > 0 {
s1.Or()
}
p(s1)
}
s.Where(s1.P())
})
} }
// Not applies the not operator on the given predicate. // Not applies the not operator on the given predicate.
func Not(p predicate.Document) predicate.Document { func Not(p predicate.Document) predicate.Document {
return predicate.Document(sql.NotPredicates(p)) return predicate.Document(func(s *sql.Selector) {
p(s.Not())
})
} }

View file

@ -269,15 +269,11 @@ func (dc *DocumentCreate) createSpec() (*Document, *sqlgraph.CreateSpec) {
// DocumentCreateBulk is the builder for creating many Document entities in bulk. // DocumentCreateBulk is the builder for creating many Document entities in bulk.
type DocumentCreateBulk struct { type DocumentCreateBulk struct {
config config
err error
builders []*DocumentCreate builders []*DocumentCreate
} }
// Save creates the Document entities in the database. // Save creates the Document entities in the database.
func (dcb *DocumentCreateBulk) Save(ctx context.Context) ([]*Document, error) { func (dcb *DocumentCreateBulk) Save(ctx context.Context) ([]*Document, error) {
if dcb.err != nil {
return nil, dcb.err
}
specs := make([]*sqlgraph.CreateSpec, len(dcb.builders)) specs := make([]*sqlgraph.CreateSpec, len(dcb.builders))
nodes := make([]*Document, len(dcb.builders)) nodes := make([]*Document, len(dcb.builders))
mutators := make([]Mutator, len(dcb.builders)) mutators := make([]Mutator, len(dcb.builders))

View file

@ -43,28 +43,12 @@ func (du *DocumentUpdate) SetTitle(s string) *DocumentUpdate {
return du return du
} }
// SetNillableTitle sets the "title" field if the given value is not nil.
func (du *DocumentUpdate) SetNillableTitle(s *string) *DocumentUpdate {
if s != nil {
du.SetTitle(*s)
}
return du
}
// SetPath sets the "path" field. // SetPath sets the "path" field.
func (du *DocumentUpdate) SetPath(s string) *DocumentUpdate { func (du *DocumentUpdate) SetPath(s string) *DocumentUpdate {
du.mutation.SetPath(s) du.mutation.SetPath(s)
return du return du
} }
// SetNillablePath sets the "path" field if the given value is not nil.
func (du *DocumentUpdate) SetNillablePath(s *string) *DocumentUpdate {
if s != nil {
du.SetPath(*s)
}
return du
}
// SetGroupID sets the "group" edge to the Group entity by ID. // SetGroupID sets the "group" edge to the Group entity by ID.
func (du *DocumentUpdate) SetGroupID(id uuid.UUID) *DocumentUpdate { func (du *DocumentUpdate) SetGroupID(id uuid.UUID) *DocumentUpdate {
du.mutation.SetGroupID(id) du.mutation.SetGroupID(id)
@ -304,28 +288,12 @@ func (duo *DocumentUpdateOne) SetTitle(s string) *DocumentUpdateOne {
return duo return duo
} }
// SetNillableTitle sets the "title" field if the given value is not nil.
func (duo *DocumentUpdateOne) SetNillableTitle(s *string) *DocumentUpdateOne {
if s != nil {
duo.SetTitle(*s)
}
return duo
}
// SetPath sets the "path" field. // SetPath sets the "path" field.
func (duo *DocumentUpdateOne) SetPath(s string) *DocumentUpdateOne { func (duo *DocumentUpdateOne) SetPath(s string) *DocumentUpdateOne {
duo.mutation.SetPath(s) duo.mutation.SetPath(s)
return duo return duo
} }
// SetNillablePath sets the "path" field if the given value is not nil.
func (duo *DocumentUpdateOne) SetNillablePath(s *string) *DocumentUpdateOne {
if s != nil {
duo.SetPath(*s)
}
return duo
}
// SetGroupID sets the "group" edge to the Group entity by ID. // SetGroupID sets the "group" edge to the Group entity by ID.
func (duo *DocumentUpdateOne) SetGroupID(id uuid.UUID) *DocumentUpdateOne { func (duo *DocumentUpdateOne) SetGroupID(id uuid.UUID) *DocumentUpdateOne {
duo.mutation.SetGroupID(id) duo.mutation.SetGroupID(id)

View file

@ -25,7 +25,7 @@ type Group struct {
// Name holds the value of the "name" field. // Name holds the value of the "name" field.
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
// Currency holds the value of the "currency" field. // Currency holds the value of the "currency" field.
Currency string `json:"currency,omitempty"` Currency group.Currency `json:"currency,omitempty"`
// Edges holds the relations/edges for other nodes in the graph. // Edges holds the relations/edges for other nodes in the graph.
// The values are being populated by the GroupQuery when eager-loading is set. // The values are being populated by the GroupQuery when eager-loading is set.
Edges GroupEdges `json:"edges"` Edges GroupEdges `json:"edges"`
@ -170,7 +170,7 @@ func (gr *Group) assignValues(columns []string, values []any) error {
if value, ok := values[i].(*sql.NullString); !ok { if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field currency", values[i]) return fmt.Errorf("unexpected type %T for field currency", values[i])
} else if value.Valid { } else if value.Valid {
gr.Currency = value.String gr.Currency = group.Currency(value.String)
} }
default: default:
gr.selectValues.Set(columns[i], values[i]) gr.selectValues.Set(columns[i], values[i])
@ -253,7 +253,7 @@ func (gr *Group) String() string {
builder.WriteString(gr.Name) builder.WriteString(gr.Name)
builder.WriteString(", ") builder.WriteString(", ")
builder.WriteString("currency=") builder.WriteString("currency=")
builder.WriteString(gr.Currency) builder.WriteString(fmt.Sprintf("%v", gr.Currency))
builder.WriteByte(')') builder.WriteByte(')')
return builder.String() return builder.String()
} }

View file

@ -3,6 +3,7 @@
package group package group
import ( import (
"fmt"
"time" "time"
"entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql"
@ -118,12 +119,64 @@ var (
UpdateDefaultUpdatedAt func() time.Time UpdateDefaultUpdatedAt func() time.Time
// NameValidator is a validator for the "name" field. It is called by the builders before save. // NameValidator is a validator for the "name" field. It is called by the builders before save.
NameValidator func(string) error NameValidator func(string) error
// DefaultCurrency holds the default value on creation for the "currency" field.
DefaultCurrency string
// DefaultID holds the default value on creation for the "id" field. // DefaultID holds the default value on creation for the "id" field.
DefaultID func() uuid.UUID DefaultID func() uuid.UUID
) )
// Currency defines the type for the "currency" enum field.
type Currency string
// CurrencyUsd is the default value of the Currency enum.
const DefaultCurrency = CurrencyUsd
// Currency values.
const (
CurrencyAed Currency = "aed"
CurrencyAud Currency = "aud"
CurrencyBgn Currency = "bgn"
CurrencyBrl Currency = "brl"
CurrencyCad Currency = "cad"
CurrencyChf Currency = "chf"
CurrencyCny Currency = "cny"
CurrencyCzk Currency = "czk"
CurrencyDkk Currency = "dkk"
CurrencyEur Currency = "eur"
CurrencyGbp Currency = "gbp"
CurrencyHkd Currency = "hkd"
CurrencyIdr Currency = "idr"
CurrencyInr Currency = "inr"
CurrencyJpy Currency = "jpy"
CurrencyKrw Currency = "krw"
CurrencyMxn Currency = "mxn"
CurrencyNok Currency = "nok"
CurrencyNzd Currency = "nzd"
CurrencyPln Currency = "pln"
CurrencyRmb Currency = "rmb"
CurrencyRon Currency = "ron"
CurrencyRub Currency = "rub"
CurrencySar Currency = "sar"
CurrencySek Currency = "sek"
CurrencySgd Currency = "sgd"
CurrencyThb Currency = "thb"
CurrencyTry Currency = "try"
CurrencyUsd Currency = "usd"
CurrencyZar Currency = "zar"
)
func (c Currency) String() string {
return string(c)
}
// CurrencyValidator is a validator for the "currency" field enum values. It is called by the builders before save.
func CurrencyValidator(c Currency) error {
switch c {
case CurrencyAed, CurrencyAud, CurrencyBgn, CurrencyBrl, CurrencyCad, CurrencyChf, CurrencyCny, CurrencyCzk, CurrencyDkk, CurrencyEur, CurrencyGbp, CurrencyHkd, CurrencyIdr, CurrencyInr, CurrencyJpy, CurrencyKrw, CurrencyMxn, CurrencyNok, CurrencyNzd, CurrencyPln, CurrencyRmb, CurrencyRon, CurrencyRub, CurrencySar, CurrencySek, CurrencySgd, CurrencyThb, CurrencyTry, CurrencyUsd, CurrencyZar:
return nil
default:
return fmt.Errorf("group: invalid enum value for currency field: %q", c)
}
}
// OrderOption defines the ordering options for the Group queries. // OrderOption defines the ordering options for the Group queries.
type OrderOption func(*sql.Selector) type OrderOption func(*sql.Selector)

View file

@ -71,11 +71,6 @@ func Name(v string) predicate.Group {
return predicate.Group(sql.FieldEQ(FieldName, v)) return predicate.Group(sql.FieldEQ(FieldName, v))
} }
// Currency applies equality check predicate on the "currency" field. It's identical to CurrencyEQ.
func Currency(v string) predicate.Group {
return predicate.Group(sql.FieldEQ(FieldCurrency, v))
}
// CreatedAtEQ applies the EQ predicate on the "created_at" field. // CreatedAtEQ applies the EQ predicate on the "created_at" field.
func CreatedAtEQ(v time.Time) predicate.Group { func CreatedAtEQ(v time.Time) predicate.Group {
return predicate.Group(sql.FieldEQ(FieldCreatedAt, v)) return predicate.Group(sql.FieldEQ(FieldCreatedAt, v))
@ -222,70 +217,25 @@ func NameContainsFold(v string) predicate.Group {
} }
// CurrencyEQ applies the EQ predicate on the "currency" field. // CurrencyEQ applies the EQ predicate on the "currency" field.
func CurrencyEQ(v string) predicate.Group { func CurrencyEQ(v Currency) predicate.Group {
return predicate.Group(sql.FieldEQ(FieldCurrency, v)) return predicate.Group(sql.FieldEQ(FieldCurrency, v))
} }
// CurrencyNEQ applies the NEQ predicate on the "currency" field. // CurrencyNEQ applies the NEQ predicate on the "currency" field.
func CurrencyNEQ(v string) predicate.Group { func CurrencyNEQ(v Currency) predicate.Group {
return predicate.Group(sql.FieldNEQ(FieldCurrency, v)) return predicate.Group(sql.FieldNEQ(FieldCurrency, v))
} }
// CurrencyIn applies the In predicate on the "currency" field. // CurrencyIn applies the In predicate on the "currency" field.
func CurrencyIn(vs ...string) predicate.Group { func CurrencyIn(vs ...Currency) predicate.Group {
return predicate.Group(sql.FieldIn(FieldCurrency, vs...)) return predicate.Group(sql.FieldIn(FieldCurrency, vs...))
} }
// CurrencyNotIn applies the NotIn predicate on the "currency" field. // CurrencyNotIn applies the NotIn predicate on the "currency" field.
func CurrencyNotIn(vs ...string) predicate.Group { func CurrencyNotIn(vs ...Currency) predicate.Group {
return predicate.Group(sql.FieldNotIn(FieldCurrency, vs...)) return predicate.Group(sql.FieldNotIn(FieldCurrency, vs...))
} }
// CurrencyGT applies the GT predicate on the "currency" field.
func CurrencyGT(v string) predicate.Group {
return predicate.Group(sql.FieldGT(FieldCurrency, v))
}
// CurrencyGTE applies the GTE predicate on the "currency" field.
func CurrencyGTE(v string) predicate.Group {
return predicate.Group(sql.FieldGTE(FieldCurrency, v))
}
// CurrencyLT applies the LT predicate on the "currency" field.
func CurrencyLT(v string) predicate.Group {
return predicate.Group(sql.FieldLT(FieldCurrency, v))
}
// CurrencyLTE applies the LTE predicate on the "currency" field.
func CurrencyLTE(v string) predicate.Group {
return predicate.Group(sql.FieldLTE(FieldCurrency, v))
}
// CurrencyContains applies the Contains predicate on the "currency" field.
func CurrencyContains(v string) predicate.Group {
return predicate.Group(sql.FieldContains(FieldCurrency, v))
}
// CurrencyHasPrefix applies the HasPrefix predicate on the "currency" field.
func CurrencyHasPrefix(v string) predicate.Group {
return predicate.Group(sql.FieldHasPrefix(FieldCurrency, v))
}
// CurrencyHasSuffix applies the HasSuffix predicate on the "currency" field.
func CurrencyHasSuffix(v string) predicate.Group {
return predicate.Group(sql.FieldHasSuffix(FieldCurrency, v))
}
// CurrencyEqualFold applies the EqualFold predicate on the "currency" field.
func CurrencyEqualFold(v string) predicate.Group {
return predicate.Group(sql.FieldEqualFold(FieldCurrency, v))
}
// CurrencyContainsFold applies the ContainsFold predicate on the "currency" field.
func CurrencyContainsFold(v string) predicate.Group {
return predicate.Group(sql.FieldContainsFold(FieldCurrency, v))
}
// HasUsers applies the HasEdge predicate on the "users" edge. // HasUsers applies the HasEdge predicate on the "users" edge.
func HasUsers() predicate.Group { func HasUsers() predicate.Group {
return predicate.Group(func(s *sql.Selector) { return predicate.Group(func(s *sql.Selector) {
@ -449,15 +399,32 @@ func HasNotifiersWith(preds ...predicate.Notifier) predicate.Group {
// And groups predicates with the AND operator between them. // And groups predicates with the AND operator between them.
func And(predicates ...predicate.Group) predicate.Group { func And(predicates ...predicate.Group) predicate.Group {
return predicate.Group(sql.AndPredicates(predicates...)) return predicate.Group(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for _, p := range predicates {
p(s1)
}
s.Where(s1.P())
})
} }
// Or groups predicates with the OR operator between them. // Or groups predicates with the OR operator between them.
func Or(predicates ...predicate.Group) predicate.Group { func Or(predicates ...predicate.Group) predicate.Group {
return predicate.Group(sql.OrPredicates(predicates...)) return predicate.Group(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for i, p := range predicates {
if i > 0 {
s1.Or()
}
p(s1)
}
s.Where(s1.P())
})
} }
// Not applies the not operator on the given predicate. // Not applies the not operator on the given predicate.
func Not(p predicate.Group) predicate.Group { func Not(p predicate.Group) predicate.Group {
return predicate.Group(sql.NotPredicates(p)) return predicate.Group(func(s *sql.Selector) {
p(s.Not())
})
} }

View file

@ -63,15 +63,15 @@ func (gc *GroupCreate) SetName(s string) *GroupCreate {
} }
// SetCurrency sets the "currency" field. // SetCurrency sets the "currency" field.
func (gc *GroupCreate) SetCurrency(s string) *GroupCreate { func (gc *GroupCreate) SetCurrency(gr group.Currency) *GroupCreate {
gc.mutation.SetCurrency(s) gc.mutation.SetCurrency(gr)
return gc return gc
} }
// SetNillableCurrency sets the "currency" field if the given value is not nil. // SetNillableCurrency sets the "currency" field if the given value is not nil.
func (gc *GroupCreate) SetNillableCurrency(s *string) *GroupCreate { func (gc *GroupCreate) SetNillableCurrency(gr *group.Currency) *GroupCreate {
if s != nil { if gr != nil {
gc.SetCurrency(*s) gc.SetCurrency(*gr)
} }
return gc return gc
} }
@ -267,6 +267,11 @@ func (gc *GroupCreate) check() error {
if _, ok := gc.mutation.Currency(); !ok { if _, ok := gc.mutation.Currency(); !ok {
return &ValidationError{Name: "currency", err: errors.New(`ent: missing required field "Group.currency"`)} return &ValidationError{Name: "currency", err: errors.New(`ent: missing required field "Group.currency"`)}
} }
if v, ok := gc.mutation.Currency(); ok {
if err := group.CurrencyValidator(v); err != nil {
return &ValidationError{Name: "currency", err: fmt.Errorf(`ent: validator failed for field "Group.currency": %w`, err)}
}
}
return nil return nil
} }
@ -315,7 +320,7 @@ func (gc *GroupCreate) createSpec() (*Group, *sqlgraph.CreateSpec) {
_node.Name = value _node.Name = value
} }
if value, ok := gc.mutation.Currency(); ok { if value, ok := gc.mutation.Currency(); ok {
_spec.SetField(group.FieldCurrency, field.TypeString, value) _spec.SetField(group.FieldCurrency, field.TypeEnum, value)
_node.Currency = value _node.Currency = value
} }
if nodes := gc.mutation.UsersIDs(); len(nodes) > 0 { if nodes := gc.mutation.UsersIDs(); len(nodes) > 0 {
@ -436,15 +441,11 @@ func (gc *GroupCreate) createSpec() (*Group, *sqlgraph.CreateSpec) {
// GroupCreateBulk is the builder for creating many Group entities in bulk. // GroupCreateBulk is the builder for creating many Group entities in bulk.
type GroupCreateBulk struct { type GroupCreateBulk struct {
config config
err error
builders []*GroupCreate builders []*GroupCreate
} }
// Save creates the Group entities in the database. // Save creates the Group entities in the database.
func (gcb *GroupCreateBulk) Save(ctx context.Context) ([]*Group, error) { func (gcb *GroupCreateBulk) Save(ctx context.Context) ([]*Group, error) {
if gcb.err != nil {
return nil, gcb.err
}
specs := make([]*sqlgraph.CreateSpec, len(gcb.builders)) specs := make([]*sqlgraph.CreateSpec, len(gcb.builders))
nodes := make([]*Group, len(gcb.builders)) nodes := make([]*Group, len(gcb.builders))
mutators := make([]Mutator, len(gcb.builders)) mutators := make([]Mutator, len(gcb.builders))

View file

@ -48,24 +48,16 @@ func (gu *GroupUpdate) SetName(s string) *GroupUpdate {
return gu return gu
} }
// SetNillableName sets the "name" field if the given value is not nil.
func (gu *GroupUpdate) SetNillableName(s *string) *GroupUpdate {
if s != nil {
gu.SetName(*s)
}
return gu
}
// SetCurrency sets the "currency" field. // SetCurrency sets the "currency" field.
func (gu *GroupUpdate) SetCurrency(s string) *GroupUpdate { func (gu *GroupUpdate) SetCurrency(gr group.Currency) *GroupUpdate {
gu.mutation.SetCurrency(s) gu.mutation.SetCurrency(gr)
return gu return gu
} }
// SetNillableCurrency sets the "currency" field if the given value is not nil. // SetNillableCurrency sets the "currency" field if the given value is not nil.
func (gu *GroupUpdate) SetNillableCurrency(s *string) *GroupUpdate { func (gu *GroupUpdate) SetNillableCurrency(gr *group.Currency) *GroupUpdate {
if s != nil { if gr != nil {
gu.SetCurrency(*s) gu.SetCurrency(*gr)
} }
return gu return gu
} }
@ -370,6 +362,11 @@ func (gu *GroupUpdate) check() error {
return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "Group.name": %w`, err)} return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "Group.name": %w`, err)}
} }
} }
if v, ok := gu.mutation.Currency(); ok {
if err := group.CurrencyValidator(v); err != nil {
return &ValidationError{Name: "currency", err: fmt.Errorf(`ent: validator failed for field "Group.currency": %w`, err)}
}
}
return nil return nil
} }
@ -392,7 +389,7 @@ func (gu *GroupUpdate) sqlSave(ctx context.Context) (n int, err error) {
_spec.SetField(group.FieldName, field.TypeString, value) _spec.SetField(group.FieldName, field.TypeString, value)
} }
if value, ok := gu.mutation.Currency(); ok { if value, ok := gu.mutation.Currency(); ok {
_spec.SetField(group.FieldCurrency, field.TypeString, value) _spec.SetField(group.FieldCurrency, field.TypeEnum, value)
} }
if gu.mutation.UsersCleared() { if gu.mutation.UsersCleared() {
edge := &sqlgraph.EdgeSpec{ edge := &sqlgraph.EdgeSpec{
@ -741,24 +738,16 @@ func (guo *GroupUpdateOne) SetName(s string) *GroupUpdateOne {
return guo return guo
} }
// SetNillableName sets the "name" field if the given value is not nil.
func (guo *GroupUpdateOne) SetNillableName(s *string) *GroupUpdateOne {
if s != nil {
guo.SetName(*s)
}
return guo
}
// SetCurrency sets the "currency" field. // SetCurrency sets the "currency" field.
func (guo *GroupUpdateOne) SetCurrency(s string) *GroupUpdateOne { func (guo *GroupUpdateOne) SetCurrency(gr group.Currency) *GroupUpdateOne {
guo.mutation.SetCurrency(s) guo.mutation.SetCurrency(gr)
return guo return guo
} }
// SetNillableCurrency sets the "currency" field if the given value is not nil. // SetNillableCurrency sets the "currency" field if the given value is not nil.
func (guo *GroupUpdateOne) SetNillableCurrency(s *string) *GroupUpdateOne { func (guo *GroupUpdateOne) SetNillableCurrency(gr *group.Currency) *GroupUpdateOne {
if s != nil { if gr != nil {
guo.SetCurrency(*s) guo.SetCurrency(*gr)
} }
return guo return guo
} }
@ -1076,6 +1065,11 @@ func (guo *GroupUpdateOne) check() error {
return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "Group.name": %w`, err)} return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "Group.name": %w`, err)}
} }
} }
if v, ok := guo.mutation.Currency(); ok {
if err := group.CurrencyValidator(v); err != nil {
return &ValidationError{Name: "currency", err: fmt.Errorf(`ent: validator failed for field "Group.currency": %w`, err)}
}
}
return nil return nil
} }
@ -1115,7 +1109,7 @@ func (guo *GroupUpdateOne) sqlSave(ctx context.Context) (_node *Group, err error
_spec.SetField(group.FieldName, field.TypeString, value) _spec.SetField(group.FieldName, field.TypeString, value)
} }
if value, ok := guo.mutation.Currency(); ok { if value, ok := guo.mutation.Currency(); ok {
_spec.SetField(group.FieldCurrency, field.TypeString, value) _spec.SetField(group.FieldCurrency, field.TypeEnum, value)
} }
if guo.mutation.UsersCleared() { if guo.mutation.UsersCleared() {
edge := &sqlgraph.EdgeSpec{ edge := &sqlgraph.EdgeSpec{

View file

@ -306,15 +306,32 @@ func HasGroupWith(preds ...predicate.Group) predicate.GroupInvitationToken {
// And groups predicates with the AND operator between them. // And groups predicates with the AND operator between them.
func And(predicates ...predicate.GroupInvitationToken) predicate.GroupInvitationToken { func And(predicates ...predicate.GroupInvitationToken) predicate.GroupInvitationToken {
return predicate.GroupInvitationToken(sql.AndPredicates(predicates...)) return predicate.GroupInvitationToken(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for _, p := range predicates {
p(s1)
}
s.Where(s1.P())
})
} }
// Or groups predicates with the OR operator between them. // Or groups predicates with the OR operator between them.
func Or(predicates ...predicate.GroupInvitationToken) predicate.GroupInvitationToken { func Or(predicates ...predicate.GroupInvitationToken) predicate.GroupInvitationToken {
return predicate.GroupInvitationToken(sql.OrPredicates(predicates...)) return predicate.GroupInvitationToken(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for i, p := range predicates {
if i > 0 {
s1.Or()
}
p(s1)
}
s.Where(s1.P())
})
} }
// Not applies the not operator on the given predicate. // Not applies the not operator on the given predicate.
func Not(p predicate.GroupInvitationToken) predicate.GroupInvitationToken { func Not(p predicate.GroupInvitationToken) predicate.GroupInvitationToken {
return predicate.GroupInvitationToken(sql.NotPredicates(p)) return predicate.GroupInvitationToken(func(s *sql.Selector) {
p(s.Not())
})
} }

View file

@ -269,15 +269,11 @@ func (gitc *GroupInvitationTokenCreate) createSpec() (*GroupInvitationToken, *sq
// GroupInvitationTokenCreateBulk is the builder for creating many GroupInvitationToken entities in bulk. // GroupInvitationTokenCreateBulk is the builder for creating many GroupInvitationToken entities in bulk.
type GroupInvitationTokenCreateBulk struct { type GroupInvitationTokenCreateBulk struct {
config config
err error
builders []*GroupInvitationTokenCreate builders []*GroupInvitationTokenCreate
} }
// Save creates the GroupInvitationToken entities in the database. // Save creates the GroupInvitationToken entities in the database.
func (gitcb *GroupInvitationTokenCreateBulk) Save(ctx context.Context) ([]*GroupInvitationToken, error) { func (gitcb *GroupInvitationTokenCreateBulk) Save(ctx context.Context) ([]*GroupInvitationToken, error) {
if gitcb.err != nil {
return nil, gitcb.err
}
specs := make([]*sqlgraph.CreateSpec, len(gitcb.builders)) specs := make([]*sqlgraph.CreateSpec, len(gitcb.builders))
nodes := make([]*GroupInvitationToken, len(gitcb.builders)) nodes := make([]*GroupInvitationToken, len(gitcb.builders))
mutators := make([]Mutator, len(gitcb.builders)) mutators := make([]Mutator, len(gitcb.builders))

View file

@ -1592,15 +1592,32 @@ func HasAttachmentsWith(preds ...predicate.Attachment) predicate.Item {
// And groups predicates with the AND operator between them. // And groups predicates with the AND operator between them.
func And(predicates ...predicate.Item) predicate.Item { func And(predicates ...predicate.Item) predicate.Item {
return predicate.Item(sql.AndPredicates(predicates...)) return predicate.Item(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for _, p := range predicates {
p(s1)
}
s.Where(s1.P())
})
} }
// Or groups predicates with the OR operator between them. // Or groups predicates with the OR operator between them.
func Or(predicates ...predicate.Item) predicate.Item { func Or(predicates ...predicate.Item) predicate.Item {
return predicate.Item(sql.OrPredicates(predicates...)) return predicate.Item(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for i, p := range predicates {
if i > 0 {
s1.Or()
}
p(s1)
}
s.Where(s1.P())
})
} }
// Not applies the not operator on the given predicate. // Not applies the not operator on the given predicate.
func Not(p predicate.Item) predicate.Item { func Not(p predicate.Item) predicate.Item {
return predicate.Item(sql.NotPredicates(p)) return predicate.Item(func(s *sql.Selector) {
p(s.Not())
})
} }

View file

@ -900,15 +900,11 @@ func (ic *ItemCreate) createSpec() (*Item, *sqlgraph.CreateSpec) {
// ItemCreateBulk is the builder for creating many Item entities in bulk. // ItemCreateBulk is the builder for creating many Item entities in bulk.
type ItemCreateBulk struct { type ItemCreateBulk struct {
config config
err error
builders []*ItemCreate builders []*ItemCreate
} }
// Save creates the Item entities in the database. // Save creates the Item entities in the database.
func (icb *ItemCreateBulk) Save(ctx context.Context) ([]*Item, error) { func (icb *ItemCreateBulk) Save(ctx context.Context) ([]*Item, error) {
if icb.err != nil {
return nil, icb.err
}
specs := make([]*sqlgraph.CreateSpec, len(icb.builders)) specs := make([]*sqlgraph.CreateSpec, len(icb.builders))
nodes := make([]*Item, len(icb.builders)) nodes := make([]*Item, len(icb.builders))
mutators := make([]Mutator, len(icb.builders)) mutators := make([]Mutator, len(icb.builders))

View file

@ -47,14 +47,6 @@ func (iu *ItemUpdate) SetName(s string) *ItemUpdate {
return iu return iu
} }
// SetNillableName sets the "name" field if the given value is not nil.
func (iu *ItemUpdate) SetNillableName(s *string) *ItemUpdate {
if s != nil {
iu.SetName(*s)
}
return iu
}
// SetDescription sets the "description" field. // SetDescription sets the "description" field.
func (iu *ItemUpdate) SetDescription(s string) *ItemUpdate { func (iu *ItemUpdate) SetDescription(s string) *ItemUpdate {
iu.mutation.SetDescription(s) iu.mutation.SetDescription(s)
@ -1255,14 +1247,6 @@ func (iuo *ItemUpdateOne) SetName(s string) *ItemUpdateOne {
return iuo return iuo
} }
// SetNillableName sets the "name" field if the given value is not nil.
func (iuo *ItemUpdateOne) SetNillableName(s *string) *ItemUpdateOne {
if s != nil {
iuo.SetName(*s)
}
return iuo
}
// SetDescription sets the "description" field. // SetDescription sets the "description" field.
func (iuo *ItemUpdateOne) SetDescription(s string) *ItemUpdateOne { func (iuo *ItemUpdateOne) SetDescription(s string) *ItemUpdateOne {
iuo.mutation.SetDescription(s) iuo.mutation.SetDescription(s)

View file

@ -536,15 +536,32 @@ func HasItemWith(preds ...predicate.Item) predicate.ItemField {
// And groups predicates with the AND operator between them. // And groups predicates with the AND operator between them.
func And(predicates ...predicate.ItemField) predicate.ItemField { func And(predicates ...predicate.ItemField) predicate.ItemField {
return predicate.ItemField(sql.AndPredicates(predicates...)) return predicate.ItemField(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for _, p := range predicates {
p(s1)
}
s.Where(s1.P())
})
} }
// Or groups predicates with the OR operator between them. // Or groups predicates with the OR operator between them.
func Or(predicates ...predicate.ItemField) predicate.ItemField { func Or(predicates ...predicate.ItemField) predicate.ItemField {
return predicate.ItemField(sql.OrPredicates(predicates...)) return predicate.ItemField(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for i, p := range predicates {
if i > 0 {
s1.Or()
}
p(s1)
}
s.Where(s1.P())
})
} }
// Not applies the not operator on the given predicate. // Not applies the not operator on the given predicate.
func Not(p predicate.ItemField) predicate.ItemField { func Not(p predicate.ItemField) predicate.ItemField {
return predicate.ItemField(sql.NotPredicates(p)) return predicate.ItemField(func(s *sql.Selector) {
p(s.Not())
})
} }

View file

@ -356,15 +356,11 @@ func (ifc *ItemFieldCreate) createSpec() (*ItemField, *sqlgraph.CreateSpec) {
// ItemFieldCreateBulk is the builder for creating many ItemField entities in bulk. // ItemFieldCreateBulk is the builder for creating many ItemField entities in bulk.
type ItemFieldCreateBulk struct { type ItemFieldCreateBulk struct {
config config
err error
builders []*ItemFieldCreate builders []*ItemFieldCreate
} }
// Save creates the ItemField entities in the database. // Save creates the ItemField entities in the database.
func (ifcb *ItemFieldCreateBulk) Save(ctx context.Context) ([]*ItemField, error) { func (ifcb *ItemFieldCreateBulk) Save(ctx context.Context) ([]*ItemField, error) {
if ifcb.err != nil {
return nil, ifcb.err
}
specs := make([]*sqlgraph.CreateSpec, len(ifcb.builders)) specs := make([]*sqlgraph.CreateSpec, len(ifcb.builders))
nodes := make([]*ItemField, len(ifcb.builders)) nodes := make([]*ItemField, len(ifcb.builders))
mutators := make([]Mutator, len(ifcb.builders)) mutators := make([]Mutator, len(ifcb.builders))

View file

@ -42,14 +42,6 @@ func (ifu *ItemFieldUpdate) SetName(s string) *ItemFieldUpdate {
return ifu return ifu
} }
// SetNillableName sets the "name" field if the given value is not nil.
func (ifu *ItemFieldUpdate) SetNillableName(s *string) *ItemFieldUpdate {
if s != nil {
ifu.SetName(*s)
}
return ifu
}
// SetDescription sets the "description" field. // SetDescription sets the "description" field.
func (ifu *ItemFieldUpdate) SetDescription(s string) *ItemFieldUpdate { func (ifu *ItemFieldUpdate) SetDescription(s string) *ItemFieldUpdate {
ifu.mutation.SetDescription(s) ifu.mutation.SetDescription(s)
@ -76,14 +68,6 @@ func (ifu *ItemFieldUpdate) SetType(i itemfield.Type) *ItemFieldUpdate {
return ifu return ifu
} }
// SetNillableType sets the "type" field if the given value is not nil.
func (ifu *ItemFieldUpdate) SetNillableType(i *itemfield.Type) *ItemFieldUpdate {
if i != nil {
ifu.SetType(*i)
}
return ifu
}
// SetTextValue sets the "text_value" field. // SetTextValue sets the "text_value" field.
func (ifu *ItemFieldUpdate) SetTextValue(s string) *ItemFieldUpdate { func (ifu *ItemFieldUpdate) SetTextValue(s string) *ItemFieldUpdate {
ifu.mutation.SetTextValue(s) ifu.mutation.SetTextValue(s)
@ -359,14 +343,6 @@ func (ifuo *ItemFieldUpdateOne) SetName(s string) *ItemFieldUpdateOne {
return ifuo return ifuo
} }
// SetNillableName sets the "name" field if the given value is not nil.
func (ifuo *ItemFieldUpdateOne) SetNillableName(s *string) *ItemFieldUpdateOne {
if s != nil {
ifuo.SetName(*s)
}
return ifuo
}
// SetDescription sets the "description" field. // SetDescription sets the "description" field.
func (ifuo *ItemFieldUpdateOne) SetDescription(s string) *ItemFieldUpdateOne { func (ifuo *ItemFieldUpdateOne) SetDescription(s string) *ItemFieldUpdateOne {
ifuo.mutation.SetDescription(s) ifuo.mutation.SetDescription(s)
@ -393,14 +369,6 @@ func (ifuo *ItemFieldUpdateOne) SetType(i itemfield.Type) *ItemFieldUpdateOne {
return ifuo return ifuo
} }
// SetNillableType sets the "type" field if the given value is not nil.
func (ifuo *ItemFieldUpdateOne) SetNillableType(i *itemfield.Type) *ItemFieldUpdateOne {
if i != nil {
ifuo.SetType(*i)
}
return ifuo
}
// SetTextValue sets the "text_value" field. // SetTextValue sets the "text_value" field.
func (ifuo *ItemFieldUpdateOne) SetTextValue(s string) *ItemFieldUpdateOne { func (ifuo *ItemFieldUpdateOne) SetTextValue(s string) *ItemFieldUpdateOne {
ifuo.mutation.SetTextValue(s) ifuo.mutation.SetTextValue(s)

View file

@ -424,15 +424,32 @@ func HasItemsWith(preds ...predicate.Item) predicate.Label {
// And groups predicates with the AND operator between them. // And groups predicates with the AND operator between them.
func And(predicates ...predicate.Label) predicate.Label { func And(predicates ...predicate.Label) predicate.Label {
return predicate.Label(sql.AndPredicates(predicates...)) return predicate.Label(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for _, p := range predicates {
p(s1)
}
s.Where(s1.P())
})
} }
// Or groups predicates with the OR operator between them. // Or groups predicates with the OR operator between them.
func Or(predicates ...predicate.Label) predicate.Label { func Or(predicates ...predicate.Label) predicate.Label {
return predicate.Label(sql.OrPredicates(predicates...)) return predicate.Label(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for i, p := range predicates {
if i > 0 {
s1.Or()
}
p(s1)
}
s.Where(s1.P())
})
} }
// Not applies the not operator on the given predicate. // Not applies the not operator on the given predicate.
func Not(p predicate.Label) predicate.Label { func Not(p predicate.Label) predicate.Label {
return predicate.Label(sql.NotPredicates(p)) return predicate.Label(func(s *sql.Selector) {
p(s.Not())
})
} }

View file

@ -297,15 +297,11 @@ func (lc *LabelCreate) createSpec() (*Label, *sqlgraph.CreateSpec) {
// LabelCreateBulk is the builder for creating many Label entities in bulk. // LabelCreateBulk is the builder for creating many Label entities in bulk.
type LabelCreateBulk struct { type LabelCreateBulk struct {
config config
err error
builders []*LabelCreate builders []*LabelCreate
} }
// Save creates the Label entities in the database. // Save creates the Label entities in the database.
func (lcb *LabelCreateBulk) Save(ctx context.Context) ([]*Label, error) { func (lcb *LabelCreateBulk) Save(ctx context.Context) ([]*Label, error) {
if lcb.err != nil {
return nil, lcb.err
}
specs := make([]*sqlgraph.CreateSpec, len(lcb.builders)) specs := make([]*sqlgraph.CreateSpec, len(lcb.builders))
nodes := make([]*Label, len(lcb.builders)) nodes := make([]*Label, len(lcb.builders))
mutators := make([]Mutator, len(lcb.builders)) mutators := make([]Mutator, len(lcb.builders))

View file

@ -43,14 +43,6 @@ func (lu *LabelUpdate) SetName(s string) *LabelUpdate {
return lu return lu
} }
// SetNillableName sets the "name" field if the given value is not nil.
func (lu *LabelUpdate) SetNillableName(s *string) *LabelUpdate {
if s != nil {
lu.SetName(*s)
}
return lu
}
// SetDescription sets the "description" field. // SetDescription sets the "description" field.
func (lu *LabelUpdate) SetDescription(s string) *LabelUpdate { func (lu *LabelUpdate) SetDescription(s string) *LabelUpdate {
lu.mutation.SetDescription(s) lu.mutation.SetDescription(s)
@ -344,14 +336,6 @@ func (luo *LabelUpdateOne) SetName(s string) *LabelUpdateOne {
return luo return luo
} }
// SetNillableName sets the "name" field if the given value is not nil.
func (luo *LabelUpdateOne) SetNillableName(s *string) *LabelUpdateOne {
if s != nil {
luo.SetName(*s)
}
return luo
}
// SetDescription sets the "description" field. // SetDescription sets the "description" field.
func (luo *LabelUpdateOne) SetDescription(s string) *LabelUpdateOne { func (luo *LabelUpdateOne) SetDescription(s string) *LabelUpdateOne {
luo.mutation.SetDescription(s) luo.mutation.SetDescription(s)

View file

@ -390,15 +390,32 @@ func HasItemsWith(preds ...predicate.Item) predicate.Location {
// And groups predicates with the AND operator between them. // And groups predicates with the AND operator between them.
func And(predicates ...predicate.Location) predicate.Location { func And(predicates ...predicate.Location) predicate.Location {
return predicate.Location(sql.AndPredicates(predicates...)) return predicate.Location(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for _, p := range predicates {
p(s1)
}
s.Where(s1.P())
})
} }
// Or groups predicates with the OR operator between them. // Or groups predicates with the OR operator between them.
func Or(predicates ...predicate.Location) predicate.Location { func Or(predicates ...predicate.Location) predicate.Location {
return predicate.Location(sql.OrPredicates(predicates...)) return predicate.Location(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for i, p := range predicates {
if i > 0 {
s1.Or()
}
p(s1)
}
s.Where(s1.P())
})
} }
// Not applies the not operator on the given predicate. // Not applies the not operator on the given predicate.
func Not(p predicate.Location) predicate.Location { func Not(p predicate.Location) predicate.Location {
return predicate.Location(sql.NotPredicates(p)) return predicate.Location(func(s *sql.Selector) {
p(s.Not())
})
} }

View file

@ -341,15 +341,11 @@ func (lc *LocationCreate) createSpec() (*Location, *sqlgraph.CreateSpec) {
// LocationCreateBulk is the builder for creating many Location entities in bulk. // LocationCreateBulk is the builder for creating many Location entities in bulk.
type LocationCreateBulk struct { type LocationCreateBulk struct {
config config
err error
builders []*LocationCreate builders []*LocationCreate
} }
// Save creates the Location entities in the database. // Save creates the Location entities in the database.
func (lcb *LocationCreateBulk) Save(ctx context.Context) ([]*Location, error) { func (lcb *LocationCreateBulk) Save(ctx context.Context) ([]*Location, error) {
if lcb.err != nil {
return nil, lcb.err
}
specs := make([]*sqlgraph.CreateSpec, len(lcb.builders)) specs := make([]*sqlgraph.CreateSpec, len(lcb.builders))
nodes := make([]*Location, len(lcb.builders)) nodes := make([]*Location, len(lcb.builders))
mutators := make([]Mutator, len(lcb.builders)) mutators := make([]Mutator, len(lcb.builders))

View file

@ -43,14 +43,6 @@ func (lu *LocationUpdate) SetName(s string) *LocationUpdate {
return lu return lu
} }
// SetNillableName sets the "name" field if the given value is not nil.
func (lu *LocationUpdate) SetNillableName(s *string) *LocationUpdate {
if s != nil {
lu.SetName(*s)
}
return lu
}
// SetDescription sets the "description" field. // SetDescription sets the "description" field.
func (lu *LocationUpdate) SetDescription(s string) *LocationUpdate { func (lu *LocationUpdate) SetDescription(s string) *LocationUpdate {
lu.mutation.SetDescription(s) lu.mutation.SetDescription(s)
@ -448,14 +440,6 @@ func (luo *LocationUpdateOne) SetName(s string) *LocationUpdateOne {
return luo return luo
} }
// SetNillableName sets the "name" field if the given value is not nil.
func (luo *LocationUpdateOne) SetNillableName(s *string) *LocationUpdateOne {
if s != nil {
luo.SetName(*s)
}
return luo
}
// SetDescription sets the "description" field. // SetDescription sets the "description" field.
func (luo *LocationUpdateOne) SetDescription(s string) *LocationUpdateOne { func (luo *LocationUpdateOne) SetDescription(s string) *LocationUpdateOne {
luo.mutation.SetDescription(s) luo.mutation.SetDescription(s)

View file

@ -501,15 +501,32 @@ func HasItemWith(preds ...predicate.Item) predicate.MaintenanceEntry {
// And groups predicates with the AND operator between them. // And groups predicates with the AND operator between them.
func And(predicates ...predicate.MaintenanceEntry) predicate.MaintenanceEntry { func And(predicates ...predicate.MaintenanceEntry) predicate.MaintenanceEntry {
return predicate.MaintenanceEntry(sql.AndPredicates(predicates...)) return predicate.MaintenanceEntry(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for _, p := range predicates {
p(s1)
}
s.Where(s1.P())
})
} }
// Or groups predicates with the OR operator between them. // Or groups predicates with the OR operator between them.
func Or(predicates ...predicate.MaintenanceEntry) predicate.MaintenanceEntry { func Or(predicates ...predicate.MaintenanceEntry) predicate.MaintenanceEntry {
return predicate.MaintenanceEntry(sql.OrPredicates(predicates...)) return predicate.MaintenanceEntry(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for i, p := range predicates {
if i > 0 {
s1.Or()
}
p(s1)
}
s.Where(s1.P())
})
} }
// Not applies the not operator on the given predicate. // Not applies the not operator on the given predicate.
func Not(p predicate.MaintenanceEntry) predicate.MaintenanceEntry { func Not(p predicate.MaintenanceEntry) predicate.MaintenanceEntry {
return predicate.MaintenanceEntry(sql.NotPredicates(p)) return predicate.MaintenanceEntry(func(s *sql.Selector) {
p(s.Not())
})
} }

View file

@ -306,15 +306,11 @@ func (mec *MaintenanceEntryCreate) createSpec() (*MaintenanceEntry, *sqlgraph.Cr
// MaintenanceEntryCreateBulk is the builder for creating many MaintenanceEntry entities in bulk. // MaintenanceEntryCreateBulk is the builder for creating many MaintenanceEntry entities in bulk.
type MaintenanceEntryCreateBulk struct { type MaintenanceEntryCreateBulk struct {
config config
err error
builders []*MaintenanceEntryCreate builders []*MaintenanceEntryCreate
} }
// Save creates the MaintenanceEntry entities in the database. // Save creates the MaintenanceEntry entities in the database.
func (mecb *MaintenanceEntryCreateBulk) Save(ctx context.Context) ([]*MaintenanceEntry, error) { func (mecb *MaintenanceEntryCreateBulk) Save(ctx context.Context) ([]*MaintenanceEntry, error) {
if mecb.err != nil {
return nil, mecb.err
}
specs := make([]*sqlgraph.CreateSpec, len(mecb.builders)) specs := make([]*sqlgraph.CreateSpec, len(mecb.builders))
nodes := make([]*MaintenanceEntry, len(mecb.builders)) nodes := make([]*MaintenanceEntry, len(mecb.builders))
mutators := make([]Mutator, len(mecb.builders)) mutators := make([]Mutator, len(mecb.builders))

View file

@ -42,14 +42,6 @@ func (meu *MaintenanceEntryUpdate) SetItemID(u uuid.UUID) *MaintenanceEntryUpdat
return meu return meu
} }
// SetNillableItemID sets the "item_id" field if the given value is not nil.
func (meu *MaintenanceEntryUpdate) SetNillableItemID(u *uuid.UUID) *MaintenanceEntryUpdate {
if u != nil {
meu.SetItemID(*u)
}
return meu
}
// SetDate sets the "date" field. // SetDate sets the "date" field.
func (meu *MaintenanceEntryUpdate) SetDate(t time.Time) *MaintenanceEntryUpdate { func (meu *MaintenanceEntryUpdate) SetDate(t time.Time) *MaintenanceEntryUpdate {
meu.mutation.SetDate(t) meu.mutation.SetDate(t)
@ -96,14 +88,6 @@ func (meu *MaintenanceEntryUpdate) SetName(s string) *MaintenanceEntryUpdate {
return meu return meu
} }
// SetNillableName sets the "name" field if the given value is not nil.
func (meu *MaintenanceEntryUpdate) SetNillableName(s *string) *MaintenanceEntryUpdate {
if s != nil {
meu.SetName(*s)
}
return meu
}
// SetDescription sets the "description" field. // SetDescription sets the "description" field.
func (meu *MaintenanceEntryUpdate) SetDescription(s string) *MaintenanceEntryUpdate { func (meu *MaintenanceEntryUpdate) SetDescription(s string) *MaintenanceEntryUpdate {
meu.mutation.SetDescription(s) meu.mutation.SetDescription(s)
@ -318,14 +302,6 @@ func (meuo *MaintenanceEntryUpdateOne) SetItemID(u uuid.UUID) *MaintenanceEntryU
return meuo return meuo
} }
// SetNillableItemID sets the "item_id" field if the given value is not nil.
func (meuo *MaintenanceEntryUpdateOne) SetNillableItemID(u *uuid.UUID) *MaintenanceEntryUpdateOne {
if u != nil {
meuo.SetItemID(*u)
}
return meuo
}
// SetDate sets the "date" field. // SetDate sets the "date" field.
func (meuo *MaintenanceEntryUpdateOne) SetDate(t time.Time) *MaintenanceEntryUpdateOne { func (meuo *MaintenanceEntryUpdateOne) SetDate(t time.Time) *MaintenanceEntryUpdateOne {
meuo.mutation.SetDate(t) meuo.mutation.SetDate(t)
@ -372,14 +348,6 @@ func (meuo *MaintenanceEntryUpdateOne) SetName(s string) *MaintenanceEntryUpdate
return meuo return meuo
} }
// SetNillableName sets the "name" field if the given value is not nil.
func (meuo *MaintenanceEntryUpdateOne) SetNillableName(s *string) *MaintenanceEntryUpdateOne {
if s != nil {
meuo.SetName(*s)
}
return meuo
}
// SetDescription sets the "description" field. // SetDescription sets the "description" field.
func (meuo *MaintenanceEntryUpdateOne) SetDescription(s string) *MaintenanceEntryUpdateOne { func (meuo *MaintenanceEntryUpdateOne) SetDescription(s string) *MaintenanceEntryUpdateOne {
meuo.mutation.SetDescription(s) meuo.mutation.SetDescription(s)

View file

@ -14,7 +14,6 @@ var (
{Name: "created_at", Type: field.TypeTime}, {Name: "created_at", Type: field.TypeTime},
{Name: "updated_at", Type: field.TypeTime}, {Name: "updated_at", Type: field.TypeTime},
{Name: "type", Type: field.TypeEnum, Enums: []string{"photo", "manual", "warranty", "attachment", "receipt"}, Default: "attachment"}, {Name: "type", Type: field.TypeEnum, Enums: []string{"photo", "manual", "warranty", "attachment", "receipt"}, Default: "attachment"},
{Name: "primary", Type: field.TypeBool, Default: false},
{Name: "document_attachments", Type: field.TypeUUID}, {Name: "document_attachments", Type: field.TypeUUID},
{Name: "item_attachments", Type: field.TypeUUID}, {Name: "item_attachments", Type: field.TypeUUID},
} }
@ -26,13 +25,13 @@ var (
ForeignKeys: []*schema.ForeignKey{ ForeignKeys: []*schema.ForeignKey{
{ {
Symbol: "attachments_documents_attachments", Symbol: "attachments_documents_attachments",
Columns: []*schema.Column{AttachmentsColumns[5]}, Columns: []*schema.Column{AttachmentsColumns[4]},
RefColumns: []*schema.Column{DocumentsColumns[0]}, RefColumns: []*schema.Column{DocumentsColumns[0]},
OnDelete: schema.Cascade, OnDelete: schema.Cascade,
}, },
{ {
Symbol: "attachments_items_attachments", Symbol: "attachments_items_attachments",
Columns: []*schema.Column{AttachmentsColumns[6]}, Columns: []*schema.Column{AttachmentsColumns[5]},
RefColumns: []*schema.Column{ItemsColumns[0]}, RefColumns: []*schema.Column{ItemsColumns[0]},
OnDelete: schema.Cascade, OnDelete: schema.Cascade,
}, },
@ -117,7 +116,7 @@ var (
{Name: "created_at", Type: field.TypeTime}, {Name: "created_at", Type: field.TypeTime},
{Name: "updated_at", Type: field.TypeTime}, {Name: "updated_at", Type: field.TypeTime},
{Name: "name", Type: field.TypeString, Size: 255}, {Name: "name", Type: field.TypeString, Size: 255},
{Name: "currency", Type: field.TypeString, Default: "usd"}, {Name: "currency", Type: field.TypeEnum, Enums: []string{"aed", "aud", "bgn", "brl", "cad", "chf", "cny", "czk", "dkk", "eur", "gbp", "hkd", "idr", "inr", "jpy", "krw", "mxn", "nok", "nzd", "pln", "rmb", "ron", "rub", "sar", "sek", "sgd", "thb", "try", "usd", "zar"}, Default: "usd"},
} }
// GroupsTable holds the schema information for the "groups" table. // GroupsTable holds the schema information for the "groups" table.
GroupsTable = &schema.Table{ GroupsTable = &schema.Table{

View file

@ -61,7 +61,6 @@ type AttachmentMutation struct {
created_at *time.Time created_at *time.Time
updated_at *time.Time updated_at *time.Time
_type *attachment.Type _type *attachment.Type
primary *bool
clearedFields map[string]struct{} clearedFields map[string]struct{}
item *uuid.UUID item *uuid.UUID
cleareditem bool cleareditem bool
@ -284,42 +283,6 @@ func (m *AttachmentMutation) ResetType() {
m._type = nil m._type = nil
} }
// SetPrimary sets the "primary" field.
func (m *AttachmentMutation) SetPrimary(b bool) {
m.primary = &b
}
// Primary returns the value of the "primary" field in the mutation.
func (m *AttachmentMutation) Primary() (r bool, exists bool) {
v := m.primary
if v == nil {
return
}
return *v, true
}
// OldPrimary returns the old "primary" field's value of the Attachment entity.
// If the Attachment object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *AttachmentMutation) OldPrimary(ctx context.Context) (v bool, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldPrimary is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldPrimary requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldPrimary: %w", err)
}
return oldValue.Primary, nil
}
// ResetPrimary resets all changes to the "primary" field.
func (m *AttachmentMutation) ResetPrimary() {
m.primary = nil
}
// SetItemID sets the "item" edge to the Item entity by id. // SetItemID sets the "item" edge to the Item entity by id.
func (m *AttachmentMutation) SetItemID(id uuid.UUID) { func (m *AttachmentMutation) SetItemID(id uuid.UUID) {
m.item = &id m.item = &id
@ -432,7 +395,7 @@ func (m *AttachmentMutation) Type() string {
// order to get all numeric fields that were incremented/decremented, call // order to get all numeric fields that were incremented/decremented, call
// AddedFields(). // AddedFields().
func (m *AttachmentMutation) Fields() []string { func (m *AttachmentMutation) Fields() []string {
fields := make([]string, 0, 4) fields := make([]string, 0, 3)
if m.created_at != nil { if m.created_at != nil {
fields = append(fields, attachment.FieldCreatedAt) fields = append(fields, attachment.FieldCreatedAt)
} }
@ -442,9 +405,6 @@ func (m *AttachmentMutation) Fields() []string {
if m._type != nil { if m._type != nil {
fields = append(fields, attachment.FieldType) fields = append(fields, attachment.FieldType)
} }
if m.primary != nil {
fields = append(fields, attachment.FieldPrimary)
}
return fields return fields
} }
@ -459,8 +419,6 @@ func (m *AttachmentMutation) Field(name string) (ent.Value, bool) {
return m.UpdatedAt() return m.UpdatedAt()
case attachment.FieldType: case attachment.FieldType:
return m.GetType() return m.GetType()
case attachment.FieldPrimary:
return m.Primary()
} }
return nil, false return nil, false
} }
@ -476,8 +434,6 @@ func (m *AttachmentMutation) OldField(ctx context.Context, name string) (ent.Val
return m.OldUpdatedAt(ctx) return m.OldUpdatedAt(ctx)
case attachment.FieldType: case attachment.FieldType:
return m.OldType(ctx) return m.OldType(ctx)
case attachment.FieldPrimary:
return m.OldPrimary(ctx)
} }
return nil, fmt.Errorf("unknown Attachment field %s", name) return nil, fmt.Errorf("unknown Attachment field %s", name)
} }
@ -508,13 +464,6 @@ func (m *AttachmentMutation) SetField(name string, value ent.Value) error {
} }
m.SetType(v) m.SetType(v)
return nil return nil
case attachment.FieldPrimary:
v, ok := value.(bool)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetPrimary(v)
return nil
} }
return fmt.Errorf("unknown Attachment field %s", name) return fmt.Errorf("unknown Attachment field %s", name)
} }
@ -573,9 +522,6 @@ func (m *AttachmentMutation) ResetField(name string) error {
case attachment.FieldType: case attachment.FieldType:
m.ResetType() m.ResetType()
return nil return nil
case attachment.FieldPrimary:
m.ResetPrimary()
return nil
} }
return fmt.Errorf("unknown Attachment field %s", name) return fmt.Errorf("unknown Attachment field %s", name)
} }
@ -2340,7 +2286,7 @@ type GroupMutation struct {
created_at *time.Time created_at *time.Time
updated_at *time.Time updated_at *time.Time
name *string name *string
currency *string currency *group.Currency
clearedFields map[string]struct{} clearedFields map[string]struct{}
users map[uuid.UUID]struct{} users map[uuid.UUID]struct{}
removedusers map[uuid.UUID]struct{} removedusers map[uuid.UUID]struct{}
@ -2581,12 +2527,12 @@ func (m *GroupMutation) ResetName() {
} }
// SetCurrency sets the "currency" field. // SetCurrency sets the "currency" field.
func (m *GroupMutation) SetCurrency(s string) { func (m *GroupMutation) SetCurrency(gr group.Currency) {
m.currency = &s m.currency = &gr
} }
// Currency returns the value of the "currency" field in the mutation. // Currency returns the value of the "currency" field in the mutation.
func (m *GroupMutation) Currency() (r string, exists bool) { func (m *GroupMutation) Currency() (r group.Currency, exists bool) {
v := m.currency v := m.currency
if v == nil { if v == nil {
return return
@ -2597,7 +2543,7 @@ func (m *GroupMutation) Currency() (r string, exists bool) {
// OldCurrency returns the old "currency" field's value of the Group entity. // OldCurrency returns the old "currency" field's value of the Group entity.
// If the Group object wasn't provided to the builder, the object is fetched from the database. // If the Group object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails. // An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *GroupMutation) OldCurrency(ctx context.Context) (v string, err error) { func (m *GroupMutation) OldCurrency(ctx context.Context) (v group.Currency, err error) {
if !m.op.Is(OpUpdateOne) { if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldCurrency is only allowed on UpdateOne operations") return v, errors.New("OldCurrency is only allowed on UpdateOne operations")
} }
@ -3105,7 +3051,7 @@ func (m *GroupMutation) SetField(name string, value ent.Value) error {
m.SetName(v) m.SetName(v)
return nil return nil
case group.FieldCurrency: case group.FieldCurrency:
v, ok := value.(string) v, ok := value.(group.Currency)
if !ok { if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name) return fmt.Errorf("unexpected type %T for field %s", value, name)
} }
@ -9529,7 +9475,6 @@ func (m *MaintenanceEntryMutation) ResetCost() {
// ClearItem clears the "item" edge to the Item entity. // ClearItem clears the "item" edge to the Item entity.
func (m *MaintenanceEntryMutation) ClearItem() { func (m *MaintenanceEntryMutation) ClearItem() {
m.cleareditem = true m.cleareditem = true
m.clearedFields[maintenanceentry.FieldItemID] = struct{}{}
} }
// ItemCleared reports if the "item" edge to the Item entity was cleared. // ItemCleared reports if the "item" edge to the Item entity was cleared.
@ -10293,7 +10238,6 @@ func (m *NotifierMutation) ResetIsActive() {
// ClearGroup clears the "group" edge to the Group entity. // ClearGroup clears the "group" edge to the Group entity.
func (m *NotifierMutation) ClearGroup() { func (m *NotifierMutation) ClearGroup() {
m.clearedgroup = true m.clearedgroup = true
m.clearedFields[notifier.FieldGroupID] = struct{}{}
} }
// GroupCleared reports if the "group" edge to the Group entity was cleared. // GroupCleared reports if the "group" edge to the Group entity was cleared.
@ -10320,7 +10264,6 @@ func (m *NotifierMutation) ResetGroup() {
// ClearUser clears the "user" edge to the User entity. // ClearUser clears the "user" edge to the User entity.
func (m *NotifierMutation) ClearUser() { func (m *NotifierMutation) ClearUser() {
m.cleareduser = true m.cleareduser = true
m.clearedFields[notifier.FieldUserID] = struct{}{}
} }
// UserCleared reports if the "user" edge to the User entity was cleared. // UserCleared reports if the "user" edge to the User entity was cleared.

View file

@ -399,15 +399,32 @@ func HasUserWith(preds ...predicate.User) predicate.Notifier {
// And groups predicates with the AND operator between them. // And groups predicates with the AND operator between them.
func And(predicates ...predicate.Notifier) predicate.Notifier { func And(predicates ...predicate.Notifier) predicate.Notifier {
return predicate.Notifier(sql.AndPredicates(predicates...)) return predicate.Notifier(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for _, p := range predicates {
p(s1)
}
s.Where(s1.P())
})
} }
// Or groups predicates with the OR operator between them. // Or groups predicates with the OR operator between them.
func Or(predicates ...predicate.Notifier) predicate.Notifier { func Or(predicates ...predicate.Notifier) predicate.Notifier {
return predicate.Notifier(sql.OrPredicates(predicates...)) return predicate.Notifier(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for i, p := range predicates {
if i > 0 {
s1.Or()
}
p(s1)
}
s.Where(s1.P())
})
} }
// Not applies the not operator on the given predicate. // Not applies the not operator on the given predicate.
func Not(p predicate.Notifier) predicate.Notifier { func Not(p predicate.Notifier) predicate.Notifier {
return predicate.Notifier(sql.NotPredicates(p)) return predicate.Notifier(func(s *sql.Selector) {
p(s.Not())
})
} }

View file

@ -300,15 +300,11 @@ func (nc *NotifierCreate) createSpec() (*Notifier, *sqlgraph.CreateSpec) {
// NotifierCreateBulk is the builder for creating many Notifier entities in bulk. // NotifierCreateBulk is the builder for creating many Notifier entities in bulk.
type NotifierCreateBulk struct { type NotifierCreateBulk struct {
config config
err error
builders []*NotifierCreate builders []*NotifierCreate
} }
// Save creates the Notifier entities in the database. // Save creates the Notifier entities in the database.
func (ncb *NotifierCreateBulk) Save(ctx context.Context) ([]*Notifier, error) { func (ncb *NotifierCreateBulk) Save(ctx context.Context) ([]*Notifier, error) {
if ncb.err != nil {
return nil, ncb.err
}
specs := make([]*sqlgraph.CreateSpec, len(ncb.builders)) specs := make([]*sqlgraph.CreateSpec, len(ncb.builders))
nodes := make([]*Notifier, len(ncb.builders)) nodes := make([]*Notifier, len(ncb.builders))
mutators := make([]Mutator, len(ncb.builders)) mutators := make([]Mutator, len(ncb.builders))

View file

@ -43,56 +43,24 @@ func (nu *NotifierUpdate) SetGroupID(u uuid.UUID) *NotifierUpdate {
return nu return nu
} }
// SetNillableGroupID sets the "group_id" field if the given value is not nil.
func (nu *NotifierUpdate) SetNillableGroupID(u *uuid.UUID) *NotifierUpdate {
if u != nil {
nu.SetGroupID(*u)
}
return nu
}
// SetUserID sets the "user_id" field. // SetUserID sets the "user_id" field.
func (nu *NotifierUpdate) SetUserID(u uuid.UUID) *NotifierUpdate { func (nu *NotifierUpdate) SetUserID(u uuid.UUID) *NotifierUpdate {
nu.mutation.SetUserID(u) nu.mutation.SetUserID(u)
return nu return nu
} }
// SetNillableUserID sets the "user_id" field if the given value is not nil.
func (nu *NotifierUpdate) SetNillableUserID(u *uuid.UUID) *NotifierUpdate {
if u != nil {
nu.SetUserID(*u)
}
return nu
}
// SetName sets the "name" field. // SetName sets the "name" field.
func (nu *NotifierUpdate) SetName(s string) *NotifierUpdate { func (nu *NotifierUpdate) SetName(s string) *NotifierUpdate {
nu.mutation.SetName(s) nu.mutation.SetName(s)
return nu return nu
} }
// SetNillableName sets the "name" field if the given value is not nil.
func (nu *NotifierUpdate) SetNillableName(s *string) *NotifierUpdate {
if s != nil {
nu.SetName(*s)
}
return nu
}
// SetURL sets the "url" field. // SetURL sets the "url" field.
func (nu *NotifierUpdate) SetURL(s string) *NotifierUpdate { func (nu *NotifierUpdate) SetURL(s string) *NotifierUpdate {
nu.mutation.SetURL(s) nu.mutation.SetURL(s)
return nu return nu
} }
// SetNillableURL sets the "url" field if the given value is not nil.
func (nu *NotifierUpdate) SetNillableURL(s *string) *NotifierUpdate {
if s != nil {
nu.SetURL(*s)
}
return nu
}
// SetIsActive sets the "is_active" field. // SetIsActive sets the "is_active" field.
func (nu *NotifierUpdate) SetIsActive(b bool) *NotifierUpdate { func (nu *NotifierUpdate) SetIsActive(b bool) *NotifierUpdate {
nu.mutation.SetIsActive(b) nu.mutation.SetIsActive(b)
@ -305,56 +273,24 @@ func (nuo *NotifierUpdateOne) SetGroupID(u uuid.UUID) *NotifierUpdateOne {
return nuo return nuo
} }
// SetNillableGroupID sets the "group_id" field if the given value is not nil.
func (nuo *NotifierUpdateOne) SetNillableGroupID(u *uuid.UUID) *NotifierUpdateOne {
if u != nil {
nuo.SetGroupID(*u)
}
return nuo
}
// SetUserID sets the "user_id" field. // SetUserID sets the "user_id" field.
func (nuo *NotifierUpdateOne) SetUserID(u uuid.UUID) *NotifierUpdateOne { func (nuo *NotifierUpdateOne) SetUserID(u uuid.UUID) *NotifierUpdateOne {
nuo.mutation.SetUserID(u) nuo.mutation.SetUserID(u)
return nuo return nuo
} }
// SetNillableUserID sets the "user_id" field if the given value is not nil.
func (nuo *NotifierUpdateOne) SetNillableUserID(u *uuid.UUID) *NotifierUpdateOne {
if u != nil {
nuo.SetUserID(*u)
}
return nuo
}
// SetName sets the "name" field. // SetName sets the "name" field.
func (nuo *NotifierUpdateOne) SetName(s string) *NotifierUpdateOne { func (nuo *NotifierUpdateOne) SetName(s string) *NotifierUpdateOne {
nuo.mutation.SetName(s) nuo.mutation.SetName(s)
return nuo return nuo
} }
// SetNillableName sets the "name" field if the given value is not nil.
func (nuo *NotifierUpdateOne) SetNillableName(s *string) *NotifierUpdateOne {
if s != nil {
nuo.SetName(*s)
}
return nuo
}
// SetURL sets the "url" field. // SetURL sets the "url" field.
func (nuo *NotifierUpdateOne) SetURL(s string) *NotifierUpdateOne { func (nuo *NotifierUpdateOne) SetURL(s string) *NotifierUpdateOne {
nuo.mutation.SetURL(s) nuo.mutation.SetURL(s)
return nuo return nuo
} }
// SetNillableURL sets the "url" field if the given value is not nil.
func (nuo *NotifierUpdateOne) SetNillableURL(s *string) *NotifierUpdateOne {
if s != nil {
nuo.SetURL(*s)
}
return nuo
}
// SetIsActive sets the "is_active" field. // SetIsActive sets the "is_active" field.
func (nuo *NotifierUpdateOne) SetIsActive(b bool) *NotifierUpdateOne { func (nuo *NotifierUpdateOne) SetIsActive(b bool) *NotifierUpdateOne {
nuo.mutation.SetIsActive(b) nuo.mutation.SetIsActive(b)

View file

@ -40,10 +40,6 @@ func init() {
attachment.DefaultUpdatedAt = attachmentDescUpdatedAt.Default.(func() time.Time) attachment.DefaultUpdatedAt = attachmentDescUpdatedAt.Default.(func() time.Time)
// attachment.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field. // attachment.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
attachment.UpdateDefaultUpdatedAt = attachmentDescUpdatedAt.UpdateDefault.(func() time.Time) attachment.UpdateDefaultUpdatedAt = attachmentDescUpdatedAt.UpdateDefault.(func() time.Time)
// attachmentDescPrimary is the schema descriptor for primary field.
attachmentDescPrimary := attachmentFields[1].Descriptor()
// attachment.DefaultPrimary holds the default value on creation for the primary field.
attachment.DefaultPrimary = attachmentDescPrimary.Default.(bool)
// attachmentDescID is the schema descriptor for id field. // attachmentDescID is the schema descriptor for id field.
attachmentDescID := attachmentMixinFields0[0].Descriptor() attachmentDescID := attachmentMixinFields0[0].Descriptor()
// attachment.DefaultID holds the default value on creation for the id field. // attachment.DefaultID holds the default value on creation for the id field.
@ -161,10 +157,6 @@ func init() {
return nil return nil
} }
}() }()
// groupDescCurrency is the schema descriptor for currency field.
groupDescCurrency := groupFields[1].Descriptor()
// group.DefaultCurrency holds the default value on creation for the currency field.
group.DefaultCurrency = groupDescCurrency.Default.(string)
// groupDescID is the schema descriptor for id field. // groupDescID is the schema descriptor for id field.
groupDescID := groupMixinFields0[0].Descriptor() groupDescID := groupMixinFields0[0].Descriptor()
// group.DefaultID holds the default value on creation for the id field. // group.DefaultID holds the default value on creation for the id field.

View file

@ -5,6 +5,6 @@ package runtime
// The schema-stitching logic is generated in github.com/hay-kot/homebox/backend/internal/data/ent/runtime.go // The schema-stitching logic is generated in github.com/hay-kot/homebox/backend/internal/data/ent/runtime.go
const ( const (
Version = "v0.12.5" // Version of ent codegen. Version = "v0.12.3" // Version of ent codegen.
Sum = "h1:KREM5E4CSoej4zeGa88Ou/gfturAnpUv0mzAjch1sj4=" // Sum of ent codegen. Sum = "h1:N5lO2EOrHpCH5HYfiMOCHYbo+oh5M8GjT0/cx5x6xkk=" // Sum of ent codegen.
) )

View file

@ -24,8 +24,6 @@ func (Attachment) Fields() []ent.Field {
field.Enum("type"). field.Enum("type").
Values("photo", "manual", "warranty", "attachment", "receipt"). Values("photo", "manual", "warranty", "attachment", "receipt").
Default("attachment"), Default("attachment"),
field.Bool("primary").
Default(false),
} }
} }

View file

@ -27,8 +27,39 @@ func (Group) Fields() []ent.Field {
field.String("name"). field.String("name").
MaxLen(255). MaxLen(255).
NotEmpty(), NotEmpty(),
field.String("currency"). field.Enum("currency").
Default("usd"), Default("usd").
Values(
"aed",
"aud",
"bgn",
"brl",
"cad",
"chf",
"czk",
"dkk",
"eur",
"gbp",
"hkd",
"idr",
"inr",
"jpy",
"krw",
"mxn",
"nok",
"nzd",
"pln",
"rmb",
"ron",
"rub",
"sar",
"sek",
"sgd",
"thb",
"try",
"usd",
"zar",
),
} }
} }

View file

@ -78,6 +78,7 @@ func (g UserMixin) Fields() []ent.Field {
} }
return nil return nil
} }
func (g UserMixin) Edges() []ent.Edge { func (g UserMixin) Edges() []ent.Edge {

View file

@ -532,15 +532,32 @@ func HasNotifiersWith(preds ...predicate.Notifier) predicate.User {
// And groups predicates with the AND operator between them. // And groups predicates with the AND operator between them.
func And(predicates ...predicate.User) predicate.User { func And(predicates ...predicate.User) predicate.User {
return predicate.User(sql.AndPredicates(predicates...)) return predicate.User(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for _, p := range predicates {
p(s1)
}
s.Where(s1.P())
})
} }
// Or groups predicates with the OR operator between them. // Or groups predicates with the OR operator between them.
func Or(predicates ...predicate.User) predicate.User { func Or(predicates ...predicate.User) predicate.User {
return predicate.User(sql.OrPredicates(predicates...)) return predicate.User(func(s *sql.Selector) {
s1 := s.Clone().SetP(nil)
for i, p := range predicates {
if i > 0 {
s1.Or()
}
p(s1)
}
s.Where(s1.P())
})
} }
// Not applies the not operator on the given predicate. // Not applies the not operator on the given predicate.
func Not(p predicate.User) predicate.User { func Not(p predicate.User) predicate.User {
return predicate.User(sql.NotPredicates(p)) return predicate.User(func(s *sql.Selector) {
p(s.Not())
})
} }

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