Compare commits

..

72 Commits

Author SHA1 Message Date
Hayden
e4ebceeeb6 remove charts.js from libs 2023-12-01 11:55:32 -06:00
Hayden
51e3ad11c4 automatically detect image types and set primary photo if first 2023-12-01 11:45:20 -06:00
Hayden
3f455cb574 fix error when item doesn't have photo attachment 2023-12-01 11:36:29 -06:00
renovate[bot]
d1d98bcb06 chore(deps): update docker/setup-qemu-action action to v3 (#625)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-30 14:25:55 -09:00
renovate[bot]
db00e7a268 chore(deps): update goreleaser/goreleaser-action action to v5 (#626)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-30 14:25:47 -09:00
renovate[bot]
7ec22ed9bd chore(deps): update dependency mkdocs-material to v9.4.14 (#630)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-30 14:25:30 -09:00
Kevin Holtkamp
10c030a56b docs: Fix a bunch of grammar and spelling, rephrased some sentences to be more readable (#635) 2023-11-30 14:25:22 -09:00
Hayden
9edbda3daa feat: set version flag (#632) 2023-11-24 10:02:02 -09:00
Hayden
8cc0f30291 fix: allow zeroing out asset ids (#624) 2023-11-15 18:46:47 -09:00
Hayden
afbc6a49ac fix: images in child items (#623)
* support parentID search

* fetch images for item children
2023-11-15 18:41:24 -09:00
renovate[bot]
2594d4cdb4 chore(deps): update dependency @types/markdown-it to v13 (#577)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-15 18:18:19 -09:00
renovate[bot]
2eafa8e72f chore(deps): update dependency @vite-pwa/nuxt to ^0.2.0 (#616)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-15 18:18:07 -09:00
renovate[bot]
e65d44fa9e fix(deps): update dependency @pinia/nuxt to ^0.5.0 (#620)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-15 18:17:57 -09:00
Hayden
eeae790fe4 feat: expose timeout variables (#622)
* expose timeout variables

* formatting
2023-11-15 18:17:43 -09:00
renovate[bot]
a70ee33759 chore(deps): update actions/setup-node action to v4 (#621)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-15 18:15:31 -09:00
Hayden
80e2071300 fix: use theme aware background color (#619) 2023-11-15 18:01:03 -09:00
renovate[bot]
db27d34b4f chore(deps): update pnpm/action-setup action to v2.4.0 (#511)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-15 17:58:30 -09:00
Owen Valentine
da22074ed3 feat : Validate bark, ntfy, generic+ shortcut (#591) 2023-11-15 17:53:06 -09:00
Hayden
51ba15f84c fix: ensure urls isn't encoded (#618) 2023-11-15 17:51:19 -09:00
Hayden
b408318acb fix: filepath sep on windows (#615) 2023-11-15 17:43:44 -09:00
Hayden
c0e8e34065 chore: bump all go dependencies (#614)
* bump all

* code-generation
2023-11-15 17:30:49 -09:00
Hayden
4738a9b131 chore: rewrite generator to resolve strange name generation (#612)
* rewrite generator to resolve strange name generation

* fix asset id types

* ignore errored types

* remove depreciated calls

* use more random words

* random user
2023-11-15 17:19:51 -09:00
renovate[bot]
b08e52104c chore(deps): update actions/checkout action to v4 (#575)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-15 08:08:46 -09:00
renovate[bot]
3e2ab29054 chore(deps): update docker/setup-buildx-action action to v3 (#579)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-15 08:08:37 -09:00
renovate[bot]
e5f66d99bc chore(deps): update dependency mkdocs-material to v9.4.8 (#592)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-15 08:08:26 -09:00
Hayden
0995478cc0 fix: restore location section (#587) 2023-10-15 06:37:47 -08:00
Hayden
ae4b95301f fix: infinite redirect issue (#583) 2023-10-10 05:43:44 -08:00
Hayden
d8482f3a13 Revert "chore(deps): update dependency nuxt to v3.7.4 (#554)" (#580)
This reverts commit 2cd3c15215.
2023-10-06 20:29:27 -08:00
Hayden
1365bdfd46 refactor: rewrite to cookie based auth (#578)
* rewrite to cookie based auth

* remove interceptor
2023-10-06 19:44:43 -08:00
renovate[bot]
2cd3c15215 chore(deps): update dependency nuxt to v3.7.4 (#554)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-06 18:51:54 -08:00
renovate[bot]
0dc4fa5d98 fix(deps): update module modernc.org/sqlite to v1.26.0 (#574)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-06 18:51:44 -08:00
Hayden
318b8be192 feat: primary images (#576)
* add support for primary images

* fix locked loading state issue

* add action to auto-set images
2023-10-06 18:51:08 -08:00
Hayden
63a966c526 fix: field values request fails (#573) 2023-10-06 14:10:44 -08:00
Hayden
db16d3fb23 feat: make selectables clearable (#572) 2023-10-06 13:32:49 -08:00
renovate[bot]
1952b9f1cb fix(deps): update module golang.org/x/crypto to v0.14.0 (#570)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-06 13:24:12 -08:00
renovate[bot]
2b31d46ab3 fix(deps): update module github.com/rs/zerolog to v1.31.0 (#569)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-06 13:24:00 -08:00
Hayden
f3f96723b2 fix: ensure loading in toggled (#571) 2023-10-06 13:22:16 -08:00
renovate[bot]
b28bb2c4a8 fix(deps): update module github.com/yeqown/go-qrcode/writer/standard to v1.2.2 (#567)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-06 13:06:00 -08:00
renovate[bot]
a33cf54a33 fix(deps): update module github.com/containrrr/shoutrrr to v0.8.0 (#555)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-06 13:05:53 -08:00
Hayden
f13bf2958d pr: fixed incorrect sum of the total items price (#568)
* Fixed incorrect sum of the total items price

https://github.com/hay-kot/homebox/issues/458

* fix eslint errors

---------

Co-authored-by: Adamko <33964772+cRaZy92@users.noreply.github.com>
2023-10-06 12:50:55 -08:00
renovate[bot]
a9712c48af chore(deps): update dependency mkdocs-material to v9.4.4 (#553)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-06 12:31:51 -08:00
renovate[bot]
e68b7cf500 fix(deps): update module github.com/go-playground/validator/v10 to v10.15.5 (#556)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-06 12:30:31 -08:00
renovate[bot]
744a5bbb47 fix(deps): update module github.com/swaggo/swag to v1.16.2 (#552)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-14 06:19:57 -08:00
renovate[bot]
fc5698410b fix(deps): update module github.com/google/uuid to v1.3.1 (#551)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-14 06:19:37 -08:00
renovate[bot]
455163d637 fix(deps): update module golang.org/x/crypto to v0.13.0 (#532)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-14 06:19:28 -08:00
Aaron von Awesome
fbc7e6e33a fix: minor typo (#546) 2023-09-14 06:13:42 -08:00
renovate[bot]
5739b2005a chore(deps): update dependency eslint-config-prettier to v9 (#533)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-14 06:11:08 -08:00
renovate[bot]
5f41960c0a fix(deps): update module modernc.org/sqlite to v1.25.0 (#531)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-14 06:10:46 -08:00
renovate[bot]
c89aa738cf fix(deps): update module github.com/rs/zerolog to v1.30.0 (#517)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-14 06:10:37 -08:00
Jonathan Gawrych
94fd9c314d fix: mobile "Create and Add Another" goes off screen (#540) 2023-08-31 09:07:45 -08:00
Hayden
0876deb1e9 fix websocket over secure connection (#542)
* fix https connection

* explicity dependency
2023-08-24 06:28:56 -08:00
tctlrd
5438898b49 feat: add currencies XAG and XAU (#535)
* Added currencies XAG and XAU to currency.ts

I added XAG and XAU for myself and others who prefer to measure value with something of substance.

Review the ISO 4217 standard to view a full list of official currency codes including the ones I have added.

https://www.iso.org/iso-4217-currency-codes.html
https://en.wikipedia.org/wiki/ISO_4217

Example:
https://www.xe.com/currencyconverter/convert/?Amount=100&From=XAG&To=USD

API for exchange rates:
https://openexchangerates.org/

* Added field values xag and xau to group.go

* Update group.go
2023-08-23 09:29:22 -08: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
230 changed files with 8588 additions and 23683 deletions

View File

@@ -35,6 +35,6 @@
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "node",
"features": {
"golang": "1.21"
"golang": "1.20"
}
}

View File

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

View File

@@ -13,13 +13,9 @@ jobs:
with:
fetch-depth: 0
- uses: actions/setup-node@v4
- uses: pnpm/action-setup@v2.4.0
with:
node-version: 20
- uses: pnpm/action-setup@v3.0.0
with:
version: 9
version: 6.0.2
- name: Install dependencies
run: pnpm install --shamefully-hoist
@@ -48,20 +44,20 @@ jobs:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v4
with:
go-version: "1.22"
go-version: "1.20"
- uses: actions/setup-node@v4
with:
node-version: 20
node-version: 18
- uses: pnpm/action-setup@v3.0.0
- uses: pnpm/action-setup@v2.4.0
with:
version: 9
version: 6.0.2
- name: Install dependencies
run: pnpm install --shamefully-hoist
run: pnpm install
working-directory: frontend
- name: Run Integration Tests

View File

@@ -22,7 +22,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v4
with:
go-version: "1.20"

View File

@@ -27,7 +27,7 @@ jobs:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v4
- uses: pnpm/action-setup@v2
with:

3
.gitignore vendored
View File

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

View File

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

View File

@@ -32,7 +32,7 @@ FROM alpine:latest
ENV HBOX_MODE=production
ENV HBOX_STORAGE_DATA=/data/
ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_pragma=busy_timeout=2000&_pragma=journal_mode=WAL&_fk=1
ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_fk=1
RUN apk --no-cache add ca-certificates
RUN mkdir /app

View File

@@ -30,14 +30,6 @@ docker run -d \
# 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
- Logo by [@lakotelman](https://github.com/lakotelman)

View File

@@ -1,15 +1,9 @@
version: "3"
env:
HBOX_LOG_LEVEL: debug
HBOX_STORAGE_SQLITE_URL: .data/homebox.db?_pragma=busy_timeout=1000&_pragma=journal_mode=WAL&_fk=1
HBOX_OPTIONS_ALLOW_REGISTRATION: true
UNSAFE_DISABLE_PASSWORD_PROJECTION: "yes_i_am_sure"
HBOX_MAILER_HOST: 127.0.0.1
HBOX_MAILER_PORT: 1025
HBOX_MAILER_USERNAME: c836555d57d205
HBOX_MAILER_PASSWORD: 3ff2f9986f3cff
HBOX_MAILER_FROM: info@example.com
tasks:
setup:
desc: Install development dependencies
@@ -84,12 +78,6 @@ tasks:
cmds:
- go mod tidy
go:fmt:
desc: Runs go fmt on the backend
dir: backend
cmds:
- gofumpt -w .
go:lint:
desc: Runs golangci-lint
dir: backend
@@ -114,7 +102,8 @@ tasks:
dir: backend/internal/
cmds:
- |
go generate ./...
go generate ./... \
--template=./data/ent/schema/templates/has_id.tmpl
sources:
- "./backend/internal/data/ent/schema/**/*"

View File

@@ -1,77 +0,0 @@
run:
timeout: 10m
linters-settings:
errcheck:
exclude-functions:
- (net/http.ResponseWriter).Write
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: false
exclude-dirs:
- internal/data/ent.*

BIN
backend/api Executable file

Binary file not shown.

View File

@@ -1,18 +1,22 @@
package main
import (
"time"
"github.com/hay-kot/homebox/backend/internal/core/services"
"github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus"
"github.com/hay-kot/homebox/backend/internal/data/ent"
"github.com/hay-kot/homebox/backend/internal/data/repo"
"github.com/hay-kot/homebox/backend/internal/sys/config"
"github.com/hay-kot/homebox/backend/pkgs/mailer"
"github.com/hay-kot/httpkit/server"
)
type app struct {
conf *config.Config
mailer *mailer.Mailer
mailer mailer.Mailer
db *ent.Client
server *server.Server
repos *repo.AllRepos
services *services.AllServices
bus *eventbus.EventBus
@@ -23,7 +27,7 @@ func new(conf *config.Config) *app {
conf: conf,
}
s.mailer = &mailer.Mailer{
s.mailer = mailer.Mailer{
Host: s.conf.Mailer.Host,
Port: s.conf.Mailer.Port,
Username: s.conf.Mailer.Username,
@@ -33,3 +37,13 @@ func new(conf *config.Config) *app {
return s
}
func (a *app) startBgTask(t time.Duration, fn func()) {
timer := time.NewTimer(t)
for {
timer.Reset(t)
a.server.Background(fn)
<-timer.C
}
}

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

View File

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

View File

@@ -1,10 +1,8 @@
// Package v1 provides the API handlers for version 1 of the API.
package v1
import (
"encoding/json"
"fmt"
"net/http"
"time"
"github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/core/services"
@@ -76,7 +74,7 @@ type (
BuildTime string `json:"buildTime"`
}
APISummary struct {
ApiSummary struct {
Healthy bool `json:"health"`
Versions []string `json:"versions"`
Title string `json:"title"`
@@ -87,7 +85,7 @@ type (
}
)
func BaseURLFunc(prefix string) func(s string) string {
func BaseUrlFunc(prefix string) func(s string) string {
return func(s string) string {
return prefix + "/v1" + s
}
@@ -113,11 +111,11 @@ func NewControllerV1(svc *services.AllServices, repos *repo.AllRepos, bus *event
// @Summary Application Info
// @Tags Base
// @Produce json
// @Success 200 {object} APISummary
// @Success 200 {object} ApiSummary
// @Router /v1/status [GET]
func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) errchain.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
return server.JSON(w, http.StatusOK, APISummary{
return server.JSON(w, http.StatusOK, ApiSummary{
Healthy: ready(),
Title: "Homebox",
Message: "Track, Manage, and Organize your Things",
@@ -128,32 +126,12 @@ func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) errchain.Hand
}
}
// HandleCurrency godoc
//
// @Summary Currency
// @Tags Base
// @Produce json
// @Success 200 {object} currencies.Currency
// @Router /v1/currency [GET]
func (ctrl *V1Controller) HandleCurrency() errchain.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
// Set Cache for 10 Minutes
w.Header().Set("Cache-Control", "max-age=600")
return server.JSON(w, http.StatusOK, ctrl.svc.Currencies.Slice())
}
}
func (ctrl *V1Controller) HandleCacheWS() errchain.HandlerFunc {
type eventMsg struct {
Event string `json:"event"`
}
m := melody.New()
m.HandleConnect(func(s *melody.Session) {
auth := services.NewContext(s.Request.Context())
s.Set("gid", auth.GroupID)
s.Set("gid", auth.GID)
})
factory := func(e string) func(data any) {
@@ -164,15 +142,9 @@ func (ctrl *V1Controller) HandleCacheWS() errchain.HandlerFunc {
return
}
msg := &eventMsg{Event: e}
jsonStr := fmt.Sprintf(`{"event": "%s"}`, e)
jsonBytes, err := json.Marshal(msg)
if err != nil {
log.Log().Msgf("error marshling event data %v: %v", data, err)
return
}
_ = m.BroadcastFilter(jsonBytes, func(s *melody.Session) bool {
_ = m.BroadcastFilter([]byte(jsonStr), func(s *melody.Session) bool {
groupIDStr, ok := s.Get("gid")
if !ok {
return false
@@ -188,25 +160,6 @@ func (ctrl *V1Controller) HandleCacheWS() errchain.HandlerFunc {
ctrl.bus.Subscribe(eventbus.EventLocationMutation, factory("location.mutation"))
ctrl.bus.Subscribe(eventbus.EventItemMutation, factory("item.mutation"))
// Persistent asynchronous ticker that keeps all websocket connections alive with periodic pings.
go func() {
const interval = 10 * time.Second
ping := time.NewTicker(interval)
defer ping.Stop()
for range ping.C {
msg := &eventMsg{Event: "ping"}
pingBytes, err := json.Marshal(msg)
if err != nil {
log.Log().Msgf("error marshaling ping: %v", err)
} else {
_ = m.Broadcast(pingBytes)
}
}
}()
return func(w http.ResponseWriter, r *http.Request) error {
return m.HandleRequest(w, r)
}

View File

@@ -20,7 +20,7 @@ func actionHandlerFactory(ref string, fn func(context.Context, uuid.UUID) (int,
return func(w http.ResponseWriter, r *http.Request) error {
ctx := services.NewContext(r.Context())
totalCompleted, err := fn(ctx, ctx.GroupID)
totalCompleted, err := fn(ctx, ctx.GID)
if err != nil {
log.Err(err).Str("action_ref", ref).Msg("failed to run action")
return validate.NewRequestError(err, http.StatusInternalServerError)

View File

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

View File

@@ -58,25 +58,6 @@ func GetCookies(r *http.Request) (*CookieContents, error) {
}, nil
}
// AuthProvider is an interface that can be implemented by any authentication provider.
// to extend authentication methods for the API.
type AuthProvider interface {
// Name returns the name of the authentication provider. This should be a unique name.
// that is URL friendly.
//
// Example: "local", "ldap"
Name() string
// Authenticate is called when a user attempts to login to the API. The implementation
// should return an error if the user cannot be authenticated. If an error is returned
// the API controller will return a vague error message to the user.
//
// Authenticate should do the following:
//
// 1. Ensure that the user exists within the database (either create, or get)
// 2. On successful authentication, they must set the user cookies.
Authenticate(w http.ResponseWriter, r *http.Request) (services.UserAuthTokenDetail, error)
}
// HandleAuthLogin godoc
//
// @Summary User Login
@@ -85,42 +66,53 @@ type AuthProvider interface {
// @Accept application/json
// @Param username formData string false "string" example(admin@admin.com)
// @Param password formData string false "string" example(admin)
// @Param payload body LoginForm true "Login Data"
// @Param provider query string false "auth provider"
// @Param payload body LoginForm true "Login Data"
// @Produce json
// @Success 200 {object} TokenResponse
// @Router /v1/users/login [POST]
func (ctrl *V1Controller) HandleAuthLogin(ps ...AuthProvider) errchain.HandlerFunc {
if len(ps) == 0 {
panic("no auth providers provided")
}
providers := make(map[string]AuthProvider)
for _, p := range ps {
log.Info().Str("name", p.Name()).Msg("registering auth provider")
providers[p.Name()] = p
}
func (ctrl *V1Controller) HandleAuthLogin() errchain.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
// Extract provider query
provider := r.URL.Query().Get("provider")
if provider == "" {
provider = "local"
loginForm := &LoginForm{}
switch r.Header.Get("Content-Type") {
case "application/x-www-form-urlencoded":
err := r.ParseForm()
if err != nil {
return errors.New("failed to parse form")
}
loginForm.Username = r.PostFormValue("username")
loginForm.Password = r.PostFormValue("password")
loginForm.StayLoggedIn = r.PostFormValue("stayLoggedIn") == "true"
case "application/json":
err := server.Decode(r, loginForm)
if err != nil {
log.Err(err).Msg("failed to decode login form")
return errors.New("failed to decode login form")
}
default:
return server.JSON(w, http.StatusBadRequest, errors.New("invalid content type"))
}
// Get the provider
p, ok := providers[provider]
if !ok {
return validate.NewRequestError(errors.New("invalid auth provider"), http.StatusBadRequest)
if loginForm.Username == "" || loginForm.Password == "" {
return validate.NewFieldErrors(
validate.FieldError{
Field: "username",
Error: "username or password is empty",
},
validate.FieldError{
Field: "password",
Error: "username or password is empty",
},
)
}
newToken, err := p.Authenticate(w, r)
newToken, err := ctrl.svc.User.Login(r.Context(), strings.ToLower(loginForm.Username), loginForm.Password, loginForm.StayLoggedIn)
if err != nil {
log.Err(err).Msg("failed to authenticate")
return server.JSON(w, http.StatusInternalServerError, err.Error())
return validate.NewRequestError(errors.New("authentication failed"), http.StatusInternalServerError)
}
ctrl.setCookies(w, noPort(r.Host), newToken.Raw, newToken.ExpiresAt, true)
ctrl.setCookies(w, noPort(r.Host), newToken.Raw, newToken.ExpiresAt, loginForm.StayLoggedIn)
return server.JSON(w, http.StatusOK, TokenResponse{
Token: "Bearer " + newToken.Raw,
ExpiresAt: newToken.ExpiresAt,
@@ -153,7 +145,7 @@ func (ctrl *V1Controller) HandleAuthLogout() errchain.HandlerFunc {
}
}
// HandleAuthRefresh godoc
// HandleAuthLogout godoc
//
// @Summary User Token Refresh
// @Description handleAuthRefresh returns a handler that will issue a new token from an existing token.

View File

@@ -6,14 +6,13 @@ import (
"github.com/hay-kot/homebox/backend/internal/core/services"
"github.com/hay-kot/homebox/backend/internal/data/repo"
"github.com/hay-kot/homebox/backend/internal/sys/validate"
"github.com/hay-kot/homebox/backend/internal/web/adapters"
"github.com/hay-kot/httpkit/errchain"
)
type (
GroupInvitationCreate struct {
Uses int `json:"uses" validate:"required,min=1,max=100"`
Uses int `json:"uses" validate:"required,min=1,max=100"`
ExpiresAt time.Time `json:"expiresAt"`
}
@@ -35,7 +34,7 @@ type (
func (ctrl *V1Controller) HandleGroupGet() errchain.HandlerFunc {
fn := func(r *http.Request) (repo.Group, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.Groups.GroupByID(auth, auth.GroupID)
return ctrl.repo.Groups.GroupByID(auth, auth.GID)
}
return adapters.Command(fn, http.StatusOK)
@@ -53,14 +52,6 @@ func (ctrl *V1Controller) HandleGroupGet() errchain.HandlerFunc {
func (ctrl *V1Controller) HandleGroupUpdate() errchain.HandlerFunc {
fn := func(r *http.Request, body repo.GroupUpdate) (repo.Group, error) {
auth := services.NewContext(r.Context())
ok := ctrl.svc.Currencies.IsSupported(body.Currency)
if !ok {
return repo.Group{}, validate.NewFieldErrors(
validate.NewFieldError("currency", "currency '"+body.Currency+"' is not supported"),
)
}
return ctrl.svc.Group.UpdateGroup(auth, body)
}

View File

@@ -27,7 +27,7 @@ import (
// @Param pageSize query int false "items per page"
// @Param labels query []string false "label Ids" collectionFormat(multi)
// @Param locations query []string false "location Ids" collectionFormat(multi)
// @Param parentIds query []string false "parent Ids" collectionFormat(multi)
// @Param parentIds query []string false "parent Ids" collectionFormat(multi)
// @Success 200 {object} repo.PaginationResult[repo.ItemSummary]{}
// @Router /v1/items [GET]
// @Security Bearer
@@ -57,7 +57,7 @@ func (ctrl *V1Controller) HandleItemsGetAll() errchain.HandlerFunc {
Search: params.Get("q"),
LocationIDs: queryUUIDList(params, "locations"),
LabelIDs: queryUUIDList(params, "labels"),
ParentItemIDs: queryUUIDList(params, "parentIds"),
ParentItemIDs: queryUUIDList(params, "parentIds"),
IncludeArchived: queryBool(params.Get("includeArchived")),
Fields: filterFieldItems(params["fields"]),
OrderBy: params.Get("orderBy"),
@@ -79,7 +79,7 @@ func (ctrl *V1Controller) HandleItemsGetAll() errchain.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
ctx := services.NewContext(r.Context())
items, err := ctrl.repo.Items.QueryByGroup(ctx, ctx.GroupID, extractQuery(r))
items, err := ctrl.repo.Items.QueryByGroup(ctx, ctx.GID, extractQuery(r))
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return server.JSON(w, http.StatusOK, repo.PaginationResult[repo.ItemSummary]{
@@ -93,48 +93,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.GroupID, ID)
if err != nil {
return nil, err
}
paths, err := ctrl.repo.Locations.PathForLoc(auth, auth.GroupID, item.Location.ID)
if err != nil {
return nil, err
}
if item.Parent != nil {
paths = append(paths, repo.ItemPath{
Type: repo.ItemTypeItem,
ID: item.Parent.ID,
Name: item.Parent.Name,
})
}
paths = append(paths, repo.ItemPath{
Type: repo.ItemTypeItem,
ID: item.ID,
Name: item.Name,
})
return paths, nil
}
return adapters.CommandID("id", fn, http.StatusOK)
}
// HandleItemsCreate godoc
//
// @Summary Create Item
@@ -165,7 +123,7 @@ func (ctrl *V1Controller) HandleItemGet() errchain.HandlerFunc {
fn := func(r *http.Request, ID uuid.UUID) (repo.ItemOut, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.Items.GetOneByGroup(auth, auth.GroupID, ID)
return ctrl.repo.Items.GetOneByGroup(auth, auth.GID, ID)
}
return adapters.CommandID("id", fn, http.StatusOK)
@@ -183,7 +141,7 @@ func (ctrl *V1Controller) HandleItemGet() errchain.HandlerFunc {
func (ctrl *V1Controller) HandleItemDelete() errchain.HandlerFunc {
fn := func(r *http.Request, ID uuid.UUID) (any, error) {
auth := services.NewContext(r.Context())
err := ctrl.repo.Items.DeleteByGroup(auth, auth.GroupID, ID)
err := ctrl.repo.Items.DeleteByGroup(auth, auth.GID, ID)
return nil, err
}
@@ -205,7 +163,7 @@ func (ctrl *V1Controller) HandleItemUpdate() errchain.HandlerFunc {
auth := services.NewContext(r.Context())
body.ID = ID
return ctrl.repo.Items.UpdateByGroup(auth, auth.GroupID, body)
return ctrl.repo.Items.UpdateByGroup(auth, auth.GID, body)
}
return adapters.ActionID("id", fn, http.StatusOK)
@@ -226,12 +184,12 @@ func (ctrl *V1Controller) HandleItemPatch() errchain.HandlerFunc {
auth := services.NewContext(r.Context())
body.ID = ID
err := ctrl.repo.Items.Patch(auth, auth.GroupID, ID, body)
err := ctrl.repo.Items.Patch(auth, auth.GID, ID, body)
if err != nil {
return repo.ItemOut{}, err
}
return ctrl.repo.Items.GetOneByGroup(auth, auth.GroupID, ID)
return ctrl.repo.Items.GetOneByGroup(auth, auth.GID, ID)
}
return adapters.ActionID("id", fn, http.StatusOK)
@@ -249,7 +207,7 @@ func (ctrl *V1Controller) HandleItemPatch() errchain.HandlerFunc {
func (ctrl *V1Controller) HandleGetAllCustomFieldNames() errchain.HandlerFunc {
fn := func(r *http.Request) ([]string, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.Items.GetAllCustomFieldNames(auth, auth.GroupID)
return ctrl.repo.Items.GetAllCustomFieldNames(auth, auth.GID)
}
return adapters.Command(fn, http.StatusOK)
@@ -271,10 +229,11 @@ func (ctrl *V1Controller) HandleGetAllCustomFieldValues() errchain.HandlerFunc {
fn := func(r *http.Request, q query) ([]string, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.Items.GetAllCustomFieldValues(auth, auth.GroupID, q.Field)
return ctrl.repo.Items.GetAllCustomFieldValues(auth, auth.GID, q.Field)
}
return adapters.Query(fn, http.StatusOK)
}
// HandleItemsImport godocs
@@ -323,7 +282,7 @@ func (ctrl *V1Controller) HandleItemsExport() errchain.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
ctx := services.NewContext(r.Context())
csvData, err := ctrl.svc.Items.ExportTSV(r.Context(), ctx.GroupID)
csvData, err := ctrl.svc.Items.ExportTSV(r.Context(), ctx.GID)
if err != nil {
log.Err(err).Msg("failed to export items")
return validate.NewRequestError(err, http.StatusInternalServerError)

View File

@@ -4,7 +4,6 @@ import (
"errors"
"net/http"
"path/filepath"
"strings"
"github.com/hay-kot/homebox/backend/internal/core/services"
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
@@ -40,6 +39,7 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() errchain.HandlerFunc {
if err != nil {
log.Err(err).Msg("failed to parse multipart form")
return validate.NewRequestError(errors.New("failed to parse multipart form"), http.StatusBadRequest)
}
errs := validate.NewFieldErrors()
@@ -71,7 +71,7 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() errchain.HandlerFunc {
// Attempt to auto-detect the type of the file
ext := filepath.Ext(attachmentName)
switch strings.ToLower(ext) {
switch ext {
case ".jpg", ".jpeg", ".png", ".webp", ".gif", ".bmp", ".tiff":
attachmentType = attachment.TypePhoto.String()
default:
@@ -168,7 +168,7 @@ func (ctrl *V1Controller) handleItemAttachmentsHandler(w http.ResponseWriter, r
// Delete Attachment Handler
case http.MethodDelete:
err = ctrl.svc.Items.AttachmentDelete(r.Context(), ctx.GroupID, ID, attachmentID)
err = ctrl.svc.Items.AttachmentDelete(r.Context(), ctx.GID, ID, attachmentID)
if err != nil {
log.Err(err).Msg("failed to delete attachment")
return validate.NewRequestError(err, http.StatusInternalServerError)

View File

@@ -21,7 +21,7 @@ import (
func (ctrl *V1Controller) HandleLabelsGetAll() errchain.HandlerFunc {
fn := func(r *http.Request) ([]repo.LabelSummary, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.Labels.GetAll(auth, auth.GroupID)
return ctrl.repo.Labels.GetAll(auth, auth.GID)
}
return adapters.Command(fn, http.StatusOK)
@@ -39,7 +39,7 @@ func (ctrl *V1Controller) HandleLabelsGetAll() errchain.HandlerFunc {
func (ctrl *V1Controller) HandleLabelsCreate() errchain.HandlerFunc {
fn := func(r *http.Request, data repo.LabelCreate) (repo.LabelOut, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.Labels.Create(auth, auth.GroupID, data)
return ctrl.repo.Labels.Create(auth, auth.GID, data)
}
return adapters.Action(fn, http.StatusCreated)
@@ -57,7 +57,7 @@ func (ctrl *V1Controller) HandleLabelsCreate() errchain.HandlerFunc {
func (ctrl *V1Controller) HandleLabelDelete() errchain.HandlerFunc {
fn := func(r *http.Request, ID uuid.UUID) (any, error) {
auth := services.NewContext(r.Context())
err := ctrl.repo.Labels.DeleteByGroup(auth, auth.GroupID, ID)
err := ctrl.repo.Labels.DeleteByGroup(auth, auth.GID, ID)
return nil, err
}
@@ -76,7 +76,7 @@ func (ctrl *V1Controller) HandleLabelDelete() errchain.HandlerFunc {
func (ctrl *V1Controller) HandleLabelGet() errchain.HandlerFunc {
fn := func(r *http.Request, ID uuid.UUID) (repo.LabelOut, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.Labels.GetOneByGroup(auth, auth.GroupID, ID)
return ctrl.repo.Labels.GetOneByGroup(auth, auth.GID, ID)
}
return adapters.CommandID("id", fn, http.StatusOK)
@@ -95,7 +95,7 @@ func (ctrl *V1Controller) HandleLabelUpdate() errchain.HandlerFunc {
fn := func(r *http.Request, ID uuid.UUID, data repo.LabelUpdate) (repo.LabelOut, error) {
auth := services.NewContext(r.Context())
data.ID = ID
return ctrl.repo.Labels.UpdateByGroup(auth, auth.GroupID, data)
return ctrl.repo.Labels.UpdateByGroup(auth, auth.GID, data)
}
return adapters.ActionID("id", fn, http.StatusOK)

View File

@@ -10,7 +10,7 @@ import (
"github.com/hay-kot/httpkit/errchain"
)
// HandleLocationTreeQuery godoc
// HandleLocationTreeQuery
//
// @Summary Get Locations Tree
// @Tags Locations
@@ -22,13 +22,13 @@ import (
func (ctrl *V1Controller) HandleLocationTreeQuery() errchain.HandlerFunc {
fn := func(r *http.Request, query repo.TreeQuery) ([]repo.TreeItem, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.Locations.Tree(auth, auth.GroupID, query)
return ctrl.repo.Locations.Tree(auth, auth.GID, query)
}
return adapters.Query(fn, http.StatusOK)
}
// HandleLocationGetAll godoc
// HandleLocationGetAll
//
// @Summary Get All Locations
// @Tags Locations
@@ -40,13 +40,13 @@ func (ctrl *V1Controller) HandleLocationTreeQuery() errchain.HandlerFunc {
func (ctrl *V1Controller) HandleLocationGetAll() errchain.HandlerFunc {
fn := func(r *http.Request, q repo.LocationQuery) ([]repo.LocationOutCount, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.Locations.GetAll(auth, auth.GroupID, q)
return ctrl.repo.Locations.GetAll(auth, auth.GID, q)
}
return adapters.Query(fn, http.StatusOK)
}
// HandleLocationCreate godoc
// HandleLocationCreate
//
// @Summary Create Location
// @Tags Locations
@@ -58,13 +58,13 @@ func (ctrl *V1Controller) HandleLocationGetAll() errchain.HandlerFunc {
func (ctrl *V1Controller) HandleLocationCreate() errchain.HandlerFunc {
fn := func(r *http.Request, createData repo.LocationCreate) (repo.LocationOut, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.Locations.Create(auth, auth.GroupID, createData)
return ctrl.repo.Locations.Create(auth, auth.GID, createData)
}
return adapters.Action(fn, http.StatusCreated)
}
// HandleLocationDelete godoc
// HandleLocationDelete
//
// @Summary Delete Location
// @Tags Locations
@@ -76,14 +76,14 @@ func (ctrl *V1Controller) HandleLocationCreate() errchain.HandlerFunc {
func (ctrl *V1Controller) HandleLocationDelete() errchain.HandlerFunc {
fn := func(r *http.Request, ID uuid.UUID) (any, error) {
auth := services.NewContext(r.Context())
err := ctrl.repo.Locations.DeleteByGroup(auth, auth.GroupID, ID)
err := ctrl.repo.Locations.DeleteByGroup(auth, auth.GID, ID)
return nil, err
}
return adapters.CommandID("id", fn, http.StatusNoContent)
}
// HandleLocationGet godoc
// HandleLocationGet
//
// @Summary Get Location
// @Tags Locations
@@ -95,13 +95,13 @@ func (ctrl *V1Controller) HandleLocationDelete() errchain.HandlerFunc {
func (ctrl *V1Controller) HandleLocationGet() errchain.HandlerFunc {
fn := func(r *http.Request, ID uuid.UUID) (repo.LocationOut, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.Locations.GetOneByGroup(auth, auth.GroupID, ID)
return ctrl.repo.Locations.GetOneByGroup(auth, auth.GID, ID)
}
return adapters.CommandID("id", fn, http.StatusOK)
}
// HandleLocationUpdate godoc
// HandleLocationUpdate
//
// @Summary Update Location
// @Tags Locations
@@ -115,7 +115,7 @@ func (ctrl *V1Controller) HandleLocationUpdate() errchain.HandlerFunc {
fn := func(r *http.Request, ID uuid.UUID, body repo.LocationUpdate) (repo.LocationOut, error) {
auth := services.NewContext(r.Context())
body.ID = ID
return ctrl.repo.Locations.UpdateByGroup(auth, auth.GroupID, ID, body)
return ctrl.repo.Locations.UpdateByGroup(auth, auth.GID, ID, body)
}
return adapters.ActionID("id", fn, http.StatusOK)

View File

@@ -10,7 +10,7 @@ import (
"github.com/hay-kot/httpkit/errchain"
)
// HandleMaintenanceLogGet godoc
// HandleMaintenanceGetLog godoc
//
// @Summary Get Maintenance Log
// @Tags Maintenance
@@ -21,7 +21,7 @@ import (
func (ctrl *V1Controller) HandleMaintenanceLogGet() errchain.HandlerFunc {
fn := func(r *http.Request, ID uuid.UUID, q repo.MaintenanceLogQuery) (repo.MaintenanceLog, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.MaintEntry.GetLog(auth, auth.GroupID, ID, q)
return ctrl.repo.MaintEntry.GetLog(auth, auth.GID, ID, q)
}
return adapters.QueryID("id", fn, http.StatusOK)

View File

@@ -40,7 +40,7 @@ func (ctrl *V1Controller) HandleGetUserNotifiers() errchain.HandlerFunc {
func (ctrl *V1Controller) HandleCreateNotifier() errchain.HandlerFunc {
fn := func(r *http.Request, in repo.NotifierCreate) (repo.NotifierOut, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.Notifiers.Create(auth, auth.GroupID, auth.UserID, in)
return ctrl.repo.Notifiers.Create(auth, auth.GID, auth.UID, in)
}
return adapters.Action(fn, http.StatusCreated)
@@ -57,7 +57,7 @@ func (ctrl *V1Controller) HandleCreateNotifier() errchain.HandlerFunc {
func (ctrl *V1Controller) HandleDeleteNotifier() errchain.HandlerFunc {
fn := func(r *http.Request, ID uuid.UUID) (any, error) {
auth := services.NewContext(r.Context())
return nil, ctrl.repo.Notifiers.Delete(auth, auth.UserID, ID)
return nil, ctrl.repo.Notifiers.Delete(auth, auth.UID, ID)
}
return adapters.CommandID("id", fn, http.StatusNoContent)
@@ -75,7 +75,7 @@ func (ctrl *V1Controller) HandleDeleteNotifier() errchain.HandlerFunc {
func (ctrl *V1Controller) HandleUpdateNotifier() errchain.HandlerFunc {
fn := func(r *http.Request, ID uuid.UUID, in repo.NotifierUpdate) (repo.NotifierOut, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.Notifiers.Update(auth, auth.UserID, ID, in)
return ctrl.repo.Notifiers.Update(auth, auth.UID, ID, in)
}
return adapters.ActionID("id", fn, http.StatusOK)

View File

@@ -12,7 +12,7 @@ import (
"github.com/hay-kot/httpkit/server"
)
// HandleGroupStatisticsLocations godoc
// HandleGroupGet godoc
//
// @Summary Get Location Statistics
// @Tags Statistics
@@ -23,7 +23,7 @@ import (
func (ctrl *V1Controller) HandleGroupStatisticsLocations() errchain.HandlerFunc {
fn := func(r *http.Request) ([]repo.TotalsByOrganizer, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.Groups.StatsLocationsByPurchasePrice(auth, auth.GroupID)
return ctrl.repo.Groups.StatsLocationsByPurchasePrice(auth, auth.GID)
}
return adapters.Command(fn, http.StatusOK)
@@ -40,7 +40,7 @@ func (ctrl *V1Controller) HandleGroupStatisticsLocations() errchain.HandlerFunc
func (ctrl *V1Controller) HandleGroupStatisticsLabels() errchain.HandlerFunc {
fn := func(r *http.Request) ([]repo.TotalsByOrganizer, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.Groups.StatsLabelsByPurchasePrice(auth, auth.GroupID)
return ctrl.repo.Groups.StatsLabelsByPurchasePrice(auth, auth.GID)
}
return adapters.Command(fn, http.StatusOK)
@@ -57,7 +57,7 @@ func (ctrl *V1Controller) HandleGroupStatisticsLabels() errchain.HandlerFunc {
func (ctrl *V1Controller) HandleGroupStatistics() errchain.HandlerFunc {
fn := func(r *http.Request) (repo.GroupStatistics, error) {
auth := services.NewContext(r.Context())
return ctrl.repo.Groups.StatsGroup(auth, auth.GroupID)
return ctrl.repo.Groups.StatsGroup(auth, auth.GID)
}
return adapters.Command(fn, http.StatusOK)
@@ -94,7 +94,7 @@ func (ctrl *V1Controller) HandleGroupStatisticsPriceOverTime() errchain.HandlerF
return validate.NewRequestError(err, http.StatusBadRequest)
}
stats, err := ctrl.repo.Groups.StatsPurchasePrice(ctx, ctx.GroupID, startDate, endDate)
stats, err := ctrl.repo.Groups.StatsPurchasePrice(ctx, ctx.GID, startDate, endDate)
if err != nil {
return validate.NewRequestError(err, http.StatusInternalServerError)
}

View File

@@ -1,7 +1,6 @@
package v1
import (
"context"
"fmt"
"net/http"
@@ -9,7 +8,6 @@ import (
"github.com/hay-kot/homebox/backend/internal/core/services"
"github.com/hay-kot/homebox/backend/internal/data/repo"
"github.com/hay-kot/homebox/backend/internal/sys/validate"
"github.com/hay-kot/homebox/backend/internal/web/adapters"
"github.com/hay-kot/httpkit/errchain"
"github.com/hay-kot/httpkit/server"
"github.com/rs/zerolog/log"
@@ -117,10 +115,12 @@ func (ctrl *V1Controller) HandleUserSelfDelete() errchain.HandlerFunc {
}
}
type ChangePassword struct {
Current string `json:"current,omitempty"`
New string `json:"new,omitempty"`
}
type (
ChangePassword struct {
Current string `json:"current,omitempty"`
New string `json:"new,omitempty"`
}
)
// HandleUserSelfChangePassword godoc
//
@@ -144,7 +144,7 @@ func (ctrl *V1Controller) HandleUserSelfChangePassword() errchain.HandlerFunc {
ctx := services.NewContext(r.Context())
ok := ctrl.svc.User.PasswordChange(ctx, cp.Current, cp.New)
ok := ctrl.svc.User.ChangePassword(ctx, cp.Current, cp.New)
if !ok {
return validate.NewRequestError(err, http.StatusInternalServerError)
}
@@ -152,73 +152,3 @@ func (ctrl *V1Controller) HandleUserSelfChangePassword() errchain.HandlerFunc {
return server.JSON(w, http.StatusNoContent, nil)
}
}
// HandleUserSelfChangePasswordWithToken godoc
//
// @Summary Change Password
// @Tags User
// @Success 204
// @Param payload body ChangePassword true "Password Payload"
// @Router /v1/users/change-password-token [PUT]
func (ctrl *V1Controller) HandleUserSelfChangePasswordWithToken() errchain.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
tokenQueryParam := r.URL.Query().Get("token")
if tokenQueryParam == "" {
return validate.NewRequestError(fmt.Errorf("missing token query param"), http.StatusBadRequest)
}
if ctrl.isDemo {
return validate.NewRequestError(nil, http.StatusForbidden)
}
var cp ChangePassword
err := server.Decode(r, &cp)
if err != nil {
log.Err(err).Msg("user failed to change password")
}
ctx := services.NewContext(r.Context())
ok := ctrl.svc.User.PasswordChange(ctx, cp.Current, cp.New)
if !ok {
return validate.NewRequestError(err, http.StatusInternalServerError)
}
return server.JSON(w, http.StatusNoContent, nil)
}
}
// HandleUserRequestPasswordReset godoc
//
// @Summary Request Password Reset
// @Tags User
// @Produce json
// @Param payload body services.PasswordResetRequest true "User Data"
// @Success 204
// @Router /v1/users/request-password-reset [Post]
func (ctrl *V1Controller) HandleUserRequestPasswordReset() errchain.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
if ctrl.isDemo {
return validate.NewRequestError(nil, http.StatusForbidden)
}
v, err := adapters.DecodeBody[services.PasswordResetRequest](r)
if err != nil {
return err
}
go func() {
ctx := context.Background()
err = ctrl.svc.User.PasswordResetRequest(ctx, v)
if err != nil {
log.Warn().
Err(err).
Str("email", v.Email).
Msg("failed to request password reset")
}
}()
return server.JSON(w, http.StatusNoContent, nil)
}
}

View File

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

View File

@@ -1,7 +1,6 @@
package main
import (
"bytes"
"context"
"fmt"
"net/http"
@@ -14,7 +13,6 @@ import (
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/hay-kot/homebox/backend/internal/core/currencies"
"github.com/hay-kot/homebox/backend/internal/core/services"
"github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus"
"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/web/mid"
"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/log"
"github.com/rs/zerolog/pkgerrors"
@@ -80,12 +78,12 @@ func run(cfg *config.Config) error {
log.Fatal().Err(err).Msg("failed to create data directory")
}
c, err := ent.Open("sqlite3", cfg.Storage.SqliteURL)
c, err := ent.Open("sqlite3", cfg.Storage.SqliteUrl)
if err != nil {
log.Fatal().
Err(err).
Str("driver", "sqlite").
Str("url", cfg.Storage.SqliteURL).
Str("url", cfg.Storage.SqliteUrl).
Msg("failed opening connection to sqlite")
}
defer func(c *ent.Client) {
@@ -115,11 +113,11 @@ func run(cfg *config.Config) error {
err = c.Schema.Create(context.Background(), options...)
if err != nil {
log.Fatal(). // nolint
Err(err).
Str("driver", "sqlite").
Str("url", cfg.Storage.SqliteURL).
Msg("failed creating schema resources")
log.Fatal().
Err(err).
Str("driver", "sqlite").
Str("url", cfg.Storage.SqliteUrl).
Msg("failed creating schema resources")
}
err = os.RemoveAll(temp)
@@ -128,42 +126,12 @@ func run(cfg *config.Config) error {
return err
}
collectFuncs := []currencies.CollectorFunc{
currencies.CollectDefaults(),
}
if cfg.Options.CurrencyConfig != "" {
log.Info().
Str("path", cfg.Options.CurrencyConfig).
Msg("loading currency config file")
content, err := os.ReadFile(cfg.Options.CurrencyConfig)
if err != nil {
log.Fatal().
Err(err).
Str("path", cfg.Options.CurrencyConfig).
Msg("failed to read currency config file")
}
collectFuncs = append(collectFuncs, currencies.CollectJSON(bytes.NewReader(content)))
}
currencies, err := currencies.CollectionCurrencies(collectFuncs...)
if err != nil {
log.Fatal().
Err(err).
Msg("failed to collect currencies")
}
app.bus = eventbus.New()
app.db = c
app.repos = repo.New(c, app.bus, cfg.Storage.Data)
app.services = services.New(
app.repos,
app.conf.BaseURL,
app.mailer,
services.WithAutoIncrementAssetID(cfg.Options.AutoIncrementAssetID),
services.WithCurrencies(currencies),
)
// =========================================================================
@@ -180,63 +148,41 @@ func run(cfg *config.Config) error {
middleware.StripSlashes,
)
chain := errchain.New(mid.Errors(logger))
chain := errchain.New(mid.Errors(app.server, logger))
app.mountRoutes(router, chain)
app.mountRoutes(router, chain, app.repos)
runner := graceful.NewRunner()
runner.AddFunc("server", func(ctx context.Context) error {
httpserver := http.Server{
Addr: fmt.Sprintf("%s:%s", cfg.Web.Host, cfg.Web.Port),
Handler: router,
ReadTimeout: cfg.Web.ReadTimeout,
WriteTimeout: cfg.Web.WriteTimeout,
IdleTimeout: cfg.Web.IdleTimeout,
}
go func() {
<-ctx.Done()
_ = httpserver.Shutdown(context.Background())
}()
log.Info().Msgf("Server is running on %s:%s", cfg.Web.Host, cfg.Web.Port)
return httpserver.ListenAndServe()
})
app.server = server.NewServer(
server.WithHost(app.conf.Web.Host),
server.WithPort(app.conf.Web.Port),
server.WithReadTimeout(app.conf.Web.ReadTimeout),
server.WithWriteTimeout(app.conf.Web.WriteTimeout),
server.WithIdleTimeout(app.conf.Web.IdleTimeout),
)
log.Info().Msgf("Starting HTTP Server on %s:%s", app.server.Host, app.server.Port)
// =========================================================================
// Start Reoccurring Tasks
runner.AddFunc("eventbus", app.bus.Run)
go app.bus.Run()
runner.AddFunc("seed_database", func(ctx context.Context) error {
// TODO: Remove through external API that does setup
if cfg.Demo {
log.Info().Msg("Running in demo mode, creating demo data")
app.SetupDemo()
}
return nil
})
runner.AddPlugin(NewTask("purge-tokens", time.Duration(24)*time.Hour, func(ctx context.Context) {
_, err := app.repos.AuthTokens.PurgeExpiredTokens(ctx)
go app.startBgTask(time.Duration(24)*time.Hour, func() {
_, err := app.repos.AuthTokens.PurgeExpiredTokens(context.Background())
if err != nil {
log.Error().
Err(err).
Msg("failed to purge expired tokens")
}
}))
runner.AddPlugin(NewTask("purge-invitations", time.Duration(24)*time.Hour, func(ctx context.Context) {
_, err := app.repos.Groups.InvitationPurge(ctx)
})
go app.startBgTask(time.Duration(24)*time.Hour, func() {
_, err := app.repos.Groups.InvitationPurge(context.Background())
if err != nil {
log.Error().
Err(err).
Msg("failed to purge expired invitations")
}
}))
runner.AddPlugin(NewTask("send-notifications", time.Duration(1)*time.Hour, func(ctx context.Context) {
})
go app.startBgTask(time.Duration(1)*time.Hour, func() {
now := time.Now()
if now.Hour() == 8 {
@@ -248,27 +194,22 @@ func run(cfg *config.Config) error {
Msg("failed to send notifiers")
}
}
}))
})
if cfg.Debug.Enabled {
runner.AddFunc("debug", func(ctx context.Context) error {
debugserver := http.Server{
Addr: fmt.Sprintf("%s:%s", cfg.Web.Host, cfg.Debug.Port),
Handler: app.debugRouter(),
ReadTimeout: cfg.Web.ReadTimeout,
WriteTimeout: cfg.Web.WriteTimeout,
IdleTimeout: cfg.Web.IdleTimeout,
}
go func() {
<-ctx.Done()
_ = debugserver.Shutdown(context.Background())
}()
log.Info().Msgf("Debug server is running on %s:%s", cfg.Web.Host, cfg.Debug.Port)
return debugserver.ListenAndServe()
})
// TODO: Remove through external API that does setup
if cfg.Demo {
log.Info().Msg("Running in demo mode, creating demo data")
app.SetupDemo()
}
return runner.Start(context.Background())
if cfg.Debug.Enabled {
debugrouter := app.debugRouter()
go func() {
if err := http.ListenAndServe(":"+cfg.Debug.Port, debugrouter); err != nil {
log.Fatal().Err(err).Msg("failed to start debug server")
}
}()
}
return app.server.Start(router)
}

View File

@@ -9,7 +9,6 @@ import (
v1 "github.com/hay-kot/homebox/backend/app/api/handlers/v1"
"github.com/hay-kot/homebox/backend/internal/core/services"
"github.com/hay-kot/homebox/backend/internal/data/ent"
"github.com/hay-kot/homebox/backend/internal/sys/validate"
"github.com/hay-kot/httpkit/errchain"
)
@@ -131,7 +130,7 @@ func (a *app) mwAuthToken(next errchain.Handler) errchain.Handler {
}
if requestToken == "" {
return validate.NewRequestError(errors.New("authorization header or query is required"), http.StatusUnauthorized)
return validate.NewRequestError(errors.New("Authorization header or query is required"), http.StatusUnauthorized)
}
requestToken = strings.TrimPrefix(requestToken, "Bearer ")
@@ -141,11 +140,7 @@ func (a *app) mwAuthToken(next errchain.Handler) errchain.Handler {
usr, err := a.services.User.GetSelf(r.Context(), requestToken)
// Check the database for the token
if err != nil {
if ent.IsNotFound(err) {
return validate.NewRequestError(errors.New("valid authorization token is required"), http.StatusUnauthorized)
}
return err
return validate.NewRequestError(errors.New("valid authorization header is required"), http.StatusUnauthorized)
}
r = r.WithContext(services.SetUserCtx(r.Context(), &usr, requestToken))

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,11 +12,11 @@ import (
"github.com/go-chi/chi/v5"
"github.com/hay-kot/homebox/backend/app/api/handlers/debughandlers"
v1 "github.com/hay-kot/homebox/backend/app/api/handlers/v1"
"github.com/hay-kot/homebox/backend/app/api/providers"
_ "github.com/hay-kot/homebox/backend/app/api/static/docs"
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
"github.com/hay-kot/homebox/backend/internal/data/repo"
"github.com/hay-kot/httpkit/errchain"
httpSwagger "github.com/swaggo/http-swagger/v2" // http-swagger middleware
httpSwagger "github.com/swaggo/http-swagger" // http-swagger middleware
)
const prefix = "/api"
@@ -36,7 +36,7 @@ func (a *app) debugRouter() *http.ServeMux {
}
// registerRoutes registers all the routes for the API
func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain) {
func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllRepos) {
registerMimes()
r.Get("/swagger/*", httpSwagger.Handler(
@@ -46,7 +46,7 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain) {
// =========================================================================
// API Version 1
v1Base := v1.BaseURLFunc(prefix)
v1Base := v1.BaseUrlFunc(prefix)
v1Ctrl := v1.NewControllerV1(
a.services,
@@ -63,15 +63,8 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain) {
BuildTime: buildTime,
})))
r.Get(v1Base("/currencies"), chain.ToHandlerFunc(v1Ctrl.HandleCurrency()))
providers := []v1.AuthProvider{
providers.NewLocalProvider(a.services.User),
}
r.Post(v1Base("/users/register"), chain.ToHandlerFunc(v1Ctrl.HandleUserRegistration()))
r.Post(v1Base("/users/login"), chain.ToHandlerFunc(v1Ctrl.HandleAuthLogin(providers...)))
r.Post(v1Base("/users/request-password-reset"), chain.ToHandlerFunc(v1Ctrl.HandleUserRequestPasswordReset()))
r.Post(v1Base("/users/login"), chain.ToHandlerFunc(v1Ctrl.HandleAuthLogin()))
userMW := []errchain.Middleware{
a.mwAuthToken,
@@ -85,7 +78,6 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain) {
r.Post(v1Base("/users/logout"), chain.ToHandlerFunc(v1Ctrl.HandleAuthLogout(), userMW...))
r.Get(v1Base("/users/refresh"), chain.ToHandlerFunc(v1Ctrl.HandleAuthRefresh(), userMW...))
r.Put(v1Base("/users/self/change-password"), chain.ToHandlerFunc(v1Ctrl.HandleUserSelfChangePassword(), userMW...))
r.Put(v1Base("/users/self/change-password-token"), chain.ToHandlerFunc(v1Ctrl.HandleUserSelfChangePasswordWithToken()))
r.Post(v1Base("/groups/invitations"), chain.ToHandlerFunc(v1Ctrl.HandleGroupInvitationsCreate(), userMW...))
r.Get(v1Base("/groups/statistics"), chain.ToHandlerFunc(v1Ctrl.HandleGroupStatistics(), userMW...))
@@ -123,7 +115,6 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain) {
r.Get(v1Base("/items/fields/values"), chain.ToHandlerFunc(v1Ctrl.HandleGetAllCustomFieldValues(), userMW...))
r.Get(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemGet(), userMW...))
r.Get(v1Base("/items/{id}/path"), chain.ToHandlerFunc(v1Ctrl.HandleItemFullPath(), userMW...))
r.Put(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemUpdate(), userMW...))
r.Patch(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemPatch(), userMW...))
r.Delete(v1Base("/items/{id}"), chain.ToHandlerFunc(v1Ctrl.HandleItemDelete(), userMW...))
@@ -187,7 +178,7 @@ func notFoundHandler() errchain.HandlerFunc {
if err != nil {
return err
}
defer func() { _ = f.Close() }()
defer f.Close()
stat, _ := f.Stat()
if stat.IsDir() {

View File

@@ -150,25 +150,6 @@ const docTemplate = `{
}
}
},
"/v1/currency": {
"get": {
"produces": [
"application/json"
],
"tags": [
"Base"
],
"summary": "Currency",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/currencies.Currency"
}
}
}
}
},
"/v1/groups": {
"get": {
"security": [
@@ -429,16 +410,6 @@ const docTemplate = `{
"description": "location Ids",
"name": "locations",
"in": "query"
},
{
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi",
"description": "parent Ids",
"name": "parentIds",
"in": "query"
}
],
"responses": {
@@ -1017,42 +988,6 @@ const docTemplate = `{
}
}
},
"/v1/items/{id}/path": {
"get": {
"security": [
{
"Bearer": []
}
],
"produces": [
"application/json"
],
"tags": [
"Items"
],
"summary": "Get the full path of an item",
"parameters": [
{
"type": "string",
"description": "Item ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemPath"
}
}
}
}
}
},
"/v1/labels": {
"get": {
"security": [
@@ -1639,7 +1574,7 @@ const docTemplate = `{
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/v1.APISummary"
"$ref": "#/definitions/v1.ApiSummary"
}
}
}
@@ -1710,12 +1645,6 @@ const docTemplate = `{
"schema": {
"$ref": "#/definitions/v1.LoginForm"
}
},
{
"type": "string",
"description": "auth provider",
"name": "provider",
"in": "query"
}
],
"responses": {
@@ -1792,33 +1721,6 @@ const docTemplate = `{
}
}
},
"/v1/users/request-password-reset": {
"post": {
"produces": [
"application/json"
],
"tags": [
"User"
],
"summary": "Request Password Reset",
"parameters": [
{
"description": "User Data",
"name": "payload",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/services.PasswordResetRequest"
}
}
],
"responses": {
"204": {
"description": "No Content"
}
}
}
},
"/v1/users/self": {
"get": {
"security": [
@@ -1921,23 +1823,6 @@ const docTemplate = `{
}
},
"definitions": {
"currencies.Currency": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"local": {
"type": "string"
},
"name": {
"type": "string"
},
"symbol": {
"type": "string"
}
}
},
"repo.DocumentOut": {
"type": "object",
"properties": {
@@ -2113,6 +1998,12 @@ const docTemplate = `{
"$ref": "#/definitions/repo.ItemAttachment"
}
},
"children": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemSummary"
}
},
"createdAt": {
"type": "string"
},
@@ -2231,20 +2122,6 @@ const docTemplate = `{
}
}
},
"repo.ItemPath": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"type": {
"$ref": "#/definitions/repo.ItemType"
}
}
},
"repo.ItemSummary": {
"type": "object",
"properties": {
@@ -2297,17 +2174,6 @@ const docTemplate = `{
}
}
},
"repo.ItemType": {
"type": "string",
"enum": [
"location",
"item"
],
"x-enum-varnames": [
"ItemTypeLocation",
"ItemTypeItem"
]
},
"repo.ItemUpdate": {
"type": "object",
"properties": {
@@ -2315,7 +2181,8 @@ const docTemplate = `{
"type": "boolean"
},
"assetId": {
"type": "string"
"type": "string",
"example": "0"
},
"description": {
"type": "string"
@@ -2852,14 +2719,6 @@ const docTemplate = `{
}
}
},
"services.PasswordResetRequest": {
"type": "object",
"properties": {
"email": {
"type": "string"
}
}
},
"services.UserRegistration": {
"type": "object",
"properties": {
@@ -2877,7 +2736,15 @@ const docTemplate = `{
}
}
},
"v1.APISummary": {
"v1.ActionAmountResult": {
"type": "object",
"properties": {
"completed": {
"type": "integer"
}
}
},
"v1.ApiSummary": {
"type": "object",
"properties": {
"allowRegistration": {
@@ -2906,14 +2773,6 @@ const docTemplate = `{
}
}
},
"v1.ActionAmountResult": {
"type": "object",
"properties": {
"completed": {
"type": "integer"
}
}
},
"v1.Build": {
"type": "object",
"properties": {

View File

@@ -143,25 +143,6 @@
}
}
},
"/v1/currency": {
"get": {
"produces": [
"application/json"
],
"tags": [
"Base"
],
"summary": "Currency",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/currencies.Currency"
}
}
}
}
},
"/v1/groups": {
"get": {
"security": [
@@ -422,16 +403,6 @@
"description": "location Ids",
"name": "locations",
"in": "query"
},
{
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi",
"description": "parent Ids",
"name": "parentIds",
"in": "query"
}
],
"responses": {
@@ -1010,42 +981,6 @@
}
}
},
"/v1/items/{id}/path": {
"get": {
"security": [
{
"Bearer": []
}
],
"produces": [
"application/json"
],
"tags": [
"Items"
],
"summary": "Get the full path of an item",
"parameters": [
{
"type": "string",
"description": "Item ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemPath"
}
}
}
}
}
},
"/v1/labels": {
"get": {
"security": [
@@ -1632,7 +1567,7 @@
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/v1.APISummary"
"$ref": "#/definitions/v1.ApiSummary"
}
}
}
@@ -1703,12 +1638,6 @@
"schema": {
"$ref": "#/definitions/v1.LoginForm"
}
},
{
"type": "string",
"description": "auth provider",
"name": "provider",
"in": "query"
}
],
"responses": {
@@ -1785,33 +1714,6 @@
}
}
},
"/v1/users/request-password-reset": {
"post": {
"produces": [
"application/json"
],
"tags": [
"User"
],
"summary": "Request Password Reset",
"parameters": [
{
"description": "User Data",
"name": "payload",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/services.PasswordResetRequest"
}
}
],
"responses": {
"204": {
"description": "No Content"
}
}
}
},
"/v1/users/self": {
"get": {
"security": [
@@ -1914,23 +1816,6 @@
}
},
"definitions": {
"currencies.Currency": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"local": {
"type": "string"
},
"name": {
"type": "string"
},
"symbol": {
"type": "string"
}
}
},
"repo.DocumentOut": {
"type": "object",
"properties": {
@@ -2106,6 +1991,12 @@
"$ref": "#/definitions/repo.ItemAttachment"
}
},
"children": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemSummary"
}
},
"createdAt": {
"type": "string"
},
@@ -2224,20 +2115,6 @@
}
}
},
"repo.ItemPath": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"type": {
"$ref": "#/definitions/repo.ItemType"
}
}
},
"repo.ItemSummary": {
"type": "object",
"properties": {
@@ -2290,17 +2167,6 @@
}
}
},
"repo.ItemType": {
"type": "string",
"enum": [
"location",
"item"
],
"x-enum-varnames": [
"ItemTypeLocation",
"ItemTypeItem"
]
},
"repo.ItemUpdate": {
"type": "object",
"properties": {
@@ -2308,7 +2174,8 @@
"type": "boolean"
},
"assetId": {
"type": "string"
"type": "string",
"example": "0"
},
"description": {
"type": "string"
@@ -2845,14 +2712,6 @@
}
}
},
"services.PasswordResetRequest": {
"type": "object",
"properties": {
"email": {
"type": "string"
}
}
},
"services.UserRegistration": {
"type": "object",
"properties": {
@@ -2870,7 +2729,15 @@
}
}
},
"v1.APISummary": {
"v1.ActionAmountResult": {
"type": "object",
"properties": {
"completed": {
"type": "integer"
}
}
},
"v1.ApiSummary": {
"type": "object",
"properties": {
"allowRegistration": {
@@ -2899,14 +2766,6 @@
}
}
},
"v1.ActionAmountResult": {
"type": "object",
"properties": {
"completed": {
"type": "integer"
}
}
},
"v1.Build": {
"type": "object",
"properties": {

View File

@@ -1,16 +1,5 @@
basePath: /api
definitions:
currencies.Currency:
properties:
code:
type: string
local:
type: string
name:
type: string
symbol:
type: string
type: object
repo.DocumentOut:
properties:
id:
@@ -127,6 +116,10 @@ definitions:
items:
$ref: '#/definitions/repo.ItemAttachment'
type: array
children:
items:
$ref: '#/definitions/repo.ItemSummary'
type: array
createdAt:
type: string
description:
@@ -206,15 +199,6 @@ definitions:
x-nullable: true
x-omitempty: true
type: object
repo.ItemPath:
properties:
id:
type: string
name:
type: string
type:
$ref: '#/definitions/repo.ItemType'
type: object
repo.ItemSummary:
properties:
archived:
@@ -249,19 +233,12 @@ definitions:
updatedAt:
type: string
type: object
repo.ItemType:
enum:
- location
- item
type: string
x-enum-varnames:
- ItemTypeLocation
- ItemTypeItem
repo.ItemUpdate:
properties:
archived:
type: boolean
assetId:
example: "0"
type: string
description:
type: string
@@ -620,11 +597,6 @@ definitions:
value:
type: number
type: object
services.PasswordResetRequest:
properties:
email:
type: string
type: object
services.UserRegistration:
properties:
email:
@@ -636,7 +608,12 @@ definitions:
token:
type: string
type: object
v1.APISummary:
v1.ActionAmountResult:
properties:
completed:
type: integer
type: object
v1.ApiSummary:
properties:
allowRegistration:
type: boolean
@@ -655,11 +632,6 @@ definitions:
type: string
type: array
type: object
v1.ActionAmountResult:
properties:
completed:
type: integer
type: object
v1.Build:
properties:
buildTime:
@@ -817,18 +789,6 @@ paths:
summary: Get Item by Asset ID
tags:
- Items
/v1/currency:
get:
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/currencies.Currency'
summary: Currency
tags:
- Base
/v1/groups:
get:
produces:
@@ -982,13 +942,6 @@ paths:
type: string
name: locations
type: array
- collectionFormat: multi
description: parent Ids
in: query
items:
type: string
name: parentIds
type: array
produces:
- application/json
responses:
@@ -1286,28 +1239,6 @@ paths:
summary: Update Maintenance Entry
tags:
- Maintenance
/v1/items/{id}/path:
get:
parameters:
- description: Item ID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/repo.ItemPath'
type: array
security:
- Bearer: []
summary: Get the full path of an item
tags:
- Items
/v1/items/export:
get:
responses:
@@ -1725,7 +1656,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/v1.APISummary'
$ref: '#/definitions/v1.ApiSummary'
summary: Application Info
tags:
- Base
@@ -1768,10 +1699,6 @@ paths:
required: true
schema:
$ref: '#/definitions/v1.LoginForm'
- description: auth provider
in: query
name: provider
type: string
produces:
- application/json
responses:
@@ -1822,23 +1749,6 @@ paths:
summary: Register New User
tags:
- User
/v1/users/request-password-reset:
post:
parameters:
- description: User Data
in: body
name: payload
required: true
schema:
$ref: '#/definitions/services.PasswordResetRequest'
produces:
- application/json
responses:
"204":
description: No Content
summary: Request Password Reset
tags:
- User
/v1/users/self:
delete:
produces:

View File

@@ -71,7 +71,7 @@ func main() {
text = replace.Regex.ReplaceAllString(text, replace.Text)
}
err = os.WriteFile(path, []byte(text), 0o644)
err = os.WriteFile(path, []byte(text), 0644)
if err != nil {
fmt.Println(err)
os.Exit(1)

View File

@@ -1,32 +1,29 @@
module github.com/hay-kot/homebox/backend
go 1.22
toolchain go1.22.0
go 1.20
require (
ariga.io/atlas v0.19.1
ariga.io/atlas v0.15.0
entgo.io/ent v0.12.5
github.com/ardanlabs/conf/v3 v3.1.7
github.com/containrrr/shoutrrr v0.8.0
github.com/go-chi/chi/v5 v5.0.12
github.com/go-playground/validator/v10 v10.18.0
github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a
github.com/google/uuid v1.6.0
github.com/go-chi/chi/v5 v5.0.10
github.com/go-playground/validator/v10 v10.16.0
github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d
github.com/google/uuid v1.4.0
github.com/gorilla/schema v1.2.1
github.com/hay-kot/easyemails v0.0.0-20240206011027-25232fb79aa3
github.com/hay-kot/httpkit v0.0.9
github.com/mattn/go-sqlite3 v1.14.22
github.com/hay-kot/httpkit v0.0.3
github.com/mattn/go-sqlite3 v1.14.18
github.com/olahol/melody v1.1.4
github.com/pkg/errors v0.9.1
github.com/rs/zerolog v1.32.0
github.com/rs/zerolog v1.31.0
github.com/stretchr/testify v1.8.4
github.com/swaggo/http-swagger/v2 v2.0.2
github.com/swaggo/swag v1.16.3
github.com/swaggo/http-swagger v1.3.4
github.com/swaggo/swag v1.16.2
github.com/yeqown/go-qrcode/v2 v2.2.2
github.com/yeqown/go-qrcode/writer/standard v1.2.2
golang.org/x/crypto v0.19.0
modernc.org/sqlite v1.29.2
golang.org/x/crypto v0.15.0
modernc.org/sqlite v1.27.0
)
require (
@@ -48,32 +45,34 @@ require (
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/hcl/v2 v2.19.1 // 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/leodido/go-urn v1.2.4 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/swaggo/files/v2 v2.0.0 // indirect
github.com/swaggo/files v1.0.1 // indirect
github.com/yeqown/reedsolomon v1.0.0 // indirect
github.com/zclconf/go-cty v1.14.1 // indirect
golang.org/x/image v0.14.0 // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.18.0 // indirect
golang.org/x/sys v0.14.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.17.0 // indirect
golang.org/x/tools v0.15.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
modernc.org/libc v1.41.0 // indirect
lukechampine.com/uint128 v1.3.0 // indirect
modernc.org/cc/v3 v3.41.0 // indirect
modernc.org/ccgo/v3 v3.16.15 // indirect
modernc.org/libc v1.34.4 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.7.2 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/strutil v1.2.0 // indirect
modernc.org/token v1.1.0 // indirect
)

View File

@@ -1,9 +1,8 @@
ariga.io/atlas v0.19.1 h1:QzBHkakwzEhmPWOzNhw8Yr/Bbicj6Iq5hwEoNI/Jr9A=
ariga.io/atlas v0.19.1/go.mod h1:VPlcXdd4w2KqKnH54yEZcry79UAhpaWaxEsmn5JRNoE=
ariga.io/atlas v0.15.0 h1:9lwSVcO/D3WgaCzstSGqR1hEDtsGibu6JqUofEI/0sY=
ariga.io/atlas v0.15.0/go.mod h1:isZrlzJ5cpoCoKFoY9knZug7Lq4pP1cm8g3XciLZ0Pw=
entgo.io/ent v0.12.5 h1:KREM5E4CSoej4zeGa88Ou/gfturAnpUv0mzAjch1sj4=
entgo.io/ent v0.12.5/go.mod h1:Y3JVAjtlIk8xVZYSn3t3mf8xlZIn5SAOXZQxD6kKI+Q=
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
@@ -12,8 +11,6 @@ github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
github.com/ardanlabs/conf/v3 v3.1.7 h1:p232cF68TafoA5U9ZlbxUIhGJtGNdKHBXF80Fdqb5t0=
github.com/ardanlabs/conf/v3 v3.1.7/go.mod h1:zclexWKe0NVj6LHQ8NgDDZ7bQ1spE0KeKPFficdtAjU=
github.com/bradleyjkemp/cupaloy v2.3.0+incompatible h1:UafIjBvWQmS9i/xRg+CamMrnLTKNzo+bdmT/oH34c2Y=
github.com/bradleyjkemp/cupaloy v2.3.0+incompatible/go.mod h1:Au1Xw1sgaJ5iSFktEhYsS0dbQiS1B0/XMXl+42y9Ilk=
github.com/containrrr/shoutrrr v0.8.0 h1:mfG2ATzIS7NR2Ec6XL+xyoHzN97H8WPjir8aYzJUSec=
github.com/containrrr/shoutrrr v0.8.0/go.mod h1:ioyQAyu1LJY6sILuNyKaQaw+9Ttik5QePU8atnAdO2o=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
@@ -29,10 +26,9 @@ github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
@@ -51,59 +47,49 @@ github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.18.0 h1:BvolUXjp4zuvkZ5YN5t7ebzbhlUtPsPm2S9NAZ5nl9U=
github.com/go-playground/validator/v10 v10.18.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE=
github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a h1:RYfmiM0zluBJOiPDJseKLEN4BapJ42uSi9SZBQ2YyiA=
github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d h1:KbPOUXFUDJxwZ04vbmDOc3yuruGvVO+LOa7cVER3yWw=
github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/schema v1.2.1 h1:tjDxcmdb+siIqkTNoV+qRH2mjYdr2hHe5MKXbp61ziM=
github.com/gorilla/schema v1.2.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hashicorp/hcl/v2 v2.19.1 h1://i05Jqznmb2EXqa39Nsvyan2o5XyMowW5fnCKW5RPI=
github.com/hashicorp/hcl/v2 v2.19.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE=
github.com/hay-kot/easyemails v0.0.0-20240206011027-25232fb79aa3 h1:EljujAOvukSS+sh8e883j4vhEiYG4EvJFAhl+XvUYe8=
github.com/hay-kot/easyemails v0.0.0-20240206011027-25232fb79aa3/go.mod h1:SZdhYMO2ZmEuTTDE7pHn0WanXhwteniOCYsQ3B5IT/o=
github.com/hay-kot/httpkit v0.0.9 h1:hu2TPY9awmIYWXxWGubaXl2U61pPvaVsm9YwboBRGu0=
github.com/hay-kot/httpkit v0.0.9/go.mod h1:AD22YluZrvBDxmtB3Pw2SOyp3A2PZqcmBZa0+COrhoU=
github.com/hay-kot/httpkit v0.0.3 h1:QYq01J5Jrn+ie0s1ptavNSEyydkOHqsrw4RLp+2LeJQ=
github.com/hay-kot/httpkit v0.0.3/go.mod h1:1s/OJwWRyH6tBtTw76jTp6kwBYvjswziXaokPQH7eKQ=
github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc=
github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
@@ -115,19 +101,15 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mattn/go-sqlite3 v1.14.18 h1:JL0eqdCOq6DJVNPSvArO/bIV9/P7fbGrV00LZHc+5aI=
github.com/mattn/go-sqlite3 v1.14.18/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/olahol/melody v1.1.4 h1:RQHfKZkQmDxI0+SLZRNBCn4LiXdqxLKRGSkT8Dyoe/E=
github.com/olahol/melody v1.1.4/go.mod h1:GgkTl6Y7yWj/HtfD48Q5vLKPVoZOH+Qqgfa7CvJgJM4=
github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -137,10 +119,9 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qq
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0=
github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -149,41 +130,69 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw=
github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM=
github.com/swaggo/http-swagger/v2 v2.0.2 h1:FKCdLsl+sFCx60KFsyM0rDarwiUSZ8DqbfSyIKC9OBg=
github.com/swaggo/http-swagger/v2 v2.0.2/go.mod h1:r7/GBkAWIfK6E/OLnE8fXnviHiDeAHmgIyooa4xm3AQ=
github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg=
github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
github.com/swaggo/http-swagger v1.3.4 h1:q7t/XLx0n15H1Q9/tk3Y9L4n210XzJF5WtnDX64a5ww=
github.com/swaggo/http-swagger v1.3.4/go.mod h1:9dAh0unqMBAlbp1uE2Uc2mQTxNMU/ha4UbucIg1MFkQ=
github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04=
github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E=
github.com/yeqown/go-qrcode/v2 v2.2.2 h1:0comk6jEwi0oWNhKEmzx4JI+Q7XIneAApmFSMKWmSVc=
github.com/yeqown/go-qrcode/v2 v2.2.2/go.mod h1:2Qsk2APUCPne0TsRo40DIkI5MYnbzYKCnKGEFWrxd24=
github.com/yeqown/go-qrcode/writer/standard v1.2.2 h1:gyzunKXgC0ZUpKqQFUImbAEwewAiwNCkxFEKZV80Kt4=
github.com/yeqown/go-qrcode/writer/standard v1.2.2/go.mod h1:bbVRiBJSRPj4UBZP/biLG7JSd9kHqXjErk1eakAMnRA=
github.com/yeqown/reedsolomon v1.0.0 h1:x1h/Ej/uJnNu8jaX7GLHBWmZKCAWjEJTetkqaabr4B0=
github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw/Iy6g1WiiM=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zclconf/go-cty v1.14.1 h1:t9fyA35fwjjUMcmL5hLER+e/rEPqrbCK1/OSE4SI9KA=
github.com/zclconf/go-cty v1.14.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -196,17 +205,27 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
modernc.org/libc v1.41.0 h1:g9YAc6BkKlgORsUWj+JwqoB1wU3o4DE3bM3yvA3k+Gk=
modernc.org/libc v1.41.0/go.mod h1:w0eszPsiXoOnoMJgrXjglgLuDy/bt5RR4y3QzUUeodY=
lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo=
lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q=
modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y=
modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0=
modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI=
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/libc v1.34.4 h1:r9+5s4wNeoCsB8CuJE67UB4N07ernbvrcry9O3MLWtQ=
modernc.org/libc v1.34.4/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
modernc.org/sqlite v1.29.2 h1:xgBSyA3gemwgP31PWFfFjtBorQNYpeypGdoSDjXhrgI=
modernc.org/sqlite v1.29.2/go.mod h1:hG41jCYxOAOoO6BRK66AdRlmOcDzXf7qnwlwjUIOqa0=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.27.0 h1:MpKAHoyYB7xqcwnUwkuD+npwEa0fojF0B5QRbN+auJ8=
modernc.org/sqlite v1.27.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY=

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,10 +1,7 @@
// Package services provides the core business logic for the application.
package services
import (
"github.com/hay-kot/homebox/backend/internal/core/currencies"
"github.com/hay-kot/homebox/backend/internal/data/repo"
"github.com/hay-kot/homebox/backend/pkgs/mailer"
)
type AllServices struct {
@@ -12,14 +9,12 @@ type AllServices struct {
Group *GroupService
Items *ItemService
BackgroundService *BackgroundService
Currencies *currencies.CurrencyRegistry
}
type OptionsFunc func(*options)
type options struct {
autoIncrementAssetID bool
currencies []currencies.Currency
}
func WithAutoIncrementAssetID(v bool) func(*options) {
@@ -28,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, baseurl string, sender *mailer.Mailer, opts ...OptionsFunc) *AllServices {
func New(repos *repo.AllRepos, opts ...OptionsFunc) *AllServices {
if repos == nil {
panic("repos cannot be nil")
}
defaultCurrencies, err := currencies.CollectionCurrencies(
currencies.CollectDefaults(),
)
if err != nil {
panic("failed to collect default currencies")
}
options := &options{
autoIncrementAssetID: true,
currencies: defaultCurrencies,
}
for _, opt := range opts {
@@ -56,17 +37,12 @@ func New(repos *repo.AllRepos, baseurl string, sender *mailer.Mailer, opts ...Op
}
return &AllServices{
User: &UserService{
repos: repos,
mailer: sender,
baseurl: baseurl,
},
User: &UserService{repos},
Group: &GroupService{repos},
Items: &ItemService{
repo: repos,
autoIncrementAssetID: options.autoIncrementAssetID,
},
BackgroundService: &BackgroundService{repos},
Currencies: currencies.NewCurrencyService(options.currencies),
}
}

View File

@@ -19,11 +19,11 @@ var (
type Context struct {
context.Context
// UserID is a unique identifier for the acting user.
UserID uuid.UUID
// UID is a unique identifier for the acting user.
UID uuid.UUID
// GroupID is a unique identifier for the acting users group.
GroupID uuid.UUID
// GID is a unique identifier for the acting users group.
GID uuid.UUID
// User is the acting user.
User *repo.UserOut
@@ -35,8 +35,8 @@ func NewContext(ctx context.Context) Context {
user := UseUserCtx(ctx)
return Context{
Context: ctx,
UserID: user.ID,
GroupID: user.GroupID,
UID: user.ID,
GID: user.GroupID,
User: user,
}
}

View File

@@ -6,12 +6,10 @@ import (
"os"
"testing"
"github.com/hay-kot/homebox/backend/internal/core/currencies"
"github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus"
"github.com/hay-kot/homebox/backend/internal/data/ent"
"github.com/hay-kot/homebox/backend/internal/data/repo"
"github.com/hay-kot/homebox/backend/pkgs/faker"
"github.com/hay-kot/homebox/backend/pkgs/mailer"
_ "github.com/mattn/go-sqlite3"
)
@@ -63,21 +61,15 @@ func TestMain(m *testing.M) {
tClient = client
tRepos = repo.New(tClient, tbus, os.TempDir()+"/homebox")
defaults, _ := currencies.CollectionCurrencies(
currencies.CollectDefaults(),
)
tSvc = New(tRepos, "", &mailer.Mailer{}, WithCurrencies(defaults))
tSvc = New(tRepos)
defer client.Close()
bootstrap()
tCtx = Context{
Context: context.Background(),
GroupID: tGroup.ID,
UserID: tUser.ID,
GID: tGroup.ID,
UID: tUser.ID,
}
exit := m.Run()
_ = client.Close()
os.Exit(exit)
os.Exit(m.Run())
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -66,6 +66,7 @@ func (svc *BackgroundService) SendNotifiersToday(ctx context.Context) error {
var sendErrs []error
for i := range urls {
err := shoutrrr.Send(urls[i], bldr.String())
if err != nil {
sendErrs = append(sendErrs, err)
}

View File

@@ -21,13 +21,13 @@ func (svc *GroupService) UpdateGroup(ctx Context, data repo.GroupUpdate) (repo.G
return repo.Group{}, errors.New("currency cannot be empty")
}
return svc.repos.Groups.GroupUpdate(ctx.Context, ctx.GroupID, data)
return svc.repos.Groups.GroupUpdate(ctx.Context, ctx.GID, data)
}
func (svc *GroupService) NewInvitation(ctx Context, uses int, expiresAt time.Time) (string, error) {
token := hasher.GenerateToken()
_, err := svc.repos.Groups.InvitationCreate(ctx, ctx.GroupID, repo.GroupInvitationCreate{
_, err := svc.repos.Groups.InvitationCreate(ctx, ctx.GID, repo.GroupInvitationCreate{
Token: token.Hash,
Uses: uses,
ExpiresAt: expiresAt,

View File

@@ -27,24 +27,24 @@ type ItemService struct {
func (svc *ItemService) Create(ctx Context, item repo.ItemCreate) (repo.ItemOut, error) {
if svc.autoIncrementAssetID {
highest, err := svc.repo.Items.GetHighestAssetID(ctx, ctx.GroupID)
highest, err := svc.repo.Items.GetHighestAssetID(ctx, ctx.GID)
if err != nil {
return repo.ItemOut{}, err
}
item.AssetID = highest + 1
item.AssetID = repo.AssetID(highest + 1)
}
return svc.repo.Items.Create(ctx, ctx.GroupID, item)
return svc.repo.Items.Create(ctx, ctx.GID, item)
}
func (svc *ItemService) EnsureAssetID(ctx context.Context, groupID uuid.UUID) (int, error) {
items, err := svc.repo.Items.GetAllZeroAssetID(ctx, groupID)
func (svc *ItemService) EnsureAssetID(ctx context.Context, GID uuid.UUID) (int, error) {
items, err := svc.repo.Items.GetAllZeroAssetID(ctx, GID)
if err != nil {
return 0, err
}
highest, err := svc.repo.Items.GetHighestAssetID(ctx, groupID)
highest, err := svc.repo.Items.GetHighestAssetID(ctx, GID)
if err != nil {
return 0, err
}
@@ -53,7 +53,7 @@ func (svc *ItemService) EnsureAssetID(ctx context.Context, groupID uuid.UUID) (i
for _, item := range items {
highest++
err = svc.repo.Items.SetAssetID(ctx, groupID, item.ID, highest)
err = svc.repo.Items.SetAssetID(ctx, GID, item.ID, repo.AssetID(highest))
if err != nil {
return 0, err
}
@@ -64,8 +64,8 @@ func (svc *ItemService) EnsureAssetID(ctx context.Context, groupID uuid.UUID) (i
return finished, nil
}
func (svc *ItemService) EnsureImportRef(ctx context.Context, groupID uuid.UUID) (int, error) {
ids, err := svc.repo.Items.GetAllZeroImportRef(ctx, groupID)
func (svc *ItemService) EnsureImportRef(ctx context.Context, GID uuid.UUID) (int, error) {
ids, err := svc.repo.Items.GetAllZeroImportRef(ctx, GID)
if err != nil {
return 0, err
}
@@ -74,7 +74,7 @@ func (svc *ItemService) EnsureImportRef(ctx context.Context, groupID uuid.UUID)
for _, itemID := range ids {
ref := uuid.New().String()[0:8]
err = svc.repo.Items.Patch(ctx, groupID, itemID, repo.ItemPatch{ImportRef: &ref})
err = svc.repo.Items.Patch(ctx, GID, itemID, repo.ItemPatch{ImportRef: &ref})
if err != nil {
return 0, err
}
@@ -96,7 +96,7 @@ func serializeLocation[T ~[]string](location T) string {
// 1. If the item does not exist, it is created.
// 2. If the item has a ImportRef and it exists it is skipped
// 3. Locations and Labels are created if they do not exist.
func (svc *ItemService) CsvImport(ctx context.Context, groupID uuid.UUID, data io.Reader) (int, error) {
func (svc *ItemService) CsvImport(ctx context.Context, GID uuid.UUID, data io.Reader) (int, error) {
sheet := reporting.IOSheet{}
err := sheet.Read(data)
@@ -109,7 +109,7 @@ func (svc *ItemService) CsvImport(ctx context.Context, groupID uuid.UUID, data i
labelMap := make(map[string]uuid.UUID)
{
labels, err := svc.repo.Labels.GetAll(ctx, groupID)
labels, err := svc.repo.Labels.GetAll(ctx, GID)
if err != nil {
return 0, err
}
@@ -124,7 +124,7 @@ func (svc *ItemService) CsvImport(ctx context.Context, groupID uuid.UUID, data i
locationMap := make(map[string]uuid.UUID)
{
locations, err := svc.repo.Locations.Tree(ctx, groupID, repo.TreeQuery{WithItems: false})
locations, err := svc.repo.Locations.Tree(ctx, GID, repo.TreeQuery{WithItems: false})
if err != nil {
return 0, err
}
@@ -153,7 +153,7 @@ func (svc *ItemService) CsvImport(ctx context.Context, groupID uuid.UUID, data i
// Asset ID Pre-Check
highestAID := repo.AssetID(-1)
if svc.autoIncrementAssetID {
highestAID, err = svc.repo.Items.GetHighestAssetID(ctx, groupID)
highestAID, err = svc.repo.Items.GetHighestAssetID(ctx, GID)
if err != nil {
return 0, err
}
@@ -169,7 +169,7 @@ func (svc *ItemService) CsvImport(ctx context.Context, groupID uuid.UUID, data i
// ========================================
// Preflight check for existing item
if row.ImportRef != "" {
exists, err := svc.repo.Items.CheckRef(ctx, groupID, row.ImportRef)
exists, err := svc.repo.Items.CheckRef(ctx, GID, row.ImportRef)
if err != nil {
return 0, fmt.Errorf("error checking for existing item with ref %q: %w", row.ImportRef, err)
}
@@ -188,7 +188,7 @@ func (svc *ItemService) CsvImport(ctx context.Context, groupID uuid.UUID, data i
id, ok := labelMap[label]
if !ok {
newLabel, err := svc.repo.Labels.Create(ctx, groupID, repo.LabelCreate{Name: label})
newLabel, err := svc.repo.Labels.Create(ctx, GID, repo.LabelCreate{Name: label})
if err != nil {
return 0, err
}
@@ -220,7 +220,7 @@ func (svc *ItemService) CsvImport(ctx context.Context, groupID uuid.UUID, data i
parentID = locationMap[parentPath]
}
newLocation, err := svc.repo.Locations.Create(ctx, groupID, repo.LocationCreate{
newLocation, err := svc.repo.Locations.Create(ctx, GID, repo.LocationCreate{
ParentID: parentID,
Name: pathElement,
})
@@ -261,12 +261,12 @@ func (svc *ItemService) CsvImport(ctx context.Context, groupID uuid.UUID, data i
LabelIDs: labelIds,
}
item, err = svc.repo.Items.Create(ctx, groupID, newItem)
item, err = svc.repo.Items.Create(ctx, GID, newItem)
if err != nil {
return 0, err
}
default:
item, err = svc.repo.Items.GetByRef(ctx, groupID, row.ImportRef)
item, err = svc.repo.Items.GetByRef(ctx, GID, row.ImportRef)
if err != nil {
return 0, err
}
@@ -318,7 +318,7 @@ func (svc *ItemService) CsvImport(ctx context.Context, groupID uuid.UUID, data i
Fields: fields,
}
item, err = svc.repo.Items.UpdateByGroup(ctx, groupID, updateItem)
item, err = svc.repo.Items.UpdateByGroup(ctx, GID, updateItem)
if err != nil {
return 0, err
}
@@ -329,15 +329,15 @@ func (svc *ItemService) CsvImport(ctx context.Context, groupID uuid.UUID, data i
return finished, nil
}
func (svc *ItemService) ExportTSV(ctx context.Context, groupID uuid.UUID) ([][]string, error) {
items, err := svc.repo.Items.GetAll(ctx, groupID)
func (svc *ItemService) ExportTSV(ctx context.Context, GID uuid.UUID) ([][]string, error) {
items, err := svc.repo.Items.GetAll(ctx, GID)
if err != nil {
return nil, err
}
sheet := reporting.IOSheet{}
err = sheet.ReadItems(ctx, items, groupID, svc.repo)
err = sheet.ReadItems(ctx, items, GID, svc.repo)
if err != nil {
return nil, err
}
@@ -345,8 +345,8 @@ func (svc *ItemService) ExportTSV(ctx context.Context, groupID uuid.UUID) ([][]s
return sheet.TSV()
}
func (svc *ItemService) ExportBillOfMaterialsTSV(ctx context.Context, groupID uuid.UUID) ([]byte, error) {
items, err := svc.repo.Items.GetAll(ctx, groupID)
func (svc *ItemService) ExportBillOfMaterialsTSV(ctx context.Context, GID uuid.UUID) ([]byte, error) {
items, err := svc.repo.Items.GetAll(ctx, GID)
if err != nil {
return nil, err
}

View File

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

View File

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

View File

@@ -3,15 +3,12 @@ package services
import (
"context"
"errors"
"net/url"
"time"
"github.com/google/uuid"
"github.com/hay-kot/easyemails"
"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/pkgs/hasher"
"github.com/hay-kot/homebox/backend/pkgs/mailer"
"github.com/rs/zerolog/log"
)
@@ -19,18 +16,11 @@ var (
oneWeek = time.Hour * 24 * 7
ErrorInvalidLogin = errors.New("invalid username or password")
ErrorInvalidToken = errors.New("invalid token")
ErrorTokenIDMismatch = errors.New("token id mismatch")
ErrorTokenIdMismatch = errors.New("token id mismatch")
)
func init() { // nolint: gochecknoinits
easyemails.ImageLogoHeader = "https://raw.githubusercontent.com/hay-kot/homebox/af9aa239af66df17478f5ed9283e303daf7c6775/docs/docs/assets/img/homebox-email-banner.jpg"
easyemails.ColorPrimary = "#5D7F67"
}
type UserService struct {
repos *repo.AllRepos
mailer *mailer.Mailer
baseurl string
repos *repo.AllRepos
}
type (
@@ -49,9 +39,6 @@ type (
Username string `json:"username"`
Password string `json:"password"`
}
PasswordResetRequest struct {
Email string `json:"email"`
}
)
// RegisterUser creates a new user and group in the data with the provided data. It also bootstraps the user's group
@@ -105,11 +92,9 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
if err != nil {
return repo.UserOut{}, err
}
log.Debug().Msg("user created")
// Create the default labels and locations for the group.
if creatingGroup {
log.Debug().Msg("creating default labels")
for _, label := range defaultLabels() {
_, err := svc.repos.Labels.Create(ctx, usr.GroupID, label)
if err != nil {
@@ -117,7 +102,6 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
}
}
log.Debug().Msg("creating default locations")
for _, location := range defaultLocations() {
_, err := svc.repos.Locations.Create(ctx, usr.GroupID, location)
if err != nil {
@@ -128,7 +112,6 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
// Decrement the invitation token if it was used.
if token.ID != uuid.Nil {
log.Debug().Msg("decrementing invitation token")
err = svc.repos.Groups.InvitationUpdate(ctx, token.ID, token.Uses-1)
if err != nil {
log.Err(err).Msg("Failed to update invitation token")
@@ -145,19 +128,19 @@ func (svc *UserService) GetSelf(ctx context.Context, requestToken string) (repo.
return svc.repos.AuthTokens.GetUserFromToken(ctx, hash)
}
func (svc *UserService) UpdateSelf(ctx context.Context, userID uuid.UUID, data repo.UserUpdate) (repo.UserOut, error) {
err := svc.repos.Users.Update(ctx, userID, data)
func (svc *UserService) UpdateSelf(ctx context.Context, ID uuid.UUID, data repo.UserUpdate) (repo.UserOut, error) {
err := svc.repos.Users.Update(ctx, ID, data)
if err != nil {
return repo.UserOut{}, err
}
return svc.repos.Users.GetOneID(ctx, userID)
return svc.repos.Users.GetOneId(ctx, ID)
}
// ============================================================================
// User Authentication
func (svc *UserService) createSessionToken(ctx context.Context, userID uuid.UUID, extendedSession bool) (UserAuthTokenDetail, error) {
func (svc *UserService) createSessionToken(ctx context.Context, userId uuid.UUID, extendedSession bool) (UserAuthTokenDetail, error) {
attachmentToken := hasher.GenerateToken()
expiresAt := time.Now().Add(oneWeek)
@@ -166,7 +149,7 @@ func (svc *UserService) createSessionToken(ctx context.Context, userID uuid.UUID
}
attachmentData := repo.UserAuthTokenCreate{
UserID: userID,
UserID: userId,
TokenHash: attachmentToken.Hash,
ExpiresAt: expiresAt,
}
@@ -178,7 +161,7 @@ func (svc *UserService) createSessionToken(ctx context.Context, userID uuid.UUID
userToken := hasher.GenerateToken()
data := repo.UserAuthTokenCreate{
UserID: userID,
UserID: userId,
TokenHash: userToken.Hash,
ExpiresAt: expiresAt,
}
@@ -230,28 +213,28 @@ func (svc *UserService) RenewToken(ctx context.Context, token string) (UserAuthT
// DeleteSelf deletes the user that is currently logged based of the provided UUID
// There is _NO_ protection against deleting the wrong user, as such this should only
// be used when the identify of the user has been confirmed.
func (svc *UserService) DeleteSelf(ctx context.Context, userID uuid.UUID) error {
return svc.repos.Users.Delete(ctx, userID)
func (svc *UserService) DeleteSelf(ctx context.Context, ID uuid.UUID) error {
return svc.repos.Users.Delete(ctx, ID)
}
func (svc *UserService) PasswordChange(ctx Context, currentPassword, newPassword string) (ok bool) {
usr, err := svc.repos.Users.GetOneID(ctx, ctx.UserID)
func (svc *UserService) ChangePassword(ctx Context, current string, new string) (ok bool) {
usr, err := svc.repos.Users.GetOneId(ctx, ctx.UID)
if err != nil {
return false
}
if !hasher.CheckPasswordHash(currentPassword, usr.PasswordHash) {
if !hasher.CheckPasswordHash(current, usr.PasswordHash) {
log.Err(errors.New("current password is incorrect")).Msg("Failed to change password")
return false
}
hashed, err := hasher.HashPassword(newPassword)
hashed, err := hasher.HashPassword(new)
if err != nil {
log.Err(err).Msg("Failed to hash password")
return false
}
err = svc.repos.Users.ChangePassword(ctx.Context, ctx.UserID, hashed)
err = svc.repos.Users.ChangePassword(ctx.Context, ctx.UID, hashed)
if err != nil {
log.Err(err).Msg("Failed to change password")
return false
@@ -259,80 +242,3 @@ func (svc *UserService) PasswordChange(ctx Context, currentPassword, newPassword
return true
}
func (svc *UserService) PasswordChangeWithToken(ctx Context, token, newPassword string) error {
hashed, err := hasher.HashPassword(newPassword)
if err != nil {
return err
}
tokenHash := hasher.HashToken(token)
resetToken, err := svc.repos.Users.PasswordResetGet(ctx.Context, tokenHash)
if err != nil {
return err
}
if resetToken.UserID != ctx.UserID {
return ErrorTokenIDMismatch
}
err = svc.repos.Users.ChangePassword(ctx.Context, ctx.UserID, hashed)
if err != nil {
return err
}
err = svc.repos.Users.PasswordResetDelete(ctx.Context, tokenHash)
if err != nil {
return err
}
return nil
}
func (svc *UserService) PasswordResetRequest(ctx context.Context, req PasswordResetRequest) error {
usr, err := svc.repos.Users.GetOneEmail(ctx, req.Email)
if err != nil {
log.Warn().Err(err).Msg("failed to get user for email reset")
return err
}
token := hasher.GenerateToken()
err = svc.repos.Users.PasswordResetCreate(ctx, usr.ID, token.Hash)
if err != nil {
return err
}
resetURL, err := url.JoinPath(svc.baseurl, "reset-password/")
if err != nil {
return err
}
resetURL = resetURL + "?token=" + token.Raw
bldr := easyemails.NewBuilder().Add(
easyemails.WithParagraph(
easyemails.WithText("You have requested a password reset. Please click the link below to reset your password."),
),
easyemails.WithButton("Reset Password", resetURL),
easyemails.WithParagraph(
easyemails.WithText("[Github](https://github.com/hay-kot/homebox) · [Docs](https://hay-kot.github.io/homebox/)").
Centered(),
).
FontSize(12),
)
msg := mailer.NewMessageBuilder().
SetBody(bldr.Render()).
SetSubject("Password Reset").
SetTo(usr.Name, usr.Email).
Build()
err = svc.mailer.Send(msg)
if err != nil {
log.Err(err).Msg("Failed to send password reset email")
return err
}
return nil
}

View File

@@ -1,184 +0,0 @@
// Code generated by ent, DO NOT EDIT.
package ent
import (
"fmt"
"strings"
"time"
"entgo.io/ent"
"entgo.io/ent/dialect/sql"
"github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/data/ent/actiontoken"
"github.com/hay-kot/homebox/backend/internal/data/ent/user"
)
// ActionToken is the model entity for the ActionToken schema.
type ActionToken struct {
config `json:"-"`
// ID of the ent.
ID uuid.UUID `json:"id,omitempty"`
// UserID holds the value of the "user_id" field.
UserID uuid.UUID `json:"user_id,omitempty"`
// CreatedAt holds the value of the "created_at" field.
CreatedAt time.Time `json:"created_at,omitempty"`
// UpdatedAt holds the value of the "updated_at" field.
UpdatedAt time.Time `json:"updated_at,omitempty"`
// Action holds the value of the "action" field.
Action actiontoken.Action `json:"action,omitempty"`
// Token holds the value of the "token" field.
Token []byte `json:"token,omitempty"`
// Edges holds the relations/edges for other nodes in the graph.
// The values are being populated by the ActionTokenQuery when eager-loading is set.
Edges ActionTokenEdges `json:"edges"`
selectValues sql.SelectValues
}
// ActionTokenEdges holds the relations/edges for other nodes in the graph.
type ActionTokenEdges struct {
// User holds the value of the user edge.
User *User `json:"user,omitempty"`
// loadedTypes holds the information for reporting if a
// type was loaded (or requested) in eager-loading or not.
loadedTypes [1]bool
}
// UserOrErr returns the User value or an error if the edge
// was not loaded in eager-loading, or loaded but was not found.
func (e ActionTokenEdges) UserOrErr() (*User, error) {
if e.loadedTypes[0] {
if e.User == nil {
// Edge was loaded but was not found.
return nil, &NotFoundError{label: user.Label}
}
return e.User, nil
}
return nil, &NotLoadedError{edge: "user"}
}
// scanValues returns the types for scanning values from sql.Rows.
func (*ActionToken) scanValues(columns []string) ([]any, error) {
values := make([]any, len(columns))
for i := range columns {
switch columns[i] {
case actiontoken.FieldToken:
values[i] = new([]byte)
case actiontoken.FieldAction:
values[i] = new(sql.NullString)
case actiontoken.FieldCreatedAt, actiontoken.FieldUpdatedAt:
values[i] = new(sql.NullTime)
case actiontoken.FieldID, actiontoken.FieldUserID:
values[i] = new(uuid.UUID)
default:
values[i] = new(sql.UnknownType)
}
}
return values, nil
}
// assignValues assigns the values that were returned from sql.Rows (after scanning)
// to the ActionToken fields.
func (at *ActionToken) assignValues(columns []string, values []any) error {
if m, n := len(values), len(columns); m < n {
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
}
for i := range columns {
switch columns[i] {
case actiontoken.FieldID:
if value, ok := values[i].(*uuid.UUID); !ok {
return fmt.Errorf("unexpected type %T for field id", values[i])
} else if value != nil {
at.ID = *value
}
case actiontoken.FieldUserID:
if value, ok := values[i].(*uuid.UUID); !ok {
return fmt.Errorf("unexpected type %T for field user_id", values[i])
} else if value != nil {
at.UserID = *value
}
case actiontoken.FieldCreatedAt:
if value, ok := values[i].(*sql.NullTime); !ok {
return fmt.Errorf("unexpected type %T for field created_at", values[i])
} else if value.Valid {
at.CreatedAt = value.Time
}
case actiontoken.FieldUpdatedAt:
if value, ok := values[i].(*sql.NullTime); !ok {
return fmt.Errorf("unexpected type %T for field updated_at", values[i])
} else if value.Valid {
at.UpdatedAt = value.Time
}
case actiontoken.FieldAction:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field action", values[i])
} else if value.Valid {
at.Action = actiontoken.Action(value.String)
}
case actiontoken.FieldToken:
if value, ok := values[i].(*[]byte); !ok {
return fmt.Errorf("unexpected type %T for field token", values[i])
} else if value != nil {
at.Token = *value
}
default:
at.selectValues.Set(columns[i], values[i])
}
}
return nil
}
// Value returns the ent.Value that was dynamically selected and assigned to the ActionToken.
// This includes values selected through modifiers, order, etc.
func (at *ActionToken) Value(name string) (ent.Value, error) {
return at.selectValues.Get(name)
}
// QueryUser queries the "user" edge of the ActionToken entity.
func (at *ActionToken) QueryUser() *UserQuery {
return NewActionTokenClient(at.config).QueryUser(at)
}
// Update returns a builder for updating this ActionToken.
// Note that you need to call ActionToken.Unwrap() before calling this method if this ActionToken
// was returned from a transaction, and the transaction was committed or rolled back.
func (at *ActionToken) Update() *ActionTokenUpdateOne {
return NewActionTokenClient(at.config).UpdateOne(at)
}
// Unwrap unwraps the ActionToken entity that was returned from a transaction after it was closed,
// so that all future queries will be executed through the driver which created the transaction.
func (at *ActionToken) Unwrap() *ActionToken {
_tx, ok := at.config.driver.(*txDriver)
if !ok {
panic("ent: ActionToken is not a transactional entity")
}
at.config.driver = _tx.drv
return at
}
// String implements the fmt.Stringer.
func (at *ActionToken) String() string {
var builder strings.Builder
builder.WriteString("ActionToken(")
builder.WriteString(fmt.Sprintf("id=%v, ", at.ID))
builder.WriteString("user_id=")
builder.WriteString(fmt.Sprintf("%v", at.UserID))
builder.WriteString(", ")
builder.WriteString("created_at=")
builder.WriteString(at.CreatedAt.Format(time.ANSIC))
builder.WriteString(", ")
builder.WriteString("updated_at=")
builder.WriteString(at.UpdatedAt.Format(time.ANSIC))
builder.WriteString(", ")
builder.WriteString("action=")
builder.WriteString(fmt.Sprintf("%v", at.Action))
builder.WriteString(", ")
builder.WriteString("token=")
builder.WriteString(fmt.Sprintf("%v", at.Token))
builder.WriteByte(')')
return builder.String()
}
// ActionTokens is a parsable slice of ActionToken.
type ActionTokens []*ActionToken

View File

@@ -1,138 +0,0 @@
// Code generated by ent, DO NOT EDIT.
package actiontoken
import (
"fmt"
"time"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"github.com/google/uuid"
)
const (
// Label holds the string label denoting the actiontoken type in the database.
Label = "action_token"
// FieldID holds the string denoting the id field in the database.
FieldID = "id"
// FieldUserID holds the string denoting the user_id field in the database.
FieldUserID = "user_id"
// FieldCreatedAt holds the string denoting the created_at field in the database.
FieldCreatedAt = "created_at"
// FieldUpdatedAt holds the string denoting the updated_at field in the database.
FieldUpdatedAt = "updated_at"
// FieldAction holds the string denoting the action field in the database.
FieldAction = "action"
// FieldToken holds the string denoting the token field in the database.
FieldToken = "token"
// EdgeUser holds the string denoting the user edge name in mutations.
EdgeUser = "user"
// Table holds the table name of the actiontoken in the database.
Table = "action_tokens"
// UserTable is the table that holds the user relation/edge.
UserTable = "action_tokens"
// UserInverseTable is the table name for the User entity.
// It exists in this package in order to avoid circular dependency with the "user" package.
UserInverseTable = "users"
// UserColumn is the table column denoting the user relation/edge.
UserColumn = "user_id"
)
// Columns holds all SQL columns for actiontoken fields.
var Columns = []string{
FieldID,
FieldUserID,
FieldCreatedAt,
FieldUpdatedAt,
FieldAction,
FieldToken,
}
// ValidColumn reports if the column name is valid (part of the table columns).
func ValidColumn(column string) bool {
for i := range Columns {
if column == Columns[i] {
return true
}
}
return false
}
var (
// DefaultCreatedAt holds the default value on creation for the "created_at" field.
DefaultCreatedAt func() time.Time
// DefaultUpdatedAt holds the default value on creation for the "updated_at" field.
DefaultUpdatedAt func() time.Time
// UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field.
UpdateDefaultUpdatedAt func() time.Time
// DefaultID holds the default value on creation for the "id" field.
DefaultID func() uuid.UUID
)
// Action defines the type for the "action" enum field.
type Action string
// ActionResetPassword is the default value of the Action enum.
const DefaultAction = ActionResetPassword
// Action values.
const (
ActionResetPassword Action = "reset_password"
)
func (a Action) String() string {
return string(a)
}
// ActionValidator is a validator for the "action" field enum values. It is called by the builders before save.
func ActionValidator(a Action) error {
switch a {
case ActionResetPassword:
return nil
default:
return fmt.Errorf("actiontoken: invalid enum value for action field: %q", a)
}
}
// OrderOption defines the ordering options for the ActionToken queries.
type OrderOption func(*sql.Selector)
// ByID orders the results by the id field.
func ByID(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldID, opts...).ToFunc()
}
// ByUserID orders the results by the user_id field.
func ByUserID(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldUserID, opts...).ToFunc()
}
// ByCreatedAt orders the results by the created_at field.
func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()
}
// ByUpdatedAt orders the results by the updated_at field.
func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc()
}
// ByAction orders the results by the action field.
func ByAction(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldAction, opts...).ToFunc()
}
// ByUserField orders the results by user field.
func ByUserField(field string, opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborTerms(s, newUserStep(), sql.OrderByField(field, opts...))
}
}
func newUserStep() *sqlgraph.Step {
return sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(UserInverseTable, FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, UserTable, UserColumn),
)
}

View File

@@ -1,275 +0,0 @@
// Code generated by ent, DO NOT EDIT.
package actiontoken
import (
"time"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
)
// ID filters vertices based on their ID field.
func ID(id uuid.UUID) predicate.ActionToken {
return predicate.ActionToken(sql.FieldEQ(FieldID, id))
}
// IDEQ applies the EQ predicate on the ID field.
func IDEQ(id uuid.UUID) predicate.ActionToken {
return predicate.ActionToken(sql.FieldEQ(FieldID, id))
}
// IDNEQ applies the NEQ predicate on the ID field.
func IDNEQ(id uuid.UUID) predicate.ActionToken {
return predicate.ActionToken(sql.FieldNEQ(FieldID, id))
}
// IDIn applies the In predicate on the ID field.
func IDIn(ids ...uuid.UUID) predicate.ActionToken {
return predicate.ActionToken(sql.FieldIn(FieldID, ids...))
}
// IDNotIn applies the NotIn predicate on the ID field.
func IDNotIn(ids ...uuid.UUID) predicate.ActionToken {
return predicate.ActionToken(sql.FieldNotIn(FieldID, ids...))
}
// IDGT applies the GT predicate on the ID field.
func IDGT(id uuid.UUID) predicate.ActionToken {
return predicate.ActionToken(sql.FieldGT(FieldID, id))
}
// IDGTE applies the GTE predicate on the ID field.
func IDGTE(id uuid.UUID) predicate.ActionToken {
return predicate.ActionToken(sql.FieldGTE(FieldID, id))
}
// IDLT applies the LT predicate on the ID field.
func IDLT(id uuid.UUID) predicate.ActionToken {
return predicate.ActionToken(sql.FieldLT(FieldID, id))
}
// IDLTE applies the LTE predicate on the ID field.
func IDLTE(id uuid.UUID) predicate.ActionToken {
return predicate.ActionToken(sql.FieldLTE(FieldID, id))
}
// UserID applies equality check predicate on the "user_id" field. It's identical to UserIDEQ.
func UserID(v uuid.UUID) predicate.ActionToken {
return predicate.ActionToken(sql.FieldEQ(FieldUserID, v))
}
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
func CreatedAt(v time.Time) predicate.ActionToken {
return predicate.ActionToken(sql.FieldEQ(FieldCreatedAt, v))
}
// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ.
func UpdatedAt(v time.Time) predicate.ActionToken {
return predicate.ActionToken(sql.FieldEQ(FieldUpdatedAt, v))
}
// Token applies equality check predicate on the "token" field. It's identical to TokenEQ.
func Token(v []byte) predicate.ActionToken {
return predicate.ActionToken(sql.FieldEQ(FieldToken, v))
}
// UserIDEQ applies the EQ predicate on the "user_id" field.
func UserIDEQ(v uuid.UUID) predicate.ActionToken {
return predicate.ActionToken(sql.FieldEQ(FieldUserID, v))
}
// UserIDNEQ applies the NEQ predicate on the "user_id" field.
func UserIDNEQ(v uuid.UUID) predicate.ActionToken {
return predicate.ActionToken(sql.FieldNEQ(FieldUserID, v))
}
// UserIDIn applies the In predicate on the "user_id" field.
func UserIDIn(vs ...uuid.UUID) predicate.ActionToken {
return predicate.ActionToken(sql.FieldIn(FieldUserID, vs...))
}
// UserIDNotIn applies the NotIn predicate on the "user_id" field.
func UserIDNotIn(vs ...uuid.UUID) predicate.ActionToken {
return predicate.ActionToken(sql.FieldNotIn(FieldUserID, vs...))
}
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
func CreatedAtEQ(v time.Time) predicate.ActionToken {
return predicate.ActionToken(sql.FieldEQ(FieldCreatedAt, v))
}
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
func CreatedAtNEQ(v time.Time) predicate.ActionToken {
return predicate.ActionToken(sql.FieldNEQ(FieldCreatedAt, v))
}
// CreatedAtIn applies the In predicate on the "created_at" field.
func CreatedAtIn(vs ...time.Time) predicate.ActionToken {
return predicate.ActionToken(sql.FieldIn(FieldCreatedAt, vs...))
}
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
func CreatedAtNotIn(vs ...time.Time) predicate.ActionToken {
return predicate.ActionToken(sql.FieldNotIn(FieldCreatedAt, vs...))
}
// CreatedAtGT applies the GT predicate on the "created_at" field.
func CreatedAtGT(v time.Time) predicate.ActionToken {
return predicate.ActionToken(sql.FieldGT(FieldCreatedAt, v))
}
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
func CreatedAtGTE(v time.Time) predicate.ActionToken {
return predicate.ActionToken(sql.FieldGTE(FieldCreatedAt, v))
}
// CreatedAtLT applies the LT predicate on the "created_at" field.
func CreatedAtLT(v time.Time) predicate.ActionToken {
return predicate.ActionToken(sql.FieldLT(FieldCreatedAt, v))
}
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
func CreatedAtLTE(v time.Time) predicate.ActionToken {
return predicate.ActionToken(sql.FieldLTE(FieldCreatedAt, v))
}
// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
func UpdatedAtEQ(v time.Time) predicate.ActionToken {
return predicate.ActionToken(sql.FieldEQ(FieldUpdatedAt, v))
}
// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
func UpdatedAtNEQ(v time.Time) predicate.ActionToken {
return predicate.ActionToken(sql.FieldNEQ(FieldUpdatedAt, v))
}
// UpdatedAtIn applies the In predicate on the "updated_at" field.
func UpdatedAtIn(vs ...time.Time) predicate.ActionToken {
return predicate.ActionToken(sql.FieldIn(FieldUpdatedAt, vs...))
}
// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
func UpdatedAtNotIn(vs ...time.Time) predicate.ActionToken {
return predicate.ActionToken(sql.FieldNotIn(FieldUpdatedAt, vs...))
}
// UpdatedAtGT applies the GT predicate on the "updated_at" field.
func UpdatedAtGT(v time.Time) predicate.ActionToken {
return predicate.ActionToken(sql.FieldGT(FieldUpdatedAt, v))
}
// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
func UpdatedAtGTE(v time.Time) predicate.ActionToken {
return predicate.ActionToken(sql.FieldGTE(FieldUpdatedAt, v))
}
// UpdatedAtLT applies the LT predicate on the "updated_at" field.
func UpdatedAtLT(v time.Time) predicate.ActionToken {
return predicate.ActionToken(sql.FieldLT(FieldUpdatedAt, v))
}
// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
func UpdatedAtLTE(v time.Time) predicate.ActionToken {
return predicate.ActionToken(sql.FieldLTE(FieldUpdatedAt, v))
}
// ActionEQ applies the EQ predicate on the "action" field.
func ActionEQ(v Action) predicate.ActionToken {
return predicate.ActionToken(sql.FieldEQ(FieldAction, v))
}
// ActionNEQ applies the NEQ predicate on the "action" field.
func ActionNEQ(v Action) predicate.ActionToken {
return predicate.ActionToken(sql.FieldNEQ(FieldAction, v))
}
// ActionIn applies the In predicate on the "action" field.
func ActionIn(vs ...Action) predicate.ActionToken {
return predicate.ActionToken(sql.FieldIn(FieldAction, vs...))
}
// ActionNotIn applies the NotIn predicate on the "action" field.
func ActionNotIn(vs ...Action) predicate.ActionToken {
return predicate.ActionToken(sql.FieldNotIn(FieldAction, vs...))
}
// TokenEQ applies the EQ predicate on the "token" field.
func TokenEQ(v []byte) predicate.ActionToken {
return predicate.ActionToken(sql.FieldEQ(FieldToken, v))
}
// TokenNEQ applies the NEQ predicate on the "token" field.
func TokenNEQ(v []byte) predicate.ActionToken {
return predicate.ActionToken(sql.FieldNEQ(FieldToken, v))
}
// TokenIn applies the In predicate on the "token" field.
func TokenIn(vs ...[]byte) predicate.ActionToken {
return predicate.ActionToken(sql.FieldIn(FieldToken, vs...))
}
// TokenNotIn applies the NotIn predicate on the "token" field.
func TokenNotIn(vs ...[]byte) predicate.ActionToken {
return predicate.ActionToken(sql.FieldNotIn(FieldToken, vs...))
}
// TokenGT applies the GT predicate on the "token" field.
func TokenGT(v []byte) predicate.ActionToken {
return predicate.ActionToken(sql.FieldGT(FieldToken, v))
}
// TokenGTE applies the GTE predicate on the "token" field.
func TokenGTE(v []byte) predicate.ActionToken {
return predicate.ActionToken(sql.FieldGTE(FieldToken, v))
}
// TokenLT applies the LT predicate on the "token" field.
func TokenLT(v []byte) predicate.ActionToken {
return predicate.ActionToken(sql.FieldLT(FieldToken, v))
}
// TokenLTE applies the LTE predicate on the "token" field.
func TokenLTE(v []byte) predicate.ActionToken {
return predicate.ActionToken(sql.FieldLTE(FieldToken, v))
}
// HasUser applies the HasEdge predicate on the "user" edge.
func HasUser() predicate.ActionToken {
return predicate.ActionToken(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, UserTable, UserColumn),
)
sqlgraph.HasNeighbors(s, step)
})
}
// HasUserWith applies the HasEdge predicate on the "user" edge with a given conditions (other predicates).
func HasUserWith(preds ...predicate.User) predicate.ActionToken {
return predicate.ActionToken(func(s *sql.Selector) {
step := newUserStep()
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds {
p(s)
}
})
})
}
// And groups predicates with the AND operator between them.
func And(predicates ...predicate.ActionToken) predicate.ActionToken {
return predicate.ActionToken(sql.AndPredicates(predicates...))
}
// Or groups predicates with the OR operator between them.
func Or(predicates ...predicate.ActionToken) predicate.ActionToken {
return predicate.ActionToken(sql.OrPredicates(predicates...))
}
// Not applies the not operator on the given predicate.
func Not(p predicate.ActionToken) predicate.ActionToken {
return predicate.ActionToken(sql.NotPredicates(p))
}

View File

@@ -1,329 +0,0 @@
// Code generated by ent, DO NOT EDIT.
package ent
import (
"context"
"errors"
"fmt"
"time"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/data/ent/actiontoken"
"github.com/hay-kot/homebox/backend/internal/data/ent/user"
)
// ActionTokenCreate is the builder for creating a ActionToken entity.
type ActionTokenCreate struct {
config
mutation *ActionTokenMutation
hooks []Hook
}
// SetUserID sets the "user_id" field.
func (atc *ActionTokenCreate) SetUserID(u uuid.UUID) *ActionTokenCreate {
atc.mutation.SetUserID(u)
return atc
}
// SetCreatedAt sets the "created_at" field.
func (atc *ActionTokenCreate) SetCreatedAt(t time.Time) *ActionTokenCreate {
atc.mutation.SetCreatedAt(t)
return atc
}
// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
func (atc *ActionTokenCreate) SetNillableCreatedAt(t *time.Time) *ActionTokenCreate {
if t != nil {
atc.SetCreatedAt(*t)
}
return atc
}
// SetUpdatedAt sets the "updated_at" field.
func (atc *ActionTokenCreate) SetUpdatedAt(t time.Time) *ActionTokenCreate {
atc.mutation.SetUpdatedAt(t)
return atc
}
// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil.
func (atc *ActionTokenCreate) SetNillableUpdatedAt(t *time.Time) *ActionTokenCreate {
if t != nil {
atc.SetUpdatedAt(*t)
}
return atc
}
// SetAction sets the "action" field.
func (atc *ActionTokenCreate) SetAction(a actiontoken.Action) *ActionTokenCreate {
atc.mutation.SetAction(a)
return atc
}
// SetNillableAction sets the "action" field if the given value is not nil.
func (atc *ActionTokenCreate) SetNillableAction(a *actiontoken.Action) *ActionTokenCreate {
if a != nil {
atc.SetAction(*a)
}
return atc
}
// SetToken sets the "token" field.
func (atc *ActionTokenCreate) SetToken(b []byte) *ActionTokenCreate {
atc.mutation.SetToken(b)
return atc
}
// SetID sets the "id" field.
func (atc *ActionTokenCreate) SetID(u uuid.UUID) *ActionTokenCreate {
atc.mutation.SetID(u)
return atc
}
// SetNillableID sets the "id" field if the given value is not nil.
func (atc *ActionTokenCreate) SetNillableID(u *uuid.UUID) *ActionTokenCreate {
if u != nil {
atc.SetID(*u)
}
return atc
}
// SetUser sets the "user" edge to the User entity.
func (atc *ActionTokenCreate) SetUser(u *User) *ActionTokenCreate {
return atc.SetUserID(u.ID)
}
// Mutation returns the ActionTokenMutation object of the builder.
func (atc *ActionTokenCreate) Mutation() *ActionTokenMutation {
return atc.mutation
}
// Save creates the ActionToken in the database.
func (atc *ActionTokenCreate) Save(ctx context.Context) (*ActionToken, error) {
atc.defaults()
return withHooks(ctx, atc.sqlSave, atc.mutation, atc.hooks)
}
// SaveX calls Save and panics if Save returns an error.
func (atc *ActionTokenCreate) SaveX(ctx context.Context) *ActionToken {
v, err := atc.Save(ctx)
if err != nil {
panic(err)
}
return v
}
// Exec executes the query.
func (atc *ActionTokenCreate) Exec(ctx context.Context) error {
_, err := atc.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (atc *ActionTokenCreate) ExecX(ctx context.Context) {
if err := atc.Exec(ctx); err != nil {
panic(err)
}
}
// defaults sets the default values of the builder before save.
func (atc *ActionTokenCreate) defaults() {
if _, ok := atc.mutation.CreatedAt(); !ok {
v := actiontoken.DefaultCreatedAt()
atc.mutation.SetCreatedAt(v)
}
if _, ok := atc.mutation.UpdatedAt(); !ok {
v := actiontoken.DefaultUpdatedAt()
atc.mutation.SetUpdatedAt(v)
}
if _, ok := atc.mutation.Action(); !ok {
v := actiontoken.DefaultAction
atc.mutation.SetAction(v)
}
if _, ok := atc.mutation.ID(); !ok {
v := actiontoken.DefaultID()
atc.mutation.SetID(v)
}
}
// check runs all checks and user-defined validators on the builder.
func (atc *ActionTokenCreate) check() error {
if _, ok := atc.mutation.UserID(); !ok {
return &ValidationError{Name: "user_id", err: errors.New(`ent: missing required field "ActionToken.user_id"`)}
}
if _, ok := atc.mutation.CreatedAt(); !ok {
return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "ActionToken.created_at"`)}
}
if _, ok := atc.mutation.UpdatedAt(); !ok {
return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "ActionToken.updated_at"`)}
}
if _, ok := atc.mutation.Action(); !ok {
return &ValidationError{Name: "action", err: errors.New(`ent: missing required field "ActionToken.action"`)}
}
if v, ok := atc.mutation.Action(); ok {
if err := actiontoken.ActionValidator(v); err != nil {
return &ValidationError{Name: "action", err: fmt.Errorf(`ent: validator failed for field "ActionToken.action": %w`, err)}
}
}
if _, ok := atc.mutation.Token(); !ok {
return &ValidationError{Name: "token", err: errors.New(`ent: missing required field "ActionToken.token"`)}
}
if _, ok := atc.mutation.UserID(); !ok {
return &ValidationError{Name: "user", err: errors.New(`ent: missing required edge "ActionToken.user"`)}
}
return nil
}
func (atc *ActionTokenCreate) sqlSave(ctx context.Context) (*ActionToken, error) {
if err := atc.check(); err != nil {
return nil, err
}
_node, _spec := atc.createSpec()
if err := sqlgraph.CreateNode(ctx, atc.driver, _spec); err != nil {
if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
return nil, err
}
if _spec.ID.Value != nil {
if id, ok := _spec.ID.Value.(*uuid.UUID); ok {
_node.ID = *id
} else if err := _node.ID.Scan(_spec.ID.Value); err != nil {
return nil, err
}
}
atc.mutation.id = &_node.ID
atc.mutation.done = true
return _node, nil
}
func (atc *ActionTokenCreate) createSpec() (*ActionToken, *sqlgraph.CreateSpec) {
var (
_node = &ActionToken{config: atc.config}
_spec = sqlgraph.NewCreateSpec(actiontoken.Table, sqlgraph.NewFieldSpec(actiontoken.FieldID, field.TypeUUID))
)
if id, ok := atc.mutation.ID(); ok {
_node.ID = id
_spec.ID.Value = &id
}
if value, ok := atc.mutation.CreatedAt(); ok {
_spec.SetField(actiontoken.FieldCreatedAt, field.TypeTime, value)
_node.CreatedAt = value
}
if value, ok := atc.mutation.UpdatedAt(); ok {
_spec.SetField(actiontoken.FieldUpdatedAt, field.TypeTime, value)
_node.UpdatedAt = value
}
if value, ok := atc.mutation.Action(); ok {
_spec.SetField(actiontoken.FieldAction, field.TypeEnum, value)
_node.Action = value
}
if value, ok := atc.mutation.Token(); ok {
_spec.SetField(actiontoken.FieldToken, field.TypeBytes, value)
_node.Token = value
}
if nodes := atc.mutation.UserIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: actiontoken.UserTable,
Columns: []string{actiontoken.UserColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_node.UserID = nodes[0]
_spec.Edges = append(_spec.Edges, edge)
}
return _node, _spec
}
// ActionTokenCreateBulk is the builder for creating many ActionToken entities in bulk.
type ActionTokenCreateBulk struct {
config
err error
builders []*ActionTokenCreate
}
// Save creates the ActionToken entities in the database.
func (atcb *ActionTokenCreateBulk) Save(ctx context.Context) ([]*ActionToken, error) {
if atcb.err != nil {
return nil, atcb.err
}
specs := make([]*sqlgraph.CreateSpec, len(atcb.builders))
nodes := make([]*ActionToken, len(atcb.builders))
mutators := make([]Mutator, len(atcb.builders))
for i := range atcb.builders {
func(i int, root context.Context) {
builder := atcb.builders[i]
builder.defaults()
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
mutation, ok := m.(*ActionTokenMutation)
if !ok {
return nil, fmt.Errorf("unexpected mutation type %T", m)
}
if err := builder.check(); err != nil {
return nil, err
}
builder.mutation = mutation
var err error
nodes[i], specs[i] = builder.createSpec()
if i < len(mutators)-1 {
_, err = mutators[i+1].Mutate(root, atcb.builders[i+1].mutation)
} else {
spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
// Invoke the actual operation on the latest mutation in the chain.
if err = sqlgraph.BatchCreate(ctx, atcb.driver, spec); err != nil {
if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
}
}
if err != nil {
return nil, err
}
mutation.id = &nodes[i].ID
mutation.done = true
return nodes[i], nil
})
for i := len(builder.hooks) - 1; i >= 0; i-- {
mut = builder.hooks[i](mut)
}
mutators[i] = mut
}(i, ctx)
}
if len(mutators) > 0 {
if _, err := mutators[0].Mutate(ctx, atcb.builders[0].mutation); err != nil {
return nil, err
}
}
return nodes, nil
}
// SaveX is like Save, but panics if an error occurs.
func (atcb *ActionTokenCreateBulk) SaveX(ctx context.Context) []*ActionToken {
v, err := atcb.Save(ctx)
if err != nil {
panic(err)
}
return v
}
// Exec executes the query.
func (atcb *ActionTokenCreateBulk) Exec(ctx context.Context) error {
_, err := atcb.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (atcb *ActionTokenCreateBulk) ExecX(ctx context.Context) {
if err := atcb.Exec(ctx); err != nil {
panic(err)
}
}

View File

@@ -1,88 +0,0 @@
// Code generated by ent, DO NOT EDIT.
package ent
import (
"context"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/hay-kot/homebox/backend/internal/data/ent/actiontoken"
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
)
// ActionTokenDelete is the builder for deleting a ActionToken entity.
type ActionTokenDelete struct {
config
hooks []Hook
mutation *ActionTokenMutation
}
// Where appends a list predicates to the ActionTokenDelete builder.
func (atd *ActionTokenDelete) Where(ps ...predicate.ActionToken) *ActionTokenDelete {
atd.mutation.Where(ps...)
return atd
}
// Exec executes the deletion query and returns how many vertices were deleted.
func (atd *ActionTokenDelete) Exec(ctx context.Context) (int, error) {
return withHooks(ctx, atd.sqlExec, atd.mutation, atd.hooks)
}
// ExecX is like Exec, but panics if an error occurs.
func (atd *ActionTokenDelete) ExecX(ctx context.Context) int {
n, err := atd.Exec(ctx)
if err != nil {
panic(err)
}
return n
}
func (atd *ActionTokenDelete) sqlExec(ctx context.Context) (int, error) {
_spec := sqlgraph.NewDeleteSpec(actiontoken.Table, sqlgraph.NewFieldSpec(actiontoken.FieldID, field.TypeUUID))
if ps := atd.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
affected, err := sqlgraph.DeleteNodes(ctx, atd.driver, _spec)
if err != nil && sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
atd.mutation.done = true
return affected, err
}
// ActionTokenDeleteOne is the builder for deleting a single ActionToken entity.
type ActionTokenDeleteOne struct {
atd *ActionTokenDelete
}
// Where appends a list predicates to the ActionTokenDelete builder.
func (atdo *ActionTokenDeleteOne) Where(ps ...predicate.ActionToken) *ActionTokenDeleteOne {
atdo.atd.mutation.Where(ps...)
return atdo
}
// Exec executes the deletion query.
func (atdo *ActionTokenDeleteOne) Exec(ctx context.Context) error {
n, err := atdo.atd.Exec(ctx)
switch {
case err != nil:
return err
case n == 0:
return &NotFoundError{actiontoken.Label}
default:
return nil
}
}
// ExecX is like Exec, but panics if an error occurs.
func (atdo *ActionTokenDeleteOne) ExecX(ctx context.Context) {
if err := atdo.Exec(ctx); err != nil {
panic(err)
}
}

View File

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

View File

@@ -1,406 +0,0 @@
// Code generated by ent, DO NOT EDIT.
package ent
import (
"context"
"errors"
"fmt"
"time"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/data/ent/actiontoken"
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
"github.com/hay-kot/homebox/backend/internal/data/ent/user"
)
// ActionTokenUpdate is the builder for updating ActionToken entities.
type ActionTokenUpdate struct {
config
hooks []Hook
mutation *ActionTokenMutation
}
// Where appends a list predicates to the ActionTokenUpdate builder.
func (atu *ActionTokenUpdate) Where(ps ...predicate.ActionToken) *ActionTokenUpdate {
atu.mutation.Where(ps...)
return atu
}
// SetUserID sets the "user_id" field.
func (atu *ActionTokenUpdate) SetUserID(u uuid.UUID) *ActionTokenUpdate {
atu.mutation.SetUserID(u)
return atu
}
// SetNillableUserID sets the "user_id" field if the given value is not nil.
func (atu *ActionTokenUpdate) SetNillableUserID(u *uuid.UUID) *ActionTokenUpdate {
if u != nil {
atu.SetUserID(*u)
}
return atu
}
// SetUpdatedAt sets the "updated_at" field.
func (atu *ActionTokenUpdate) SetUpdatedAt(t time.Time) *ActionTokenUpdate {
atu.mutation.SetUpdatedAt(t)
return atu
}
// SetAction sets the "action" field.
func (atu *ActionTokenUpdate) SetAction(a actiontoken.Action) *ActionTokenUpdate {
atu.mutation.SetAction(a)
return atu
}
// SetNillableAction sets the "action" field if the given value is not nil.
func (atu *ActionTokenUpdate) SetNillableAction(a *actiontoken.Action) *ActionTokenUpdate {
if a != nil {
atu.SetAction(*a)
}
return atu
}
// SetToken sets the "token" field.
func (atu *ActionTokenUpdate) SetToken(b []byte) *ActionTokenUpdate {
atu.mutation.SetToken(b)
return atu
}
// SetUser sets the "user" edge to the User entity.
func (atu *ActionTokenUpdate) SetUser(u *User) *ActionTokenUpdate {
return atu.SetUserID(u.ID)
}
// Mutation returns the ActionTokenMutation object of the builder.
func (atu *ActionTokenUpdate) Mutation() *ActionTokenMutation {
return atu.mutation
}
// ClearUser clears the "user" edge to the User entity.
func (atu *ActionTokenUpdate) ClearUser() *ActionTokenUpdate {
atu.mutation.ClearUser()
return atu
}
// Save executes the query and returns the number of nodes affected by the update operation.
func (atu *ActionTokenUpdate) Save(ctx context.Context) (int, error) {
atu.defaults()
return withHooks(ctx, atu.sqlSave, atu.mutation, atu.hooks)
}
// SaveX is like Save, but panics if an error occurs.
func (atu *ActionTokenUpdate) SaveX(ctx context.Context) int {
affected, err := atu.Save(ctx)
if err != nil {
panic(err)
}
return affected
}
// Exec executes the query.
func (atu *ActionTokenUpdate) Exec(ctx context.Context) error {
_, err := atu.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (atu *ActionTokenUpdate) ExecX(ctx context.Context) {
if err := atu.Exec(ctx); err != nil {
panic(err)
}
}
// defaults sets the default values of the builder before save.
func (atu *ActionTokenUpdate) defaults() {
if _, ok := atu.mutation.UpdatedAt(); !ok {
v := actiontoken.UpdateDefaultUpdatedAt()
atu.mutation.SetUpdatedAt(v)
}
}
// check runs all checks and user-defined validators on the builder.
func (atu *ActionTokenUpdate) check() error {
if v, ok := atu.mutation.Action(); ok {
if err := actiontoken.ActionValidator(v); err != nil {
return &ValidationError{Name: "action", err: fmt.Errorf(`ent: validator failed for field "ActionToken.action": %w`, err)}
}
}
if _, ok := atu.mutation.UserID(); atu.mutation.UserCleared() && !ok {
return errors.New(`ent: clearing a required unique edge "ActionToken.user"`)
}
return nil
}
func (atu *ActionTokenUpdate) sqlSave(ctx context.Context) (n int, err error) {
if err := atu.check(); err != nil {
return n, err
}
_spec := sqlgraph.NewUpdateSpec(actiontoken.Table, actiontoken.Columns, sqlgraph.NewFieldSpec(actiontoken.FieldID, field.TypeUUID))
if ps := atu.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if value, ok := atu.mutation.UpdatedAt(); ok {
_spec.SetField(actiontoken.FieldUpdatedAt, field.TypeTime, value)
}
if value, ok := atu.mutation.Action(); ok {
_spec.SetField(actiontoken.FieldAction, field.TypeEnum, value)
}
if value, ok := atu.mutation.Token(); ok {
_spec.SetField(actiontoken.FieldToken, field.TypeBytes, value)
}
if atu.mutation.UserCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: actiontoken.UserTable,
Columns: []string{actiontoken.UserColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := atu.mutation.UserIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: actiontoken.UserTable,
Columns: []string{actiontoken.UserColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if n, err = sqlgraph.UpdateNodes(ctx, atu.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{actiontoken.Label}
} else if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
return 0, err
}
atu.mutation.done = true
return n, nil
}
// ActionTokenUpdateOne is the builder for updating a single ActionToken entity.
type ActionTokenUpdateOne struct {
config
fields []string
hooks []Hook
mutation *ActionTokenMutation
}
// SetUserID sets the "user_id" field.
func (atuo *ActionTokenUpdateOne) SetUserID(u uuid.UUID) *ActionTokenUpdateOne {
atuo.mutation.SetUserID(u)
return atuo
}
// SetNillableUserID sets the "user_id" field if the given value is not nil.
func (atuo *ActionTokenUpdateOne) SetNillableUserID(u *uuid.UUID) *ActionTokenUpdateOne {
if u != nil {
atuo.SetUserID(*u)
}
return atuo
}
// SetUpdatedAt sets the "updated_at" field.
func (atuo *ActionTokenUpdateOne) SetUpdatedAt(t time.Time) *ActionTokenUpdateOne {
atuo.mutation.SetUpdatedAt(t)
return atuo
}
// SetAction sets the "action" field.
func (atuo *ActionTokenUpdateOne) SetAction(a actiontoken.Action) *ActionTokenUpdateOne {
atuo.mutation.SetAction(a)
return atuo
}
// SetNillableAction sets the "action" field if the given value is not nil.
func (atuo *ActionTokenUpdateOne) SetNillableAction(a *actiontoken.Action) *ActionTokenUpdateOne {
if a != nil {
atuo.SetAction(*a)
}
return atuo
}
// SetToken sets the "token" field.
func (atuo *ActionTokenUpdateOne) SetToken(b []byte) *ActionTokenUpdateOne {
atuo.mutation.SetToken(b)
return atuo
}
// SetUser sets the "user" edge to the User entity.
func (atuo *ActionTokenUpdateOne) SetUser(u *User) *ActionTokenUpdateOne {
return atuo.SetUserID(u.ID)
}
// Mutation returns the ActionTokenMutation object of the builder.
func (atuo *ActionTokenUpdateOne) Mutation() *ActionTokenMutation {
return atuo.mutation
}
// ClearUser clears the "user" edge to the User entity.
func (atuo *ActionTokenUpdateOne) ClearUser() *ActionTokenUpdateOne {
atuo.mutation.ClearUser()
return atuo
}
// Where appends a list predicates to the ActionTokenUpdate builder.
func (atuo *ActionTokenUpdateOne) Where(ps ...predicate.ActionToken) *ActionTokenUpdateOne {
atuo.mutation.Where(ps...)
return atuo
}
// Select allows selecting one or more fields (columns) of the returned entity.
// The default is selecting all fields defined in the entity schema.
func (atuo *ActionTokenUpdateOne) Select(field string, fields ...string) *ActionTokenUpdateOne {
atuo.fields = append([]string{field}, fields...)
return atuo
}
// Save executes the query and returns the updated ActionToken entity.
func (atuo *ActionTokenUpdateOne) Save(ctx context.Context) (*ActionToken, error) {
atuo.defaults()
return withHooks(ctx, atuo.sqlSave, atuo.mutation, atuo.hooks)
}
// SaveX is like Save, but panics if an error occurs.
func (atuo *ActionTokenUpdateOne) SaveX(ctx context.Context) *ActionToken {
node, err := atuo.Save(ctx)
if err != nil {
panic(err)
}
return node
}
// Exec executes the query on the entity.
func (atuo *ActionTokenUpdateOne) Exec(ctx context.Context) error {
_, err := atuo.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (atuo *ActionTokenUpdateOne) ExecX(ctx context.Context) {
if err := atuo.Exec(ctx); err != nil {
panic(err)
}
}
// defaults sets the default values of the builder before save.
func (atuo *ActionTokenUpdateOne) defaults() {
if _, ok := atuo.mutation.UpdatedAt(); !ok {
v := actiontoken.UpdateDefaultUpdatedAt()
atuo.mutation.SetUpdatedAt(v)
}
}
// check runs all checks and user-defined validators on the builder.
func (atuo *ActionTokenUpdateOne) check() error {
if v, ok := atuo.mutation.Action(); ok {
if err := actiontoken.ActionValidator(v); err != nil {
return &ValidationError{Name: "action", err: fmt.Errorf(`ent: validator failed for field "ActionToken.action": %w`, err)}
}
}
if _, ok := atuo.mutation.UserID(); atuo.mutation.UserCleared() && !ok {
return errors.New(`ent: clearing a required unique edge "ActionToken.user"`)
}
return nil
}
func (atuo *ActionTokenUpdateOne) sqlSave(ctx context.Context) (_node *ActionToken, err error) {
if err := atuo.check(); err != nil {
return _node, err
}
_spec := sqlgraph.NewUpdateSpec(actiontoken.Table, actiontoken.Columns, sqlgraph.NewFieldSpec(actiontoken.FieldID, field.TypeUUID))
id, ok := atuo.mutation.ID()
if !ok {
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "ActionToken.id" for update`)}
}
_spec.Node.ID.Value = id
if fields := atuo.fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, actiontoken.FieldID)
for _, f := range fields {
if !actiontoken.ValidColumn(f) {
return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
if f != actiontoken.FieldID {
_spec.Node.Columns = append(_spec.Node.Columns, f)
}
}
}
if ps := atuo.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if value, ok := atuo.mutation.UpdatedAt(); ok {
_spec.SetField(actiontoken.FieldUpdatedAt, field.TypeTime, value)
}
if value, ok := atuo.mutation.Action(); ok {
_spec.SetField(actiontoken.FieldAction, field.TypeEnum, value)
}
if value, ok := atuo.mutation.Token(); ok {
_spec.SetField(actiontoken.FieldToken, field.TypeBytes, value)
}
if atuo.mutation.UserCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: actiontoken.UserTable,
Columns: []string{actiontoken.UserColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := atuo.mutation.UserIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: actiontoken.UserTable,
Columns: []string{actiontoken.UserColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
_node = &ActionToken{config: atuo.config}
_spec.Assign = _node.assignValues
_spec.ScanValues = _node.scanValues
if err = sqlgraph.UpdateNode(ctx, atuo.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{actiontoken.Label}
} else if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
return nil, err
}
atuo.mutation.done = true
return _node, nil
}

View File

@@ -16,7 +16,6 @@ import (
"entgo.io/ent/dialect"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"github.com/hay-kot/homebox/backend/internal/data/ent/actiontoken"
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
@@ -37,8 +36,6 @@ type Client struct {
config
// Schema is the client for creating, migrating and dropping schema.
Schema *migrate.Schema
// ActionToken is the client for interacting with the ActionToken builders.
ActionToken *ActionTokenClient
// Attachment is the client for interacting with the Attachment builders.
Attachment *AttachmentClient
// AuthRoles is the client for interacting with the AuthRoles builders.
@@ -76,7 +73,6 @@ func NewClient(opts ...Option) *Client {
func (c *Client) init() {
c.Schema = migrate.NewSchema(c.driver)
c.ActionToken = NewActionTokenClient(c.config)
c.Attachment = NewAttachmentClient(c.config)
c.AuthRoles = NewAuthRolesClient(c.config)
c.AuthTokens = NewAuthTokensClient(c.config)
@@ -182,7 +178,6 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) {
return &Tx{
ctx: ctx,
config: cfg,
ActionToken: NewActionTokenClient(cfg),
Attachment: NewAttachmentClient(cfg),
AuthRoles: NewAuthRolesClient(cfg),
AuthTokens: NewAuthTokensClient(cfg),
@@ -215,7 +210,6 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error)
return &Tx{
ctx: ctx,
config: cfg,
ActionToken: NewActionTokenClient(cfg),
Attachment: NewAttachmentClient(cfg),
AuthRoles: NewAuthRolesClient(cfg),
AuthTokens: NewAuthTokensClient(cfg),
@@ -235,7 +229,7 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error)
// Debug returns a new debug-client. It's used to get verbose logging on specific operations.
//
// client.Debug().
// ActionToken.
// Attachment.
// Query().
// Count(ctx)
func (c *Client) Debug() *Client {
@@ -258,7 +252,7 @@ func (c *Client) Close() error {
// In order to add hooks to a specific client, call: `client.Node.Use(...)`.
func (c *Client) Use(hooks ...Hook) {
for _, n := range []interface{ Use(...Hook) }{
c.ActionToken, c.Attachment, c.AuthRoles, c.AuthTokens, c.Document, c.Group,
c.Attachment, c.AuthRoles, c.AuthTokens, c.Document, c.Group,
c.GroupInvitationToken, c.Item, c.ItemField, c.Label, c.Location,
c.MaintenanceEntry, c.Notifier, c.User,
} {
@@ -270,7 +264,7 @@ func (c *Client) Use(hooks ...Hook) {
// In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`.
func (c *Client) Intercept(interceptors ...Interceptor) {
for _, n := range []interface{ Intercept(...Interceptor) }{
c.ActionToken, c.Attachment, c.AuthRoles, c.AuthTokens, c.Document, c.Group,
c.Attachment, c.AuthRoles, c.AuthTokens, c.Document, c.Group,
c.GroupInvitationToken, c.Item, c.ItemField, c.Label, c.Location,
c.MaintenanceEntry, c.Notifier, c.User,
} {
@@ -281,8 +275,6 @@ func (c *Client) Intercept(interceptors ...Interceptor) {
// Mutate implements the ent.Mutator interface.
func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) {
switch m := m.(type) {
case *ActionTokenMutation:
return c.ActionToken.mutate(ctx, m)
case *AttachmentMutation:
return c.Attachment.mutate(ctx, m)
case *AuthRolesMutation:
@@ -314,155 +306,6 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) {
}
}
// ActionTokenClient is a client for the ActionToken schema.
type ActionTokenClient struct {
config
}
// NewActionTokenClient returns a client for the ActionToken from the given config.
func NewActionTokenClient(c config) *ActionTokenClient {
return &ActionTokenClient{config: c}
}
// Use adds a list of mutation hooks to the hooks stack.
// A call to `Use(f, g, h)` equals to `actiontoken.Hooks(f(g(h())))`.
func (c *ActionTokenClient) Use(hooks ...Hook) {
c.hooks.ActionToken = append(c.hooks.ActionToken, hooks...)
}
// Intercept adds a list of query interceptors to the interceptors stack.
// A call to `Intercept(f, g, h)` equals to `actiontoken.Intercept(f(g(h())))`.
func (c *ActionTokenClient) Intercept(interceptors ...Interceptor) {
c.inters.ActionToken = append(c.inters.ActionToken, interceptors...)
}
// Create returns a builder for creating a ActionToken entity.
func (c *ActionTokenClient) Create() *ActionTokenCreate {
mutation := newActionTokenMutation(c.config, OpCreate)
return &ActionTokenCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// CreateBulk returns a builder for creating a bulk of ActionToken entities.
func (c *ActionTokenClient) CreateBulk(builders ...*ActionTokenCreate) *ActionTokenCreateBulk {
return &ActionTokenCreateBulk{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 *ActionTokenClient) MapCreateBulk(slice any, setFunc func(*ActionTokenCreate, int)) *ActionTokenCreateBulk {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice {
return &ActionTokenCreateBulk{err: fmt.Errorf("calling to ActionTokenClient.MapCreateBulk with wrong type %T, need slice", slice)}
}
builders := make([]*ActionTokenCreate, rv.Len())
for i := 0; i < rv.Len(); i++ {
builders[i] = c.Create()
setFunc(builders[i], i)
}
return &ActionTokenCreateBulk{config: c.config, builders: builders}
}
// Update returns an update builder for ActionToken.
func (c *ActionTokenClient) Update() *ActionTokenUpdate {
mutation := newActionTokenMutation(c.config, OpUpdate)
return &ActionTokenUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// UpdateOne returns an update builder for the given entity.
func (c *ActionTokenClient) UpdateOne(at *ActionToken) *ActionTokenUpdateOne {
mutation := newActionTokenMutation(c.config, OpUpdateOne, withActionToken(at))
return &ActionTokenUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// UpdateOneID returns an update builder for the given id.
func (c *ActionTokenClient) UpdateOneID(id uuid.UUID) *ActionTokenUpdateOne {
mutation := newActionTokenMutation(c.config, OpUpdateOne, withActionTokenID(id))
return &ActionTokenUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// Delete returns a delete builder for ActionToken.
func (c *ActionTokenClient) Delete() *ActionTokenDelete {
mutation := newActionTokenMutation(c.config, OpDelete)
return &ActionTokenDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// DeleteOne returns a builder for deleting the given entity.
func (c *ActionTokenClient) DeleteOne(at *ActionToken) *ActionTokenDeleteOne {
return c.DeleteOneID(at.ID)
}
// DeleteOneID returns a builder for deleting the given entity by its id.
func (c *ActionTokenClient) DeleteOneID(id uuid.UUID) *ActionTokenDeleteOne {
builder := c.Delete().Where(actiontoken.ID(id))
builder.mutation.id = &id
builder.mutation.op = OpDeleteOne
return &ActionTokenDeleteOne{builder}
}
// Query returns a query builder for ActionToken.
func (c *ActionTokenClient) Query() *ActionTokenQuery {
return &ActionTokenQuery{
config: c.config,
ctx: &QueryContext{Type: TypeActionToken},
inters: c.Interceptors(),
}
}
// Get returns a ActionToken entity by its id.
func (c *ActionTokenClient) Get(ctx context.Context, id uuid.UUID) (*ActionToken, error) {
return c.Query().Where(actiontoken.ID(id)).Only(ctx)
}
// GetX is like Get, but panics if an error occurs.
func (c *ActionTokenClient) GetX(ctx context.Context, id uuid.UUID) *ActionToken {
obj, err := c.Get(ctx, id)
if err != nil {
panic(err)
}
return obj
}
// QueryUser queries the user edge of a ActionToken.
func (c *ActionTokenClient) QueryUser(at *ActionToken) *UserQuery {
query := (&UserClient{config: c.config}).Query()
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
id := at.ID
step := sqlgraph.NewStep(
sqlgraph.From(actiontoken.Table, actiontoken.FieldID, id),
sqlgraph.To(user.Table, user.FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, actiontoken.UserTable, actiontoken.UserColumn),
)
fromV = sqlgraph.Neighbors(at.driver.Dialect(), step)
return fromV, nil
}
return query
}
// Hooks returns the client hooks.
func (c *ActionTokenClient) Hooks() []Hook {
return c.hooks.ActionToken
}
// Interceptors returns the client interceptors.
func (c *ActionTokenClient) Interceptors() []Interceptor {
return c.inters.ActionToken
}
func (c *ActionTokenClient) mutate(ctx context.Context, m *ActionTokenMutation) (Value, error) {
switch m.Op() {
case OpCreate:
return (&ActionTokenCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
case OpUpdate:
return (&ActionTokenUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
case OpUpdateOne:
return (&ActionTokenUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
case OpDelete, OpDeleteOne:
return (&ActionTokenDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
default:
return nil, fmt.Errorf("ent: unknown ActionToken mutation op: %q", m.Op())
}
}
// AttachmentClient is a client for the Attachment schema.
type AttachmentClient struct {
config
@@ -2743,22 +2586,6 @@ func (c *UserClient) QueryNotifiers(u *User) *NotifierQuery {
return query
}
// QueryActionTokens queries the action_tokens edge of a User.
func (c *UserClient) QueryActionTokens(u *User) *ActionTokenQuery {
query := (&ActionTokenClient{config: c.config}).Query()
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
id := u.ID
step := sqlgraph.NewStep(
sqlgraph.From(user.Table, user.FieldID, id),
sqlgraph.To(actiontoken.Table, actiontoken.FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, user.ActionTokensTable, user.ActionTokensColumn),
)
fromV = sqlgraph.Neighbors(u.driver.Dialect(), step)
return fromV, nil
}
return query
}
// Hooks returns the client hooks.
func (c *UserClient) Hooks() []Hook {
return c.hooks.User
@@ -2787,13 +2614,11 @@ func (c *UserClient) mutate(ctx context.Context, m *UserMutation) (Value, error)
// hooks and interceptors per client, for fast access.
type (
hooks struct {
ActionToken, Attachment, AuthRoles, AuthTokens, Document, Group,
GroupInvitationToken, Item, ItemField, Label, Location, MaintenanceEntry,
Notifier, User []ent.Hook
Attachment, AuthRoles, AuthTokens, Document, Group, GroupInvitationToken, Item,
ItemField, Label, Location, MaintenanceEntry, Notifier, User []ent.Hook
}
inters struct {
ActionToken, Attachment, AuthRoles, AuthTokens, Document, Group,
GroupInvitationToken, Item, ItemField, Label, Location, MaintenanceEntry,
Notifier, User []ent.Interceptor
Attachment, AuthRoles, AuthTokens, Document, Group, GroupInvitationToken, Item,
ItemField, Label, Location, MaintenanceEntry, Notifier, User []ent.Interceptor
}
)

View File

@@ -12,7 +12,6 @@ import (
"entgo.io/ent"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"github.com/hay-kot/homebox/backend/internal/data/ent/actiontoken"
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
@@ -86,7 +85,6 @@ var (
func checkColumn(table, column string) error {
initCheck.Do(func() {
columnCheck = sql.NewColumnCheck(map[string]func(string) bool{
actiontoken.Table: actiontoken.ValidColumn,
attachment.Table: attachment.ValidColumn,
authroles.Table: authroles.ValidColumn,
authtokens.Table: authtokens.ValidColumn,

View File

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

View File

@@ -3,6 +3,7 @@
package group
import (
"fmt"
"time"
"entgo.io/ent/dialect/sql"
@@ -118,12 +119,65 @@ var (
UpdateDefaultUpdatedAt func() time.Time
// NameValidator is a validator for the "name" field. It is called by the builders before save.
NameValidator func(string) error
// DefaultCurrency holds the default value on creation for the "currency" field.
DefaultCurrency string
// DefaultID holds the default value on creation for the "id" field.
DefaultID func() uuid.UUID
)
// 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"
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"
CurrencyXag Currency = "xag"
CurrencyXau Currency = "xau"
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, CurrencyCzk, CurrencyDkk, CurrencyEur, CurrencyGbp, CurrencyHkd, CurrencyIdr, CurrencyInr, CurrencyJpy, CurrencyKrw, CurrencyMxn, CurrencyNok, CurrencyNzd, CurrencyPln, CurrencyRmb, CurrencyRon, CurrencyRub, CurrencySar, CurrencySek, CurrencySgd, CurrencyThb, CurrencyTry, CurrencyUsd, CurrencyXag, CurrencyXau, 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.
type OrderOption func(*sql.Selector)

View File

@@ -71,11 +71,6 @@ func Name(v string) predicate.Group {
return predicate.Group(sql.FieldEQ(FieldName, v))
}
// Currency applies equality check predicate on the "currency" field. It's identical to CurrencyEQ.
func Currency(v string) predicate.Group {
return predicate.Group(sql.FieldEQ(FieldCurrency, v))
}
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
func CreatedAtEQ(v time.Time) predicate.Group {
return predicate.Group(sql.FieldEQ(FieldCreatedAt, v))
@@ -222,70 +217,25 @@ func NameContainsFold(v string) predicate.Group {
}
// CurrencyEQ applies the EQ predicate on the "currency" field.
func CurrencyEQ(v string) predicate.Group {
func CurrencyEQ(v Currency) predicate.Group {
return predicate.Group(sql.FieldEQ(FieldCurrency, v))
}
// CurrencyNEQ applies the NEQ predicate on the "currency" field.
func CurrencyNEQ(v string) predicate.Group {
func CurrencyNEQ(v Currency) predicate.Group {
return predicate.Group(sql.FieldNEQ(FieldCurrency, v))
}
// CurrencyIn applies the In predicate on the "currency" field.
func CurrencyIn(vs ...string) predicate.Group {
func CurrencyIn(vs ...Currency) predicate.Group {
return predicate.Group(sql.FieldIn(FieldCurrency, vs...))
}
// CurrencyNotIn applies the NotIn predicate on the "currency" field.
func CurrencyNotIn(vs ...string) predicate.Group {
func CurrencyNotIn(vs ...Currency) predicate.Group {
return predicate.Group(sql.FieldNotIn(FieldCurrency, vs...))
}
// CurrencyGT applies the GT predicate on the "currency" field.
func CurrencyGT(v string) predicate.Group {
return predicate.Group(sql.FieldGT(FieldCurrency, v))
}
// CurrencyGTE applies the GTE predicate on the "currency" field.
func CurrencyGTE(v string) predicate.Group {
return predicate.Group(sql.FieldGTE(FieldCurrency, v))
}
// CurrencyLT applies the LT predicate on the "currency" field.
func CurrencyLT(v string) predicate.Group {
return predicate.Group(sql.FieldLT(FieldCurrency, v))
}
// CurrencyLTE applies the LTE predicate on the "currency" field.
func CurrencyLTE(v string) predicate.Group {
return predicate.Group(sql.FieldLTE(FieldCurrency, v))
}
// CurrencyContains applies the Contains predicate on the "currency" field.
func CurrencyContains(v string) predicate.Group {
return predicate.Group(sql.FieldContains(FieldCurrency, v))
}
// CurrencyHasPrefix applies the HasPrefix predicate on the "currency" field.
func CurrencyHasPrefix(v string) predicate.Group {
return predicate.Group(sql.FieldHasPrefix(FieldCurrency, v))
}
// CurrencyHasSuffix applies the HasSuffix predicate on the "currency" field.
func CurrencyHasSuffix(v string) predicate.Group {
return predicate.Group(sql.FieldHasSuffix(FieldCurrency, v))
}
// CurrencyEqualFold applies the EqualFold predicate on the "currency" field.
func CurrencyEqualFold(v string) predicate.Group {
return predicate.Group(sql.FieldEqualFold(FieldCurrency, v))
}
// CurrencyContainsFold applies the ContainsFold predicate on the "currency" field.
func CurrencyContainsFold(v string) predicate.Group {
return predicate.Group(sql.FieldContainsFold(FieldCurrency, v))
}
// HasUsers applies the HasEdge predicate on the "users" edge.
func HasUsers() predicate.Group {
return predicate.Group(func(s *sql.Selector) {

View File

@@ -63,15 +63,15 @@ func (gc *GroupCreate) SetName(s string) *GroupCreate {
}
// SetCurrency sets the "currency" field.
func (gc *GroupCreate) SetCurrency(s string) *GroupCreate {
gc.mutation.SetCurrency(s)
func (gc *GroupCreate) SetCurrency(gr group.Currency) *GroupCreate {
gc.mutation.SetCurrency(gr)
return gc
}
// SetNillableCurrency sets the "currency" field if the given value is not nil.
func (gc *GroupCreate) SetNillableCurrency(s *string) *GroupCreate {
if s != nil {
gc.SetCurrency(*s)
func (gc *GroupCreate) SetNillableCurrency(gr *group.Currency) *GroupCreate {
if gr != nil {
gc.SetCurrency(*gr)
}
return gc
}
@@ -267,6 +267,11 @@ func (gc *GroupCreate) check() error {
if _, ok := gc.mutation.Currency(); !ok {
return &ValidationError{Name: "currency", err: errors.New(`ent: missing required field "Group.currency"`)}
}
if v, ok := gc.mutation.Currency(); ok {
if err := group.CurrencyValidator(v); err != nil {
return &ValidationError{Name: "currency", err: fmt.Errorf(`ent: validator failed for field "Group.currency": %w`, err)}
}
}
return nil
}
@@ -315,7 +320,7 @@ func (gc *GroupCreate) createSpec() (*Group, *sqlgraph.CreateSpec) {
_node.Name = value
}
if value, ok := gc.mutation.Currency(); ok {
_spec.SetField(group.FieldCurrency, field.TypeString, value)
_spec.SetField(group.FieldCurrency, field.TypeEnum, value)
_node.Currency = value
}
if nodes := gc.mutation.UsersIDs(); len(nodes) > 0 {

View File

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

View File

@@ -4,10 +4,6 @@ package ent
import "github.com/google/uuid"
func (at *ActionToken) GetID() uuid.UUID {
return at.ID
}
func (a *Attachment) GetID() uuid.UUID {
return a.ID
}

View File

@@ -9,18 +9,6 @@ import (
"github.com/hay-kot/homebox/backend/internal/data/ent"
)
// The ActionTokenFunc type is an adapter to allow the use of ordinary
// function as ActionToken mutator.
type ActionTokenFunc func(context.Context, *ent.ActionTokenMutation) (ent.Value, error)
// Mutate calls f(ctx, m).
func (f ActionTokenFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
if mv, ok := m.(*ent.ActionTokenMutation); ok {
return f(ctx, mv)
}
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ActionTokenMutation", m)
}
// The AttachmentFunc type is an adapter to allow the use of ordinary
// function as Attachment mutator.
type AttachmentFunc func(context.Context, *ent.AttachmentMutation) (ent.Value, error)

View File

@@ -8,46 +8,6 @@ import (
)
var (
// ActionTokensColumns holds the columns for the "action_tokens" table.
ActionTokensColumns = []*schema.Column{
{Name: "id", Type: field.TypeUUID},
{Name: "created_at", Type: field.TypeTime},
{Name: "updated_at", Type: field.TypeTime},
{Name: "action", Type: field.TypeEnum, Enums: []string{"reset_password"}, Default: "reset_password"},
{Name: "token", Type: field.TypeBytes, Unique: true},
{Name: "user_id", Type: field.TypeUUID},
}
// ActionTokensTable holds the schema information for the "action_tokens" table.
ActionTokensTable = &schema.Table{
Name: "action_tokens",
Columns: ActionTokensColumns,
PrimaryKey: []*schema.Column{ActionTokensColumns[0]},
ForeignKeys: []*schema.ForeignKey{
{
Symbol: "action_tokens_users_action_tokens",
Columns: []*schema.Column{ActionTokensColumns[5]},
RefColumns: []*schema.Column{UsersColumns[0]},
OnDelete: schema.Cascade,
},
},
Indexes: []*schema.Index{
{
Name: "actiontoken_token",
Unique: false,
Columns: []*schema.Column{ActionTokensColumns[4]},
},
{
Name: "actiontoken_action",
Unique: false,
Columns: []*schema.Column{ActionTokensColumns[3]},
},
{
Name: "actiontoken_user_id",
Unique: false,
Columns: []*schema.Column{ActionTokensColumns[5]},
},
},
}
// AttachmentsColumns holds the columns for the "attachments" table.
AttachmentsColumns = []*schema.Column{
{Name: "id", Type: field.TypeUUID},
@@ -157,7 +117,7 @@ var (
{Name: "created_at", Type: field.TypeTime},
{Name: "updated_at", Type: field.TypeTime},
{Name: "name", Type: field.TypeString, Size: 255},
{Name: "currency", Type: field.TypeString, Default: "usd"},
{Name: "currency", Type: field.TypeEnum, Enums: []string{"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", "xag", "xau", "zar"}, Default: "usd"},
}
// GroupsTable holds the schema information for the "groups" table.
GroupsTable = &schema.Table{
@@ -493,7 +453,6 @@ var (
}
// Tables holds all the tables in the schema.
Tables = []*schema.Table{
ActionTokensTable,
AttachmentsTable,
AuthRolesTable,
AuthTokensTable,
@@ -512,7 +471,6 @@ var (
)
func init() {
ActionTokensTable.ForeignKeys[0].RefTable = UsersTable
AttachmentsTable.ForeignKeys[0].RefTable = DocumentsTable
AttachmentsTable.ForeignKeys[1].RefTable = ItemsTable
AuthRolesTable.ForeignKeys[0].RefTable = AuthTokensTable

View File

@@ -12,7 +12,6 @@ import (
"entgo.io/ent"
"entgo.io/ent/dialect/sql"
"github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/data/ent/actiontoken"
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
@@ -38,7 +37,6 @@ const (
OpUpdateOne = ent.OpUpdateOne
// Node types.
TypeActionToken = "ActionToken"
TypeAttachment = "Attachment"
TypeAuthRoles = "AuthRoles"
TypeAuthTokens = "AuthTokens"
@@ -54,608 +52,6 @@ const (
TypeUser = "User"
)
// ActionTokenMutation represents an operation that mutates the ActionToken nodes in the graph.
type ActionTokenMutation struct {
config
op Op
typ string
id *uuid.UUID
created_at *time.Time
updated_at *time.Time
action *actiontoken.Action
token *[]byte
clearedFields map[string]struct{}
user *uuid.UUID
cleareduser bool
done bool
oldValue func(context.Context) (*ActionToken, error)
predicates []predicate.ActionToken
}
var _ ent.Mutation = (*ActionTokenMutation)(nil)
// actiontokenOption allows management of the mutation configuration using functional options.
type actiontokenOption func(*ActionTokenMutation)
// newActionTokenMutation creates new mutation for the ActionToken entity.
func newActionTokenMutation(c config, op Op, opts ...actiontokenOption) *ActionTokenMutation {
m := &ActionTokenMutation{
config: c,
op: op,
typ: TypeActionToken,
clearedFields: make(map[string]struct{}),
}
for _, opt := range opts {
opt(m)
}
return m
}
// withActionTokenID sets the ID field of the mutation.
func withActionTokenID(id uuid.UUID) actiontokenOption {
return func(m *ActionTokenMutation) {
var (
err error
once sync.Once
value *ActionToken
)
m.oldValue = func(ctx context.Context) (*ActionToken, error) {
once.Do(func() {
if m.done {
err = errors.New("querying old values post mutation is not allowed")
} else {
value, err = m.Client().ActionToken.Get(ctx, id)
}
})
return value, err
}
m.id = &id
}
}
// withActionToken sets the old ActionToken of the mutation.
func withActionToken(node *ActionToken) actiontokenOption {
return func(m *ActionTokenMutation) {
m.oldValue = func(context.Context) (*ActionToken, error) {
return node, nil
}
m.id = &node.ID
}
}
// Client returns a new `ent.Client` from the mutation. If the mutation was
// executed in a transaction (ent.Tx), a transactional client is returned.
func (m ActionTokenMutation) Client() *Client {
client := &Client{config: m.config}
client.init()
return client
}
// Tx returns an `ent.Tx` for mutations that were executed in transactions;
// it returns an error otherwise.
func (m ActionTokenMutation) Tx() (*Tx, error) {
if _, ok := m.driver.(*txDriver); !ok {
return nil, errors.New("ent: mutation is not running in a transaction")
}
tx := &Tx{config: m.config}
tx.init()
return tx, nil
}
// SetID sets the value of the id field. Note that this
// operation is only accepted on creation of ActionToken entities.
func (m *ActionTokenMutation) SetID(id uuid.UUID) {
m.id = &id
}
// ID returns the ID value in the mutation. Note that the ID is only available
// if it was provided to the builder or after it was returned from the database.
func (m *ActionTokenMutation) ID() (id uuid.UUID, exists bool) {
if m.id == nil {
return
}
return *m.id, true
}
// IDs queries the database and returns the entity ids that match the mutation's predicate.
// That means, if the mutation is applied within a transaction with an isolation level such
// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated
// or updated by the mutation.
func (m *ActionTokenMutation) IDs(ctx context.Context) ([]uuid.UUID, error) {
switch {
case m.op.Is(OpUpdateOne | OpDeleteOne):
id, exists := m.ID()
if exists {
return []uuid.UUID{id}, nil
}
fallthrough
case m.op.Is(OpUpdate | OpDelete):
return m.Client().ActionToken.Query().Where(m.predicates...).IDs(ctx)
default:
return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op)
}
}
// SetUserID sets the "user_id" field.
func (m *ActionTokenMutation) SetUserID(u uuid.UUID) {
m.user = &u
}
// UserID returns the value of the "user_id" field in the mutation.
func (m *ActionTokenMutation) UserID() (r uuid.UUID, exists bool) {
v := m.user
if v == nil {
return
}
return *v, true
}
// OldUserID returns the old "user_id" field's value of the ActionToken entity.
// If the ActionToken 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 *ActionTokenMutation) OldUserID(ctx context.Context) (v uuid.UUID, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldUserID is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldUserID requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldUserID: %w", err)
}
return oldValue.UserID, nil
}
// ResetUserID resets all changes to the "user_id" field.
func (m *ActionTokenMutation) ResetUserID() {
m.user = nil
}
// SetCreatedAt sets the "created_at" field.
func (m *ActionTokenMutation) SetCreatedAt(t time.Time) {
m.created_at = &t
}
// CreatedAt returns the value of the "created_at" field in the mutation.
func (m *ActionTokenMutation) CreatedAt() (r time.Time, exists bool) {
v := m.created_at
if v == nil {
return
}
return *v, true
}
// OldCreatedAt returns the old "created_at" field's value of the ActionToken entity.
// If the ActionToken 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 *ActionTokenMutation) OldCreatedAt(ctx context.Context) (v time.Time, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldCreatedAt is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldCreatedAt requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldCreatedAt: %w", err)
}
return oldValue.CreatedAt, nil
}
// ResetCreatedAt resets all changes to the "created_at" field.
func (m *ActionTokenMutation) ResetCreatedAt() {
m.created_at = nil
}
// SetUpdatedAt sets the "updated_at" field.
func (m *ActionTokenMutation) SetUpdatedAt(t time.Time) {
m.updated_at = &t
}
// UpdatedAt returns the value of the "updated_at" field in the mutation.
func (m *ActionTokenMutation) UpdatedAt() (r time.Time, exists bool) {
v := m.updated_at
if v == nil {
return
}
return *v, true
}
// OldUpdatedAt returns the old "updated_at" field's value of the ActionToken entity.
// If the ActionToken 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 *ActionTokenMutation) OldUpdatedAt(ctx context.Context) (v time.Time, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldUpdatedAt is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldUpdatedAt requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldUpdatedAt: %w", err)
}
return oldValue.UpdatedAt, nil
}
// ResetUpdatedAt resets all changes to the "updated_at" field.
func (m *ActionTokenMutation) ResetUpdatedAt() {
m.updated_at = nil
}
// SetAction sets the "action" field.
func (m *ActionTokenMutation) SetAction(a actiontoken.Action) {
m.action = &a
}
// Action returns the value of the "action" field in the mutation.
func (m *ActionTokenMutation) Action() (r actiontoken.Action, exists bool) {
v := m.action
if v == nil {
return
}
return *v, true
}
// OldAction returns the old "action" field's value of the ActionToken entity.
// If the ActionToken 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 *ActionTokenMutation) OldAction(ctx context.Context) (v actiontoken.Action, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldAction is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldAction requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldAction: %w", err)
}
return oldValue.Action, nil
}
// ResetAction resets all changes to the "action" field.
func (m *ActionTokenMutation) ResetAction() {
m.action = nil
}
// SetToken sets the "token" field.
func (m *ActionTokenMutation) SetToken(b []byte) {
m.token = &b
}
// Token returns the value of the "token" field in the mutation.
func (m *ActionTokenMutation) Token() (r []byte, exists bool) {
v := m.token
if v == nil {
return
}
return *v, true
}
// OldToken returns the old "token" field's value of the ActionToken entity.
// If the ActionToken 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 *ActionTokenMutation) OldToken(ctx context.Context) (v []byte, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldToken is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldToken requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldToken: %w", err)
}
return oldValue.Token, nil
}
// ResetToken resets all changes to the "token" field.
func (m *ActionTokenMutation) ResetToken() {
m.token = nil
}
// ClearUser clears the "user" edge to the User entity.
func (m *ActionTokenMutation) ClearUser() {
m.cleareduser = true
m.clearedFields[actiontoken.FieldUserID] = struct{}{}
}
// UserCleared reports if the "user" edge to the User entity was cleared.
func (m *ActionTokenMutation) UserCleared() bool {
return m.cleareduser
}
// UserIDs returns the "user" edge IDs in the mutation.
// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use
// UserID instead. It exists only for internal usage by the builders.
func (m *ActionTokenMutation) UserIDs() (ids []uuid.UUID) {
if id := m.user; id != nil {
ids = append(ids, *id)
}
return
}
// ResetUser resets all changes to the "user" edge.
func (m *ActionTokenMutation) ResetUser() {
m.user = nil
m.cleareduser = false
}
// Where appends a list predicates to the ActionTokenMutation builder.
func (m *ActionTokenMutation) Where(ps ...predicate.ActionToken) {
m.predicates = append(m.predicates, ps...)
}
// WhereP appends storage-level predicates to the ActionTokenMutation builder. Using this method,
// users can use type-assertion to append predicates that do not depend on any generated package.
func (m *ActionTokenMutation) WhereP(ps ...func(*sql.Selector)) {
p := make([]predicate.ActionToken, len(ps))
for i := range ps {
p[i] = ps[i]
}
m.Where(p...)
}
// Op returns the operation name.
func (m *ActionTokenMutation) Op() Op {
return m.op
}
// SetOp allows setting the mutation operation.
func (m *ActionTokenMutation) SetOp(op Op) {
m.op = op
}
// Type returns the node type of this mutation (ActionToken).
func (m *ActionTokenMutation) Type() string {
return m.typ
}
// Fields returns all fields that were changed during this mutation. Note that in
// order to get all numeric fields that were incremented/decremented, call
// AddedFields().
func (m *ActionTokenMutation) Fields() []string {
fields := make([]string, 0, 5)
if m.user != nil {
fields = append(fields, actiontoken.FieldUserID)
}
if m.created_at != nil {
fields = append(fields, actiontoken.FieldCreatedAt)
}
if m.updated_at != nil {
fields = append(fields, actiontoken.FieldUpdatedAt)
}
if m.action != nil {
fields = append(fields, actiontoken.FieldAction)
}
if m.token != nil {
fields = append(fields, actiontoken.FieldToken)
}
return fields
}
// Field returns the value of a field with the given name. The second boolean
// return value indicates that this field was not set, or was not defined in the
// schema.
func (m *ActionTokenMutation) Field(name string) (ent.Value, bool) {
switch name {
case actiontoken.FieldUserID:
return m.UserID()
case actiontoken.FieldCreatedAt:
return m.CreatedAt()
case actiontoken.FieldUpdatedAt:
return m.UpdatedAt()
case actiontoken.FieldAction:
return m.Action()
case actiontoken.FieldToken:
return m.Token()
}
return nil, false
}
// OldField returns the old value of the field from the database. An error is
// returned if the mutation operation is not UpdateOne, or the query to the
// database failed.
func (m *ActionTokenMutation) OldField(ctx context.Context, name string) (ent.Value, error) {
switch name {
case actiontoken.FieldUserID:
return m.OldUserID(ctx)
case actiontoken.FieldCreatedAt:
return m.OldCreatedAt(ctx)
case actiontoken.FieldUpdatedAt:
return m.OldUpdatedAt(ctx)
case actiontoken.FieldAction:
return m.OldAction(ctx)
case actiontoken.FieldToken:
return m.OldToken(ctx)
}
return nil, fmt.Errorf("unknown ActionToken field %s", name)
}
// SetField sets the value of a field with the given name. It returns an error if
// the field is not defined in the schema, or if the type mismatched the field
// type.
func (m *ActionTokenMutation) SetField(name string, value ent.Value) error {
switch name {
case actiontoken.FieldUserID:
v, ok := value.(uuid.UUID)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetUserID(v)
return nil
case actiontoken.FieldCreatedAt:
v, ok := value.(time.Time)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetCreatedAt(v)
return nil
case actiontoken.FieldUpdatedAt:
v, ok := value.(time.Time)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetUpdatedAt(v)
return nil
case actiontoken.FieldAction:
v, ok := value.(actiontoken.Action)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetAction(v)
return nil
case actiontoken.FieldToken:
v, ok := value.([]byte)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetToken(v)
return nil
}
return fmt.Errorf("unknown ActionToken field %s", name)
}
// AddedFields returns all numeric fields that were incremented/decremented during
// this mutation.
func (m *ActionTokenMutation) AddedFields() []string {
return nil
}
// AddedField returns the numeric value that was incremented/decremented on a field
// with the given name. The second boolean return value indicates that this field
// was not set, or was not defined in the schema.
func (m *ActionTokenMutation) AddedField(name string) (ent.Value, bool) {
return nil, false
}
// AddField adds the value to the field with the given name. It returns an error if
// the field is not defined in the schema, or if the type mismatched the field
// type.
func (m *ActionTokenMutation) AddField(name string, value ent.Value) error {
switch name {
}
return fmt.Errorf("unknown ActionToken numeric field %s", name)
}
// ClearedFields returns all nullable fields that were cleared during this
// mutation.
func (m *ActionTokenMutation) ClearedFields() []string {
return nil
}
// FieldCleared returns a boolean indicating if a field with the given name was
// cleared in this mutation.
func (m *ActionTokenMutation) FieldCleared(name string) bool {
_, ok := m.clearedFields[name]
return ok
}
// ClearField clears the value of the field with the given name. It returns an
// error if the field is not defined in the schema.
func (m *ActionTokenMutation) ClearField(name string) error {
return fmt.Errorf("unknown ActionToken nullable field %s", name)
}
// ResetField resets all changes in the mutation for the field with the given name.
// It returns an error if the field is not defined in the schema.
func (m *ActionTokenMutation) ResetField(name string) error {
switch name {
case actiontoken.FieldUserID:
m.ResetUserID()
return nil
case actiontoken.FieldCreatedAt:
m.ResetCreatedAt()
return nil
case actiontoken.FieldUpdatedAt:
m.ResetUpdatedAt()
return nil
case actiontoken.FieldAction:
m.ResetAction()
return nil
case actiontoken.FieldToken:
m.ResetToken()
return nil
}
return fmt.Errorf("unknown ActionToken field %s", name)
}
// AddedEdges returns all edge names that were set/added in this mutation.
func (m *ActionTokenMutation) AddedEdges() []string {
edges := make([]string, 0, 1)
if m.user != nil {
edges = append(edges, actiontoken.EdgeUser)
}
return edges
}
// AddedIDs returns all IDs (to other nodes) that were added for the given edge
// name in this mutation.
func (m *ActionTokenMutation) AddedIDs(name string) []ent.Value {
switch name {
case actiontoken.EdgeUser:
if id := m.user; id != nil {
return []ent.Value{*id}
}
}
return nil
}
// RemovedEdges returns all edge names that were removed in this mutation.
func (m *ActionTokenMutation) RemovedEdges() []string {
edges := make([]string, 0, 1)
return edges
}
// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with
// the given name in this mutation.
func (m *ActionTokenMutation) RemovedIDs(name string) []ent.Value {
return nil
}
// ClearedEdges returns all edge names that were cleared in this mutation.
func (m *ActionTokenMutation) ClearedEdges() []string {
edges := make([]string, 0, 1)
if m.cleareduser {
edges = append(edges, actiontoken.EdgeUser)
}
return edges
}
// EdgeCleared returns a boolean which indicates if the edge with the given name
// was cleared in this mutation.
func (m *ActionTokenMutation) EdgeCleared(name string) bool {
switch name {
case actiontoken.EdgeUser:
return m.cleareduser
}
return false
}
// ClearEdge clears the value of the edge with the given name. It returns an error
// if that edge is not defined in the schema.
func (m *ActionTokenMutation) ClearEdge(name string) error {
switch name {
case actiontoken.EdgeUser:
m.ClearUser()
return nil
}
return fmt.Errorf("unknown ActionToken unique edge %s", name)
}
// ResetEdge resets all changes to the edge with the given name in this mutation.
// It returns an error if the edge is not defined in the schema.
func (m *ActionTokenMutation) ResetEdge(name string) error {
switch name {
case actiontoken.EdgeUser:
m.ResetUser()
return nil
}
return fmt.Errorf("unknown ActionToken edge %s", name)
}
// AttachmentMutation represents an operation that mutates the Attachment nodes in the graph.
type AttachmentMutation struct {
config
@@ -2944,7 +2340,7 @@ type GroupMutation struct {
created_at *time.Time
updated_at *time.Time
name *string
currency *string
currency *group.Currency
clearedFields map[string]struct{}
users map[uuid.UUID]struct{}
removedusers map[uuid.UUID]struct{}
@@ -3185,12 +2581,12 @@ func (m *GroupMutation) ResetName() {
}
// SetCurrency sets the "currency" field.
func (m *GroupMutation) SetCurrency(s string) {
m.currency = &s
func (m *GroupMutation) SetCurrency(gr group.Currency) {
m.currency = &gr
}
// Currency returns the value of the "currency" field in the mutation.
func (m *GroupMutation) Currency() (r string, exists bool) {
func (m *GroupMutation) Currency() (r group.Currency, exists bool) {
v := m.currency
if v == nil {
return
@@ -3201,7 +2597,7 @@ func (m *GroupMutation) Currency() (r string, exists bool) {
// OldCurrency returns the old "currency" field's value of the Group entity.
// If the Group object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *GroupMutation) OldCurrency(ctx context.Context) (v string, err error) {
func (m *GroupMutation) OldCurrency(ctx context.Context) (v group.Currency, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldCurrency is only allowed on UpdateOne operations")
}
@@ -3709,7 +3105,7 @@ func (m *GroupMutation) SetField(name string, value ent.Value) error {
m.SetName(v)
return nil
case group.FieldCurrency:
v, ok := value.(string)
v, ok := value.(group.Currency)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
@@ -11276,33 +10672,30 @@ func (m *NotifierMutation) ResetEdge(name string) error {
// UserMutation represents an operation that mutates the User nodes in the graph.
type UserMutation struct {
config
op Op
typ string
id *uuid.UUID
created_at *time.Time
updated_at *time.Time
name *string
email *string
password *string
is_superuser *bool
superuser *bool
role *user.Role
activated_on *time.Time
clearedFields map[string]struct{}
group *uuid.UUID
clearedgroup bool
auth_tokens map[uuid.UUID]struct{}
removedauth_tokens map[uuid.UUID]struct{}
clearedauth_tokens bool
notifiers map[uuid.UUID]struct{}
removednotifiers map[uuid.UUID]struct{}
clearednotifiers bool
action_tokens map[uuid.UUID]struct{}
removedaction_tokens map[uuid.UUID]struct{}
clearedaction_tokens bool
done bool
oldValue func(context.Context) (*User, error)
predicates []predicate.User
op Op
typ string
id *uuid.UUID
created_at *time.Time
updated_at *time.Time
name *string
email *string
password *string
is_superuser *bool
superuser *bool
role *user.Role
activated_on *time.Time
clearedFields map[string]struct{}
group *uuid.UUID
clearedgroup bool
auth_tokens map[uuid.UUID]struct{}
removedauth_tokens map[uuid.UUID]struct{}
clearedauth_tokens bool
notifiers map[uuid.UUID]struct{}
removednotifiers map[uuid.UUID]struct{}
clearednotifiers bool
done bool
oldValue func(context.Context) (*User, error)
predicates []predicate.User
}
var _ ent.Mutation = (*UserMutation)(nil)
@@ -11893,60 +11286,6 @@ func (m *UserMutation) ResetNotifiers() {
m.removednotifiers = nil
}
// AddActionTokenIDs adds the "action_tokens" edge to the ActionToken entity by ids.
func (m *UserMutation) AddActionTokenIDs(ids ...uuid.UUID) {
if m.action_tokens == nil {
m.action_tokens = make(map[uuid.UUID]struct{})
}
for i := range ids {
m.action_tokens[ids[i]] = struct{}{}
}
}
// ClearActionTokens clears the "action_tokens" edge to the ActionToken entity.
func (m *UserMutation) ClearActionTokens() {
m.clearedaction_tokens = true
}
// ActionTokensCleared reports if the "action_tokens" edge to the ActionToken entity was cleared.
func (m *UserMutation) ActionTokensCleared() bool {
return m.clearedaction_tokens
}
// RemoveActionTokenIDs removes the "action_tokens" edge to the ActionToken entity by IDs.
func (m *UserMutation) RemoveActionTokenIDs(ids ...uuid.UUID) {
if m.removedaction_tokens == nil {
m.removedaction_tokens = make(map[uuid.UUID]struct{})
}
for i := range ids {
delete(m.action_tokens, ids[i])
m.removedaction_tokens[ids[i]] = struct{}{}
}
}
// RemovedActionTokens returns the removed IDs of the "action_tokens" edge to the ActionToken entity.
func (m *UserMutation) RemovedActionTokensIDs() (ids []uuid.UUID) {
for id := range m.removedaction_tokens {
ids = append(ids, id)
}
return
}
// ActionTokensIDs returns the "action_tokens" edge IDs in the mutation.
func (m *UserMutation) ActionTokensIDs() (ids []uuid.UUID) {
for id := range m.action_tokens {
ids = append(ids, id)
}
return
}
// ResetActionTokens resets all changes to the "action_tokens" edge.
func (m *UserMutation) ResetActionTokens() {
m.action_tokens = nil
m.clearedaction_tokens = false
m.removedaction_tokens = nil
}
// Where appends a list predicates to the UserMutation builder.
func (m *UserMutation) Where(ps ...predicate.User) {
m.predicates = append(m.predicates, ps...)
@@ -12225,7 +11564,7 @@ func (m *UserMutation) ResetField(name string) error {
// AddedEdges returns all edge names that were set/added in this mutation.
func (m *UserMutation) AddedEdges() []string {
edges := make([]string, 0, 4)
edges := make([]string, 0, 3)
if m.group != nil {
edges = append(edges, user.EdgeGroup)
}
@@ -12235,9 +11574,6 @@ func (m *UserMutation) AddedEdges() []string {
if m.notifiers != nil {
edges = append(edges, user.EdgeNotifiers)
}
if m.action_tokens != nil {
edges = append(edges, user.EdgeActionTokens)
}
return edges
}
@@ -12261,28 +11597,19 @@ func (m *UserMutation) AddedIDs(name string) []ent.Value {
ids = append(ids, id)
}
return ids
case user.EdgeActionTokens:
ids := make([]ent.Value, 0, len(m.action_tokens))
for id := range m.action_tokens {
ids = append(ids, id)
}
return ids
}
return nil
}
// RemovedEdges returns all edge names that were removed in this mutation.
func (m *UserMutation) RemovedEdges() []string {
edges := make([]string, 0, 4)
edges := make([]string, 0, 3)
if m.removedauth_tokens != nil {
edges = append(edges, user.EdgeAuthTokens)
}
if m.removednotifiers != nil {
edges = append(edges, user.EdgeNotifiers)
}
if m.removedaction_tokens != nil {
edges = append(edges, user.EdgeActionTokens)
}
return edges
}
@@ -12302,19 +11629,13 @@ func (m *UserMutation) RemovedIDs(name string) []ent.Value {
ids = append(ids, id)
}
return ids
case user.EdgeActionTokens:
ids := make([]ent.Value, 0, len(m.removedaction_tokens))
for id := range m.removedaction_tokens {
ids = append(ids, id)
}
return ids
}
return nil
}
// ClearedEdges returns all edge names that were cleared in this mutation.
func (m *UserMutation) ClearedEdges() []string {
edges := make([]string, 0, 4)
edges := make([]string, 0, 3)
if m.clearedgroup {
edges = append(edges, user.EdgeGroup)
}
@@ -12324,9 +11645,6 @@ func (m *UserMutation) ClearedEdges() []string {
if m.clearednotifiers {
edges = append(edges, user.EdgeNotifiers)
}
if m.clearedaction_tokens {
edges = append(edges, user.EdgeActionTokens)
}
return edges
}
@@ -12340,8 +11658,6 @@ func (m *UserMutation) EdgeCleared(name string) bool {
return m.clearedauth_tokens
case user.EdgeNotifiers:
return m.clearednotifiers
case user.EdgeActionTokens:
return m.clearedaction_tokens
}
return false
}
@@ -12370,9 +11686,6 @@ func (m *UserMutation) ResetEdge(name string) error {
case user.EdgeNotifiers:
m.ResetNotifiers()
return nil
case user.EdgeActionTokens:
m.ResetActionTokens()
return nil
}
return fmt.Errorf("unknown User edge %s", name)
}

View File

@@ -6,9 +6,6 @@ import (
"entgo.io/ent/dialect/sql"
)
// ActionToken is the predicate function for actiontoken builders.
type ActionToken func(*sql.Selector)
// Attachment is the predicate function for attachment builders.
type Attachment func(*sql.Selector)

View File

@@ -6,7 +6,6 @@ import (
"time"
"github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/data/ent/actiontoken"
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
"github.com/hay-kot/homebox/backend/internal/data/ent/document"
@@ -26,25 +25,6 @@ import (
// (default values, validators, hooks and policies) and stitches it
// to their package variables.
func init() {
actiontokenMixin := schema.ActionToken{}.Mixin()
actiontokenMixinFields1 := actiontokenMixin[1].Fields()
_ = actiontokenMixinFields1
actiontokenFields := schema.ActionToken{}.Fields()
_ = actiontokenFields
// actiontokenDescCreatedAt is the schema descriptor for created_at field.
actiontokenDescCreatedAt := actiontokenMixinFields1[1].Descriptor()
// actiontoken.DefaultCreatedAt holds the default value on creation for the created_at field.
actiontoken.DefaultCreatedAt = actiontokenDescCreatedAt.Default.(func() time.Time)
// actiontokenDescUpdatedAt is the schema descriptor for updated_at field.
actiontokenDescUpdatedAt := actiontokenMixinFields1[2].Descriptor()
// actiontoken.DefaultUpdatedAt holds the default value on creation for the updated_at field.
actiontoken.DefaultUpdatedAt = actiontokenDescUpdatedAt.Default.(func() time.Time)
// actiontoken.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
actiontoken.UpdateDefaultUpdatedAt = actiontokenDescUpdatedAt.UpdateDefault.(func() time.Time)
// actiontokenDescID is the schema descriptor for id field.
actiontokenDescID := actiontokenMixinFields1[0].Descriptor()
// actiontoken.DefaultID holds the default value on creation for the id field.
actiontoken.DefaultID = actiontokenDescID.Default.(func() uuid.UUID)
attachmentMixin := schema.Attachment{}.Mixin()
attachmentMixinFields0 := attachmentMixin[0].Fields()
_ = attachmentMixinFields0
@@ -181,10 +161,6 @@ func init() {
return nil
}
}()
// groupDescCurrency is the schema descriptor for currency field.
groupDescCurrency := groupFields[1].Descriptor()
// group.DefaultCurrency holds the default value on creation for the currency field.
group.DefaultCurrency = groupDescCurrency.Default.(string)
// groupDescID is the schema descriptor for id field.
groupDescID := groupMixinFields0[0].Descriptor()
// group.DefaultID holds the default value on creation for the id field.

View File

@@ -1,42 +0,0 @@
package schema
import (
"entgo.io/ent"
"entgo.io/ent/schema/field"
"entgo.io/ent/schema/index"
"github.com/hay-kot/homebox/backend/internal/data/ent/schema/mixins"
)
type ActionToken struct {
ent.Schema
}
func (ActionToken) Mixin() []ent.Mixin {
return []ent.Mixin{
UserMixin{
ref: "action_tokens",
field: "user_id",
},
mixins.BaseMixin{},
}
}
// Fields of the ActionToken.
func (ActionToken) Fields() []ent.Field {
return []ent.Field{
field.Enum("action").
Values("reset_password").
Default("reset_password"),
field.Bytes("token").
Unique(),
}
}
func (ActionToken) Indexes() []ent.Index {
return []ent.Index{
index.Fields("token"),
index.Fields("action"),
index.Fields("user_id"),
}
}

View File

@@ -27,8 +27,41 @@ func (Group) Fields() []ent.Field {
field.String("name").
MaxLen(255).
NotEmpty(),
field.String("currency").
Default("usd"),
field.Enum("currency").
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",
"xag",
"xau",
"zar",
),
}
}

View File

@@ -20,4 +20,4 @@ import "github.com/google/uuid"
}
{{ end }}
{{ end }}
{{ end }}

View File

@@ -52,11 +52,13 @@ func (User) Fields() []ent.Field {
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("auth_tokens", AuthTokens.Type).
Annotations(entsql.Annotation{OnDelete: entsql.Cascade}),
Annotations(entsql.Annotation{
OnDelete: entsql.Cascade,
}),
edge.To("notifiers", Notifier.Type).
Annotations(entsql.Annotation{OnDelete: entsql.Cascade}),
edge.To("action_tokens", ActionToken.Type).
Annotations(entsql.Annotation{OnDelete: entsql.Cascade}),
Annotations(entsql.Annotation{
OnDelete: entsql.Cascade,
}),
}
}
@@ -76,6 +78,7 @@ func (g UserMixin) Fields() []ent.Field {
}
return nil
}
func (g UserMixin) Edges() []ent.Edge {

View File

@@ -12,8 +12,6 @@ import (
// Tx is a transactional client that is created by calling Client.Tx().
type Tx struct {
config
// ActionToken is the client for interacting with the ActionToken builders.
ActionToken *ActionTokenClient
// Attachment is the client for interacting with the Attachment builders.
Attachment *AttachmentClient
// AuthRoles is the client for interacting with the AuthRoles builders.
@@ -171,7 +169,6 @@ func (tx *Tx) Client() *Client {
}
func (tx *Tx) init() {
tx.ActionToken = NewActionTokenClient(tx.config)
tx.Attachment = NewAttachmentClient(tx.config)
tx.AuthRoles = NewAuthRolesClient(tx.config)
tx.AuthTokens = NewAuthTokensClient(tx.config)
@@ -194,7 +191,7 @@ func (tx *Tx) init() {
// of them in order to commit or rollback the transaction.
//
// If a closed transaction is embedded in one of the generated entities, and the entity
// applies a query, for example: ActionToken.QueryXXX(), the query will be executed
// applies a query, for example: Attachment.QueryXXX(), the query will be executed
// through the driver which created this transaction.
//
// Note that txDriver is not goroutine safe.

View File

@@ -52,11 +52,9 @@ type UserEdges struct {
AuthTokens []*AuthTokens `json:"auth_tokens,omitempty"`
// Notifiers holds the value of the notifiers edge.
Notifiers []*Notifier `json:"notifiers,omitempty"`
// ActionTokens holds the value of the action_tokens edge.
ActionTokens []*ActionToken `json:"action_tokens,omitempty"`
// loadedTypes holds the information for reporting if a
// type was loaded (or requested) in eager-loading or not.
loadedTypes [4]bool
loadedTypes [3]bool
}
// GroupOrErr returns the Group value or an error if the edge
@@ -90,15 +88,6 @@ func (e UserEdges) NotifiersOrErr() ([]*Notifier, error) {
return nil, &NotLoadedError{edge: "notifiers"}
}
// ActionTokensOrErr returns the ActionTokens value or an error if the edge
// was not loaded in eager-loading.
func (e UserEdges) ActionTokensOrErr() ([]*ActionToken, error) {
if e.loadedTypes[3] {
return e.ActionTokens, nil
}
return nil, &NotLoadedError{edge: "action_tokens"}
}
// scanValues returns the types for scanning values from sql.Rows.
func (*User) scanValues(columns []string) ([]any, error) {
values := make([]any, len(columns))
@@ -224,11 +213,6 @@ func (u *User) QueryNotifiers() *NotifierQuery {
return NewUserClient(u.config).QueryNotifiers(u)
}
// QueryActionTokens queries the "action_tokens" edge of the User entity.
func (u *User) QueryActionTokens() *ActionTokenQuery {
return NewUserClient(u.config).QueryActionTokens(u)
}
// Update returns a builder for updating this User.
// Note that you need to call User.Unwrap() before calling this method if this User
// was returned from a transaction, and the transaction was committed or rolled back.

View File

@@ -40,8 +40,6 @@ const (
EdgeAuthTokens = "auth_tokens"
// EdgeNotifiers holds the string denoting the notifiers edge name in mutations.
EdgeNotifiers = "notifiers"
// EdgeActionTokens holds the string denoting the action_tokens edge name in mutations.
EdgeActionTokens = "action_tokens"
// Table holds the table name of the user in the database.
Table = "users"
// GroupTable is the table that holds the group relation/edge.
@@ -65,13 +63,6 @@ const (
NotifiersInverseTable = "notifiers"
// NotifiersColumn is the table column denoting the notifiers relation/edge.
NotifiersColumn = "user_id"
// ActionTokensTable is the table that holds the action_tokens relation/edge.
ActionTokensTable = "action_tokens"
// ActionTokensInverseTable is the table name for the ActionToken entity.
// It exists in this package in order to avoid circular dependency with the "actiontoken" package.
ActionTokensInverseTable = "action_tokens"
// ActionTokensColumn is the table column denoting the action_tokens relation/edge.
ActionTokensColumn = "user_id"
)
// Columns holds all SQL columns for user fields.
@@ -243,20 +234,6 @@ func ByNotifiers(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
sqlgraph.OrderByNeighborTerms(s, newNotifiersStep(), append([]sql.OrderTerm{term}, terms...)...)
}
}
// ByActionTokensCount orders the results by action_tokens count.
func ByActionTokensCount(opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborsCount(s, newActionTokensStep(), opts...)
}
}
// ByActionTokens orders the results by action_tokens terms.
func ByActionTokens(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborTerms(s, newActionTokensStep(), append([]sql.OrderTerm{term}, terms...)...)
}
}
func newGroupStep() *sqlgraph.Step {
return sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
@@ -278,10 +255,3 @@ func newNotifiersStep() *sqlgraph.Step {
sqlgraph.Edge(sqlgraph.O2M, false, NotifiersTable, NotifiersColumn),
)
}
func newActionTokensStep() *sqlgraph.Step {
return sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(ActionTokensInverseTable, FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, ActionTokensTable, ActionTokensColumn),
)
}

View File

@@ -530,29 +530,6 @@ func HasNotifiersWith(preds ...predicate.Notifier) predicate.User {
})
}
// HasActionTokens applies the HasEdge predicate on the "action_tokens" edge.
func HasActionTokens() predicate.User {
return predicate.User(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, ActionTokensTable, ActionTokensColumn),
)
sqlgraph.HasNeighbors(s, step)
})
}
// HasActionTokensWith applies the HasEdge predicate on the "action_tokens" edge with a given conditions (other predicates).
func HasActionTokensWith(preds ...predicate.ActionToken) predicate.User {
return predicate.User(func(s *sql.Selector) {
step := newActionTokensStep()
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds {
p(s)
}
})
})
}
// And groups predicates with the AND operator between them.
func And(predicates ...predicate.User) predicate.User {
return predicate.User(sql.AndPredicates(predicates...))

View File

@@ -11,7 +11,6 @@ import (
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/data/ent/actiontoken"
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
"github.com/hay-kot/homebox/backend/internal/data/ent/group"
"github.com/hay-kot/homebox/backend/internal/data/ent/notifier"
@@ -182,21 +181,6 @@ func (uc *UserCreate) AddNotifiers(n ...*Notifier) *UserCreate {
return uc.AddNotifierIDs(ids...)
}
// AddActionTokenIDs adds the "action_tokens" edge to the ActionToken entity by IDs.
func (uc *UserCreate) AddActionTokenIDs(ids ...uuid.UUID) *UserCreate {
uc.mutation.AddActionTokenIDs(ids...)
return uc
}
// AddActionTokens adds the "action_tokens" edges to the ActionToken entity.
func (uc *UserCreate) AddActionTokens(a ...*ActionToken) *UserCreate {
ids := make([]uuid.UUID, len(a))
for i := range a {
ids[i] = a[i].ID
}
return uc.AddActionTokenIDs(ids...)
}
// Mutation returns the UserMutation object of the builder.
func (uc *UserCreate) Mutation() *UserMutation {
return uc.mutation
@@ -427,22 +411,6 @@ func (uc *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) {
}
_spec.Edges = append(_spec.Edges, edge)
}
if nodes := uc.mutation.ActionTokensIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: user.ActionTokensTable,
Columns: []string{user.ActionTokensColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(actiontoken.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges = append(_spec.Edges, edge)
}
return _node, _spec
}

View File

@@ -12,7 +12,6 @@ import (
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/data/ent/actiontoken"
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
"github.com/hay-kot/homebox/backend/internal/data/ent/group"
"github.com/hay-kot/homebox/backend/internal/data/ent/notifier"
@@ -23,15 +22,14 @@ import (
// UserQuery is the builder for querying User entities.
type UserQuery struct {
config
ctx *QueryContext
order []user.OrderOption
inters []Interceptor
predicates []predicate.User
withGroup *GroupQuery
withAuthTokens *AuthTokensQuery
withNotifiers *NotifierQuery
withActionTokens *ActionTokenQuery
withFKs bool
ctx *QueryContext
order []user.OrderOption
inters []Interceptor
predicates []predicate.User
withGroup *GroupQuery
withAuthTokens *AuthTokensQuery
withNotifiers *NotifierQuery
withFKs bool
// intermediate query (i.e. traversal path).
sql *sql.Selector
path func(context.Context) (*sql.Selector, error)
@@ -134,28 +132,6 @@ func (uq *UserQuery) QueryNotifiers() *NotifierQuery {
return query
}
// QueryActionTokens chains the current query on the "action_tokens" edge.
func (uq *UserQuery) QueryActionTokens() *ActionTokenQuery {
query := (&ActionTokenClient{config: uq.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := uq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := uq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(user.Table, user.FieldID, selector),
sqlgraph.To(actiontoken.Table, actiontoken.FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, user.ActionTokensTable, user.ActionTokensColumn),
)
fromU = sqlgraph.SetNeighbors(uq.driver.Dialect(), step)
return fromU, nil
}
return query
}
// First returns the first User entity from the query.
// Returns a *NotFoundError when no User was found.
func (uq *UserQuery) First(ctx context.Context) (*User, error) {
@@ -343,15 +319,14 @@ func (uq *UserQuery) Clone() *UserQuery {
return nil
}
return &UserQuery{
config: uq.config,
ctx: uq.ctx.Clone(),
order: append([]user.OrderOption{}, uq.order...),
inters: append([]Interceptor{}, uq.inters...),
predicates: append([]predicate.User{}, uq.predicates...),
withGroup: uq.withGroup.Clone(),
withAuthTokens: uq.withAuthTokens.Clone(),
withNotifiers: uq.withNotifiers.Clone(),
withActionTokens: uq.withActionTokens.Clone(),
config: uq.config,
ctx: uq.ctx.Clone(),
order: append([]user.OrderOption{}, uq.order...),
inters: append([]Interceptor{}, uq.inters...),
predicates: append([]predicate.User{}, uq.predicates...),
withGroup: uq.withGroup.Clone(),
withAuthTokens: uq.withAuthTokens.Clone(),
withNotifiers: uq.withNotifiers.Clone(),
// clone intermediate query.
sql: uq.sql.Clone(),
path: uq.path,
@@ -391,17 +366,6 @@ func (uq *UserQuery) WithNotifiers(opts ...func(*NotifierQuery)) *UserQuery {
return uq
}
// WithActionTokens tells the query-builder to eager-load the nodes that are connected to
// the "action_tokens" edge. The optional arguments are used to configure the query builder of the edge.
func (uq *UserQuery) WithActionTokens(opts ...func(*ActionTokenQuery)) *UserQuery {
query := (&ActionTokenClient{config: uq.config}).Query()
for _, opt := range opts {
opt(query)
}
uq.withActionTokens = query
return uq
}
// GroupBy is used to group vertices by one or more fields/columns.
// It is often used with aggregate functions, like: count, max, mean, min, sum.
//
@@ -481,11 +445,10 @@ func (uq *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
nodes = []*User{}
withFKs = uq.withFKs
_spec = uq.querySpec()
loadedTypes = [4]bool{
loadedTypes = [3]bool{
uq.withGroup != nil,
uq.withAuthTokens != nil,
uq.withNotifiers != nil,
uq.withActionTokens != nil,
}
)
if uq.withGroup != nil {
@@ -532,13 +495,6 @@ func (uq *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
return nil, err
}
}
if query := uq.withActionTokens; query != nil {
if err := uq.loadActionTokens(ctx, query, nodes,
func(n *User) { n.Edges.ActionTokens = []*ActionToken{} },
func(n *User, e *ActionToken) { n.Edges.ActionTokens = append(n.Edges.ActionTokens, e) }); err != nil {
return nil, err
}
}
return nodes, nil
}
@@ -635,36 +591,6 @@ func (uq *UserQuery) loadNotifiers(ctx context.Context, query *NotifierQuery, no
}
return nil
}
func (uq *UserQuery) loadActionTokens(ctx context.Context, query *ActionTokenQuery, nodes []*User, init func(*User), assign func(*User, *ActionToken)) error {
fks := make([]driver.Value, 0, len(nodes))
nodeids := make(map[uuid.UUID]*User)
for i := range nodes {
fks = append(fks, nodes[i].ID)
nodeids[nodes[i].ID] = nodes[i]
if init != nil {
init(nodes[i])
}
}
if len(query.ctx.Fields) > 0 {
query.ctx.AppendFieldOnce(actiontoken.FieldUserID)
}
query.Where(predicate.ActionToken(func(s *sql.Selector) {
s.Where(sql.InValues(s.C(user.ActionTokensColumn), fks...))
}))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
fk := n.UserID
node, ok := nodeids[fk]
if !ok {
return fmt.Errorf(`unexpected referenced foreign-key "user_id" returned %v for node %v`, fk, n.ID)
}
assign(node, n)
}
return nil
}
func (uq *UserQuery) sqlCount(ctx context.Context) (int, error) {
_spec := uq.querySpec()

View File

@@ -12,7 +12,6 @@ import (
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/data/ent/actiontoken"
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
"github.com/hay-kot/homebox/backend/internal/data/ent/group"
"github.com/hay-kot/homebox/backend/internal/data/ent/notifier"
@@ -184,21 +183,6 @@ func (uu *UserUpdate) AddNotifiers(n ...*Notifier) *UserUpdate {
return uu.AddNotifierIDs(ids...)
}
// AddActionTokenIDs adds the "action_tokens" edge to the ActionToken entity by IDs.
func (uu *UserUpdate) AddActionTokenIDs(ids ...uuid.UUID) *UserUpdate {
uu.mutation.AddActionTokenIDs(ids...)
return uu
}
// AddActionTokens adds the "action_tokens" edges to the ActionToken entity.
func (uu *UserUpdate) AddActionTokens(a ...*ActionToken) *UserUpdate {
ids := make([]uuid.UUID, len(a))
for i := range a {
ids[i] = a[i].ID
}
return uu.AddActionTokenIDs(ids...)
}
// Mutation returns the UserMutation object of the builder.
func (uu *UserUpdate) Mutation() *UserMutation {
return uu.mutation
@@ -252,27 +236,6 @@ func (uu *UserUpdate) RemoveNotifiers(n ...*Notifier) *UserUpdate {
return uu.RemoveNotifierIDs(ids...)
}
// ClearActionTokens clears all "action_tokens" edges to the ActionToken entity.
func (uu *UserUpdate) ClearActionTokens() *UserUpdate {
uu.mutation.ClearActionTokens()
return uu
}
// RemoveActionTokenIDs removes the "action_tokens" edge to ActionToken entities by IDs.
func (uu *UserUpdate) RemoveActionTokenIDs(ids ...uuid.UUID) *UserUpdate {
uu.mutation.RemoveActionTokenIDs(ids...)
return uu
}
// RemoveActionTokens removes "action_tokens" edges to ActionToken entities.
func (uu *UserUpdate) RemoveActionTokens(a ...*ActionToken) *UserUpdate {
ids := make([]uuid.UUID, len(a))
for i := range a {
ids[i] = a[i].ID
}
return uu.RemoveActionTokenIDs(ids...)
}
// Save executes the query and returns the number of nodes affected by the update operation.
func (uu *UserUpdate) Save(ctx context.Context) (int, error) {
uu.defaults()
@@ -495,51 +458,6 @@ func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) {
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if uu.mutation.ActionTokensCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: user.ActionTokensTable,
Columns: []string{user.ActionTokensColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(actiontoken.FieldID, field.TypeUUID),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := uu.mutation.RemovedActionTokensIDs(); len(nodes) > 0 && !uu.mutation.ActionTokensCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: user.ActionTokensTable,
Columns: []string{user.ActionTokensColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(actiontoken.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := uu.mutation.ActionTokensIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: user.ActionTokensTable,
Columns: []string{user.ActionTokensColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(actiontoken.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if n, err = sqlgraph.UpdateNodes(ctx, uu.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{user.Label}
@@ -711,21 +629,6 @@ func (uuo *UserUpdateOne) AddNotifiers(n ...*Notifier) *UserUpdateOne {
return uuo.AddNotifierIDs(ids...)
}
// AddActionTokenIDs adds the "action_tokens" edge to the ActionToken entity by IDs.
func (uuo *UserUpdateOne) AddActionTokenIDs(ids ...uuid.UUID) *UserUpdateOne {
uuo.mutation.AddActionTokenIDs(ids...)
return uuo
}
// AddActionTokens adds the "action_tokens" edges to the ActionToken entity.
func (uuo *UserUpdateOne) AddActionTokens(a ...*ActionToken) *UserUpdateOne {
ids := make([]uuid.UUID, len(a))
for i := range a {
ids[i] = a[i].ID
}
return uuo.AddActionTokenIDs(ids...)
}
// Mutation returns the UserMutation object of the builder.
func (uuo *UserUpdateOne) Mutation() *UserMutation {
return uuo.mutation
@@ -779,27 +682,6 @@ func (uuo *UserUpdateOne) RemoveNotifiers(n ...*Notifier) *UserUpdateOne {
return uuo.RemoveNotifierIDs(ids...)
}
// ClearActionTokens clears all "action_tokens" edges to the ActionToken entity.
func (uuo *UserUpdateOne) ClearActionTokens() *UserUpdateOne {
uuo.mutation.ClearActionTokens()
return uuo
}
// RemoveActionTokenIDs removes the "action_tokens" edge to ActionToken entities by IDs.
func (uuo *UserUpdateOne) RemoveActionTokenIDs(ids ...uuid.UUID) *UserUpdateOne {
uuo.mutation.RemoveActionTokenIDs(ids...)
return uuo
}
// RemoveActionTokens removes "action_tokens" edges to ActionToken entities.
func (uuo *UserUpdateOne) RemoveActionTokens(a ...*ActionToken) *UserUpdateOne {
ids := make([]uuid.UUID, len(a))
for i := range a {
ids[i] = a[i].ID
}
return uuo.RemoveActionTokenIDs(ids...)
}
// Where appends a list predicates to the UserUpdate builder.
func (uuo *UserUpdateOne) Where(ps ...predicate.User) *UserUpdateOne {
uuo.mutation.Where(ps...)
@@ -1052,51 +934,6 @@ func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if uuo.mutation.ActionTokensCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: user.ActionTokensTable,
Columns: []string{user.ActionTokensColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(actiontoken.FieldID, field.TypeUUID),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := uuo.mutation.RemovedActionTokensIDs(); len(nodes) > 0 && !uuo.mutation.ActionTokensCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: user.ActionTokensTable,
Columns: []string{user.ActionTokensColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(actiontoken.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := uuo.mutation.ActionTokensIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: user.ActionTokensTable,
Columns: []string{user.ActionTokensColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(actiontoken.FieldID, field.TypeUUID),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
_node = &User{config: uuo.config}
_spec.Assign = _node.assignValues
_spec.ScanValues = _node.scanValues

View File

@@ -1,4 +1,3 @@
// Package migrations provides a way to embed the migrations into the binary.
package migrations
import (

View File

@@ -1,10 +0,0 @@
-- Create "action_tokens" table
CREATE TABLE `action_tokens` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `action` text NOT NULL DEFAULT ('reset_password'), `token` blob NOT NULL, `user_id` uuid NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `action_tokens_users_action_tokens` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE);
-- Create index "action_tokens_token_key" to table: "action_tokens"
CREATE UNIQUE INDEX `action_tokens_token_key` ON `action_tokens` (`token`);
-- Create index "actiontoken_token" to table: "action_tokens"
CREATE INDEX `actiontoken_token` ON `action_tokens` (`token`);
-- Create index "actiontoken_action" to table: "action_tokens"
CREATE INDEX `actiontoken_action` ON `action_tokens` (`action`);
-- Create index "actiontoken_user_id" to table: "action_tokens"
CREATE INDEX `actiontoken_user_id` ON `action_tokens` (`user_id`);

View File

@@ -1,4 +1,4 @@
h1:6CJ6qlt5IqAoKF6R9yH8Ei2eqkAbkCqjM1dDUvA24f8=
h1:sjJCTAqc9FG8BKBIzh5ZynYD/Ilz6vnLqM4XX83WQ4M=
20220929052825_init.sql h1:ZlCqm1wzjDmofeAcSX3jE4h4VcdTNGpRg2eabztDy9Q=
20221001210956_group_invitations.sql h1:YQKJFtE39wFOcRNbZQ/d+ZlHwrcfcsZlcv/pLEYdpjw=
20221009173029_add_user_roles.sql h1:vWmzAfgEWQeGk0Vn70zfVPCcfEZth3E0JcvyKTjpYyU=
@@ -13,4 +13,3 @@ h1:6CJ6qlt5IqAoKF6R9yH8Ei2eqkAbkCqjM1dDUvA24f8=
20230305065819_add_notifier_types.sql h1:r5xrgCKYQ2o9byBqYeAX1zdp94BLdaxf4vq9OmGHNl0=
20230305071524_add_group_id_to_notifiers.sql h1:xDShqbyClcFhvJbwclOHdczgXbdffkxXNWjV61hL/t4=
20231006213457_add_primary_attachment_flag.sql h1:J4tMSJQFa7vaj0jpnh8YKTssdyIjRyq6RXDXZIzDDu4=
20240302172225_user_action_tokens.sql h1:nAdtVdh9O7p/AyKnURvZcS0H/Zoj1sM9HpwCOO09zDE=

View File

@@ -16,9 +16,9 @@ func (aid AssetID) Int() int {
return int(aid)
}
func ParseAssetIDBytes(d []byte) (assetID AssetID, ok bool) {
d = bytes.ReplaceAll(d, []byte(`"`), []byte(``))
d = bytes.ReplaceAll(d, []byte(`-`), []byte(``))
func ParseAssetIDBytes(d []byte) (AID AssetID, ok bool) {
d = bytes.Replace(d, []byte(`"`), []byte(``), -1)
d = bytes.Replace(d, []byte(`-`), []byte(``), -1)
aidInt, err := strconv.Atoi(string(d))
if err != nil {
@@ -28,7 +28,7 @@ func ParseAssetIDBytes(d []byte) (assetID AssetID, ok bool) {
return AssetID(aidInt), true
}
func ParseAssetID(s string) (assetID AssetID, ok bool) {
func ParseAssetID(s string) (AID AssetID, ok bool) {
return ParseAssetIDBytes([]byte(s))
}
@@ -52,8 +52,8 @@ func (aid *AssetID) UnmarshalJSON(d []byte) error {
return nil
}
d = bytes.ReplaceAll(d, []byte(`"`), []byte(``))
d = bytes.ReplaceAll(d, []byte(`-`), []byte(``))
d = bytes.Replace(d, []byte(`"`), []byte(``), -1)
d = bytes.Replace(d, []byte(`-`), []byte(``), -1)
aidInt, err := strconv.Atoi(string(d))
if err != nil {

View File

@@ -45,9 +45,7 @@ func TestMain(m *testing.M) {
log.Fatalf("failed opening connection to sqlite: %v", err)
}
go func() {
_ = tbus.Run(context.Background())
}()
go tbus.Run()
err = client.Schema.Create(context.Background())
if err != nil {
@@ -56,10 +54,9 @@ func TestMain(m *testing.M) {
tClient = client
tRepos = New(tClient, tbus, os.TempDir())
defer client.Close()
bootstrap()
exit := m.Run()
_ = client.Close()
os.Exit(exit)
os.Exit(m.Run())
}

View File

@@ -11,7 +11,6 @@ import (
"github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/data/ent"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func useDocs(t *testing.T, num int) []DocumentOut {
@@ -26,7 +25,7 @@ func useDocs(t *testing.T, num int) []DocumentOut {
Content: bytes.NewReader([]byte(fk.Str(10))),
})
require.NoError(t, err)
assert.NoError(t, err)
assert.NotNil(t, doc)
results = append(results, doc)
ids = append(ids, doc.ID)
@@ -81,31 +80,31 @@ func TestDocumentRepository_CreateUpdateDelete(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
// Create Document
got, err := r.Create(tt.args.ctx, tt.args.gid, tt.args.doc)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, tt.title, got.Title)
assert.Equal(t, fmt.Sprintf("%s/%s/documents", temp, tt.args.gid), filepath.Dir(got.Path))
ensureRead := func() {
// Read Document
bts, err := os.ReadFile(got.Path)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, tt.content, string(bts))
}
ensureRead()
// Update Document
got, err = r.Rename(tt.args.ctx, got.ID, "__"+tt.title+"__")
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, "__"+tt.title+"__", got.Title)
ensureRead()
// Delete Document
err = r.Delete(tt.args.ctx, got.ID)
require.NoError(t, err)
assert.NoError(t, err)
_, err = os.Stat(got.Path)
require.Error(t, err)
assert.Error(t, err)
})
}
}

View File

@@ -28,7 +28,7 @@ func NewGroupRepository(db *ent.Client) *GroupRepository {
Name: g.Name,
CreatedAt: g.CreatedAt,
UpdatedAt: g.UpdatedAt,
Currency: strings.ToUpper(g.Currency),
Currency: strings.ToUpper(g.Currency.String()),
}
}
@@ -109,12 +109,12 @@ func (r *GroupRepository) GetAllGroups(ctx context.Context) ([]Group, error) {
return r.groupMapper.MapEachErr(r.db.Group.Query().All(ctx))
}
func (r *GroupRepository) StatsLocationsByPurchasePrice(ctx context.Context, groupID uuid.UUID) ([]TotalsByOrganizer, error) {
func (r *GroupRepository) StatsLocationsByPurchasePrice(ctx context.Context, GID uuid.UUID) ([]TotalsByOrganizer, error) {
var v []TotalsByOrganizer
err := r.db.Location.Query().
Where(
location.HasGroupWith(group.ID(groupID)),
location.HasGroupWith(group.ID(GID)),
).
GroupBy(location.FieldID, location.FieldName).
Aggregate(func(sq *sql.Selector) string {
@@ -131,12 +131,12 @@ func (r *GroupRepository) StatsLocationsByPurchasePrice(ctx context.Context, gro
return v, err
}
func (r *GroupRepository) StatsLabelsByPurchasePrice(ctx context.Context, groupID uuid.UUID) ([]TotalsByOrganizer, error) {
func (r *GroupRepository) StatsLabelsByPurchasePrice(ctx context.Context, GID uuid.UUID) ([]TotalsByOrganizer, error) {
var v []TotalsByOrganizer
err := r.db.Label.Query().
Where(
label.HasGroupWith(group.ID(groupID)),
label.HasGroupWith(group.ID(GID)),
).
GroupBy(label.FieldID, label.FieldName).
Aggregate(func(sq *sql.Selector) string {
@@ -157,7 +157,7 @@ func (r *GroupRepository) StatsLabelsByPurchasePrice(ctx context.Context, groupI
return v, err
}
func (r *GroupRepository) StatsPurchasePrice(ctx context.Context, groupID uuid.UUID, start, end time.Time) (*ValueOverTime, error) {
func (r *GroupRepository) StatsPurchasePrice(ctx context.Context, GID uuid.UUID, start, end time.Time) (*ValueOverTime, error) {
// Get the Totals for the Start and End of the Given Time Period
q := `
SELECT
@@ -180,7 +180,7 @@ func (r *GroupRepository) StatsPurchasePrice(ctx context.Context, groupID uuid.U
var maybeStart *float64
var maybeEnd *float64
row := r.db.Sql().QueryRowContext(ctx, q, groupID, sqliteDateFormat(start), groupID, sqliteDateFormat(end))
row := r.db.Sql().QueryRowContext(ctx, q, GID, sqliteDateFormat(start), GID, sqliteDateFormat(end))
err := row.Scan(&maybeStart, &maybeEnd)
if err != nil {
return nil, err
@@ -198,7 +198,7 @@ func (r *GroupRepository) StatsPurchasePrice(ctx context.Context, groupID uuid.U
// Get Created Date and Price of all items between start and end
err = r.db.Item.Query().
Where(
item.HasGroupWith(group.ID(groupID)),
item.HasGroupWith(group.ID(GID)),
item.CreatedAtGTE(start),
item.CreatedAtLTE(end),
item.Archived(false),
@@ -209,6 +209,7 @@ func (r *GroupRepository) StatsPurchasePrice(ctx context.Context, groupID uuid.U
item.FieldPurchasePrice,
).
Scan(ctx, &v)
if err != nil {
return nil, err
}
@@ -225,7 +226,7 @@ func (r *GroupRepository) StatsPurchasePrice(ctx context.Context, groupID uuid.U
return &stats, nil
}
func (r *GroupRepository) StatsGroup(ctx context.Context, groupID uuid.UUID) (GroupStatistics, error) {
func (r *GroupRepository) StatsGroup(ctx context.Context, GID uuid.UUID) (GroupStatistics, error) {
q := `
SELECT
(SELECT COUNT(*) FROM users WHERE group_users = ?) AS total_users,
@@ -241,7 +242,7 @@ func (r *GroupRepository) StatsGroup(ctx context.Context, groupID uuid.UUID) (Gr
) AS total_with_warranty
`
var stats GroupStatistics
row := r.db.Sql().QueryRowContext(ctx, q, groupID, groupID, groupID, groupID, groupID, groupID)
row := r.db.Sql().QueryRowContext(ctx, q, GID, GID, GID, GID, GID, GID)
var maybeTotalItemPrice *float64
var maybeTotalWithWarranty *int
@@ -263,17 +264,19 @@ func (r *GroupRepository) GroupCreate(ctx context.Context, name string) (Group,
Save(ctx))
}
func (r *GroupRepository) GroupUpdate(ctx context.Context, groupID uuid.UUID, data GroupUpdate) (Group, error) {
entity, err := r.db.Group.UpdateOneID(groupID).
func (r *GroupRepository) GroupUpdate(ctx context.Context, ID uuid.UUID, data GroupUpdate) (Group, error) {
currency := group.Currency(strings.ToLower(data.Currency))
entity, err := r.db.Group.UpdateOneID(ID).
SetName(data.Name).
SetCurrency(strings.ToLower(data.Currency)).
SetCurrency(currency).
Save(ctx)
return r.groupMapper.MapErr(entity, err)
}
func (r *GroupRepository) GroupByID(ctx context.Context, groupID uuid.UUID) (Group, error) {
return r.groupMapper.MapErr(r.db.Group.Get(ctx, groupID))
func (r *GroupRepository) GroupByID(ctx context.Context, id uuid.UUID) (Group, error) {
return r.groupMapper.MapErr(r.db.Group.Get(ctx, id))
}
func (r *GroupRepository) InvitationGet(ctx context.Context, token []byte) (GroupInvitation, error) {

View File

@@ -5,30 +5,29 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_Group_Create(t *testing.T) {
g, err := tRepos.Groups.GroupCreate(context.Background(), "test")
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, "test", g.Name)
// Get by ID
foundGroup, err := tRepos.Groups.GroupByID(context.Background(), g.ID)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, g.ID, foundGroup.ID)
}
func Test_Group_Update(t *testing.T) {
g, err := tRepos.Groups.GroupCreate(context.Background(), "test")
require.NoError(t, err)
assert.NoError(t, err)
g, err = tRepos.Groups.GroupUpdate(context.Background(), g.ID, GroupUpdate{
Name: "test2",
Currency: "eur",
})
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, "test2", g.Name)
assert.Equal(t, "EUR", g.Currency)
}
@@ -39,7 +38,7 @@ func Test_Group_GroupStatistics(t *testing.T) {
stats, err := tRepos.Groups.StatsGroup(context.Background(), tGroup.ID)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, 20, stats.TotalItems)
assert.Equal(t, 20, stats.TotalLabels)
assert.Equal(t, 1, stats.TotalUsers)

View File

@@ -51,31 +51,31 @@ func ToItemAttachment(attachment *ent.Attachment) ItemAttachment {
}
}
func (r *AttachmentRepo) Create(ctx context.Context, itemID, docID uuid.UUID, typ attachment.Type) (*ent.Attachment, error) {
func (r *AttachmentRepo) Create(ctx context.Context, itemId, docId uuid.UUID, typ attachment.Type) (*ent.Attachment, error) {
bldr := r.db.Attachment.Create().
SetType(typ).
SetDocumentID(docID).
SetItemID(itemID)
SetDocumentID(docId).
SetItemID(itemId)
// Autoset primary to true if this is the first attachment
// that is of type photo
if typ == attachment.TypePhoto {
cnt, err := r.db.Attachment.Query().
Where(
attachment.HasItemWith(item.ID(itemID)),
attachment.TypeEQ(typ),
).
Count(ctx)
if err != nil {
return nil, err
}
// Autoset primary to true if this is the first attachment
// that is of type photo
if typ == attachment.TypePhoto {
cnt, err := r.db.Attachment.Query().
Where(
attachment.HasItemWith(item.ID(itemId)),
attachment.TypeEQ(typ),
).
Count(ctx)
if err != nil {
return nil, err
}
if cnt == 0 {
bldr = bldr.SetPrimary(true)
}
}
if cnt == 0 {
bldr = bldr.SetPrimary(true)
}
}
return bldr.Save(ctx)
return bldr.Save(ctx)
}
func (r *AttachmentRepo) Get(ctx context.Context, id uuid.UUID) (*ent.Attachment, error) {
@@ -87,11 +87,11 @@ func (r *AttachmentRepo) Get(ctx context.Context, id uuid.UUID) (*ent.Attachment
Only(ctx)
}
func (r *AttachmentRepo) Update(ctx context.Context, itemID uuid.UUID, data *ItemAttachmentUpdate) (*ent.Attachment, error) {
func (r *AttachmentRepo) Update(ctx context.Context, itemId uuid.UUID, data *ItemAttachmentUpdate) (*ent.Attachment, error) {
// TODO: execute within Tx
typ := attachment.Type(data.Type)
bldr := r.db.Attachment.UpdateOneID(itemID).
bldr := r.db.Attachment.UpdateOneID(itemId).
SetType(typ)
// Primary only applies to photos
@@ -109,7 +109,7 @@ func (r *AttachmentRepo) Update(ctx context.Context, itemID uuid.UUID, data *Ite
// Ensure all other attachments are not primary
err = r.db.Attachment.Update().
Where(
attachment.HasItemWith(item.ID(itemID)),
attachment.HasItemWith(item.ID(itemId)),
attachment.IDNEQ(itm.ID),
).
SetPrimary(false).

View File

@@ -8,7 +8,6 @@ import (
"github.com/hay-kot/homebox/backend/internal/data/ent"
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestAttachmentRepo_Create(t *testing.T) {
@@ -24,8 +23,8 @@ func TestAttachmentRepo_Create(t *testing.T) {
type args struct {
ctx context.Context
itemID uuid.UUID
docID uuid.UUID
itemId uuid.UUID
docId uuid.UUID
typ attachment.Type
}
tests := []struct {
@@ -38,8 +37,8 @@ func TestAttachmentRepo_Create(t *testing.T) {
name: "create attachment",
args: args{
ctx: context.Background(),
itemID: item.ID,
docID: doc.ID,
itemId: item.ID,
docId: doc.ID,
typ: attachment.TypePhoto,
},
want: &ent.Attachment{
@@ -50,8 +49,8 @@ func TestAttachmentRepo_Create(t *testing.T) {
name: "create attachment with invalid item id",
args: args{
ctx: context.Background(),
itemID: uuid.New(),
docID: doc.ID,
itemId: uuid.New(),
docId: doc.ID,
typ: "blarg",
},
wantErr: true,
@@ -59,7 +58,7 @@ func TestAttachmentRepo_Create(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := tRepos.Attachments.Create(tt.args.ctx, tt.args.itemID, tt.args.docID, tt.args.typ)
got, err := tRepos.Attachments.Create(tt.args.ctx, tt.args.itemId, tt.args.docId, tt.args.typ)
if (err != nil) != tt.wantErr {
t.Errorf("AttachmentRepo.Create() error = %v, wantErr %v", err, tt.wantErr)
return
@@ -72,9 +71,9 @@ func TestAttachmentRepo_Create(t *testing.T) {
assert.Equal(t, tt.want.Type, got.Type)
withItems, err := tRepos.Attachments.Get(tt.args.ctx, got.ID)
require.NoError(t, err)
assert.Equal(t, tt.args.itemID, withItems.Edges.Item.ID)
assert.Equal(t, tt.args.docID, withItems.Edges.Document.ID)
assert.NoError(t, err)
assert.Equal(t, tt.args.itemId, withItems.Edges.Item.ID)
assert.Equal(t, tt.args.docId, withItems.Edges.Document.ID)
ids = append(ids, got.ID)
})
@@ -97,7 +96,7 @@ func useAttachments(t *testing.T, n int) []*ent.Attachment {
attachments := make([]*ent.Attachment, n)
for i := 0; i < n; i++ {
attachment, err := tRepos.Attachments.Create(context.Background(), item.ID, doc.ID, attachment.TypePhoto)
require.NoError(t, err)
assert.NoError(t, err)
attachments[i] = attachment
ids = append(ids, attachment.ID)
@@ -115,10 +114,10 @@ func TestAttachmentRepo_Update(t *testing.T) {
Type: string(typ),
})
require.NoError(t, err)
assert.NoError(t, err)
updated, err := tRepos.Attachments.Get(context.Background(), entity.ID)
require.NoError(t, err)
assert.NoError(t, err)
assert.Equal(t, typ, updated.Type)
})
}
@@ -128,8 +127,8 @@ func TestAttachmentRepo_Delete(t *testing.T) {
entity := useAttachments(t, 1)[0]
err := tRepos.Attachments.Delete(context.Background(), entity.ID)
require.NoError(t, err)
assert.NoError(t, err)
_, err = tRepos.Attachments.Get(context.Background(), entity.ID)
require.Error(t, err)
assert.Error(t, err)
}

View File

@@ -55,8 +55,8 @@ type (
ItemCreate struct {
ImportRef string `json:"-"`
ParentID uuid.UUID `json:"parentId" extensions:"x-nullable"`
Name string `json:"name" validate:"required,min=1,max=255"`
ParentID uuid.UUID `json:"parentId" extensions:"x-nullable"`
Name string `json:"name" validate:"required,min=1,max=255"`
Description string `json:"description" validate:"max=1000"`
AssetID AssetID `json:"-"`
@@ -66,9 +66,9 @@ type (
}
ItemUpdate struct {
ParentID uuid.UUID `json:"parentId" extensions:"x-nullable,x-omitempty"`
ParentID uuid.UUID `json:"parentId" extensions:"x-nullable,x-omitempty"`
ID uuid.UUID `json:"id"`
AssetID AssetID `json:"assetId" swaggertype:"string"`
AssetID AssetID `json:"assetId"`
Name string `json:"name"`
Description string `json:"description"`
Quantity int `json:"quantity"`
@@ -108,7 +108,7 @@ type (
ItemPatch struct {
ID uuid.UUID `json:"id"`
Quantity *int `json:"quantity,omitempty" extensions:"x-nullable,x-omitempty"`
ImportRef *string `json:"-,omitempty" extensions:"x-nullable,x-omitempty"`
ImportRef *string `json:"-,omitempty" extensions:"x-nullable,x-omitempty"`
}
ItemSummary struct {
@@ -276,9 +276,9 @@ func mapItemOut(item *ent.Item) ItemOut {
}
}
func (e *ItemsRepository) publishMutationEvent(groupID uuid.UUID) {
if e.bus != nil {
e.bus.Publish(eventbus.EventItemMutation, eventbus.GroupMutationEvent{GID: groupID})
func (r *ItemsRepository) publishMutationEvent(GID uuid.UUID) {
if r.bus != nil {
r.bus.Publish(eventbus.EventItemMutation, eventbus.GroupMutationEvent{GID: GID})
}
}
@@ -304,13 +304,13 @@ func (e *ItemsRepository) GetOne(ctx context.Context, id uuid.UUID) (ItemOut, er
return e.getOne(ctx, item.ID(id))
}
func (e *ItemsRepository) CheckRef(ctx context.Context, groupID uuid.UUID, ref string) (bool, error) {
q := e.db.Item.Query().Where(item.HasGroupWith(group.ID(groupID)))
func (e *ItemsRepository) CheckRef(ctx context.Context, GID uuid.UUID, ref string) (bool, error) {
q := e.db.Item.Query().Where(item.HasGroupWith(group.ID(GID)))
return q.Where(item.ImportRef(ref)).Exist(ctx)
}
func (e *ItemsRepository) GetByRef(ctx context.Context, groupID uuid.UUID, ref string) (ItemOut, error) {
return e.getOne(ctx, item.ImportRef(ref), item.HasGroupWith(group.ID(groupID)))
func (e *ItemsRepository) GetByRef(ctx context.Context, GID uuid.UUID, ref string) (ItemOut, error) {
return e.getOne(ctx, item.ImportRef(ref), item.HasGroupWith(group.ID(GID)))
}
// GetOneByGroup returns a single item by ID. If the item does not exist, an error is returned.
@@ -341,10 +341,8 @@ func (e *ItemsRepository) QueryByGroup(ctx context.Context, gid uuid.UUID, q Ite
item.Or(
item.NameContainsFold(q.Search),
item.DescriptionContainsFold(q.Search),
item.SerialNumberContainsFold(q.Search),
item.ModelNumberContainsFold(q.Search),
item.ManufacturerContainsFold(q.Search),
item.NotesContainsFold(q.Search),
item.ManufacturerContainsFold(q.Search),
),
)
}
@@ -490,9 +488,9 @@ func (e *ItemsRepository) GetAll(ctx context.Context, gid uuid.UUID) ([]ItemOut,
All(ctx))
}
func (e *ItemsRepository) GetAllZeroAssetID(ctx context.Context, groupID uuid.UUID) ([]ItemSummary, error) {
func (e *ItemsRepository) GetAllZeroAssetID(ctx context.Context, GID uuid.UUID) ([]ItemSummary, error) {
q := e.db.Item.Query().Where(
item.HasGroupWith(group.ID(groupID)),
item.HasGroupWith(group.ID(GID)),
item.AssetID(0),
).Order(
ent.Asc(item.FieldCreatedAt),
@@ -501,9 +499,9 @@ func (e *ItemsRepository) GetAllZeroAssetID(ctx context.Context, groupID uuid.UU
return mapItemsSummaryErr(q.All(ctx))
}
func (e *ItemsRepository) GetHighestAssetID(ctx context.Context, groupID uuid.UUID) (AssetID, error) {
func (e *ItemsRepository) GetHighestAssetID(ctx context.Context, GID uuid.UUID) (AssetID, error) {
q := e.db.Item.Query().Where(
item.HasGroupWith(group.ID(groupID)),
item.HasGroupWith(group.ID(GID)),
).Order(
ent.Desc(item.FieldAssetID),
).Limit(1)
@@ -519,10 +517,10 @@ func (e *ItemsRepository) GetHighestAssetID(ctx context.Context, groupID uuid.UU
return AssetID(result.AssetID), nil
}
func (e *ItemsRepository) SetAssetID(ctx context.Context, groupID uuid.UUID, itemID uuid.UUID, assetID AssetID) error {
func (e *ItemsRepository) SetAssetID(ctx context.Context, GID uuid.UUID, ID uuid.UUID, assetID AssetID) error {
q := e.db.Item.Update().Where(
item.HasGroupWith(group.ID(groupID)),
item.ID(itemID),
item.HasGroupWith(group.ID(GID)),
item.ID(ID),
)
_, err := q.SetAssetID(int(assetID)).Save(ctx)
@@ -576,8 +574,8 @@ func (e *ItemsRepository) DeleteByGroup(ctx context.Context, gid, id uuid.UUID)
return err
}
func (e *ItemsRepository) UpdateByGroup(ctx context.Context, groupID uuid.UUID, data ItemUpdate) (ItemOut, error) {
q := e.db.Item.Update().Where(item.ID(data.ID), item.HasGroupWith(group.ID(groupID))).
func (e *ItemsRepository) UpdateByGroup(ctx context.Context, GID uuid.UUID, data ItemUpdate) (ItemOut, error) {
q := e.db.Item.Update().Where(item.ID(data.ID), item.HasGroupWith(group.ID(GID))).
SetName(data.Name).
SetDescription(data.Description).
SetLocationID(data.LocationID).
@@ -688,16 +686,16 @@ func (e *ItemsRepository) UpdateByGroup(ctx context.Context, groupID uuid.UUID,
}
}
e.publishMutationEvent(groupID)
e.publishMutationEvent(GID)
return e.GetOne(ctx, data.ID)
}
func (e *ItemsRepository) GetAllZeroImportRef(ctx context.Context, groupID uuid.UUID) ([]uuid.UUID, error) {
func (e *ItemsRepository) GetAllZeroImportRef(ctx context.Context, GID uuid.UUID) ([]uuid.UUID, error) {
var ids []uuid.UUID
err := e.db.Item.Query().
Where(
item.HasGroupWith(group.ID(groupID)),
item.HasGroupWith(group.ID(GID)),
item.Or(
item.ImportRefEQ(""),
item.ImportRefIsNil(),
@@ -712,11 +710,11 @@ func (e *ItemsRepository) GetAllZeroImportRef(ctx context.Context, groupID uuid.
return ids, nil
}
func (e *ItemsRepository) Patch(ctx context.Context, groupID, itemID uuid.UUID, data ItemPatch) error {
func (e *ItemsRepository) Patch(ctx context.Context, GID, ID uuid.UUID, data ItemPatch) error {
q := e.db.Item.Update().
Where(
item.ID(itemID),
item.HasGroupWith(group.ID(groupID)),
item.ID(ID),
item.HasGroupWith(group.ID(GID)),
)
if data.ImportRef != nil {
@@ -727,11 +725,11 @@ func (e *ItemsRepository) Patch(ctx context.Context, groupID, itemID uuid.UUID,
q.SetQuantity(*data.Quantity)
}
e.publishMutationEvent(groupID)
e.publishMutationEvent(GID)
return q.Exec(ctx)
}
func (e *ItemsRepository) GetAllCustomFieldValues(ctx context.Context, groupID uuid.UUID, name string) ([]string, error) {
func (e *ItemsRepository) GetAllCustomFieldValues(ctx context.Context, GID uuid.UUID, name string) ([]string, error) {
type st struct {
Value string `json:"text_value"`
}
@@ -740,7 +738,7 @@ func (e *ItemsRepository) GetAllCustomFieldValues(ctx context.Context, groupID u
err := e.db.Item.Query().
Where(
item.HasGroupWith(group.ID(groupID)),
item.HasGroupWith(group.ID(GID)),
).
QueryFields().
Where(
@@ -761,7 +759,7 @@ func (e *ItemsRepository) GetAllCustomFieldValues(ctx context.Context, groupID u
return valueStrings, nil
}
func (e *ItemsRepository) GetAllCustomFieldNames(ctx context.Context, groupID uuid.UUID) ([]string, error) {
func (e *ItemsRepository) GetAllCustomFieldNames(ctx context.Context, GID uuid.UUID) ([]string, error) {
type st struct {
Name string `json:"name"`
}
@@ -770,7 +768,7 @@ func (e *ItemsRepository) GetAllCustomFieldNames(ctx context.Context, groupID uu
err := e.db.Item.Query().
Where(
item.HasGroupWith(group.ID(groupID)),
item.HasGroupWith(group.ID(GID)),
).
QueryFields().
Unique(true).
@@ -794,16 +792,13 @@ func (e *ItemsRepository) GetAllCustomFieldNames(ctx context.Context, groupID uu
// This is designed to resolve a long-time bug that has since been fixed with the time selector on the
// frontend. This function is intended to be used as a one-time fix for existing databases and may be
// removed in the future.
func (e *ItemsRepository) ZeroOutTimeFields(ctx context.Context, groupID uuid.UUID) (int, error) {
func (e *ItemsRepository) ZeroOutTimeFields(ctx context.Context, GID uuid.UUID) (int, error) {
q := e.db.Item.Query().Where(
item.HasGroupWith(group.ID(groupID)),
item.HasGroupWith(group.ID(GID)),
item.Or(
item.PurchaseTimeNotNil(),
item.PurchaseFromLT("0002-01-01"),
item.SoldTimeNotNil(),
item.SoldToLT("0002-01-01"),
item.WarrantyExpiresNotNil(),
item.WarrantyDetailsLT("0002-01-01"),
),
)
@@ -822,36 +817,15 @@ func (e *ItemsRepository) ZeroOutTimeFields(ctx context.Context, groupID uuid.UU
updateQ := e.db.Item.Update().Where(item.ID(i.ID))
if !i.PurchaseTime.IsZero() {
switch {
case i.PurchaseTime.Year() < 100:
updateQ.ClearPurchaseTime()
default:
updateQ.SetPurchaseTime(toDateOnly(i.PurchaseTime))
}
} else {
updateQ.ClearPurchaseTime()
updateQ.SetPurchaseTime(toDateOnly(i.PurchaseTime))
}
if !i.SoldTime.IsZero() {
switch {
case i.SoldTime.Year() < 100:
updateQ.ClearSoldTime()
default:
updateQ.SetSoldTime(toDateOnly(i.SoldTime))
}
} else {
updateQ.ClearSoldTime()
updateQ.SetSoldTime(toDateOnly(i.SoldTime))
}
if !i.WarrantyExpires.IsZero() {
switch {
case i.WarrantyExpires.Year() < 100:
updateQ.ClearWarrantyExpires()
default:
updateQ.SetWarrantyExpires(toDateOnly(i.WarrantyExpires))
}
} else {
updateQ.ClearWarrantyExpires()
updateQ.SetWarrantyExpires(toDateOnly(i.WarrantyExpires))
}
_, err = updateQ.Save(ctx)
@@ -865,11 +839,11 @@ func (e *ItemsRepository) ZeroOutTimeFields(ctx context.Context, groupID uuid.UU
return updated, nil
}
func (e *ItemsRepository) SetPrimaryPhotos(ctx context.Context, groupID uuid.UUID) (int, error) {
func (e *ItemsRepository) SetPrimaryPhotos(ctx context.Context, GID uuid.UUID) (int, error) {
// All items where there is no primary photo
itemIDs, err := e.db.Item.Query().
Where(
item.HasGroupWith(group.ID(groupID)),
item.HasGroupWith(group.ID(GID)),
item.HasAttachmentsWith(
attachment.TypeEQ(attachment.TypePhoto),
attachment.Not(
@@ -903,6 +877,7 @@ func (e *ItemsRepository) SetPrimaryPhotos(ctx context.Context, groupID uuid.UUI
_, err = e.db.Attachment.UpdateOne(a).
SetPrimary(true).
Save(ctx)
if err != nil {
return updated, err
}

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