mirror of
https://github.com/sysadminsmedia/homebox.git
synced 2025-12-28 07:56:35 +01:00
Compare commits
1 Commits
katos/test
...
mk/multi-g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd873a95da |
@@ -55,7 +55,7 @@ func (a *app) SetupDemo() error {
|
||||
return errors.New("failed to setup demo")
|
||||
}
|
||||
|
||||
_, err = a.services.Items.CsvImport(ctx, self.GroupID, strings.NewReader(csvText))
|
||||
_, err = a.services.Items.CsvImport(ctx, self.DefaultGroupID, strings.NewReader(csvText))
|
||||
if err != nil {
|
||||
log.Err(err).Msg("Failed to import CSV")
|
||||
return errors.New("failed to setup demo")
|
||||
|
||||
@@ -339,7 +339,7 @@ func (ctrl *V1Controller) HandleItemsImport() errchain.HandlerFunc {
|
||||
|
||||
user := services.UseUserCtx(r.Context())
|
||||
|
||||
_, err = ctrl.svc.Items.CsvImport(r.Context(), user.GroupID, file)
|
||||
_, err = ctrl.svc.Items.CsvImport(r.Context(), user.DefaultGroupID, file)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to import items")
|
||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/hay-kot/httpkit/errchain"
|
||||
"github.com/sysadminsmedia/homebox/backend/internal/core/services"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// HandleBillOfMaterialsExport godoc
|
||||
@@ -18,7 +19,7 @@ func (ctrl *V1Controller) HandleBillOfMaterialsExport() errchain.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
actor := services.UseUserCtx(r.Context())
|
||||
|
||||
csv, err := ctrl.svc.Items.ExportBillOfMaterialsCSV(r.Context(), actor.GroupID)
|
||||
csv, err := ctrl.svc.Items.ExportBillOfMaterialsCSV(r.Context(), actor.DefaultGroupID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/httpkit/errchain"
|
||||
v1 "github.com/sysadminsmedia/homebox/backend/app/api/handlers/v1"
|
||||
"github.com/sysadminsmedia/homebox/backend/internal/core/services"
|
||||
@@ -152,3 +153,48 @@ func (a *app) mwAuthToken(next errchain.Handler) errchain.Handler {
|
||||
return next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// mwTenant is a middleware that will parse the X-Tenant header and validate the user has access
|
||||
// to the requested tenant. If no header is provided, the user's default group is used.
|
||||
//
|
||||
// WARNING: This middleware _MUST_ be called after mwAuthToken
|
||||
func (a *app) mwTenant(next errchain.Handler) errchain.Handler {
|
||||
return errchain.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
|
||||
ctx := r.Context()
|
||||
|
||||
// Get the user from context (set by mwAuthToken)
|
||||
user := services.UseUserCtx(ctx)
|
||||
if user == nil {
|
||||
return validate.NewRequestError(errors.New("user context not found"), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
tenantID := user.DefaultGroupID
|
||||
|
||||
// Check for X-Tenant header
|
||||
if tenantHeader := r.Header.Get("X-Tenant"); tenantHeader != "" {
|
||||
parsedTenantID, err := uuid.Parse(tenantHeader)
|
||||
if err != nil {
|
||||
return validate.NewRequestError(errors.New("invalid X-Tenant header format"), http.StatusBadRequest)
|
||||
}
|
||||
|
||||
// Validate user has access to the requested tenant
|
||||
hasAccess := false
|
||||
for _, gid := range user.GroupIDs {
|
||||
if gid == parsedTenantID {
|
||||
hasAccess = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !hasAccess {
|
||||
return validate.NewRequestError(errors.New("user does not have access to the requested tenant"), http.StatusForbidden)
|
||||
}
|
||||
|
||||
tenantID = parsedTenantID
|
||||
}
|
||||
|
||||
// Set the tenant in context
|
||||
r = r.WithContext(services.SetTenantCtx(ctx, tenantID))
|
||||
return next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
|
||||
|
||||
userMW := []errchain.Middleware{
|
||||
a.mwAuthToken,
|
||||
a.mwTenant,
|
||||
a.mwRoles(RoleModeOr, authroles.RoleUser.String()),
|
||||
}
|
||||
|
||||
|
||||
@@ -350,6 +350,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.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs=
|
||||
github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY=
|
||||
@@ -374,6 +376,8 @@ github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOF
|
||||
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/olahol/melody v1.4.0 h1:Pa5SdeZL/zXPi1tJuMAPDbl4n3gQOThSL6G1p4qZ4SI=
|
||||
github.com/olahol/melody v1.4.0/go.mod h1:GgkTl6Y7yWj/HtfD48Q5vLKPVoZOH+Qqgfa7CvJgJM4=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
|
||||
github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
|
||||
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
|
||||
@@ -418,6 +422,10 @@ github.com/shirou/gopsutil/v4 v4.25.11 h1:X53gB7muL9Gnwwo2evPSE+SfOrltMoR6V3xJAX
|
||||
github.com/shirou/gopsutil/v4 v4.25.11/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo=
|
||||
github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
|
||||
@@ -14,6 +14,7 @@ type contextKeys struct {
|
||||
var (
|
||||
ContextUser = &contextKeys{name: "User"}
|
||||
ContextUserToken = &contextKeys{name: "UserToken"}
|
||||
ContextTenant = &contextKeys{name: "Tenant"}
|
||||
)
|
||||
|
||||
type Context struct {
|
||||
@@ -33,10 +34,14 @@ type Context struct {
|
||||
// This extracts the users from the context and embeds it into the ServiceContext struct
|
||||
func NewContext(ctx context.Context) Context {
|
||||
user := UseUserCtx(ctx)
|
||||
gid := UseTenantCtx(ctx)
|
||||
if gid == uuid.Nil && user != nil {
|
||||
gid = user.DefaultGroupID
|
||||
}
|
||||
return Context{
|
||||
Context: ctx,
|
||||
UID: user.ID,
|
||||
GID: user.GroupID,
|
||||
GID: gid,
|
||||
User: user,
|
||||
}
|
||||
}
|
||||
@@ -64,3 +69,17 @@ func UseTokenCtx(ctx context.Context) string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// UseTenantCtx is a helper function that returns the tenant group ID from the context.
|
||||
// Returns uuid.Nil if not set.
|
||||
func UseTenantCtx(ctx context.Context) uuid.UUID {
|
||||
if val := ctx.Value(ContextTenant); val != nil {
|
||||
return val.(uuid.UUID)
|
||||
}
|
||||
return uuid.Nil
|
||||
}
|
||||
|
||||
// SetTenantCtx is a helper function that sets the ContextTenant in the context.
|
||||
func SetTenantCtx(ctx context.Context, tenantID uuid.UUID) context.Context {
|
||||
return context.WithValue(ctx, ContextTenant, tenantID)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ type GroupService struct {
|
||||
|
||||
func (svc *GroupService) UpdateGroup(ctx Context, data repo.GroupUpdate) (repo.Group, error) {
|
||||
if data.Name == "" {
|
||||
data.Name = ctx.User.GroupName
|
||||
return repo.Group{}, errors.New("group name cannot be empty")
|
||||
}
|
||||
|
||||
if data.Currency == "" {
|
||||
|
||||
@@ -81,12 +81,12 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
|
||||
|
||||
hashed, _ := hasher.HashPassword(data.Password)
|
||||
usrCreate := repo.UserCreate{
|
||||
Name: data.Name,
|
||||
Email: data.Email,
|
||||
Password: &hashed,
|
||||
IsSuperuser: false,
|
||||
GroupID: group.ID,
|
||||
IsOwner: creatingGroup,
|
||||
Name: data.Name,
|
||||
Email: data.Email,
|
||||
Password: &hashed,
|
||||
IsSuperuser: false,
|
||||
DefaultGroupID: group.ID,
|
||||
IsOwner: creatingGroup,
|
||||
}
|
||||
|
||||
usr, err := svc.repos.Users.Create(ctx, usrCreate)
|
||||
@@ -99,7 +99,7 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
|
||||
if creatingGroup {
|
||||
log.Debug().Msg("creating default labels")
|
||||
for _, label := range defaultLabels() {
|
||||
_, err := svc.repos.Labels.Create(ctx, usr.GroupID, label)
|
||||
_, err := svc.repos.Labels.Create(ctx, usr.DefaultGroupID, label)
|
||||
if err != nil {
|
||||
return repo.UserOut{}, err
|
||||
}
|
||||
@@ -107,7 +107,7 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
|
||||
|
||||
log.Debug().Msg("creating default locations")
|
||||
for _, location := range defaultLocations() {
|
||||
_, err := svc.repos.Locations.Create(ctx, usr.GroupID, location)
|
||||
_, err := svc.repos.Locations.Create(ctx, usr.DefaultGroupID, location)
|
||||
if err != nil {
|
||||
return repo.UserOut{}, err
|
||||
}
|
||||
@@ -287,12 +287,12 @@ func (svc *UserService) registerOIDCUser(ctx context.Context, issuer, subject, e
|
||||
}
|
||||
|
||||
usrCreate := repo.UserCreate{
|
||||
Name: name,
|
||||
Email: email,
|
||||
Password: nil,
|
||||
IsSuperuser: false,
|
||||
GroupID: group.ID,
|
||||
IsOwner: true,
|
||||
Name: name,
|
||||
Email: email,
|
||||
Password: nil,
|
||||
IsSuperuser: false,
|
||||
DefaultGroupID: group.ID,
|
||||
IsOwner: true,
|
||||
}
|
||||
|
||||
entUser, err := svc.repos.Users.CreateWithOIDC(ctx, usrCreate, issuer, subject)
|
||||
|
||||
6
backend/internal/data/ent/client.go
generated
6
backend/internal/data/ent/client.go
generated
@@ -2711,15 +2711,15 @@ func (c *UserClient) GetX(ctx context.Context, id uuid.UUID) *User {
|
||||
return obj
|
||||
}
|
||||
|
||||
// QueryGroup queries the group edge of a User.
|
||||
func (c *UserClient) QueryGroup(_m *User) *GroupQuery {
|
||||
// QueryGroups queries the groups edge of a User.
|
||||
func (c *UserClient) QueryGroups(_m *User) *GroupQuery {
|
||||
query := (&GroupClient{config: c.config}).Query()
|
||||
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
|
||||
id := _m.ID
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(user.Table, user.FieldID, id),
|
||||
sqlgraph.To(group.Table, group.FieldID),
|
||||
sqlgraph.Edge(sqlgraph.M2O, true, user.GroupTable, user.GroupColumn),
|
||||
sqlgraph.Edge(sqlgraph.O2M, false, user.GroupsTable, user.GroupsColumn),
|
||||
)
|
||||
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
|
||||
return fromV, nil
|
||||
|
||||
10
backend/internal/data/ent/group.go
generated
10
backend/internal/data/ent/group.go
generated
@@ -29,6 +29,7 @@ type Group struct {
|
||||
// Edges holds the relations/edges for other nodes in the graph.
|
||||
// The values are being populated by the GroupQuery when eager-loading is set.
|
||||
Edges GroupEdges `json:"edges"`
|
||||
user_groups *uuid.UUID
|
||||
selectValues sql.SelectValues
|
||||
}
|
||||
|
||||
@@ -127,6 +128,8 @@ func (*Group) scanValues(columns []string) ([]any, error) {
|
||||
values[i] = new(sql.NullTime)
|
||||
case group.FieldID:
|
||||
values[i] = new(uuid.UUID)
|
||||
case group.ForeignKeys[0]: // user_groups
|
||||
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
|
||||
default:
|
||||
values[i] = new(sql.UnknownType)
|
||||
}
|
||||
@@ -172,6 +175,13 @@ func (_m *Group) assignValues(columns []string, values []any) error {
|
||||
} else if value.Valid {
|
||||
_m.Currency = value.String
|
||||
}
|
||||
case group.ForeignKeys[0]:
|
||||
if value, ok := values[i].(*sql.NullScanner); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field user_groups", values[i])
|
||||
} else if value.Valid {
|
||||
_m.user_groups = new(uuid.UUID)
|
||||
*_m.user_groups = *value.S.(*uuid.UUID)
|
||||
}
|
||||
default:
|
||||
_m.selectValues.Set(columns[i], values[i])
|
||||
}
|
||||
|
||||
11
backend/internal/data/ent/group/group.go
generated
11
backend/internal/data/ent/group/group.go
generated
@@ -99,6 +99,12 @@ var Columns = []string{
|
||||
FieldCurrency,
|
||||
}
|
||||
|
||||
// ForeignKeys holds the SQL foreign-keys that are owned by the "groups"
|
||||
// table and are not defined as standalone fields in the schema.
|
||||
var ForeignKeys = []string{
|
||||
"user_groups",
|
||||
}
|
||||
|
||||
// ValidColumn reports if the column name is valid (part of the table columns).
|
||||
func ValidColumn(column string) bool {
|
||||
for i := range Columns {
|
||||
@@ -106,6 +112,11 @@ func ValidColumn(column string) bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for i := range ForeignKeys {
|
||||
if column == ForeignKeys[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
5
backend/internal/data/ent/group_query.go
generated
5
backend/internal/data/ent/group_query.go
generated
@@ -38,6 +38,7 @@ type GroupQuery struct {
|
||||
withInvitationTokens *GroupInvitationTokenQuery
|
||||
withNotifiers *NotifierQuery
|
||||
withItemTemplates *ItemTemplateQuery
|
||||
withFKs bool
|
||||
// intermediate query (i.e. traversal path).
|
||||
sql *sql.Selector
|
||||
path func(context.Context) (*sql.Selector, error)
|
||||
@@ -587,6 +588,7 @@ func (_q *GroupQuery) prepareQuery(ctx context.Context) error {
|
||||
func (_q *GroupQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Group, error) {
|
||||
var (
|
||||
nodes = []*Group{}
|
||||
withFKs = _q.withFKs
|
||||
_spec = _q.querySpec()
|
||||
loadedTypes = [7]bool{
|
||||
_q.withUsers != nil,
|
||||
@@ -598,6 +600,9 @@ func (_q *GroupQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Group,
|
||||
_q.withItemTemplates != nil,
|
||||
}
|
||||
)
|
||||
if withFKs {
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, group.ForeignKeys...)
|
||||
}
|
||||
_spec.ScanValues = func(columns []string) ([]any, error) {
|
||||
return (*Group).scanValues(nil, columns)
|
||||
}
|
||||
|
||||
17
backend/internal/data/ent/migrate/schema.go
generated
17
backend/internal/data/ent/migrate/schema.go
generated
@@ -98,12 +98,21 @@ var (
|
||||
{Name: "updated_at", Type: field.TypeTime},
|
||||
{Name: "name", Type: field.TypeString, Size: 255},
|
||||
{Name: "currency", Type: field.TypeString, Default: "usd"},
|
||||
{Name: "user_groups", Type: field.TypeUUID, Nullable: true},
|
||||
}
|
||||
// GroupsTable holds the schema information for the "groups" table.
|
||||
GroupsTable = &schema.Table{
|
||||
Name: "groups",
|
||||
Columns: GroupsColumns,
|
||||
PrimaryKey: []*schema.Column{GroupsColumns[0]},
|
||||
ForeignKeys: []*schema.ForeignKey{
|
||||
{
|
||||
Symbol: "groups_users_groups",
|
||||
Columns: []*schema.Column{GroupsColumns[5]},
|
||||
RefColumns: []*schema.Column{UsersColumns[0]},
|
||||
OnDelete: schema.SetNull,
|
||||
},
|
||||
},
|
||||
}
|
||||
// GroupInvitationTokensColumns holds the columns for the "group_invitation_tokens" table.
|
||||
GroupInvitationTokensColumns = []*schema.Column{
|
||||
@@ -468,7 +477,8 @@ var (
|
||||
{Name: "activated_on", Type: field.TypeTime, Nullable: true},
|
||||
{Name: "oidc_issuer", Type: field.TypeString, Nullable: true},
|
||||
{Name: "oidc_subject", Type: field.TypeString, Nullable: true},
|
||||
{Name: "group_users", Type: field.TypeUUID},
|
||||
{Name: "default_group_id", Type: field.TypeUUID, Nullable: true},
|
||||
{Name: "group_users", Type: field.TypeUUID, Nullable: true},
|
||||
}
|
||||
// UsersTable holds the schema information for the "users" table.
|
||||
UsersTable = &schema.Table{
|
||||
@@ -478,9 +488,9 @@ var (
|
||||
ForeignKeys: []*schema.ForeignKey{
|
||||
{
|
||||
Symbol: "users_groups_users",
|
||||
Columns: []*schema.Column{UsersColumns[12]},
|
||||
Columns: []*schema.Column{UsersColumns[13]},
|
||||
RefColumns: []*schema.Column{GroupsColumns[0]},
|
||||
OnDelete: schema.Cascade,
|
||||
OnDelete: schema.SetNull,
|
||||
},
|
||||
},
|
||||
Indexes: []*schema.Index{
|
||||
@@ -541,6 +551,7 @@ func init() {
|
||||
AttachmentsTable.ForeignKeys[1].RefTable = ItemsTable
|
||||
AuthRolesTable.ForeignKeys[0].RefTable = AuthTokensTable
|
||||
AuthTokensTable.ForeignKeys[0].RefTable = UsersTable
|
||||
GroupsTable.ForeignKeys[0].RefTable = UsersTable
|
||||
GroupInvitationTokensTable.ForeignKeys[0].RefTable = GroupsTable
|
||||
ItemsTable.ForeignKeys[0].RefTable = GroupsTable
|
||||
ItemsTable.ForeignKeys[1].RefTable = ItemsTable
|
||||
|
||||
177
backend/internal/data/ent/mutation.go
generated
177
backend/internal/data/ent/mutation.go
generated
@@ -12583,9 +12583,11 @@ type UserMutation struct {
|
||||
activated_on *time.Time
|
||||
oidc_issuer *string
|
||||
oidc_subject *string
|
||||
default_group_id *uuid.UUID
|
||||
clearedFields map[string]struct{}
|
||||
group *uuid.UUID
|
||||
clearedgroup bool
|
||||
groups map[uuid.UUID]struct{}
|
||||
removedgroups map[uuid.UUID]struct{}
|
||||
clearedgroups bool
|
||||
auth_tokens map[uuid.UUID]struct{}
|
||||
removedauth_tokens map[uuid.UUID]struct{}
|
||||
clearedauth_tokens bool
|
||||
@@ -13149,43 +13151,107 @@ func (m *UserMutation) ResetOidcSubject() {
|
||||
delete(m.clearedFields, user.FieldOidcSubject)
|
||||
}
|
||||
|
||||
// SetGroupID sets the "group" edge to the Group entity by id.
|
||||
func (m *UserMutation) SetGroupID(id uuid.UUID) {
|
||||
m.group = &id
|
||||
// SetDefaultGroupID sets the "default_group_id" field.
|
||||
func (m *UserMutation) SetDefaultGroupID(u uuid.UUID) {
|
||||
m.default_group_id = &u
|
||||
}
|
||||
|
||||
// ClearGroup clears the "group" edge to the Group entity.
|
||||
func (m *UserMutation) ClearGroup() {
|
||||
m.clearedgroup = true
|
||||
// DefaultGroupID returns the value of the "default_group_id" field in the mutation.
|
||||
func (m *UserMutation) DefaultGroupID() (r uuid.UUID, exists bool) {
|
||||
v := m.default_group_id
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// GroupCleared reports if the "group" edge to the Group entity was cleared.
|
||||
func (m *UserMutation) GroupCleared() bool {
|
||||
return m.clearedgroup
|
||||
// OldDefaultGroupID returns the old "default_group_id" field's value of the User entity.
|
||||
// If the User 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 *UserMutation) OldDefaultGroupID(ctx context.Context) (v *uuid.UUID, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldDefaultGroupID is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldDefaultGroupID requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldDefaultGroupID: %w", err)
|
||||
}
|
||||
return oldValue.DefaultGroupID, nil
|
||||
}
|
||||
|
||||
// GroupID returns the "group" edge ID in the mutation.
|
||||
func (m *UserMutation) GroupID() (id uuid.UUID, exists bool) {
|
||||
if m.group != nil {
|
||||
return *m.group, true
|
||||
// ClearDefaultGroupID clears the value of the "default_group_id" field.
|
||||
func (m *UserMutation) ClearDefaultGroupID() {
|
||||
m.default_group_id = nil
|
||||
m.clearedFields[user.FieldDefaultGroupID] = struct{}{}
|
||||
}
|
||||
|
||||
// DefaultGroupIDCleared returns if the "default_group_id" field was cleared in this mutation.
|
||||
func (m *UserMutation) DefaultGroupIDCleared() bool {
|
||||
_, ok := m.clearedFields[user.FieldDefaultGroupID]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ResetDefaultGroupID resets all changes to the "default_group_id" field.
|
||||
func (m *UserMutation) ResetDefaultGroupID() {
|
||||
m.default_group_id = nil
|
||||
delete(m.clearedFields, user.FieldDefaultGroupID)
|
||||
}
|
||||
|
||||
// AddGroupIDs adds the "groups" edge to the Group entity by ids.
|
||||
func (m *UserMutation) AddGroupIDs(ids ...uuid.UUID) {
|
||||
if m.groups == nil {
|
||||
m.groups = make(map[uuid.UUID]struct{})
|
||||
}
|
||||
for i := range ids {
|
||||
m.groups[ids[i]] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// ClearGroups clears the "groups" edge to the Group entity.
|
||||
func (m *UserMutation) ClearGroups() {
|
||||
m.clearedgroups = true
|
||||
}
|
||||
|
||||
// GroupsCleared reports if the "groups" edge to the Group entity was cleared.
|
||||
func (m *UserMutation) GroupsCleared() bool {
|
||||
return m.clearedgroups
|
||||
}
|
||||
|
||||
// RemoveGroupIDs removes the "groups" edge to the Group entity by IDs.
|
||||
func (m *UserMutation) RemoveGroupIDs(ids ...uuid.UUID) {
|
||||
if m.removedgroups == nil {
|
||||
m.removedgroups = make(map[uuid.UUID]struct{})
|
||||
}
|
||||
for i := range ids {
|
||||
delete(m.groups, ids[i])
|
||||
m.removedgroups[ids[i]] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// RemovedGroups returns the removed IDs of the "groups" edge to the Group entity.
|
||||
func (m *UserMutation) RemovedGroupsIDs() (ids []uuid.UUID) {
|
||||
for id := range m.removedgroups {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GroupIDs returns the "group" edge IDs in the mutation.
|
||||
// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use
|
||||
// GroupID instead. It exists only for internal usage by the builders.
|
||||
func (m *UserMutation) GroupIDs() (ids []uuid.UUID) {
|
||||
if id := m.group; id != nil {
|
||||
ids = append(ids, *id)
|
||||
// GroupsIDs returns the "groups" edge IDs in the mutation.
|
||||
func (m *UserMutation) GroupsIDs() (ids []uuid.UUID) {
|
||||
for id := range m.groups {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ResetGroup resets all changes to the "group" edge.
|
||||
func (m *UserMutation) ResetGroup() {
|
||||
m.group = nil
|
||||
m.clearedgroup = false
|
||||
// ResetGroups resets all changes to the "groups" edge.
|
||||
func (m *UserMutation) ResetGroups() {
|
||||
m.groups = nil
|
||||
m.clearedgroups = false
|
||||
m.removedgroups = nil
|
||||
}
|
||||
|
||||
// AddAuthTokenIDs adds the "auth_tokens" edge to the AuthTokens entity by ids.
|
||||
@@ -13330,7 +13396,7 @@ func (m *UserMutation) Type() string {
|
||||
// order to get all numeric fields that were incremented/decremented, call
|
||||
// AddedFields().
|
||||
func (m *UserMutation) Fields() []string {
|
||||
fields := make([]string, 0, 11)
|
||||
fields := make([]string, 0, 12)
|
||||
if m.created_at != nil {
|
||||
fields = append(fields, user.FieldCreatedAt)
|
||||
}
|
||||
@@ -13364,6 +13430,9 @@ func (m *UserMutation) Fields() []string {
|
||||
if m.oidc_subject != nil {
|
||||
fields = append(fields, user.FieldOidcSubject)
|
||||
}
|
||||
if m.default_group_id != nil {
|
||||
fields = append(fields, user.FieldDefaultGroupID)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
@@ -13394,6 +13463,8 @@ func (m *UserMutation) Field(name string) (ent.Value, bool) {
|
||||
return m.OidcIssuer()
|
||||
case user.FieldOidcSubject:
|
||||
return m.OidcSubject()
|
||||
case user.FieldDefaultGroupID:
|
||||
return m.DefaultGroupID()
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
@@ -13425,6 +13496,8 @@ func (m *UserMutation) OldField(ctx context.Context, name string) (ent.Value, er
|
||||
return m.OldOidcIssuer(ctx)
|
||||
case user.FieldOidcSubject:
|
||||
return m.OldOidcSubject(ctx)
|
||||
case user.FieldDefaultGroupID:
|
||||
return m.OldDefaultGroupID(ctx)
|
||||
}
|
||||
return nil, fmt.Errorf("unknown User field %s", name)
|
||||
}
|
||||
@@ -13511,6 +13584,13 @@ func (m *UserMutation) SetField(name string, value ent.Value) error {
|
||||
}
|
||||
m.SetOidcSubject(v)
|
||||
return nil
|
||||
case user.FieldDefaultGroupID:
|
||||
v, ok := value.(uuid.UUID)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetDefaultGroupID(v)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown User field %s", name)
|
||||
}
|
||||
@@ -13553,6 +13633,9 @@ func (m *UserMutation) ClearedFields() []string {
|
||||
if m.FieldCleared(user.FieldOidcSubject) {
|
||||
fields = append(fields, user.FieldOidcSubject)
|
||||
}
|
||||
if m.FieldCleared(user.FieldDefaultGroupID) {
|
||||
fields = append(fields, user.FieldDefaultGroupID)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
@@ -13579,6 +13662,9 @@ func (m *UserMutation) ClearField(name string) error {
|
||||
case user.FieldOidcSubject:
|
||||
m.ClearOidcSubject()
|
||||
return nil
|
||||
case user.FieldDefaultGroupID:
|
||||
m.ClearDefaultGroupID()
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown User nullable field %s", name)
|
||||
}
|
||||
@@ -13620,6 +13706,9 @@ func (m *UserMutation) ResetField(name string) error {
|
||||
case user.FieldOidcSubject:
|
||||
m.ResetOidcSubject()
|
||||
return nil
|
||||
case user.FieldDefaultGroupID:
|
||||
m.ResetDefaultGroupID()
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown User field %s", name)
|
||||
}
|
||||
@@ -13627,8 +13716,8 @@ func (m *UserMutation) ResetField(name string) error {
|
||||
// AddedEdges returns all edge names that were set/added in this mutation.
|
||||
func (m *UserMutation) AddedEdges() []string {
|
||||
edges := make([]string, 0, 3)
|
||||
if m.group != nil {
|
||||
edges = append(edges, user.EdgeGroup)
|
||||
if m.groups != nil {
|
||||
edges = append(edges, user.EdgeGroups)
|
||||
}
|
||||
if m.auth_tokens != nil {
|
||||
edges = append(edges, user.EdgeAuthTokens)
|
||||
@@ -13643,10 +13732,12 @@ func (m *UserMutation) AddedEdges() []string {
|
||||
// name in this mutation.
|
||||
func (m *UserMutation) AddedIDs(name string) []ent.Value {
|
||||
switch name {
|
||||
case user.EdgeGroup:
|
||||
if id := m.group; id != nil {
|
||||
return []ent.Value{*id}
|
||||
case user.EdgeGroups:
|
||||
ids := make([]ent.Value, 0, len(m.groups))
|
||||
for id := range m.groups {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
return ids
|
||||
case user.EdgeAuthTokens:
|
||||
ids := make([]ent.Value, 0, len(m.auth_tokens))
|
||||
for id := range m.auth_tokens {
|
||||
@@ -13666,6 +13757,9 @@ func (m *UserMutation) AddedIDs(name string) []ent.Value {
|
||||
// RemovedEdges returns all edge names that were removed in this mutation.
|
||||
func (m *UserMutation) RemovedEdges() []string {
|
||||
edges := make([]string, 0, 3)
|
||||
if m.removedgroups != nil {
|
||||
edges = append(edges, user.EdgeGroups)
|
||||
}
|
||||
if m.removedauth_tokens != nil {
|
||||
edges = append(edges, user.EdgeAuthTokens)
|
||||
}
|
||||
@@ -13679,6 +13773,12 @@ func (m *UserMutation) RemovedEdges() []string {
|
||||
// the given name in this mutation.
|
||||
func (m *UserMutation) RemovedIDs(name string) []ent.Value {
|
||||
switch name {
|
||||
case user.EdgeGroups:
|
||||
ids := make([]ent.Value, 0, len(m.removedgroups))
|
||||
for id := range m.removedgroups {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
return ids
|
||||
case user.EdgeAuthTokens:
|
||||
ids := make([]ent.Value, 0, len(m.removedauth_tokens))
|
||||
for id := range m.removedauth_tokens {
|
||||
@@ -13698,8 +13798,8 @@ func (m *UserMutation) RemovedIDs(name string) []ent.Value {
|
||||
// ClearedEdges returns all edge names that were cleared in this mutation.
|
||||
func (m *UserMutation) ClearedEdges() []string {
|
||||
edges := make([]string, 0, 3)
|
||||
if m.clearedgroup {
|
||||
edges = append(edges, user.EdgeGroup)
|
||||
if m.clearedgroups {
|
||||
edges = append(edges, user.EdgeGroups)
|
||||
}
|
||||
if m.clearedauth_tokens {
|
||||
edges = append(edges, user.EdgeAuthTokens)
|
||||
@@ -13714,8 +13814,8 @@ func (m *UserMutation) ClearedEdges() []string {
|
||||
// was cleared in this mutation.
|
||||
func (m *UserMutation) EdgeCleared(name string) bool {
|
||||
switch name {
|
||||
case user.EdgeGroup:
|
||||
return m.clearedgroup
|
||||
case user.EdgeGroups:
|
||||
return m.clearedgroups
|
||||
case user.EdgeAuthTokens:
|
||||
return m.clearedauth_tokens
|
||||
case user.EdgeNotifiers:
|
||||
@@ -13728,9 +13828,6 @@ func (m *UserMutation) EdgeCleared(name string) bool {
|
||||
// if that edge is not defined in the schema.
|
||||
func (m *UserMutation) ClearEdge(name string) error {
|
||||
switch name {
|
||||
case user.EdgeGroup:
|
||||
m.ClearGroup()
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown User unique edge %s", name)
|
||||
}
|
||||
@@ -13739,8 +13836,8 @@ func (m *UserMutation) ClearEdge(name string) error {
|
||||
// It returns an error if the edge is not defined in the schema.
|
||||
func (m *UserMutation) ResetEdge(name string) error {
|
||||
switch name {
|
||||
case user.EdgeGroup:
|
||||
m.ResetGroup()
|
||||
case user.EdgeGroups:
|
||||
m.ResetGroups()
|
||||
return nil
|
||||
case user.EdgeAuthTokens:
|
||||
m.ResetAuthTokens()
|
||||
|
||||
@@ -42,7 +42,7 @@ func (Group) Edges() []ent.Edge {
|
||||
}
|
||||
|
||||
return []ent.Edge{
|
||||
owned("users", User.Type),
|
||||
edge.To("users", User.Type),
|
||||
owned("locations", Location.Type),
|
||||
owned("items", Item.Type),
|
||||
owned("labels", Label.Type),
|
||||
@@ -72,14 +72,14 @@ func (g GroupMixin) Fields() []ent.Field {
|
||||
}
|
||||
|
||||
func (g GroupMixin) Edges() []ent.Edge {
|
||||
edge := edge.From("group", Group.Type).
|
||||
e := edge.From("group", Group.Type).
|
||||
Ref(g.ref).
|
||||
Unique().
|
||||
Required()
|
||||
|
||||
if g.field != "" {
|
||||
edge = edge.Field(g.field)
|
||||
e = e.Field(g.field)
|
||||
}
|
||||
|
||||
return []ent.Edge{edge}
|
||||
return []ent.Edge{e}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ type User struct {
|
||||
func (User) Mixin() []ent.Mixin {
|
||||
return []ent.Mixin{
|
||||
mixins.BaseMixin{},
|
||||
GroupMixin{ref: "users"},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +53,10 @@ func (User) Fields() []ent.Field {
|
||||
field.String("oidc_subject").
|
||||
Optional().
|
||||
Nillable(),
|
||||
// default_group_id is the user's primary tenant/group
|
||||
field.UUID("default_group_id", uuid.UUID{}).
|
||||
Optional().
|
||||
Nillable(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +69,7 @@ func (User) Indexes() []ent.Index {
|
||||
// Edges of the User.
|
||||
func (User) Edges() []ent.Edge {
|
||||
return []ent.Edge{
|
||||
edge.To("groups", Group.Type),
|
||||
edge.To("auth_tokens", AuthTokens.Type).
|
||||
Annotations(entsql.Annotation{
|
||||
OnDelete: entsql.Cascade,
|
||||
|
||||
41
backend/internal/data/ent/user.go
generated
41
backend/internal/data/ent/user.go
generated
@@ -10,7 +10,6 @@ import (
|
||||
"entgo.io/ent"
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"github.com/google/uuid"
|
||||
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/group"
|
||||
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/user"
|
||||
)
|
||||
|
||||
@@ -41,6 +40,8 @@ type User struct {
|
||||
OidcIssuer *string `json:"oidc_issuer,omitempty"`
|
||||
// OidcSubject holds the value of the "oidc_subject" field.
|
||||
OidcSubject *string `json:"oidc_subject,omitempty"`
|
||||
// DefaultGroupID holds the value of the "default_group_id" field.
|
||||
DefaultGroupID *uuid.UUID `json:"default_group_id,omitempty"`
|
||||
// Edges holds the relations/edges for other nodes in the graph.
|
||||
// The values are being populated by the UserQuery when eager-loading is set.
|
||||
Edges UserEdges `json:"edges"`
|
||||
@@ -50,8 +51,8 @@ type User struct {
|
||||
|
||||
// UserEdges holds the relations/edges for other nodes in the graph.
|
||||
type UserEdges struct {
|
||||
// Group holds the value of the group edge.
|
||||
Group *Group `json:"group,omitempty"`
|
||||
// Groups holds the value of the groups edge.
|
||||
Groups []*Group `json:"groups,omitempty"`
|
||||
// AuthTokens holds the value of the auth_tokens edge.
|
||||
AuthTokens []*AuthTokens `json:"auth_tokens,omitempty"`
|
||||
// Notifiers holds the value of the notifiers edge.
|
||||
@@ -61,15 +62,13 @@ type UserEdges struct {
|
||||
loadedTypes [3]bool
|
||||
}
|
||||
|
||||
// GroupOrErr returns the Group value or an error if the edge
|
||||
// was not loaded in eager-loading, or loaded but was not found.
|
||||
func (e UserEdges) GroupOrErr() (*Group, error) {
|
||||
if e.Group != nil {
|
||||
return e.Group, nil
|
||||
} else if e.loadedTypes[0] {
|
||||
return nil, &NotFoundError{label: group.Label}
|
||||
// GroupsOrErr returns the Groups value or an error if the edge
|
||||
// was not loaded in eager-loading.
|
||||
func (e UserEdges) GroupsOrErr() ([]*Group, error) {
|
||||
if e.loadedTypes[0] {
|
||||
return e.Groups, nil
|
||||
}
|
||||
return nil, &NotLoadedError{edge: "group"}
|
||||
return nil, &NotLoadedError{edge: "groups"}
|
||||
}
|
||||
|
||||
// AuthTokensOrErr returns the AuthTokens value or an error if the edge
|
||||
@@ -95,6 +94,8 @@ func (*User) scanValues(columns []string) ([]any, error) {
|
||||
values := make([]any, len(columns))
|
||||
for i := range columns {
|
||||
switch columns[i] {
|
||||
case user.FieldDefaultGroupID:
|
||||
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
|
||||
case user.FieldIsSuperuser, user.FieldSuperuser:
|
||||
values[i] = new(sql.NullBool)
|
||||
case user.FieldName, user.FieldEmail, user.FieldPassword, user.FieldRole, user.FieldOidcIssuer, user.FieldOidcSubject:
|
||||
@@ -195,6 +196,13 @@ func (_m *User) assignValues(columns []string, values []any) error {
|
||||
_m.OidcSubject = new(string)
|
||||
*_m.OidcSubject = value.String
|
||||
}
|
||||
case user.FieldDefaultGroupID:
|
||||
if value, ok := values[i].(*sql.NullScanner); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field default_group_id", values[i])
|
||||
} else if value.Valid {
|
||||
_m.DefaultGroupID = new(uuid.UUID)
|
||||
*_m.DefaultGroupID = *value.S.(*uuid.UUID)
|
||||
}
|
||||
case user.ForeignKeys[0]:
|
||||
if value, ok := values[i].(*sql.NullScanner); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field group_users", values[i])
|
||||
@@ -215,9 +223,9 @@ func (_m *User) Value(name string) (ent.Value, error) {
|
||||
return _m.selectValues.Get(name)
|
||||
}
|
||||
|
||||
// QueryGroup queries the "group" edge of the User entity.
|
||||
func (_m *User) QueryGroup() *GroupQuery {
|
||||
return NewUserClient(_m.config).QueryGroup(_m)
|
||||
// QueryGroups queries the "groups" edge of the User entity.
|
||||
func (_m *User) QueryGroups() *GroupQuery {
|
||||
return NewUserClient(_m.config).QueryGroups(_m)
|
||||
}
|
||||
|
||||
// QueryAuthTokens queries the "auth_tokens" edge of the User entity.
|
||||
@@ -288,6 +296,11 @@ func (_m *User) String() string {
|
||||
builder.WriteString("oidc_subject=")
|
||||
builder.WriteString(*v)
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
if v := _m.DefaultGroupID; v != nil {
|
||||
builder.WriteString("default_group_id=")
|
||||
builder.WriteString(fmt.Sprintf("%v", *v))
|
||||
}
|
||||
builder.WriteByte(')')
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
43
backend/internal/data/ent/user/user.go
generated
43
backend/internal/data/ent/user/user.go
generated
@@ -38,21 +38,23 @@ const (
|
||||
FieldOidcIssuer = "oidc_issuer"
|
||||
// FieldOidcSubject holds the string denoting the oidc_subject field in the database.
|
||||
FieldOidcSubject = "oidc_subject"
|
||||
// EdgeGroup holds the string denoting the group edge name in mutations.
|
||||
EdgeGroup = "group"
|
||||
// FieldDefaultGroupID holds the string denoting the default_group_id field in the database.
|
||||
FieldDefaultGroupID = "default_group_id"
|
||||
// EdgeGroups holds the string denoting the groups edge name in mutations.
|
||||
EdgeGroups = "groups"
|
||||
// EdgeAuthTokens holds the string denoting the auth_tokens edge name in mutations.
|
||||
EdgeAuthTokens = "auth_tokens"
|
||||
// EdgeNotifiers holds the string denoting the notifiers edge name in mutations.
|
||||
EdgeNotifiers = "notifiers"
|
||||
// Table holds the table name of the user in the database.
|
||||
Table = "users"
|
||||
// GroupTable is the table that holds the group relation/edge.
|
||||
GroupTable = "users"
|
||||
// GroupInverseTable is the table name for the Group entity.
|
||||
// GroupsTable is the table that holds the groups relation/edge.
|
||||
GroupsTable = "groups"
|
||||
// GroupsInverseTable is the table name for the Group entity.
|
||||
// It exists in this package in order to avoid circular dependency with the "group" package.
|
||||
GroupInverseTable = "groups"
|
||||
// GroupColumn is the table column denoting the group relation/edge.
|
||||
GroupColumn = "group_users"
|
||||
GroupsInverseTable = "groups"
|
||||
// GroupsColumn is the table column denoting the groups relation/edge.
|
||||
GroupsColumn = "user_groups"
|
||||
// AuthTokensTable is the table that holds the auth_tokens relation/edge.
|
||||
AuthTokensTable = "auth_tokens"
|
||||
// AuthTokensInverseTable is the table name for the AuthTokens entity.
|
||||
@@ -83,6 +85,7 @@ var Columns = []string{
|
||||
FieldActivatedOn,
|
||||
FieldOidcIssuer,
|
||||
FieldOidcSubject,
|
||||
FieldDefaultGroupID,
|
||||
}
|
||||
|
||||
// ForeignKeys holds the SQL foreign-keys that are owned by the "users"
|
||||
@@ -216,10 +219,22 @@ func ByOidcSubject(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldOidcSubject, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByGroupField orders the results by group field.
|
||||
func ByGroupField(field string, opts ...sql.OrderTermOption) OrderOption {
|
||||
// ByDefaultGroupID orders the results by the default_group_id field.
|
||||
func ByDefaultGroupID(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldDefaultGroupID, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByGroupsCount orders the results by groups count.
|
||||
func ByGroupsCount(opts ...sql.OrderTermOption) OrderOption {
|
||||
return func(s *sql.Selector) {
|
||||
sqlgraph.OrderByNeighborTerms(s, newGroupStep(), sql.OrderByField(field, opts...))
|
||||
sqlgraph.OrderByNeighborsCount(s, newGroupsStep(), opts...)
|
||||
}
|
||||
}
|
||||
|
||||
// ByGroups orders the results by groups terms.
|
||||
func ByGroups(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
|
||||
return func(s *sql.Selector) {
|
||||
sqlgraph.OrderByNeighborTerms(s, newGroupsStep(), append([]sql.OrderTerm{term}, terms...)...)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,11 +265,11 @@ func ByNotifiers(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
|
||||
sqlgraph.OrderByNeighborTerms(s, newNotifiersStep(), append([]sql.OrderTerm{term}, terms...)...)
|
||||
}
|
||||
}
|
||||
func newGroupStep() *sqlgraph.Step {
|
||||
func newGroupsStep() *sqlgraph.Step {
|
||||
return sqlgraph.NewStep(
|
||||
sqlgraph.From(Table, FieldID),
|
||||
sqlgraph.To(GroupInverseTable, FieldID),
|
||||
sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn),
|
||||
sqlgraph.To(GroupsInverseTable, FieldID),
|
||||
sqlgraph.Edge(sqlgraph.O2M, false, GroupsTable, GroupsColumn),
|
||||
)
|
||||
}
|
||||
func newAuthTokensStep() *sqlgraph.Step {
|
||||
|
||||
67
backend/internal/data/ent/user/where.go
generated
67
backend/internal/data/ent/user/where.go
generated
@@ -106,6 +106,11 @@ func OidcSubject(v string) predicate.User {
|
||||
return predicate.User(sql.FieldEQ(FieldOidcSubject, v))
|
||||
}
|
||||
|
||||
// DefaultGroupID applies equality check predicate on the "default_group_id" field. It's identical to DefaultGroupIDEQ.
|
||||
func DefaultGroupID(v uuid.UUID) predicate.User {
|
||||
return predicate.User(sql.FieldEQ(FieldDefaultGroupID, v))
|
||||
}
|
||||
|
||||
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
||||
func CreatedAtEQ(v time.Time) predicate.User {
|
||||
return predicate.User(sql.FieldEQ(FieldCreatedAt, v))
|
||||
@@ -631,21 +636,71 @@ func OidcSubjectContainsFold(v string) predicate.User {
|
||||
return predicate.User(sql.FieldContainsFold(FieldOidcSubject, v))
|
||||
}
|
||||
|
||||
// HasGroup applies the HasEdge predicate on the "group" edge.
|
||||
func HasGroup() predicate.User {
|
||||
// DefaultGroupIDEQ applies the EQ predicate on the "default_group_id" field.
|
||||
func DefaultGroupIDEQ(v uuid.UUID) predicate.User {
|
||||
return predicate.User(sql.FieldEQ(FieldDefaultGroupID, v))
|
||||
}
|
||||
|
||||
// DefaultGroupIDNEQ applies the NEQ predicate on the "default_group_id" field.
|
||||
func DefaultGroupIDNEQ(v uuid.UUID) predicate.User {
|
||||
return predicate.User(sql.FieldNEQ(FieldDefaultGroupID, v))
|
||||
}
|
||||
|
||||
// DefaultGroupIDIn applies the In predicate on the "default_group_id" field.
|
||||
func DefaultGroupIDIn(vs ...uuid.UUID) predicate.User {
|
||||
return predicate.User(sql.FieldIn(FieldDefaultGroupID, vs...))
|
||||
}
|
||||
|
||||
// DefaultGroupIDNotIn applies the NotIn predicate on the "default_group_id" field.
|
||||
func DefaultGroupIDNotIn(vs ...uuid.UUID) predicate.User {
|
||||
return predicate.User(sql.FieldNotIn(FieldDefaultGroupID, vs...))
|
||||
}
|
||||
|
||||
// DefaultGroupIDGT applies the GT predicate on the "default_group_id" field.
|
||||
func DefaultGroupIDGT(v uuid.UUID) predicate.User {
|
||||
return predicate.User(sql.FieldGT(FieldDefaultGroupID, v))
|
||||
}
|
||||
|
||||
// DefaultGroupIDGTE applies the GTE predicate on the "default_group_id" field.
|
||||
func DefaultGroupIDGTE(v uuid.UUID) predicate.User {
|
||||
return predicate.User(sql.FieldGTE(FieldDefaultGroupID, v))
|
||||
}
|
||||
|
||||
// DefaultGroupIDLT applies the LT predicate on the "default_group_id" field.
|
||||
func DefaultGroupIDLT(v uuid.UUID) predicate.User {
|
||||
return predicate.User(sql.FieldLT(FieldDefaultGroupID, v))
|
||||
}
|
||||
|
||||
// DefaultGroupIDLTE applies the LTE predicate on the "default_group_id" field.
|
||||
func DefaultGroupIDLTE(v uuid.UUID) predicate.User {
|
||||
return predicate.User(sql.FieldLTE(FieldDefaultGroupID, v))
|
||||
}
|
||||
|
||||
// DefaultGroupIDIsNil applies the IsNil predicate on the "default_group_id" field.
|
||||
func DefaultGroupIDIsNil() predicate.User {
|
||||
return predicate.User(sql.FieldIsNull(FieldDefaultGroupID))
|
||||
}
|
||||
|
||||
// DefaultGroupIDNotNil applies the NotNil predicate on the "default_group_id" field.
|
||||
func DefaultGroupIDNotNil() predicate.User {
|
||||
return predicate.User(sql.FieldNotNull(FieldDefaultGroupID))
|
||||
}
|
||||
|
||||
// HasGroups applies the HasEdge predicate on the "groups" edge.
|
||||
func HasGroups() predicate.User {
|
||||
return predicate.User(func(s *sql.Selector) {
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(Table, FieldID),
|
||||
sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn),
|
||||
sqlgraph.Edge(sqlgraph.O2M, false, GroupsTable, GroupsColumn),
|
||||
)
|
||||
sqlgraph.HasNeighbors(s, step)
|
||||
})
|
||||
}
|
||||
|
||||
// HasGroupWith applies the HasEdge predicate on the "group" edge with a given conditions (other predicates).
|
||||
func HasGroupWith(preds ...predicate.Group) predicate.User {
|
||||
// HasGroupsWith applies the HasEdge predicate on the "groups" edge with a given conditions (other predicates).
|
||||
func HasGroupsWith(preds ...predicate.Group) predicate.User {
|
||||
return predicate.User(func(s *sql.Selector) {
|
||||
step := newGroupStep()
|
||||
step := newGroupsStep()
|
||||
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
||||
for _, p := range preds {
|
||||
p(s)
|
||||
|
||||
48
backend/internal/data/ent/user_create.go
generated
48
backend/internal/data/ent/user_create.go
generated
@@ -162,6 +162,20 @@ func (_c *UserCreate) SetNillableOidcSubject(v *string) *UserCreate {
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetDefaultGroupID sets the "default_group_id" field.
|
||||
func (_c *UserCreate) SetDefaultGroupID(v uuid.UUID) *UserCreate {
|
||||
_c.mutation.SetDefaultGroupID(v)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetNillableDefaultGroupID sets the "default_group_id" field if the given value is not nil.
|
||||
func (_c *UserCreate) SetNillableDefaultGroupID(v *uuid.UUID) *UserCreate {
|
||||
if v != nil {
|
||||
_c.SetDefaultGroupID(*v)
|
||||
}
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetID sets the "id" field.
|
||||
func (_c *UserCreate) SetID(v uuid.UUID) *UserCreate {
|
||||
_c.mutation.SetID(v)
|
||||
@@ -176,15 +190,19 @@ func (_c *UserCreate) SetNillableID(v *uuid.UUID) *UserCreate {
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetGroupID sets the "group" edge to the Group entity by ID.
|
||||
func (_c *UserCreate) SetGroupID(id uuid.UUID) *UserCreate {
|
||||
_c.mutation.SetGroupID(id)
|
||||
// AddGroupIDs adds the "groups" edge to the Group entity by IDs.
|
||||
func (_c *UserCreate) AddGroupIDs(ids ...uuid.UUID) *UserCreate {
|
||||
_c.mutation.AddGroupIDs(ids...)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetGroup sets the "group" edge to the Group entity.
|
||||
func (_c *UserCreate) SetGroup(v *Group) *UserCreate {
|
||||
return _c.SetGroupID(v.ID)
|
||||
// AddGroups adds the "groups" edges to the Group entity.
|
||||
func (_c *UserCreate) AddGroups(v ...*Group) *UserCreate {
|
||||
ids := make([]uuid.UUID, len(v))
|
||||
for i := range v {
|
||||
ids[i] = v[i].ID
|
||||
}
|
||||
return _c.AddGroupIDs(ids...)
|
||||
}
|
||||
|
||||
// AddAuthTokenIDs adds the "auth_tokens" edge to the AuthTokens entity by IDs.
|
||||
@@ -321,9 +339,6 @@ func (_c *UserCreate) check() error {
|
||||
return &ValidationError{Name: "role", err: fmt.Errorf(`ent: validator failed for field "User.role": %w`, err)}
|
||||
}
|
||||
}
|
||||
if len(_c.mutation.GroupIDs()) == 0 {
|
||||
return &ValidationError{Name: "group", err: errors.New(`ent: missing required edge "User.group"`)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -403,12 +418,16 @@ func (_c *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) {
|
||||
_spec.SetField(user.FieldOidcSubject, field.TypeString, value)
|
||||
_node.OidcSubject = &value
|
||||
}
|
||||
if nodes := _c.mutation.GroupIDs(); len(nodes) > 0 {
|
||||
if value, ok := _c.mutation.DefaultGroupID(); ok {
|
||||
_spec.SetField(user.FieldDefaultGroupID, field.TypeUUID, value)
|
||||
_node.DefaultGroupID = &value
|
||||
}
|
||||
if nodes := _c.mutation.GroupsIDs(); len(nodes) > 0 {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.M2O,
|
||||
Inverse: true,
|
||||
Table: user.GroupTable,
|
||||
Columns: []string{user.GroupColumn},
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: user.GroupsTable,
|
||||
Columns: []string{user.GroupsColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
|
||||
@@ -417,7 +436,6 @@ func (_c *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) {
|
||||
for _, k := range nodes {
|
||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||
}
|
||||
_node.group_users = &nodes[0]
|
||||
_spec.Edges = append(_spec.Edges, edge)
|
||||
}
|
||||
if nodes := _c.mutation.AuthTokensIDs(); len(nodes) > 0 {
|
||||
|
||||
67
backend/internal/data/ent/user_query.go
generated
67
backend/internal/data/ent/user_query.go
generated
@@ -27,7 +27,7 @@ type UserQuery struct {
|
||||
order []user.OrderOption
|
||||
inters []Interceptor
|
||||
predicates []predicate.User
|
||||
withGroup *GroupQuery
|
||||
withGroups *GroupQuery
|
||||
withAuthTokens *AuthTokensQuery
|
||||
withNotifiers *NotifierQuery
|
||||
withFKs bool
|
||||
@@ -67,8 +67,8 @@ func (_q *UserQuery) Order(o ...user.OrderOption) *UserQuery {
|
||||
return _q
|
||||
}
|
||||
|
||||
// QueryGroup chains the current query on the "group" edge.
|
||||
func (_q *UserQuery) QueryGroup() *GroupQuery {
|
||||
// QueryGroups chains the current query on the "groups" edge.
|
||||
func (_q *UserQuery) QueryGroups() *GroupQuery {
|
||||
query := (&GroupClient{config: _q.config}).Query()
|
||||
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
||||
if err := _q.prepareQuery(ctx); err != nil {
|
||||
@@ -81,7 +81,7 @@ func (_q *UserQuery) QueryGroup() *GroupQuery {
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(user.Table, user.FieldID, selector),
|
||||
sqlgraph.To(group.Table, group.FieldID),
|
||||
sqlgraph.Edge(sqlgraph.M2O, true, user.GroupTable, user.GroupColumn),
|
||||
sqlgraph.Edge(sqlgraph.O2M, false, user.GroupsTable, user.GroupsColumn),
|
||||
)
|
||||
fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step)
|
||||
return fromU, nil
|
||||
@@ -325,7 +325,7 @@ func (_q *UserQuery) Clone() *UserQuery {
|
||||
order: append([]user.OrderOption{}, _q.order...),
|
||||
inters: append([]Interceptor{}, _q.inters...),
|
||||
predicates: append([]predicate.User{}, _q.predicates...),
|
||||
withGroup: _q.withGroup.Clone(),
|
||||
withGroups: _q.withGroups.Clone(),
|
||||
withAuthTokens: _q.withAuthTokens.Clone(),
|
||||
withNotifiers: _q.withNotifiers.Clone(),
|
||||
// clone intermediate query.
|
||||
@@ -334,14 +334,14 @@ func (_q *UserQuery) Clone() *UserQuery {
|
||||
}
|
||||
}
|
||||
|
||||
// WithGroup tells the query-builder to eager-load the nodes that are connected to
|
||||
// the "group" edge. The optional arguments are used to configure the query builder of the edge.
|
||||
func (_q *UserQuery) WithGroup(opts ...func(*GroupQuery)) *UserQuery {
|
||||
// WithGroups tells the query-builder to eager-load the nodes that are connected to
|
||||
// the "groups" edge. The optional arguments are used to configure the query builder of the edge.
|
||||
func (_q *UserQuery) WithGroups(opts ...func(*GroupQuery)) *UserQuery {
|
||||
query := (&GroupClient{config: _q.config}).Query()
|
||||
for _, opt := range opts {
|
||||
opt(query)
|
||||
}
|
||||
_q.withGroup = query
|
||||
_q.withGroups = query
|
||||
return _q
|
||||
}
|
||||
|
||||
@@ -447,14 +447,11 @@ func (_q *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
|
||||
withFKs = _q.withFKs
|
||||
_spec = _q.querySpec()
|
||||
loadedTypes = [3]bool{
|
||||
_q.withGroup != nil,
|
||||
_q.withGroups != nil,
|
||||
_q.withAuthTokens != nil,
|
||||
_q.withNotifiers != nil,
|
||||
}
|
||||
)
|
||||
if _q.withGroup != nil {
|
||||
withFKs = true
|
||||
}
|
||||
if withFKs {
|
||||
_spec.Node.Columns = append(_spec.Node.Columns, user.ForeignKeys...)
|
||||
}
|
||||
@@ -476,9 +473,10 @@ func (_q *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
|
||||
if len(nodes) == 0 {
|
||||
return nodes, nil
|
||||
}
|
||||
if query := _q.withGroup; query != nil {
|
||||
if err := _q.loadGroup(ctx, query, nodes, nil,
|
||||
func(n *User, e *Group) { n.Edges.Group = e }); err != nil {
|
||||
if query := _q.withGroups; query != nil {
|
||||
if err := _q.loadGroups(ctx, query, nodes,
|
||||
func(n *User) { n.Edges.Groups = []*Group{} },
|
||||
func(n *User, e *Group) { n.Edges.Groups = append(n.Edges.Groups, e) }); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -499,35 +497,34 @@ func (_q *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
func (_q *UserQuery) loadGroup(ctx context.Context, query *GroupQuery, nodes []*User, init func(*User), assign func(*User, *Group)) error {
|
||||
ids := make([]uuid.UUID, 0, len(nodes))
|
||||
nodeids := make(map[uuid.UUID][]*User)
|
||||
func (_q *UserQuery) loadGroups(ctx context.Context, query *GroupQuery, nodes []*User, init func(*User), assign func(*User, *Group)) error {
|
||||
fks := make([]driver.Value, 0, len(nodes))
|
||||
nodeids := make(map[uuid.UUID]*User)
|
||||
for i := range nodes {
|
||||
if nodes[i].group_users == nil {
|
||||
continue
|
||||
fks = append(fks, nodes[i].ID)
|
||||
nodeids[nodes[i].ID] = nodes[i]
|
||||
if init != nil {
|
||||
init(nodes[i])
|
||||
}
|
||||
fk := *nodes[i].group_users
|
||||
if _, ok := nodeids[fk]; !ok {
|
||||
ids = append(ids, fk)
|
||||
}
|
||||
nodeids[fk] = append(nodeids[fk], nodes[i])
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
return nil
|
||||
}
|
||||
query.Where(group.IDIn(ids...))
|
||||
query.withFKs = true
|
||||
query.Where(predicate.Group(func(s *sql.Selector) {
|
||||
s.Where(sql.InValues(s.C(user.GroupsColumn), fks...))
|
||||
}))
|
||||
neighbors, err := query.All(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, n := range neighbors {
|
||||
nodes, ok := nodeids[n.ID]
|
||||
fk := n.user_groups
|
||||
if fk == nil {
|
||||
return fmt.Errorf(`foreign-key "user_groups" is nil for node %v`, n.ID)
|
||||
}
|
||||
node, ok := nodeids[*fk]
|
||||
if !ok {
|
||||
return fmt.Errorf(`unexpected foreign-key "group_users" returned %v`, n.ID)
|
||||
}
|
||||
for i := range nodes {
|
||||
assign(nodes[i], n)
|
||||
return fmt.Errorf(`unexpected referenced foreign-key "user_groups" returned %v for node %v`, *fk, n.ID)
|
||||
}
|
||||
assign(node, n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
204
backend/internal/data/ent/user_update.go
generated
204
backend/internal/data/ent/user_update.go
generated
@@ -188,15 +188,39 @@ func (_u *UserUpdate) ClearOidcSubject() *UserUpdate {
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetGroupID sets the "group" edge to the Group entity by ID.
|
||||
func (_u *UserUpdate) SetGroupID(id uuid.UUID) *UserUpdate {
|
||||
_u.mutation.SetGroupID(id)
|
||||
// SetDefaultGroupID sets the "default_group_id" field.
|
||||
func (_u *UserUpdate) SetDefaultGroupID(v uuid.UUID) *UserUpdate {
|
||||
_u.mutation.SetDefaultGroupID(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetGroup sets the "group" edge to the Group entity.
|
||||
func (_u *UserUpdate) SetGroup(v *Group) *UserUpdate {
|
||||
return _u.SetGroupID(v.ID)
|
||||
// SetNillableDefaultGroupID sets the "default_group_id" field if the given value is not nil.
|
||||
func (_u *UserUpdate) SetNillableDefaultGroupID(v *uuid.UUID) *UserUpdate {
|
||||
if v != nil {
|
||||
_u.SetDefaultGroupID(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// ClearDefaultGroupID clears the value of the "default_group_id" field.
|
||||
func (_u *UserUpdate) ClearDefaultGroupID() *UserUpdate {
|
||||
_u.mutation.ClearDefaultGroupID()
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddGroupIDs adds the "groups" edge to the Group entity by IDs.
|
||||
func (_u *UserUpdate) AddGroupIDs(ids ...uuid.UUID) *UserUpdate {
|
||||
_u.mutation.AddGroupIDs(ids...)
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddGroups adds the "groups" edges to the Group entity.
|
||||
func (_u *UserUpdate) AddGroups(v ...*Group) *UserUpdate {
|
||||
ids := make([]uuid.UUID, len(v))
|
||||
for i := range v {
|
||||
ids[i] = v[i].ID
|
||||
}
|
||||
return _u.AddGroupIDs(ids...)
|
||||
}
|
||||
|
||||
// AddAuthTokenIDs adds the "auth_tokens" edge to the AuthTokens entity by IDs.
|
||||
@@ -234,12 +258,27 @@ func (_u *UserUpdate) Mutation() *UserMutation {
|
||||
return _u.mutation
|
||||
}
|
||||
|
||||
// ClearGroup clears the "group" edge to the Group entity.
|
||||
func (_u *UserUpdate) ClearGroup() *UserUpdate {
|
||||
_u.mutation.ClearGroup()
|
||||
// ClearGroups clears all "groups" edges to the Group entity.
|
||||
func (_u *UserUpdate) ClearGroups() *UserUpdate {
|
||||
_u.mutation.ClearGroups()
|
||||
return _u
|
||||
}
|
||||
|
||||
// RemoveGroupIDs removes the "groups" edge to Group entities by IDs.
|
||||
func (_u *UserUpdate) RemoveGroupIDs(ids ...uuid.UUID) *UserUpdate {
|
||||
_u.mutation.RemoveGroupIDs(ids...)
|
||||
return _u
|
||||
}
|
||||
|
||||
// RemoveGroups removes "groups" edges to Group entities.
|
||||
func (_u *UserUpdate) RemoveGroups(v ...*Group) *UserUpdate {
|
||||
ids := make([]uuid.UUID, len(v))
|
||||
for i := range v {
|
||||
ids[i] = v[i].ID
|
||||
}
|
||||
return _u.RemoveGroupIDs(ids...)
|
||||
}
|
||||
|
||||
// ClearAuthTokens clears all "auth_tokens" edges to the AuthTokens entity.
|
||||
func (_u *UserUpdate) ClearAuthTokens() *UserUpdate {
|
||||
_u.mutation.ClearAuthTokens()
|
||||
@@ -340,9 +379,6 @@ func (_u *UserUpdate) check() error {
|
||||
return &ValidationError{Name: "role", err: fmt.Errorf(`ent: validator failed for field "User.role": %w`, err)}
|
||||
}
|
||||
}
|
||||
if _u.mutation.GroupCleared() && len(_u.mutation.GroupIDs()) > 0 {
|
||||
return errors.New(`ent: clearing a required unique edge "User.group"`)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -400,12 +436,18 @@ func (_u *UserUpdate) sqlSave(ctx context.Context) (_node int, err error) {
|
||||
if _u.mutation.OidcSubjectCleared() {
|
||||
_spec.ClearField(user.FieldOidcSubject, field.TypeString)
|
||||
}
|
||||
if _u.mutation.GroupCleared() {
|
||||
if value, ok := _u.mutation.DefaultGroupID(); ok {
|
||||
_spec.SetField(user.FieldDefaultGroupID, field.TypeUUID, value)
|
||||
}
|
||||
if _u.mutation.DefaultGroupIDCleared() {
|
||||
_spec.ClearField(user.FieldDefaultGroupID, field.TypeUUID)
|
||||
}
|
||||
if _u.mutation.GroupsCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.M2O,
|
||||
Inverse: true,
|
||||
Table: user.GroupTable,
|
||||
Columns: []string{user.GroupColumn},
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: user.GroupsTable,
|
||||
Columns: []string{user.GroupsColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
|
||||
@@ -413,12 +455,28 @@ func (_u *UserUpdate) sqlSave(ctx context.Context) (_node int, err error) {
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
}
|
||||
if nodes := _u.mutation.GroupIDs(); len(nodes) > 0 {
|
||||
if nodes := _u.mutation.RemovedGroupsIDs(); len(nodes) > 0 && !_u.mutation.GroupsCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.M2O,
|
||||
Inverse: true,
|
||||
Table: user.GroupTable,
|
||||
Columns: []string{user.GroupColumn},
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: user.GroupsTable,
|
||||
Columns: []string{user.GroupsColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(group.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 := _u.mutation.GroupsIDs(); len(nodes) > 0 {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: user.GroupsTable,
|
||||
Columns: []string{user.GroupsColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
|
||||
@@ -695,15 +753,39 @@ func (_u *UserUpdateOne) ClearOidcSubject() *UserUpdateOne {
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetGroupID sets the "group" edge to the Group entity by ID.
|
||||
func (_u *UserUpdateOne) SetGroupID(id uuid.UUID) *UserUpdateOne {
|
||||
_u.mutation.SetGroupID(id)
|
||||
// SetDefaultGroupID sets the "default_group_id" field.
|
||||
func (_u *UserUpdateOne) SetDefaultGroupID(v uuid.UUID) *UserUpdateOne {
|
||||
_u.mutation.SetDefaultGroupID(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetGroup sets the "group" edge to the Group entity.
|
||||
func (_u *UserUpdateOne) SetGroup(v *Group) *UserUpdateOne {
|
||||
return _u.SetGroupID(v.ID)
|
||||
// SetNillableDefaultGroupID sets the "default_group_id" field if the given value is not nil.
|
||||
func (_u *UserUpdateOne) SetNillableDefaultGroupID(v *uuid.UUID) *UserUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetDefaultGroupID(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// ClearDefaultGroupID clears the value of the "default_group_id" field.
|
||||
func (_u *UserUpdateOne) ClearDefaultGroupID() *UserUpdateOne {
|
||||
_u.mutation.ClearDefaultGroupID()
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddGroupIDs adds the "groups" edge to the Group entity by IDs.
|
||||
func (_u *UserUpdateOne) AddGroupIDs(ids ...uuid.UUID) *UserUpdateOne {
|
||||
_u.mutation.AddGroupIDs(ids...)
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddGroups adds the "groups" edges to the Group entity.
|
||||
func (_u *UserUpdateOne) AddGroups(v ...*Group) *UserUpdateOne {
|
||||
ids := make([]uuid.UUID, len(v))
|
||||
for i := range v {
|
||||
ids[i] = v[i].ID
|
||||
}
|
||||
return _u.AddGroupIDs(ids...)
|
||||
}
|
||||
|
||||
// AddAuthTokenIDs adds the "auth_tokens" edge to the AuthTokens entity by IDs.
|
||||
@@ -741,12 +823,27 @@ func (_u *UserUpdateOne) Mutation() *UserMutation {
|
||||
return _u.mutation
|
||||
}
|
||||
|
||||
// ClearGroup clears the "group" edge to the Group entity.
|
||||
func (_u *UserUpdateOne) ClearGroup() *UserUpdateOne {
|
||||
_u.mutation.ClearGroup()
|
||||
// ClearGroups clears all "groups" edges to the Group entity.
|
||||
func (_u *UserUpdateOne) ClearGroups() *UserUpdateOne {
|
||||
_u.mutation.ClearGroups()
|
||||
return _u
|
||||
}
|
||||
|
||||
// RemoveGroupIDs removes the "groups" edge to Group entities by IDs.
|
||||
func (_u *UserUpdateOne) RemoveGroupIDs(ids ...uuid.UUID) *UserUpdateOne {
|
||||
_u.mutation.RemoveGroupIDs(ids...)
|
||||
return _u
|
||||
}
|
||||
|
||||
// RemoveGroups removes "groups" edges to Group entities.
|
||||
func (_u *UserUpdateOne) RemoveGroups(v ...*Group) *UserUpdateOne {
|
||||
ids := make([]uuid.UUID, len(v))
|
||||
for i := range v {
|
||||
ids[i] = v[i].ID
|
||||
}
|
||||
return _u.RemoveGroupIDs(ids...)
|
||||
}
|
||||
|
||||
// ClearAuthTokens clears all "auth_tokens" edges to the AuthTokens entity.
|
||||
func (_u *UserUpdateOne) ClearAuthTokens() *UserUpdateOne {
|
||||
_u.mutation.ClearAuthTokens()
|
||||
@@ -860,9 +957,6 @@ func (_u *UserUpdateOne) check() error {
|
||||
return &ValidationError{Name: "role", err: fmt.Errorf(`ent: validator failed for field "User.role": %w`, err)}
|
||||
}
|
||||
}
|
||||
if _u.mutation.GroupCleared() && len(_u.mutation.GroupIDs()) > 0 {
|
||||
return errors.New(`ent: clearing a required unique edge "User.group"`)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -937,12 +1031,18 @@ func (_u *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) {
|
||||
if _u.mutation.OidcSubjectCleared() {
|
||||
_spec.ClearField(user.FieldOidcSubject, field.TypeString)
|
||||
}
|
||||
if _u.mutation.GroupCleared() {
|
||||
if value, ok := _u.mutation.DefaultGroupID(); ok {
|
||||
_spec.SetField(user.FieldDefaultGroupID, field.TypeUUID, value)
|
||||
}
|
||||
if _u.mutation.DefaultGroupIDCleared() {
|
||||
_spec.ClearField(user.FieldDefaultGroupID, field.TypeUUID)
|
||||
}
|
||||
if _u.mutation.GroupsCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.M2O,
|
||||
Inverse: true,
|
||||
Table: user.GroupTable,
|
||||
Columns: []string{user.GroupColumn},
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: user.GroupsTable,
|
||||
Columns: []string{user.GroupsColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
|
||||
@@ -950,12 +1050,28 @@ func (_u *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) {
|
||||
}
|
||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||
}
|
||||
if nodes := _u.mutation.GroupIDs(); len(nodes) > 0 {
|
||||
if nodes := _u.mutation.RemovedGroupsIDs(); len(nodes) > 0 && !_u.mutation.GroupsCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.M2O,
|
||||
Inverse: true,
|
||||
Table: user.GroupTable,
|
||||
Columns: []string{user.GroupColumn},
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: user.GroupsTable,
|
||||
Columns: []string{user.GroupsColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(group.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 := _u.mutation.GroupsIDs(); len(nodes) > 0 {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.O2M,
|
||||
Inverse: false,
|
||||
Table: user.GroupsTable,
|
||||
Columns: []string{user.GroupsColumn},
|
||||
Bidi: false,
|
||||
Target: &sqlgraph.EdgeTarget{
|
||||
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
-- +goose Up
|
||||
-- Create user_groups junction table for M:M relationship
|
||||
CREATE TABLE IF NOT EXISTS "user_groups" (
|
||||
"user_id" uuid NOT NULL,
|
||||
"group_id" uuid NOT NULL,
|
||||
PRIMARY KEY ("user_id", "group_id"),
|
||||
CONSTRAINT "user_groups_user_id" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON UPDATE NO ACTION ON DELETE CASCADE,
|
||||
CONSTRAINT "user_groups_group_id" FOREIGN KEY ("group_id") REFERENCES "groups" ("id") ON UPDATE NO ACTION ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Migrate existing user->group relationships to the junction table
|
||||
INSERT INTO "user_groups" ("user_id", "group_id")
|
||||
SELECT "id", "group_users" FROM "users" WHERE "group_users" IS NOT NULL;
|
||||
|
||||
-- Add default_group_id column to users table
|
||||
ALTER TABLE "users" ADD COLUMN "default_group_id" uuid;
|
||||
|
||||
-- Set default_group_id to the user's current group
|
||||
UPDATE "users" SET "default_group_id" = "group_users" WHERE "group_users" IS NOT NULL;
|
||||
|
||||
-- Drop the old group_users foreign key constraint and column
|
||||
ALTER TABLE "users" DROP CONSTRAINT "users_groups_users";
|
||||
ALTER TABLE "users" DROP COLUMN "group_users";
|
||||
|
||||
-- Add foreign key constraint for default_group_id
|
||||
ALTER TABLE "users" ADD CONSTRAINT "users_groups_users_default" FOREIGN KEY ("default_group_id") REFERENCES "groups" ("id") ON UPDATE NO ACTION ON DELETE SET NULL;
|
||||
|
||||
-- +goose Down
|
||||
-- Recreate group_users column with foreign key
|
||||
ALTER TABLE "users" ADD COLUMN "group_users" uuid;
|
||||
|
||||
-- Restore the group_users values from user_groups (using the default_group_id or first entry)
|
||||
UPDATE "users"
|
||||
SET "group_users" = COALESCE("default_group_id", (
|
||||
SELECT "group_id" FROM "user_groups" WHERE "user_id" = "users"."id" LIMIT 1
|
||||
));
|
||||
|
||||
-- Drop the default_group_id foreign key and column
|
||||
ALTER TABLE "users" DROP CONSTRAINT "users_groups_users_default";
|
||||
ALTER TABLE "users" DROP COLUMN "default_group_id";
|
||||
|
||||
-- Add back the original foreign key constraint
|
||||
ALTER TABLE "users" ADD CONSTRAINT "users_groups_users" FOREIGN KEY ("group_users") REFERENCES "groups" ("id") ON UPDATE NO ACTION ON DELETE CASCADE;
|
||||
|
||||
-- Drop the junction table
|
||||
DROP TABLE IF EXISTS "user_groups";
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
-- +goose Up
|
||||
-- Create user_groups junction table for M:M relationship
|
||||
CREATE TABLE IF NOT EXISTS user_groups (
|
||||
user_id UUID NOT NULL,
|
||||
group_id UUID NOT NULL,
|
||||
PRIMARY KEY (user_id, group_id),
|
||||
CONSTRAINT user_groups_user_id FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
CONSTRAINT user_groups_group_id FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Migrate existing user->group relationships to the junction table
|
||||
INSERT INTO user_groups (user_id, group_id)
|
||||
SELECT id, group_users FROM users WHERE group_users IS NOT NULL;
|
||||
|
||||
-- Add default_group_id column to users table
|
||||
ALTER TABLE users ADD COLUMN default_group_id UUID;
|
||||
|
||||
-- Set default_group_id to the user's current group
|
||||
UPDATE users SET default_group_id = group_users WHERE group_users IS NOT NULL;
|
||||
|
||||
-- Add foreign key constraint for default_group_id
|
||||
CREATE TABLE users_new (
|
||||
id UUID NOT NULL,
|
||||
created_at DATETIME NOT NULL,
|
||||
updated_at DATETIME NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
password TEXT,
|
||||
is_superuser BOOLEAN NOT NULL DEFAULT false,
|
||||
superuser BOOLEAN NOT NULL DEFAULT false,
|
||||
role TEXT NOT NULL DEFAULT 'user',
|
||||
activated_on DATETIME,
|
||||
oidc_issuer TEXT,
|
||||
oidc_subject TEXT,
|
||||
default_group_id UUID,
|
||||
PRIMARY KEY (id),
|
||||
CONSTRAINT users_groups_users_default FOREIGN KEY (default_group_id) REFERENCES groups(id) ON DELETE SET NULL,
|
||||
UNIQUE (oidc_issuer, oidc_subject)
|
||||
);
|
||||
|
||||
-- Copy data from old table to new table
|
||||
INSERT INTO users_new (
|
||||
id, created_at, updated_at, name, email, password, is_superuser, superuser, role,
|
||||
activated_on, oidc_issuer, oidc_subject, default_group_id
|
||||
)
|
||||
SELECT
|
||||
id, created_at, updated_at, name, email, password, is_superuser, superuser, role,
|
||||
activated_on, oidc_issuer, oidc_subject, default_group_id
|
||||
FROM users;
|
||||
|
||||
-- Drop old indexes
|
||||
DROP INDEX IF EXISTS users_email_key;
|
||||
DROP INDEX IF EXISTS users_oidc_issuer_subject_key;
|
||||
|
||||
-- Drop old table
|
||||
DROP TABLE users;
|
||||
|
||||
-- Rename new table to users
|
||||
ALTER TABLE users_new RENAME TO users;
|
||||
|
||||
-- Recreate indexes
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS users_email_key ON users(email);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS users_oidc_issuer_subject_key ON users(oidc_issuer, oidc_subject);
|
||||
|
||||
-- +goose Down
|
||||
-- Recreate the old schema
|
||||
CREATE TABLE users_old (
|
||||
id UUID NOT NULL,
|
||||
created_at DATETIME NOT NULL,
|
||||
updated_at DATETIME NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
password TEXT,
|
||||
is_superuser BOOLEAN NOT NULL DEFAULT false,
|
||||
superuser BOOLEAN NOT NULL DEFAULT false,
|
||||
role TEXT NOT NULL DEFAULT 'user',
|
||||
activated_on DATETIME,
|
||||
oidc_issuer TEXT,
|
||||
oidc_subject TEXT,
|
||||
group_users UUID NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
CONSTRAINT users_groups_users FOREIGN KEY (group_users) REFERENCES groups(id) ON DELETE CASCADE,
|
||||
UNIQUE (oidc_issuer, oidc_subject)
|
||||
);
|
||||
|
||||
-- Copy data back, using the first group from user_groups
|
||||
INSERT INTO users_old (
|
||||
id, created_at, updated_at, name, email, password, is_superuser, superuser, role,
|
||||
activated_on, oidc_issuer, oidc_subject, group_users
|
||||
)
|
||||
SELECT
|
||||
u.id, u.created_at, u.updated_at, u.name, u.email, u.password, u.is_superuser, u.superuser, u.role,
|
||||
u.activated_on, u.oidc_issuer, u.oidc_subject, COALESCE(u.default_group_id, (SELECT group_id FROM user_groups WHERE user_id = u.id LIMIT 1))
|
||||
FROM users u;
|
||||
|
||||
DROP INDEX IF EXISTS users_email_key;
|
||||
DROP INDEX IF EXISTS users_oidc_issuer_subject_key;
|
||||
DROP TABLE users;
|
||||
ALTER TABLE users_old RENAME TO users;
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS users_email_key ON users(email);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS users_oidc_issuer_subject_key ON users(oidc_issuer, oidc_subject);
|
||||
|
||||
DROP TABLE IF EXISTS user_groups;
|
||||
|
||||
@@ -313,7 +313,7 @@ func TestItemRepository_GetAllCustomFields(t *testing.T) {
|
||||
|
||||
// Test getting all values from field
|
||||
{
|
||||
results, err := tRepos.Items.GetAllCustomFieldValues(context.Background(), tUser.GroupID, names[0])
|
||||
results, err := tRepos.Items.GetAllCustomFieldValues(context.Background(), tUser.DefaultGroupID, names[0])
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.ElementsMatch(t, values[:1], results)
|
||||
@@ -397,5 +397,3 @@ func TestItemsRepository_DeleteByGroupWithAttachments(t *testing.T) {
|
||||
_, err = tRepos.Attachments.Get(context.Background(), tGroup.ID, attachment.ID)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ func (r *TokenRepository) GetUserFromToken(ctx context.Context, token []byte) (U
|
||||
Where(authtokens.ExpiresAtGTE(time.Now())).
|
||||
WithUser().
|
||||
QueryUser().
|
||||
WithGroup().
|
||||
WithGroups().
|
||||
Only(ctx)
|
||||
if err != nil {
|
||||
return UserOut{}, err
|
||||
|
||||
@@ -17,12 +17,12 @@ type (
|
||||
// in the database. It should to create users from an API unless the user has
|
||||
// rights to create SuperUsers. For regular user in data use the UserIn struct.
|
||||
UserCreate struct {
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
Password *string `json:"password"`
|
||||
IsSuperuser bool `json:"isSuperuser"`
|
||||
GroupID uuid.UUID `json:"groupID"`
|
||||
IsOwner bool `json:"isOwner"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
Password *string `json:"password"`
|
||||
IsSuperuser bool `json:"isSuperuser"`
|
||||
DefaultGroupID uuid.UUID `json:"defaultGroupID"`
|
||||
IsOwner bool `json:"isOwner"`
|
||||
}
|
||||
|
||||
UserUpdate struct {
|
||||
@@ -31,16 +31,16 @@ type (
|
||||
}
|
||||
|
||||
UserOut struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
IsSuperuser bool `json:"isSuperuser"`
|
||||
GroupID uuid.UUID `json:"groupId"`
|
||||
GroupName string `json:"groupName"`
|
||||
PasswordHash string `json:"-"`
|
||||
IsOwner bool `json:"isOwner"`
|
||||
OidcIssuer *string `json:"oidcIssuer"`
|
||||
OidcSubject *string `json:"oidcSubject"`
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
IsSuperuser bool `json:"isSuperuser"`
|
||||
DefaultGroupID uuid.UUID `json:"defaultGroupId"`
|
||||
GroupIDs []uuid.UUID `json:"groupIds"`
|
||||
PasswordHash string `json:"-"`
|
||||
IsOwner bool `json:"isOwner"`
|
||||
OidcIssuer *string `json:"oidcIssuer"`
|
||||
OidcSubject *string `json:"oidcSubject"`
|
||||
}
|
||||
)
|
||||
|
||||
@@ -55,37 +55,48 @@ func mapUserOut(user *ent.User) UserOut {
|
||||
passwordHash = *user.Password
|
||||
}
|
||||
|
||||
groupIDs := make([]uuid.UUID, len(user.Edges.Groups))
|
||||
for i, g := range user.Edges.Groups {
|
||||
groupIDs[i] = g.ID
|
||||
}
|
||||
|
||||
// Get the default group ID, handling the optional pointer
|
||||
defaultGroupID := uuid.Nil
|
||||
if user.DefaultGroupID != nil {
|
||||
defaultGroupID = *user.DefaultGroupID
|
||||
}
|
||||
|
||||
return UserOut{
|
||||
ID: user.ID,
|
||||
Name: user.Name,
|
||||
Email: user.Email,
|
||||
IsSuperuser: user.IsSuperuser,
|
||||
GroupID: user.Edges.Group.ID,
|
||||
GroupName: user.Edges.Group.Name,
|
||||
PasswordHash: passwordHash,
|
||||
IsOwner: user.Role == "owner",
|
||||
OidcIssuer: user.OidcIssuer,
|
||||
OidcSubject: user.OidcSubject,
|
||||
ID: user.ID,
|
||||
Name: user.Name,
|
||||
Email: user.Email,
|
||||
IsSuperuser: user.IsSuperuser,
|
||||
DefaultGroupID: defaultGroupID,
|
||||
GroupIDs: groupIDs,
|
||||
PasswordHash: passwordHash,
|
||||
IsOwner: user.Role == "owner",
|
||||
OidcIssuer: user.OidcIssuer,
|
||||
OidcSubject: user.OidcSubject,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *UserRepository) GetOneID(ctx context.Context, id uuid.UUID) (UserOut, error) {
|
||||
return mapUserOutErr(r.db.User.Query().
|
||||
Where(user.ID(id)).
|
||||
WithGroup().
|
||||
WithGroups().
|
||||
Only(ctx))
|
||||
}
|
||||
|
||||
func (r *UserRepository) GetOneEmail(ctx context.Context, email string) (UserOut, error) {
|
||||
return mapUserOutErr(r.db.User.Query().
|
||||
Where(user.EmailEqualFold(email)).
|
||||
WithGroup().
|
||||
WithGroups().
|
||||
Only(ctx),
|
||||
)
|
||||
}
|
||||
|
||||
func (r *UserRepository) GetAll(ctx context.Context) ([]UserOut, error) {
|
||||
return mapUsersOutErr(r.db.User.Query().WithGroup().All(ctx))
|
||||
return mapUsersOutErr(r.db.User.Query().WithGroups().All(ctx))
|
||||
}
|
||||
|
||||
func (r *UserRepository) Create(ctx context.Context, usr UserCreate) (UserOut, error) {
|
||||
@@ -99,8 +110,9 @@ func (r *UserRepository) Create(ctx context.Context, usr UserCreate) (UserOut, e
|
||||
SetName(usr.Name).
|
||||
SetEmail(usr.Email).
|
||||
SetIsSuperuser(usr.IsSuperuser).
|
||||
SetGroupID(usr.GroupID).
|
||||
SetRole(role)
|
||||
SetDefaultGroupID(usr.DefaultGroupID).
|
||||
SetRole(role).
|
||||
AddGroupIDs(usr.DefaultGroupID)
|
||||
|
||||
// Only set password if provided (non-nil)
|
||||
if usr.Password != nil {
|
||||
@@ -126,10 +138,11 @@ func (r *UserRepository) CreateWithOIDC(ctx context.Context, usr UserCreate, iss
|
||||
SetName(usr.Name).
|
||||
SetEmail(usr.Email).
|
||||
SetIsSuperuser(usr.IsSuperuser).
|
||||
SetGroupID(usr.GroupID).
|
||||
SetDefaultGroupID(usr.DefaultGroupID).
|
||||
SetRole(role).
|
||||
SetOidcIssuer(issuer).
|
||||
SetOidcSubject(subject)
|
||||
SetOidcSubject(subject).
|
||||
AddGroupIDs(usr.DefaultGroupID)
|
||||
|
||||
if usr.Password != nil {
|
||||
createQuery = createQuery.SetPassword(*usr.Password)
|
||||
@@ -183,6 +196,6 @@ func (r *UserRepository) SetOIDCIdentity(ctx context.Context, uid uuid.UUID, iss
|
||||
func (r *UserRepository) GetOneOIDC(ctx context.Context, issuer, subject string) (UserOut, error) {
|
||||
return mapUserOutErr(r.db.User.Query().
|
||||
Where(user.OidcIssuerEQ(issuer), user.OidcSubjectEQ(subject)).
|
||||
WithGroup().
|
||||
WithGroups().
|
||||
Only(ctx))
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -11,11 +12,11 @@ import (
|
||||
func userFactory() UserCreate {
|
||||
password := fk.Str(10)
|
||||
return UserCreate{
|
||||
Name: fk.Str(10),
|
||||
Email: fk.Email(),
|
||||
Password: &password,
|
||||
IsSuperuser: fk.Bool(),
|
||||
GroupID: tGroup.ID,
|
||||
Name: fk.Str(10),
|
||||
Email: fk.Email(),
|
||||
Password: &password,
|
||||
IsSuperuser: fk.Bool(),
|
||||
DefaultGroupID: tGroup.ID,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +88,8 @@ func TestUserRepo_GetAll(t *testing.T) {
|
||||
assert.Equal(t, usr.Email, usr2.Email)
|
||||
|
||||
// Check groups are loaded
|
||||
assert.NotNil(t, usr2.GroupID)
|
||||
assert.NotEqual(t, uuid.Nil, usr2.DefaultGroupID)
|
||||
assert.Greater(t, len(usr2.GroupIDs), 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user