email improvements

This commit is contained in:
Hayden 2024-03-02 12:02:41 -06:00
parent 6fd8457e5a
commit 29e30bfaba
No known key found for this signature in database
GPG key ID: 17CF79474E257545
47 changed files with 3710 additions and 95 deletions

View file

@ -5,6 +5,11 @@ env:
HBOX_STORAGE_SQLITE_URL: .data/homebox.db?_pragma=busy_timeout=1000&_pragma=journal_mode=WAL&_fk=1 HBOX_STORAGE_SQLITE_URL: .data/homebox.db?_pragma=busy_timeout=1000&_pragma=journal_mode=WAL&_fk=1
HBOX_OPTIONS_ALLOW_REGISTRATION: true HBOX_OPTIONS_ALLOW_REGISTRATION: true
UNSAFE_DISABLE_PASSWORD_PROJECTION: "yes_i_am_sure" UNSAFE_DISABLE_PASSWORD_PROJECTION: "yes_i_am_sure"
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: tasks:
setup: setup:
desc: Install development dependencies desc: Install development dependencies

View file

@ -71,4 +71,4 @@ linters:
- sqlclosecheck - sqlclosecheck
issues: issues:
exclude-use-default: false exclude-use-default: false
fix: true fix: false

View file

@ -11,7 +11,7 @@ import (
type app struct { type app struct {
conf *config.Config conf *config.Config
mailer mailer.Mailer mailer *mailer.Mailer
db *ent.Client db *ent.Client
repos *repo.AllRepos repos *repo.AllRepos
services *services.AllServices services *services.AllServices
@ -23,7 +23,7 @@ func new(conf *config.Config) *app {
conf: conf, conf: conf,
} }
s.mailer = mailer.Mailer{ s.mailer = &mailer.Mailer{
Host: s.conf.Mailer.Host, Host: s.conf.Mailer.Host,
Port: s.conf.Mailer.Port, Port: s.conf.Mailer.Port,
Username: s.conf.Mailer.Username, Username: s.conf.Mailer.Username,

View file

@ -8,6 +8,7 @@ import (
"github.com/hay-kot/homebox/backend/internal/core/services" "github.com/hay-kot/homebox/backend/internal/core/services"
"github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/data/repo"
"github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/internal/sys/validate"
"github.com/hay-kot/homebox/backend/internal/web/adapters"
"github.com/hay-kot/httpkit/errchain" "github.com/hay-kot/httpkit/errchain"
"github.com/hay-kot/httpkit/server" "github.com/hay-kot/httpkit/server"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
@ -152,3 +153,31 @@ func (ctrl *V1Controller) HandleUserSelfChangePassword() errchain.HandlerFunc {
return server.JSON(w, http.StatusNoContent, nil) 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 {
v, err := adapters.DecodeBody[services.PasswordResetRequest](r)
if err != nil {
return err
}
err = ctrl.svc.User.RequestPasswordReset(r.Context(), v)
if err != nil {
log.Err(err).Msg("failed to request password reset")
return server.Error().
Msg("unknow error occurred").
Status(http.StatusInternalServerError).
Write(r.Context(), w)
}
return nil
}
}

View file

@ -160,6 +160,8 @@ func run(cfg *config.Config) error {
app.repos = repo.New(c, app.bus, cfg.Storage.Data) app.repos = repo.New(c, app.bus, cfg.Storage.Data)
app.services = services.New( app.services = services.New(
app.repos, app.repos,
app.conf.BaseURL,
app.mailer,
services.WithAutoIncrementAssetID(cfg.Options.AutoIncrementAssetID), services.WithAutoIncrementAssetID(cfg.Options.AutoIncrementAssetID),
services.WithCurrencies(currencies), services.WithCurrencies(currencies),
) )
@ -180,7 +182,7 @@ func run(cfg *config.Config) error {
chain := errchain.New(mid.Errors(logger)) chain := errchain.New(mid.Errors(logger))
app.mountRoutes(router, chain, app.repos) app.mountRoutes(router, chain)
runner := graceful.NewRunner() runner := graceful.NewRunner()

View file

@ -15,7 +15,6 @@ import (
"github.com/hay-kot/homebox/backend/app/api/providers" "github.com/hay-kot/homebox/backend/app/api/providers"
_ "github.com/hay-kot/homebox/backend/app/api/static/docs" _ "github.com/hay-kot/homebox/backend/app/api/static/docs"
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles" "github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
"github.com/hay-kot/homebox/backend/internal/data/repo"
"github.com/hay-kot/httpkit/errchain" "github.com/hay-kot/httpkit/errchain"
httpSwagger "github.com/swaggo/http-swagger/v2" // http-swagger middleware httpSwagger "github.com/swaggo/http-swagger/v2" // http-swagger middleware
) )
@ -37,7 +36,7 @@ func (a *app) debugRouter() *http.ServeMux {
} }
// registerRoutes registers all the routes for the API // registerRoutes registers all the routes for the API
func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllRepos) { func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain) {
registerMimes() registerMimes()
r.Get("/swagger/*", httpSwagger.Handler( r.Get("/swagger/*", httpSwagger.Handler(
@ -72,6 +71,7 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
r.Post(v1Base("/users/register"), chain.ToHandlerFunc(v1Ctrl.HandleUserRegistration())) r.Post(v1Base("/users/register"), chain.ToHandlerFunc(v1Ctrl.HandleUserRegistration()))
r.Post(v1Base("/users/login"), chain.ToHandlerFunc(v1Ctrl.HandleAuthLogin(providers...))) r.Post(v1Base("/users/login"), chain.ToHandlerFunc(v1Ctrl.HandleAuthLogin(providers...)))
r.Post(v1Base("/users/request-password-reset"), chain.ToHandlerFunc(v1Ctrl.HandleUserRequestPasswordReset()))
userMW := []errchain.Middleware{ userMW := []errchain.Middleware{
a.mwAuthToken, a.mwAuthToken,

View file

@ -1792,6 +1792,33 @@ 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": { "/v1/users/self": {
"get": { "get": {
"security": [ "security": [
@ -2825,6 +2852,14 @@ const docTemplate = `{
} }
} }
}, },
"services.PasswordResetRequest": {
"type": "object",
"properties": {
"email": {
"type": "string"
}
}
},
"services.UserRegistration": { "services.UserRegistration": {
"type": "object", "type": "object",
"properties": { "properties": {

View file

@ -1785,6 +1785,33 @@
} }
} }
}, },
"/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": { "/v1/users/self": {
"get": { "get": {
"security": [ "security": [
@ -2818,6 +2845,14 @@
} }
} }
}, },
"services.PasswordResetRequest": {
"type": "object",
"properties": {
"email": {
"type": "string"
}
}
},
"services.UserRegistration": { "services.UserRegistration": {
"type": "object", "type": "object",
"properties": { "properties": {

View file

@ -620,6 +620,11 @@ definitions:
value: value:
type: number type: number
type: object type: object
services.PasswordResetRequest:
properties:
email:
type: string
type: object
services.UserRegistration: services.UserRegistration:
properties: properties:
email: email:
@ -1817,6 +1822,23 @@ paths:
summary: Register New User summary: Register New User
tags: tags:
- User - 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: /v1/users/self:
delete: delete:
produces: produces:

View file

@ -14,6 +14,7 @@ require (
github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/gorilla/schema v1.2.1 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/hay-kot/httpkit v0.0.9
github.com/mattn/go-sqlite3 v1.14.22 github.com/mattn/go-sqlite3 v1.14.22
github.com/olahol/melody v1.1.4 github.com/olahol/melody v1.1.4

View file

@ -1,5 +1,3 @@
ariga.io/atlas v0.19.0 h1:gilVpXabeiGhGI9lj/rQURkXBemnloc41RGOtwVLNc4=
ariga.io/atlas v0.19.0/go.mod h1:uj3pm+hUTVN/X5yfdBexHlZv+1Xu5u5ZbZx7+CDavNU=
ariga.io/atlas v0.19.1 h1:QzBHkakwzEhmPWOzNhw8Yr/Bbicj6Iq5hwEoNI/Jr9A= ariga.io/atlas v0.19.1 h1:QzBHkakwzEhmPWOzNhw8Yr/Bbicj6Iq5hwEoNI/Jr9A=
ariga.io/atlas v0.19.1/go.mod h1:VPlcXdd4w2KqKnH54yEZcry79UAhpaWaxEsmn5JRNoE= ariga.io/atlas v0.19.1/go.mod h1:VPlcXdd4w2KqKnH54yEZcry79UAhpaWaxEsmn5JRNoE=
entgo.io/ent v0.12.5 h1:KREM5E4CSoej4zeGa88Ou/gfturAnpUv0mzAjch1sj4= entgo.io/ent v0.12.5 h1:KREM5E4CSoej4zeGa88Ou/gfturAnpUv0mzAjch1sj4=
@ -14,6 +12,8 @@ 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/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 h1:p232cF68TafoA5U9ZlbxUIhGJtGNdKHBXF80Fdqb5t0=
github.com/ardanlabs/conf/v3 v3.1.7/go.mod h1:zclexWKe0NVj6LHQ8NgDDZ7bQ1spE0KeKPFficdtAjU= 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 h1:mfG2ATzIS7NR2Ec6XL+xyoHzN97H8WPjir8aYzJUSec=
github.com/containrrr/shoutrrr v0.8.0/go.mod h1:ioyQAyu1LJY6sILuNyKaQaw+9Ttik5QePU8atnAdO2o= github.com/containrrr/shoutrrr v0.8.0/go.mod h1:ioyQAyu1LJY6sILuNyKaQaw+9Ttik5QePU8atnAdO2o=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
@ -84,12 +84,8 @@ github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= 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 h1://i05Jqznmb2EXqa39Nsvyan2o5XyMowW5fnCKW5RPI=
github.com/hashicorp/hcl/v2 v2.19.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE= github.com/hashicorp/hcl/v2 v2.19.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE=
github.com/hay-kot/httpkit v0.0.6 h1:BidC4UrkS7zRhoTdpKLeF8ODJPKcOZkJ2tk2t2ZIQjQ= github.com/hay-kot/easyemails v0.0.0-20240206011027-25232fb79aa3 h1:EljujAOvukSS+sh8e883j4vhEiYG4EvJFAhl+XvUYe8=
github.com/hay-kot/httpkit v0.0.6/go.mod h1:1s/OJwWRyH6tBtTw76jTp6kwBYvjswziXaokPQH7eKQ= github.com/hay-kot/easyemails v0.0.0-20240206011027-25232fb79aa3/go.mod h1:SZdhYMO2ZmEuTTDE7pHn0WanXhwteniOCYsQ3B5IT/o=
github.com/hay-kot/httpkit v0.0.7 h1:KxGi+MwXFavfFUfJEMpye5cnMef9TlFu3v7UZipUB8U=
github.com/hay-kot/httpkit v0.0.7/go.mod h1:AD22YluZrvBDxmtB3Pw2SOyp3A2PZqcmBZa0+COrhoU=
github.com/hay-kot/httpkit v0.0.8 h1:n+Z5z35YZcdD9cGwbnIPRbrgDw9LY6lqakH4zYr5z+A=
github.com/hay-kot/httpkit v0.0.8/go.mod h1:AD22YluZrvBDxmtB3Pw2SOyp3A2PZqcmBZa0+COrhoU=
github.com/hay-kot/httpkit v0.0.9 h1:hu2TPY9awmIYWXxWGubaXl2U61pPvaVsm9YwboBRGu0= 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.9/go.mod h1:AD22YluZrvBDxmtB3Pw2SOyp3A2PZqcmBZa0+COrhoU=
github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc= github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc=
@ -119,6 +115,8 @@ 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.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 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= 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.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
@ -128,6 +126,8 @@ github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJm
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= 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 h1:RQHfKZkQmDxI0+SLZRNBCn4LiXdqxLKRGSkT8Dyoe/E=
github.com/olahol/melody v1.1.4/go.mod h1:GgkTl6Y7yWj/HtfD48Q5vLKPVoZOH+Qqgfa7CvJgJM4= github.com/olahol/melody v1.1.4/go.mod h1:GgkTl6Y7yWj/HtfD48Q5vLKPVoZOH+Qqgfa7CvJgJM4=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= 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/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 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
@ -145,6 +145,10 @@ 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.32.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 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@ -173,8 +177,6 @@ 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.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4= golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
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/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= 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/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 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=

View file

@ -4,6 +4,7 @@ package services
import ( import (
"github.com/hay-kot/homebox/backend/internal/core/currencies" "github.com/hay-kot/homebox/backend/internal/core/currencies"
"github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/data/repo"
"github.com/hay-kot/homebox/backend/pkgs/mailer"
) )
type AllServices struct { type AllServices struct {
@ -33,7 +34,7 @@ func WithCurrencies(v []currencies.Currency) func(*options) {
} }
} }
func New(repos *repo.AllRepos, opts ...OptionsFunc) *AllServices { func New(repos *repo.AllRepos, baseurl string, sender *mailer.Mailer, opts ...OptionsFunc) *AllServices {
if repos == nil { if repos == nil {
panic("repos cannot be nil") panic("repos cannot be nil")
} }
@ -55,7 +56,11 @@ func New(repos *repo.AllRepos, opts ...OptionsFunc) *AllServices {
} }
return &AllServices{ return &AllServices{
User: &UserService{repos}, User: &UserService{
repos: repos,
mailer: sender,
baseurl: baseurl,
},
Group: &GroupService{repos}, Group: &GroupService{repos},
Items: &ItemService{ Items: &ItemService{
repo: repos, repo: repos,

View file

@ -11,6 +11,7 @@ import (
"github.com/hay-kot/homebox/backend/internal/data/ent" "github.com/hay-kot/homebox/backend/internal/data/ent"
"github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/data/repo"
"github.com/hay-kot/homebox/backend/pkgs/faker" "github.com/hay-kot/homebox/backend/pkgs/faker"
"github.com/hay-kot/homebox/backend/pkgs/mailer"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
) )
@ -67,7 +68,7 @@ func TestMain(m *testing.M) {
currencies.CollectDefaults(), currencies.CollectDefaults(),
) )
tSvc = New(tRepos, WithCurrencies(defaults)) tSvc = New(tRepos, "", &mailer.Mailer{}, WithCurrencies(defaults))
defer func() { _ = client.Close() }() defer func() { _ = client.Close() }()
bootstrap() bootstrap()

View file

@ -3,12 +3,15 @@ package services
import ( import (
"context" "context"
"errors" "errors"
"net/url"
"time" "time"
"github.com/google/uuid" "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/ent/authroles"
"github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/data/repo"
"github.com/hay-kot/homebox/backend/pkgs/hasher" "github.com/hay-kot/homebox/backend/pkgs/hasher"
"github.com/hay-kot/homebox/backend/pkgs/mailer"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
@ -20,7 +23,9 @@ var (
) )
type UserService struct { type UserService struct {
repos *repo.AllRepos repos *repo.AllRepos
mailer *mailer.Mailer
baseurl string
} }
type ( type (
@ -39,6 +44,9 @@ type (
Username string `json:"username"` Username string `json:"username"`
Password string `json:"password"` 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 // RegisterUser creates a new user and group in the data with the provided data. It also bootstraps the user's group
@ -246,3 +254,50 @@ func (svc *UserService) ChangePassword(ctx Context, current string, new string)
return true return true
} }
func (svc *UserService) RequestPasswordReset(ctx context.Context, req PasswordResetRequest) error {
usr, err := svc.repos.Users.GetOneEmail(ctx, req.Email)
if err != nil {
log.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

@ -0,0 +1,184 @@
// 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

@ -0,0 +1,138 @@
// 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

@ -0,0 +1,275 @@
// 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

@ -0,0 +1,329 @@
// 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

@ -0,0 +1,88 @@
// Code generated by ent, DO NOT EDIT.
package ent
import (
"context"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/hay-kot/homebox/backend/internal/data/ent/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

@ -0,0 +1,606 @@
// 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

@ -0,0 +1,406 @@
// 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,6 +16,7 @@ import (
"entgo.io/ent/dialect" "entgo.io/ent/dialect"
"entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph" "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/attachment"
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles" "github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens" "github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
@ -36,6 +37,8 @@ type Client struct {
config config
// Schema is the client for creating, migrating and dropping schema. // Schema is the client for creating, migrating and dropping schema.
Schema *migrate.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 is the client for interacting with the Attachment builders.
Attachment *AttachmentClient Attachment *AttachmentClient
// AuthRoles is the client for interacting with the AuthRoles builders. // AuthRoles is the client for interacting with the AuthRoles builders.
@ -73,6 +76,7 @@ func NewClient(opts ...Option) *Client {
func (c *Client) init() { func (c *Client) init() {
c.Schema = migrate.NewSchema(c.driver) c.Schema = migrate.NewSchema(c.driver)
c.ActionToken = NewActionTokenClient(c.config)
c.Attachment = NewAttachmentClient(c.config) c.Attachment = NewAttachmentClient(c.config)
c.AuthRoles = NewAuthRolesClient(c.config) c.AuthRoles = NewAuthRolesClient(c.config)
c.AuthTokens = NewAuthTokensClient(c.config) c.AuthTokens = NewAuthTokensClient(c.config)
@ -178,6 +182,7 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) {
return &Tx{ return &Tx{
ctx: ctx, ctx: ctx,
config: cfg, config: cfg,
ActionToken: NewActionTokenClient(cfg),
Attachment: NewAttachmentClient(cfg), Attachment: NewAttachmentClient(cfg),
AuthRoles: NewAuthRolesClient(cfg), AuthRoles: NewAuthRolesClient(cfg),
AuthTokens: NewAuthTokensClient(cfg), AuthTokens: NewAuthTokensClient(cfg),
@ -210,6 +215,7 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error)
return &Tx{ return &Tx{
ctx: ctx, ctx: ctx,
config: cfg, config: cfg,
ActionToken: NewActionTokenClient(cfg),
Attachment: NewAttachmentClient(cfg), Attachment: NewAttachmentClient(cfg),
AuthRoles: NewAuthRolesClient(cfg), AuthRoles: NewAuthRolesClient(cfg),
AuthTokens: NewAuthTokensClient(cfg), AuthTokens: NewAuthTokensClient(cfg),
@ -229,7 +235,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. // Debug returns a new debug-client. It's used to get verbose logging on specific operations.
// //
// client.Debug(). // client.Debug().
// Attachment. // ActionToken.
// Query(). // Query().
// Count(ctx) // Count(ctx)
func (c *Client) Debug() *Client { func (c *Client) Debug() *Client {
@ -252,7 +258,7 @@ func (c *Client) Close() error {
// In order to add hooks to a specific client, call: `client.Node.Use(...)`. // In order to add hooks to a specific client, call: `client.Node.Use(...)`.
func (c *Client) Use(hooks ...Hook) { func (c *Client) Use(hooks ...Hook) {
for _, n := range []interface{ Use(...Hook) }{ for _, n := range []interface{ Use(...Hook) }{
c.Attachment, c.AuthRoles, c.AuthTokens, c.Document, c.Group, c.ActionToken, c.Attachment, c.AuthRoles, c.AuthTokens, c.Document, c.Group,
c.GroupInvitationToken, c.Item, c.ItemField, c.Label, c.Location, c.GroupInvitationToken, c.Item, c.ItemField, c.Label, c.Location,
c.MaintenanceEntry, c.Notifier, c.User, c.MaintenanceEntry, c.Notifier, c.User,
} { } {
@ -264,7 +270,7 @@ func (c *Client) Use(hooks ...Hook) {
// In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`. // In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`.
func (c *Client) Intercept(interceptors ...Interceptor) { func (c *Client) Intercept(interceptors ...Interceptor) {
for _, n := range []interface{ Intercept(...Interceptor) }{ for _, n := range []interface{ Intercept(...Interceptor) }{
c.Attachment, c.AuthRoles, c.AuthTokens, c.Document, c.Group, c.ActionToken, c.Attachment, c.AuthRoles, c.AuthTokens, c.Document, c.Group,
c.GroupInvitationToken, c.Item, c.ItemField, c.Label, c.Location, c.GroupInvitationToken, c.Item, c.ItemField, c.Label, c.Location,
c.MaintenanceEntry, c.Notifier, c.User, c.MaintenanceEntry, c.Notifier, c.User,
} { } {
@ -275,6 +281,8 @@ func (c *Client) Intercept(interceptors ...Interceptor) {
// Mutate implements the ent.Mutator interface. // Mutate implements the ent.Mutator interface.
func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) { func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) {
switch m := m.(type) { switch m := m.(type) {
case *ActionTokenMutation:
return c.ActionToken.mutate(ctx, m)
case *AttachmentMutation: case *AttachmentMutation:
return c.Attachment.mutate(ctx, m) return c.Attachment.mutate(ctx, m)
case *AuthRolesMutation: case *AuthRolesMutation:
@ -306,6 +314,155 @@ 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. // AttachmentClient is a client for the Attachment schema.
type AttachmentClient struct { type AttachmentClient struct {
config config
@ -2586,6 +2743,22 @@ func (c *UserClient) QueryNotifiers(u *User) *NotifierQuery {
return query 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. // Hooks returns the client hooks.
func (c *UserClient) Hooks() []Hook { func (c *UserClient) Hooks() []Hook {
return c.hooks.User return c.hooks.User
@ -2614,11 +2787,13 @@ func (c *UserClient) mutate(ctx context.Context, m *UserMutation) (Value, error)
// hooks and interceptors per client, for fast access. // hooks and interceptors per client, for fast access.
type ( type (
hooks struct { hooks struct {
Attachment, AuthRoles, AuthTokens, Document, Group, GroupInvitationToken, Item, ActionToken, Attachment, AuthRoles, AuthTokens, Document, Group,
ItemField, Label, Location, MaintenanceEntry, Notifier, User []ent.Hook GroupInvitationToken, Item, ItemField, Label, Location, MaintenanceEntry,
Notifier, User []ent.Hook
} }
inters struct { inters struct {
Attachment, AuthRoles, AuthTokens, Document, Group, GroupInvitationToken, Item, ActionToken, Attachment, AuthRoles, AuthTokens, Document, Group,
ItemField, Label, Location, MaintenanceEntry, Notifier, User []ent.Interceptor GroupInvitationToken, Item, ItemField, Label, Location, MaintenanceEntry,
Notifier, User []ent.Interceptor
} }
) )

View file

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

View file

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

View file

@ -9,6 +9,18 @@ import (
"github.com/hay-kot/homebox/backend/internal/data/ent" "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 // The AttachmentFunc type is an adapter to allow the use of ordinary
// function as Attachment mutator. // function as Attachment mutator.
type AttachmentFunc func(context.Context, *ent.AttachmentMutation) (ent.Value, error) type AttachmentFunc func(context.Context, *ent.AttachmentMutation) (ent.Value, error)

View file

@ -8,6 +8,46 @@ import (
) )
var ( 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 holds the columns for the "attachments" table.
AttachmentsColumns = []*schema.Column{ AttachmentsColumns = []*schema.Column{
{Name: "id", Type: field.TypeUUID}, {Name: "id", Type: field.TypeUUID},
@ -453,6 +493,7 @@ var (
} }
// Tables holds all the tables in the schema. // Tables holds all the tables in the schema.
Tables = []*schema.Table{ Tables = []*schema.Table{
ActionTokensTable,
AttachmentsTable, AttachmentsTable,
AuthRolesTable, AuthRolesTable,
AuthTokensTable, AuthTokensTable,
@ -471,6 +512,7 @@ var (
) )
func init() { func init() {
ActionTokensTable.ForeignKeys[0].RefTable = UsersTable
AttachmentsTable.ForeignKeys[0].RefTable = DocumentsTable AttachmentsTable.ForeignKeys[0].RefTable = DocumentsTable
AttachmentsTable.ForeignKeys[1].RefTable = ItemsTable AttachmentsTable.ForeignKeys[1].RefTable = ItemsTable
AuthRolesTable.ForeignKeys[0].RefTable = AuthTokensTable AuthRolesTable.ForeignKeys[0].RefTable = AuthTokensTable

View file

@ -12,6 +12,7 @@ import (
"entgo.io/ent" "entgo.io/ent"
"entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/data/ent/actiontoken"
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment" "github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles" "github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens" "github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
@ -37,6 +38,7 @@ const (
OpUpdateOne = ent.OpUpdateOne OpUpdateOne = ent.OpUpdateOne
// Node types. // Node types.
TypeActionToken = "ActionToken"
TypeAttachment = "Attachment" TypeAttachment = "Attachment"
TypeAuthRoles = "AuthRoles" TypeAuthRoles = "AuthRoles"
TypeAuthTokens = "AuthTokens" TypeAuthTokens = "AuthTokens"
@ -52,6 +54,608 @@ const (
TypeUser = "User" 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. // AttachmentMutation represents an operation that mutates the Attachment nodes in the graph.
type AttachmentMutation struct { type AttachmentMutation struct {
config config
@ -10672,30 +11276,33 @@ func (m *NotifierMutation) ResetEdge(name string) error {
// UserMutation represents an operation that mutates the User nodes in the graph. // UserMutation represents an operation that mutates the User nodes in the graph.
type UserMutation struct { type UserMutation struct {
config config
op Op op Op
typ string typ string
id *uuid.UUID id *uuid.UUID
created_at *time.Time created_at *time.Time
updated_at *time.Time updated_at *time.Time
name *string name *string
email *string email *string
password *string password *string
is_superuser *bool is_superuser *bool
superuser *bool superuser *bool
role *user.Role role *user.Role
activated_on *time.Time activated_on *time.Time
clearedFields map[string]struct{} clearedFields map[string]struct{}
group *uuid.UUID group *uuid.UUID
clearedgroup bool clearedgroup bool
auth_tokens map[uuid.UUID]struct{} auth_tokens map[uuid.UUID]struct{}
removedauth_tokens map[uuid.UUID]struct{} removedauth_tokens map[uuid.UUID]struct{}
clearedauth_tokens bool clearedauth_tokens bool
notifiers map[uuid.UUID]struct{} notifiers map[uuid.UUID]struct{}
removednotifiers map[uuid.UUID]struct{} removednotifiers map[uuid.UUID]struct{}
clearednotifiers bool clearednotifiers bool
done bool action_tokens map[uuid.UUID]struct{}
oldValue func(context.Context) (*User, error) removedaction_tokens map[uuid.UUID]struct{}
predicates []predicate.User clearedaction_tokens bool
done bool
oldValue func(context.Context) (*User, error)
predicates []predicate.User
} }
var _ ent.Mutation = (*UserMutation)(nil) var _ ent.Mutation = (*UserMutation)(nil)
@ -11286,6 +11893,60 @@ func (m *UserMutation) ResetNotifiers() {
m.removednotifiers = nil 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. // Where appends a list predicates to the UserMutation builder.
func (m *UserMutation) Where(ps ...predicate.User) { func (m *UserMutation) Where(ps ...predicate.User) {
m.predicates = append(m.predicates, ps...) m.predicates = append(m.predicates, ps...)
@ -11564,7 +12225,7 @@ func (m *UserMutation) ResetField(name string) error {
// AddedEdges returns all edge names that were set/added in this mutation. // AddedEdges returns all edge names that were set/added in this mutation.
func (m *UserMutation) AddedEdges() []string { func (m *UserMutation) AddedEdges() []string {
edges := make([]string, 0, 3) edges := make([]string, 0, 4)
if m.group != nil { if m.group != nil {
edges = append(edges, user.EdgeGroup) edges = append(edges, user.EdgeGroup)
} }
@ -11574,6 +12235,9 @@ func (m *UserMutation) AddedEdges() []string {
if m.notifiers != nil { if m.notifiers != nil {
edges = append(edges, user.EdgeNotifiers) edges = append(edges, user.EdgeNotifiers)
} }
if m.action_tokens != nil {
edges = append(edges, user.EdgeActionTokens)
}
return edges return edges
} }
@ -11597,19 +12261,28 @@ func (m *UserMutation) AddedIDs(name string) []ent.Value {
ids = append(ids, id) ids = append(ids, id)
} }
return ids 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 return nil
} }
// RemovedEdges returns all edge names that were removed in this mutation. // RemovedEdges returns all edge names that were removed in this mutation.
func (m *UserMutation) RemovedEdges() []string { func (m *UserMutation) RemovedEdges() []string {
edges := make([]string, 0, 3) edges := make([]string, 0, 4)
if m.removedauth_tokens != nil { if m.removedauth_tokens != nil {
edges = append(edges, user.EdgeAuthTokens) edges = append(edges, user.EdgeAuthTokens)
} }
if m.removednotifiers != nil { if m.removednotifiers != nil {
edges = append(edges, user.EdgeNotifiers) edges = append(edges, user.EdgeNotifiers)
} }
if m.removedaction_tokens != nil {
edges = append(edges, user.EdgeActionTokens)
}
return edges return edges
} }
@ -11629,13 +12302,19 @@ func (m *UserMutation) RemovedIDs(name string) []ent.Value {
ids = append(ids, id) ids = append(ids, id)
} }
return ids 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 return nil
} }
// ClearedEdges returns all edge names that were cleared in this mutation. // ClearedEdges returns all edge names that were cleared in this mutation.
func (m *UserMutation) ClearedEdges() []string { func (m *UserMutation) ClearedEdges() []string {
edges := make([]string, 0, 3) edges := make([]string, 0, 4)
if m.clearedgroup { if m.clearedgroup {
edges = append(edges, user.EdgeGroup) edges = append(edges, user.EdgeGroup)
} }
@ -11645,6 +12324,9 @@ func (m *UserMutation) ClearedEdges() []string {
if m.clearednotifiers { if m.clearednotifiers {
edges = append(edges, user.EdgeNotifiers) edges = append(edges, user.EdgeNotifiers)
} }
if m.clearedaction_tokens {
edges = append(edges, user.EdgeActionTokens)
}
return edges return edges
} }
@ -11658,6 +12340,8 @@ func (m *UserMutation) EdgeCleared(name string) bool {
return m.clearedauth_tokens return m.clearedauth_tokens
case user.EdgeNotifiers: case user.EdgeNotifiers:
return m.clearednotifiers return m.clearednotifiers
case user.EdgeActionTokens:
return m.clearedaction_tokens
} }
return false return false
} }
@ -11686,6 +12370,9 @@ func (m *UserMutation) ResetEdge(name string) error {
case user.EdgeNotifiers: case user.EdgeNotifiers:
m.ResetNotifiers() m.ResetNotifiers()
return nil return nil
case user.EdgeActionTokens:
m.ResetActionTokens()
return nil
} }
return fmt.Errorf("unknown User edge %s", name) return fmt.Errorf("unknown User edge %s", name)
} }

View file

@ -6,6 +6,9 @@ import (
"entgo.io/ent/dialect/sql" "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. // Attachment is the predicate function for attachment builders.
type Attachment func(*sql.Selector) type Attachment func(*sql.Selector)

View file

@ -6,6 +6,7 @@ import (
"time" "time"
"github.com/google/uuid" "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/attachment"
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens" "github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
"github.com/hay-kot/homebox/backend/internal/data/ent/document" "github.com/hay-kot/homebox/backend/internal/data/ent/document"
@ -25,6 +26,25 @@ import (
// (default values, validators, hooks and policies) and stitches it // (default values, validators, hooks and policies) and stitches it
// to their package variables. // to their package variables.
func init() { 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() attachmentMixin := schema.Attachment{}.Mixin()
attachmentMixinFields0 := attachmentMixin[0].Fields() attachmentMixinFields0 := attachmentMixin[0].Fields()
_ = attachmentMixinFields0 _ = attachmentMixinFields0

View file

@ -0,0 +1,42 @@
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

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

View file

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

View file

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

View file

@ -40,6 +40,8 @@ const (
EdgeAuthTokens = "auth_tokens" EdgeAuthTokens = "auth_tokens"
// EdgeNotifiers holds the string denoting the notifiers edge name in mutations. // EdgeNotifiers holds the string denoting the notifiers edge name in mutations.
EdgeNotifiers = "notifiers" 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 holds the table name of the user in the database.
Table = "users" Table = "users"
// GroupTable is the table that holds the group relation/edge. // GroupTable is the table that holds the group relation/edge.
@ -63,6 +65,13 @@ const (
NotifiersInverseTable = "notifiers" NotifiersInverseTable = "notifiers"
// NotifiersColumn is the table column denoting the notifiers relation/edge. // NotifiersColumn is the table column denoting the notifiers relation/edge.
NotifiersColumn = "user_id" 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. // Columns holds all SQL columns for user fields.
@ -234,6 +243,20 @@ func ByNotifiers(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
sqlgraph.OrderByNeighborTerms(s, newNotifiersStep(), append([]sql.OrderTerm{term}, terms...)...) 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 { func newGroupStep() *sqlgraph.Step {
return sqlgraph.NewStep( return sqlgraph.NewStep(
sqlgraph.From(Table, FieldID), sqlgraph.From(Table, FieldID),
@ -255,3 +278,10 @@ func newNotifiersStep() *sqlgraph.Step {
sqlgraph.Edge(sqlgraph.O2M, false, NotifiersTable, NotifiersColumn), 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,6 +530,29 @@ 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. // And groups predicates with the AND operator between them.
func And(predicates ...predicate.User) predicate.User { func And(predicates ...predicate.User) predicate.User {
return predicate.User(sql.AndPredicates(predicates...)) return predicate.User(sql.AndPredicates(predicates...))

View file

@ -11,6 +11,7 @@ import (
"entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field" "entgo.io/ent/schema/field"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/data/ent/actiontoken"
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens" "github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
"github.com/hay-kot/homebox/backend/internal/data/ent/group" "github.com/hay-kot/homebox/backend/internal/data/ent/group"
"github.com/hay-kot/homebox/backend/internal/data/ent/notifier" "github.com/hay-kot/homebox/backend/internal/data/ent/notifier"
@ -181,6 +182,21 @@ func (uc *UserCreate) AddNotifiers(n ...*Notifier) *UserCreate {
return uc.AddNotifierIDs(ids...) 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. // Mutation returns the UserMutation object of the builder.
func (uc *UserCreate) Mutation() *UserMutation { func (uc *UserCreate) Mutation() *UserMutation {
return uc.mutation return uc.mutation
@ -411,6 +427,22 @@ func (uc *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) {
} }
_spec.Edges = append(_spec.Edges, edge) _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 return _node, _spec
} }

View file

@ -12,6 +12,7 @@ import (
"entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field" "entgo.io/ent/schema/field"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/data/ent/actiontoken"
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens" "github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
"github.com/hay-kot/homebox/backend/internal/data/ent/group" "github.com/hay-kot/homebox/backend/internal/data/ent/group"
"github.com/hay-kot/homebox/backend/internal/data/ent/notifier" "github.com/hay-kot/homebox/backend/internal/data/ent/notifier"
@ -22,14 +23,15 @@ import (
// UserQuery is the builder for querying User entities. // UserQuery is the builder for querying User entities.
type UserQuery struct { type UserQuery struct {
config config
ctx *QueryContext ctx *QueryContext
order []user.OrderOption order []user.OrderOption
inters []Interceptor inters []Interceptor
predicates []predicate.User predicates []predicate.User
withGroup *GroupQuery withGroup *GroupQuery
withAuthTokens *AuthTokensQuery withAuthTokens *AuthTokensQuery
withNotifiers *NotifierQuery withNotifiers *NotifierQuery
withFKs bool withActionTokens *ActionTokenQuery
withFKs bool
// intermediate query (i.e. traversal path). // intermediate query (i.e. traversal path).
sql *sql.Selector sql *sql.Selector
path func(context.Context) (*sql.Selector, error) path func(context.Context) (*sql.Selector, error)
@ -132,6 +134,28 @@ func (uq *UserQuery) QueryNotifiers() *NotifierQuery {
return query 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. // First returns the first User entity from the query.
// Returns a *NotFoundError when no User was found. // Returns a *NotFoundError when no User was found.
func (uq *UserQuery) First(ctx context.Context) (*User, error) { func (uq *UserQuery) First(ctx context.Context) (*User, error) {
@ -319,14 +343,15 @@ func (uq *UserQuery) Clone() *UserQuery {
return nil return nil
} }
return &UserQuery{ return &UserQuery{
config: uq.config, config: uq.config,
ctx: uq.ctx.Clone(), ctx: uq.ctx.Clone(),
order: append([]user.OrderOption{}, uq.order...), order: append([]user.OrderOption{}, uq.order...),
inters: append([]Interceptor{}, uq.inters...), inters: append([]Interceptor{}, uq.inters...),
predicates: append([]predicate.User{}, uq.predicates...), predicates: append([]predicate.User{}, uq.predicates...),
withGroup: uq.withGroup.Clone(), withGroup: uq.withGroup.Clone(),
withAuthTokens: uq.withAuthTokens.Clone(), withAuthTokens: uq.withAuthTokens.Clone(),
withNotifiers: uq.withNotifiers.Clone(), withNotifiers: uq.withNotifiers.Clone(),
withActionTokens: uq.withActionTokens.Clone(),
// clone intermediate query. // clone intermediate query.
sql: uq.sql.Clone(), sql: uq.sql.Clone(),
path: uq.path, path: uq.path,
@ -366,6 +391,17 @@ func (uq *UserQuery) WithNotifiers(opts ...func(*NotifierQuery)) *UserQuery {
return uq 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. // GroupBy is used to group vertices by one or more fields/columns.
// It is often used with aggregate functions, like: count, max, mean, min, sum. // It is often used with aggregate functions, like: count, max, mean, min, sum.
// //
@ -445,10 +481,11 @@ func (uq *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
nodes = []*User{} nodes = []*User{}
withFKs = uq.withFKs withFKs = uq.withFKs
_spec = uq.querySpec() _spec = uq.querySpec()
loadedTypes = [3]bool{ loadedTypes = [4]bool{
uq.withGroup != nil, uq.withGroup != nil,
uq.withAuthTokens != nil, uq.withAuthTokens != nil,
uq.withNotifiers != nil, uq.withNotifiers != nil,
uq.withActionTokens != nil,
} }
) )
if uq.withGroup != nil { if uq.withGroup != nil {
@ -495,6 +532,13 @@ func (uq *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
return nil, err 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 return nodes, nil
} }
@ -591,6 +635,36 @@ func (uq *UserQuery) loadNotifiers(ctx context.Context, query *NotifierQuery, no
} }
return nil 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) { func (uq *UserQuery) sqlCount(ctx context.Context) (int, error) {
_spec := uq.querySpec() _spec := uq.querySpec()

View file

@ -12,6 +12,7 @@ import (
"entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field" "entgo.io/ent/schema/field"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/data/ent/actiontoken"
"github.com/hay-kot/homebox/backend/internal/data/ent/authtokens" "github.com/hay-kot/homebox/backend/internal/data/ent/authtokens"
"github.com/hay-kot/homebox/backend/internal/data/ent/group" "github.com/hay-kot/homebox/backend/internal/data/ent/group"
"github.com/hay-kot/homebox/backend/internal/data/ent/notifier" "github.com/hay-kot/homebox/backend/internal/data/ent/notifier"
@ -183,6 +184,21 @@ func (uu *UserUpdate) AddNotifiers(n ...*Notifier) *UserUpdate {
return uu.AddNotifierIDs(ids...) 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. // Mutation returns the UserMutation object of the builder.
func (uu *UserUpdate) Mutation() *UserMutation { func (uu *UserUpdate) Mutation() *UserMutation {
return uu.mutation return uu.mutation
@ -236,6 +252,27 @@ func (uu *UserUpdate) RemoveNotifiers(n ...*Notifier) *UserUpdate {
return uu.RemoveNotifierIDs(ids...) 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. // Save executes the query and returns the number of nodes affected by the update operation.
func (uu *UserUpdate) Save(ctx context.Context) (int, error) { func (uu *UserUpdate) Save(ctx context.Context) (int, error) {
uu.defaults() uu.defaults()
@ -458,6 +495,51 @@ func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) {
} }
_spec.Edges.Add = append(_spec.Edges.Add, edge) _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 n, err = sqlgraph.UpdateNodes(ctx, uu.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok { if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{user.Label} err = &NotFoundError{user.Label}
@ -629,6 +711,21 @@ func (uuo *UserUpdateOne) AddNotifiers(n ...*Notifier) *UserUpdateOne {
return uuo.AddNotifierIDs(ids...) 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. // Mutation returns the UserMutation object of the builder.
func (uuo *UserUpdateOne) Mutation() *UserMutation { func (uuo *UserUpdateOne) Mutation() *UserMutation {
return uuo.mutation return uuo.mutation
@ -682,6 +779,27 @@ func (uuo *UserUpdateOne) RemoveNotifiers(n ...*Notifier) *UserUpdateOne {
return uuo.RemoveNotifierIDs(ids...) 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. // Where appends a list predicates to the UserUpdate builder.
func (uuo *UserUpdateOne) Where(ps ...predicate.User) *UserUpdateOne { func (uuo *UserUpdateOne) Where(ps ...predicate.User) *UserUpdateOne {
uuo.mutation.Where(ps...) uuo.mutation.Where(ps...)
@ -934,6 +1052,51 @@ func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error)
} }
_spec.Edges.Add = append(_spec.Edges.Add, edge) _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} _node = &User{config: uuo.config}
_spec.Assign = _node.assignValues _spec.Assign = _node.assignValues
_spec.ScanValues = _node.scanValues _spec.ScanValues = _node.scanValues

View file

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

View file

@ -5,6 +5,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/data/ent" "github.com/hay-kot/homebox/backend/internal/data/ent"
"github.com/hay-kot/homebox/backend/internal/data/ent/actiontoken"
"github.com/hay-kot/homebox/backend/internal/data/ent/user" "github.com/hay-kot/homebox/backend/internal/data/ent/user"
) )
@ -133,3 +134,18 @@ func (r *UserRepository) GetSuperusers(ctx context.Context) ([]*ent.User, error)
func (r *UserRepository) ChangePassword(ctx context.Context, UID uuid.UUID, pw string) error { func (r *UserRepository) ChangePassword(ctx context.Context, UID uuid.UUID, pw string) error {
return r.db.User.UpdateOneID(UID).SetPassword(pw).Exec(ctx) return r.db.User.UpdateOneID(UID).SetPassword(pw).Exec(ctx)
} }
func (r *UserRepository) PasswordResetCreate(ctx context.Context, UID uuid.UUID, token []byte) error {
return r.db.ActionToken.Create().
SetUserID(UID).
SetToken(token).
SetAction(actiontoken.ActionResetPassword).
Exec(ctx)
}
func (r *UserRepository) PasswordResetGet(ctx context.Context, token []byte) (*ent.ActionToken, error) {
return r.db.ActionToken.Query().
Where(actiontoken.Token(token)).
WithUser().
Only(ctx)
}

View file

@ -18,13 +18,14 @@ const (
type Config struct { type Config struct {
conf.Version conf.Version
Mode string `yaml:"mode" conf:"default:development"` // development or production Mode string `yaml:"mode" conf:"default:development"` // development or production
Web WebConfig `yaml:"web"` Web WebConfig `yaml:"web"`
Storage Storage `yaml:"storage"` Storage Storage `yaml:"storage"`
Log LoggerConf `yaml:"logger"` Log LoggerConf `yaml:"logger"`
Mailer MailerConf `yaml:"mailer"` Mailer MailerConf `yaml:"mailer"`
Demo bool `yaml:"demo"` Demo bool `yaml:"demo"`
Debug DebugConf `yaml:"debug"` Debug DebugConf `yaml:"debug"`
BaseURL string `yaml:"base_url" conf:"default:http://localhost:3000"`
Options Options `yaml:"options"` Options Options `yaml:"options"`
} }

View file

@ -5,11 +5,11 @@ type MailerConf struct {
Port int `conf:""` Port int `conf:""`
Username string `conf:""` Username string `conf:""`
Password string `conf:""` Password string `conf:""`
From string `conf:""` From string `conf:"info@example.com"`
} }
// Ready is a simple check to ensure that the configuration is not empty. // Ready is a simple check to ensure that the configuration is not empty.
// or with it's default state. // or with it's default state.
func (mc *MailerConf) Ready() bool { func (mc *MailerConf) Ready() bool {
return mc.Host != "" && mc.Port != 0 && mc.Username != "" && mc.Password != "" && mc.From != "" return mc.Host != "" && mc.Port != 0 && mc.From != ""
} }

View file

@ -1,4 +1,4 @@
// Package mailer provides a simple mailer for sending emails. // Package mailer provides a simple interface to send emails using SMTP.
package mailer package mailer
import ( import (
@ -25,16 +25,16 @@ func (m *Mailer) server() string {
return m.Host + ":" + strconv.Itoa(m.Port) return m.Host + ":" + strconv.Itoa(m.Port)
} }
func (m *Mailer) Send(msg *Message) error { func (m *Mailer) Send(msg Message) error {
server := m.server() server := m.server()
header := make(map[string]string) header := map[string]string{
header["From"] = msg.From.String() "From": m.From,
header["To"] = msg.To.String() "Subject": mime.QEncoding.Encode("UTF-8", msg.Subject),
header["Subject"] = mime.QEncoding.Encode("UTF-8", msg.Subject) "MIME-Version": "1.0",
header["MIME-Version"] = "1.0" "Content-Type": "text/html; charset=\"utf-8\"",
header["Content-Type"] = "text/html; charset=\"utf-8\"" "Content-Transfer-Encoding": "base64",
header["Content-Transfer-Encoding"] = "base64" }
message := "" message := ""
for k, v := range header { for k, v := range header {
@ -46,7 +46,7 @@ func (m *Mailer) Send(msg *Message) error {
server, server,
smtp.PlainAuth("", m.Username, m.Password, m.Host), smtp.PlainAuth("", m.Username, m.Password, m.Host),
m.From, m.From,
[]string{msg.To.Address}, msg.ToAddresses(),
[]byte(message), []byte(message),
) )
} }

View file

@ -9,6 +9,10 @@ type Message struct {
Body string Body string
} }
func (m Message) ToAddresses() []string {
return []string{m.To.Address}
}
type MessageBuilder struct { type MessageBuilder struct {
subject string subject string
to mail.Address to mail.Address
@ -20,8 +24,8 @@ func NewMessageBuilder() *MessageBuilder {
return &MessageBuilder{} return &MessageBuilder{}
} }
func (mb *MessageBuilder) Build() *Message { func (mb *MessageBuilder) Build() Message {
return &Message{ return Message{
Subject: mb.subject, Subject: mb.subject,
To: mb.to, To: mb.to,
From: mb.from, From: mb.from,

View file

@ -1785,6 +1785,33 @@
} }
} }
}, },
"/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": { "/v1/users/self": {
"get": { "get": {
"security": [ "security": [
@ -2818,6 +2845,14 @@
} }
} }
}, },
"services.PasswordResetRequest": {
"type": "object",
"properties": {
"email": {
"type": "string"
}
}
},
"services.UserRegistration": { "services.UserRegistration": {
"type": "object", "type": "object",
"properties": { "properties": {

View file

@ -373,6 +373,10 @@ export interface ValueOverTimeEntry {
value: number; value: number;
} }
export interface PasswordResetRequest {
email: string;
}
export interface UserRegistration { export interface UserRegistration {
email: string; email: string;
name: string; name: string;