mirror of
https://github.com/sysadminsmedia/homebox.git
synced 2026-01-01 10:37:22 +01:00
Compare commits
13 Commits
main
...
mk/multi-g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6dc801d024 | ||
|
|
2e5a2c9323 | ||
|
|
301098bad5 | ||
|
|
e6c1a5a47f | ||
|
|
6c4ce49093 | ||
|
|
825eda0f00 | ||
|
|
ab9b821de9 | ||
|
|
74bdaa47d2 | ||
|
|
f3b4c0cad3 | ||
|
|
9f5095a1d2 | ||
|
|
3fcb1ccfd0 | ||
|
|
70adb00400 | ||
|
|
dd873a95da |
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/sysadminsmedia/homebox/backend/internal/core/services"
|
"github.com/sysadminsmedia/homebox/backend/internal/core/services"
|
||||||
|
"github.com/sysadminsmedia/homebox/backend/internal/data/ent"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *app) SetupDemo() error {
|
func (a *app) SetupDemo() error {
|
||||||
@@ -29,21 +30,26 @@ func (a *app) SetupDemo() error {
|
|||||||
Password: "demo",
|
Password: "demo",
|
||||||
}
|
}
|
||||||
|
|
||||||
// First check if we've already setup a demo user and skip if so
|
// If demo user already exists, skip all demo seeding tasks
|
||||||
log.Debug().Msg("Checking if demo user already exists")
|
if a.services.User.ExistsByEmail(ctx, registration.Email) {
|
||||||
_, err := a.services.User.Login(ctx, registration.Email, registration.Password, false)
|
log.Info().Msg("Demo user already exists; skipping demo seeding")
|
||||||
if err == nil {
|
|
||||||
log.Info().Msg("Demo user already exists, skipping setup")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug().Msg("Demo user does not exist, setting up demo")
|
// Otherwise, register the demo user
|
||||||
_, err = a.services.User.RegisterUser(ctx, registration)
|
log.Debug().Msg("Registering demo user")
|
||||||
|
_, err := a.services.User.RegisterUser(ctx, registration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if ent.IsConstraintError(err) {
|
||||||
|
// Concurrent creation race: treat as exists and skip
|
||||||
|
log.Info().Msg("Demo user concurrently created; skipping seeding")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
log.Err(err).Msg("Failed to register demo user")
|
log.Err(err).Msg("Failed to register demo user")
|
||||||
return errors.New("failed to setup demo")
|
return errors.New("failed to setup demo")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Login the demo user to get a token
|
||||||
token, err := a.services.User.Login(ctx, registration.Email, registration.Password, false)
|
token, err := a.services.User.Login(ctx, registration.Email, registration.Password, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg("Failed to login demo user")
|
log.Err(err).Msg("Failed to login demo user")
|
||||||
@@ -55,7 +61,7 @@ func (a *app) SetupDemo() error {
|
|||||||
return errors.New("failed to setup demo")
|
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 {
|
if err != nil {
|
||||||
log.Err(err).Msg("Failed to import CSV")
|
log.Err(err).Msg("Failed to import CSV")
|
||||||
return errors.New("failed to setup demo")
|
return errors.New("failed to setup demo")
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/hay-kot/httpkit/errchain"
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
"github.com/sysadminsmedia/homebox/backend/internal/core/services"
|
"github.com/sysadminsmedia/homebox/backend/internal/core/services"
|
||||||
"github.com/sysadminsmedia/homebox/backend/internal/data/repo"
|
"github.com/sysadminsmedia/homebox/backend/internal/data/repo"
|
||||||
@@ -22,6 +23,10 @@ type (
|
|||||||
ExpiresAt time.Time `json:"expiresAt"`
|
ExpiresAt time.Time `json:"expiresAt"`
|
||||||
Uses int `json:"uses"`
|
Uses int `json:"uses"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GroupMemberAdd struct {
|
||||||
|
UserID uuid.UUID `json:"userId" validate:"required"`
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// HandleGroupGet godoc
|
// HandleGroupGet godoc
|
||||||
@@ -95,3 +100,132 @@ func (ctrl *V1Controller) HandleGroupInvitationsCreate() errchain.HandlerFunc {
|
|||||||
|
|
||||||
return adapters.Action(fn, http.StatusCreated)
|
return adapters.Action(fn, http.StatusCreated)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HandleGroupsGetAll godoc
|
||||||
|
//
|
||||||
|
// @Summary Get All Groups
|
||||||
|
// @Tags Group
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} []repo.Group
|
||||||
|
// @Router /v1/groups [Get]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleGroupsGetAll() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request) ([]repo.Group, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
return ctrl.repo.Groups.GetAllGroups(auth)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.Command(fn, http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleGroupCreate godoc
|
||||||
|
//
|
||||||
|
// @Summary Create Group
|
||||||
|
// @Tags Group
|
||||||
|
// @Produce json
|
||||||
|
// @Param name body string true "Group Name"
|
||||||
|
// @Success 201 {object} repo.Group
|
||||||
|
// @Router /v1/groups/{id} [Post]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleGroupCreate() errchain.HandlerFunc {
|
||||||
|
type CreateRequest struct {
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn := func(r *http.Request, body CreateRequest) (repo.Group, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
return ctrl.svc.Group.CreateGroup(auth, body.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.Action(fn, http.StatusCreated)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleGroupDelete godoc
|
||||||
|
//
|
||||||
|
// @Summary Delete Group
|
||||||
|
// @Tags Group
|
||||||
|
// @Produce json
|
||||||
|
// @Success 204
|
||||||
|
// @Router /v1/groups/{id} [Delete]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleGroupDelete() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request) (any, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
err := ctrl.svc.Group.DeleteGroup(auth)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.Command(fn, http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleGroupInvitationsGetAll godoc
|
||||||
|
//
|
||||||
|
// @Summary Get All Group Invitations
|
||||||
|
// @Tags Group
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} []repo.GroupInvitation
|
||||||
|
// @Router /v1/groups/invitations [Get]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleGroupInvitationsGetAll() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request) ([]repo.GroupInvitation, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
return ctrl.repo.Groups.InvitationGetAll(auth, auth.GID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.Command(fn, http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleGroupMembersGetAll godoc
|
||||||
|
//
|
||||||
|
// @Summary Get All Group Members
|
||||||
|
// @Tags Group
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} []repo.UserOut
|
||||||
|
// @Router /v1/groups/{id}/members [Get]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleGroupMembersGetAll() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request) ([]repo.UserOut, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
return ctrl.repo.Users.GetUsersByGroupID(auth, auth.GID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.Command(fn, http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleGroupMemberAdd godoc
|
||||||
|
//
|
||||||
|
// @Summary Add User to Group
|
||||||
|
// @Tags Group
|
||||||
|
// @Produce json
|
||||||
|
// @Param payload body GroupMemberAdd true "User ID"
|
||||||
|
// @Success 204
|
||||||
|
// @Router /v1/groups/{id}/members [Post]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleGroupMemberAdd() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request, body GroupMemberAdd) (any, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
err := ctrl.svc.Group.AddMember(auth, body.UserID)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.Action(fn, http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleGroupMemberRemove godoc
|
||||||
|
//
|
||||||
|
// @Summary Remove User from Group
|
||||||
|
// @Tags Group
|
||||||
|
// @Produce json
|
||||||
|
// @Param user_id path string true "User ID"
|
||||||
|
// @Success 204
|
||||||
|
// @Router /v1/groups/{id}/members/{user_id} [Delete]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleGroupMemberRemove() errchain.HandlerFunc {
|
||||||
|
fn := func(r *http.Request, userID uuid.UUID) (any, error) {
|
||||||
|
auth := services.NewContext(r.Context())
|
||||||
|
err := ctrl.svc.Group.RemoveMember(auth, userID)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.CommandID("user_id", fn, http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|||||||
@@ -337,9 +337,9 @@ func (ctrl *V1Controller) HandleItemsImport() errchain.HandlerFunc {
|
|||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
user := services.UseUserCtx(r.Context())
|
tenant := services.UseTenantCtx(r.Context())
|
||||||
|
|
||||||
_, err = ctrl.svc.Items.CsvImport(r.Context(), user.GroupID, file)
|
_, err = ctrl.svc.Items.CsvImport(r.Context(), tenant, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg("failed to import items")
|
log.Err(err).Msg("failed to import items")
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"github.com/hay-kot/httpkit/errchain"
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
"github.com/sysadminsmedia/homebox/backend/internal/core/services"
|
"github.com/sysadminsmedia/homebox/backend/internal/core/services"
|
||||||
"net/http"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// HandleBillOfMaterialsExport godoc
|
// HandleBillOfMaterialsExport godoc
|
||||||
@@ -16,9 +17,9 @@ import (
|
|||||||
// @Security Bearer
|
// @Security Bearer
|
||||||
func (ctrl *V1Controller) HandleBillOfMaterialsExport() errchain.HandlerFunc {
|
func (ctrl *V1Controller) HandleBillOfMaterialsExport() errchain.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
actor := services.UseUserCtx(r.Context())
|
tenant := services.UseTenantCtx(r.Context())
|
||||||
|
|
||||||
csv, err := ctrl.svc.Items.ExportBillOfMaterialsCSV(r.Context(), actor.GroupID)
|
csv, err := ctrl.svc.Items.ExportBillOfMaterialsCSV(r.Context(), tenant)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/hay-kot/httpkit/errchain"
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
v1 "github.com/sysadminsmedia/homebox/backend/app/api/handlers/v1"
|
v1 "github.com/sysadminsmedia/homebox/backend/app/api/handlers/v1"
|
||||||
"github.com/sysadminsmedia/homebox/backend/internal/core/services"
|
"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)
|
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,10 +82,13 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
|
|||||||
|
|
||||||
userMW := []errchain.Middleware{
|
userMW := []errchain.Middleware{
|
||||||
a.mwAuthToken,
|
a.mwAuthToken,
|
||||||
|
a.mwTenant,
|
||||||
a.mwRoles(RoleModeOr, authroles.RoleUser.String()),
|
a.mwRoles(RoleModeOr, authroles.RoleUser.String()),
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Get("/ws/events", chain.ToHandlerFunc(v1Ctrl.HandleCacheWS(), userMW...))
|
r.Get("/ws/events", chain.ToHandlerFunc(v1Ctrl.HandleCacheWS(), userMW...))
|
||||||
|
|
||||||
|
// User management endpoints
|
||||||
r.Get("/users/self", chain.ToHandlerFunc(v1Ctrl.HandleUserSelf(), userMW...))
|
r.Get("/users/self", chain.ToHandlerFunc(v1Ctrl.HandleUserSelf(), userMW...))
|
||||||
r.Put("/users/self", chain.ToHandlerFunc(v1Ctrl.HandleUserSelfUpdate(), userMW...))
|
r.Put("/users/self", chain.ToHandlerFunc(v1Ctrl.HandleUserSelfUpdate(), userMW...))
|
||||||
r.Delete("/users/self", chain.ToHandlerFunc(v1Ctrl.HandleUserSelfDelete(), userMW...))
|
r.Delete("/users/self", chain.ToHandlerFunc(v1Ctrl.HandleUserSelfDelete(), userMW...))
|
||||||
@@ -93,16 +96,25 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
|
|||||||
r.Get("/users/refresh", chain.ToHandlerFunc(v1Ctrl.HandleAuthRefresh(), userMW...))
|
r.Get("/users/refresh", chain.ToHandlerFunc(v1Ctrl.HandleAuthRefresh(), userMW...))
|
||||||
r.Put("/users/self/change-password", chain.ToHandlerFunc(v1Ctrl.HandleUserSelfChangePassword(), userMW...))
|
r.Put("/users/self/change-password", chain.ToHandlerFunc(v1Ctrl.HandleUserSelfChangePassword(), userMW...))
|
||||||
|
|
||||||
|
// Group management endpoints
|
||||||
|
r.Get("/groups", chain.ToHandlerFunc(v1Ctrl.HandleGroupsGetAll(), userMW...))
|
||||||
|
r.Get("/groups/{id}", chain.ToHandlerFunc(v1Ctrl.HandleGroupGet(), userMW...))
|
||||||
|
r.Post("/groups/{id}", chain.ToHandlerFunc(v1Ctrl.HandleGroupCreate(), userMW...))
|
||||||
|
r.Put("/groups/{id}", chain.ToHandlerFunc(v1Ctrl.HandleGroupUpdate(), userMW...))
|
||||||
|
r.Delete("/groups/{id}", chain.ToHandlerFunc(v1Ctrl.HandleGroupDelete(), userMW...))
|
||||||
|
|
||||||
|
r.Get("/groups/{id}/members", chain.ToHandlerFunc(v1Ctrl.HandleGroupMembersGetAll(), userMW...))
|
||||||
|
r.Post("/groups/{id}/members", chain.ToHandlerFunc(v1Ctrl.HandleGroupMemberAdd(), userMW...))
|
||||||
|
r.Delete("/groups/{id}/members/{user_id}", chain.ToHandlerFunc(v1Ctrl.HandleGroupMemberRemove(), userMW...))
|
||||||
|
|
||||||
|
r.Get("/groups/invitations", chain.ToHandlerFunc(v1Ctrl.HandleGroupInvitationsGetAll(), userMW...))
|
||||||
r.Post("/groups/invitations", chain.ToHandlerFunc(v1Ctrl.HandleGroupInvitationsCreate(), userMW...))
|
r.Post("/groups/invitations", chain.ToHandlerFunc(v1Ctrl.HandleGroupInvitationsCreate(), userMW...))
|
||||||
r.Get("/groups/statistics", chain.ToHandlerFunc(v1Ctrl.HandleGroupStatistics(), userMW...))
|
r.Get("/groups/statistics", chain.ToHandlerFunc(v1Ctrl.HandleGroupStatistics(), userMW...))
|
||||||
r.Get("/groups/statistics/purchase-price", chain.ToHandlerFunc(v1Ctrl.HandleGroupStatisticsPriceOverTime(), userMW...))
|
r.Get("/groups/statistics/purchase-price", chain.ToHandlerFunc(v1Ctrl.HandleGroupStatisticsPriceOverTime(), userMW...))
|
||||||
r.Get("/groups/statistics/locations", chain.ToHandlerFunc(v1Ctrl.HandleGroupStatisticsLocations(), userMW...))
|
r.Get("/groups/statistics/locations", chain.ToHandlerFunc(v1Ctrl.HandleGroupStatisticsLocations(), userMW...))
|
||||||
r.Get("/groups/statistics/labels", chain.ToHandlerFunc(v1Ctrl.HandleGroupStatisticsLabels(), userMW...))
|
r.Get("/groups/statistics/labels", chain.ToHandlerFunc(v1Ctrl.HandleGroupStatisticsLabels(), userMW...))
|
||||||
|
|
||||||
// TODO: I don't like /groups being the URL for users
|
// Action endpoints
|
||||||
r.Get("/groups", chain.ToHandlerFunc(v1Ctrl.HandleGroupGet(), userMW...))
|
|
||||||
r.Put("/groups", chain.ToHandlerFunc(v1Ctrl.HandleGroupUpdate(), userMW...))
|
|
||||||
|
|
||||||
r.Post("/actions/ensure-asset-ids", chain.ToHandlerFunc(v1Ctrl.HandleEnsureAssetID(), userMW...))
|
r.Post("/actions/ensure-asset-ids", chain.ToHandlerFunc(v1Ctrl.HandleEnsureAssetID(), userMW...))
|
||||||
r.Post("/actions/zero-item-time-fields", chain.ToHandlerFunc(v1Ctrl.HandleItemDateZeroOut(), userMW...))
|
r.Post("/actions/zero-item-time-fields", chain.ToHandlerFunc(v1Ctrl.HandleItemDateZeroOut(), userMW...))
|
||||||
r.Post("/actions/ensure-import-refs", chain.ToHandlerFunc(v1Ctrl.HandleEnsureImportRefs(), userMW...))
|
r.Post("/actions/ensure-import-refs", chain.ToHandlerFunc(v1Ctrl.HandleEnsureImportRefs(), userMW...))
|
||||||
@@ -110,6 +122,7 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
|
|||||||
r.Post("/actions/create-missing-thumbnails", chain.ToHandlerFunc(v1Ctrl.HandleCreateMissingThumbnails(), userMW...))
|
r.Post("/actions/create-missing-thumbnails", chain.ToHandlerFunc(v1Ctrl.HandleCreateMissingThumbnails(), userMW...))
|
||||||
r.Post("/actions/wipe-inventory", chain.ToHandlerFunc(v1Ctrl.HandleWipeInventory(), userMW...))
|
r.Post("/actions/wipe-inventory", chain.ToHandlerFunc(v1Ctrl.HandleWipeInventory(), userMW...))
|
||||||
|
|
||||||
|
// Location endpoints
|
||||||
r.Get("/locations", chain.ToHandlerFunc(v1Ctrl.HandleLocationGetAll(), userMW...))
|
r.Get("/locations", chain.ToHandlerFunc(v1Ctrl.HandleLocationGetAll(), userMW...))
|
||||||
r.Post("/locations", chain.ToHandlerFunc(v1Ctrl.HandleLocationCreate(), userMW...))
|
r.Post("/locations", chain.ToHandlerFunc(v1Ctrl.HandleLocationCreate(), userMW...))
|
||||||
r.Get("/locations/tree", chain.ToHandlerFunc(v1Ctrl.HandleLocationTreeQuery(), userMW...))
|
r.Get("/locations/tree", chain.ToHandlerFunc(v1Ctrl.HandleLocationTreeQuery(), userMW...))
|
||||||
@@ -117,12 +130,14 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
|
|||||||
r.Put("/locations/{id}", chain.ToHandlerFunc(v1Ctrl.HandleLocationUpdate(), userMW...))
|
r.Put("/locations/{id}", chain.ToHandlerFunc(v1Ctrl.HandleLocationUpdate(), userMW...))
|
||||||
r.Delete("/locations/{id}", chain.ToHandlerFunc(v1Ctrl.HandleLocationDelete(), userMW...))
|
r.Delete("/locations/{id}", chain.ToHandlerFunc(v1Ctrl.HandleLocationDelete(), userMW...))
|
||||||
|
|
||||||
|
// Labels (tags) endpoints
|
||||||
r.Get("/labels", chain.ToHandlerFunc(v1Ctrl.HandleLabelsGetAll(), userMW...))
|
r.Get("/labels", chain.ToHandlerFunc(v1Ctrl.HandleLabelsGetAll(), userMW...))
|
||||||
r.Post("/labels", chain.ToHandlerFunc(v1Ctrl.HandleLabelsCreate(), userMW...))
|
r.Post("/labels", chain.ToHandlerFunc(v1Ctrl.HandleLabelsCreate(), userMW...))
|
||||||
r.Get("/labels/{id}", chain.ToHandlerFunc(v1Ctrl.HandleLabelGet(), userMW...))
|
r.Get("/labels/{id}", chain.ToHandlerFunc(v1Ctrl.HandleLabelGet(), userMW...))
|
||||||
r.Put("/labels/{id}", chain.ToHandlerFunc(v1Ctrl.HandleLabelUpdate(), userMW...))
|
r.Put("/labels/{id}", chain.ToHandlerFunc(v1Ctrl.HandleLabelUpdate(), userMW...))
|
||||||
r.Delete("/labels/{id}", chain.ToHandlerFunc(v1Ctrl.HandleLabelDelete(), userMW...))
|
r.Delete("/labels/{id}", chain.ToHandlerFunc(v1Ctrl.HandleLabelDelete(), userMW...))
|
||||||
|
|
||||||
|
// Item endpoints
|
||||||
r.Get("/items", chain.ToHandlerFunc(v1Ctrl.HandleItemsGetAll(), userMW...))
|
r.Get("/items", chain.ToHandlerFunc(v1Ctrl.HandleItemsGetAll(), userMW...))
|
||||||
r.Post("/items", chain.ToHandlerFunc(v1Ctrl.HandleItemsCreate(), userMW...))
|
r.Post("/items", chain.ToHandlerFunc(v1Ctrl.HandleItemsCreate(), userMW...))
|
||||||
r.Post("/items/import", chain.ToHandlerFunc(v1Ctrl.HandleItemsImport(), userMW...))
|
r.Post("/items/import", chain.ToHandlerFunc(v1Ctrl.HandleItemsImport(), userMW...))
|
||||||
@@ -137,10 +152,12 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
|
|||||||
r.Delete("/items/{id}", chain.ToHandlerFunc(v1Ctrl.HandleItemDelete(), userMW...))
|
r.Delete("/items/{id}", chain.ToHandlerFunc(v1Ctrl.HandleItemDelete(), userMW...))
|
||||||
r.Post("/items/{id}/duplicate", chain.ToHandlerFunc(v1Ctrl.HandleItemDuplicate(), userMW...))
|
r.Post("/items/{id}/duplicate", chain.ToHandlerFunc(v1Ctrl.HandleItemDuplicate(), userMW...))
|
||||||
|
|
||||||
|
// Item attachment endpoints
|
||||||
r.Post("/items/{id}/attachments", chain.ToHandlerFunc(v1Ctrl.HandleItemAttachmentCreate(), userMW...))
|
r.Post("/items/{id}/attachments", chain.ToHandlerFunc(v1Ctrl.HandleItemAttachmentCreate(), userMW...))
|
||||||
r.Put("/items/{id}/attachments/{attachment_id}", chain.ToHandlerFunc(v1Ctrl.HandleItemAttachmentUpdate(), userMW...))
|
r.Put("/items/{id}/attachments/{attachment_id}", chain.ToHandlerFunc(v1Ctrl.HandleItemAttachmentUpdate(), userMW...))
|
||||||
r.Delete("/items/{id}/attachments/{attachment_id}", chain.ToHandlerFunc(v1Ctrl.HandleItemAttachmentDelete(), userMW...))
|
r.Delete("/items/{id}/attachments/{attachment_id}", chain.ToHandlerFunc(v1Ctrl.HandleItemAttachmentDelete(), userMW...))
|
||||||
|
|
||||||
|
// Item maintenance endpoints
|
||||||
r.Get("/items/{id}/maintenance", chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceLogGet(), userMW...))
|
r.Get("/items/{id}/maintenance", chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceLogGet(), userMW...))
|
||||||
r.Post("/items/{id}/maintenance", chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceEntryCreate(), userMW...))
|
r.Post("/items/{id}/maintenance", chain.ToHandlerFunc(v1Ctrl.HandleMaintenanceEntryCreate(), userMW...))
|
||||||
|
|
||||||
|
|||||||
@@ -243,15 +243,18 @@ const docTemplate = `{
|
|||||||
"tags": [
|
"tags": [
|
||||||
"Group"
|
"Group"
|
||||||
],
|
],
|
||||||
"summary": "Get Group",
|
"summary": "Get All Groups",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
"$ref": "#/definitions/repo.Group"
|
"$ref": "#/definitions/repo.Group"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"put": {
|
"put": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -288,6 +291,31 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/v1/groups/invitations": {
|
"/v1/groups/invitations": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Get All Group Invitations",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/repo.GroupInvitation"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
@@ -438,6 +466,147 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/v1/groups/{id}": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Create Group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Group Name",
|
||||||
|
"name": "name",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": "Created",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/repo.Group"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Delete Group",
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/v1/groups/{id}/members": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Get All Group Members",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/repo.UserOut"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Add User to Group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "User ID",
|
||||||
|
"name": "payload",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1.GroupMemberAdd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/v1/groups/{id}/members/{user_id}": {
|
||||||
|
"delete": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Remove User from Group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "User ID",
|
||||||
|
"name": "user_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/v1/items": {
|
"/v1/items": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -3529,6 +3698,10 @@ const docTemplate = `{
|
|||||||
"description": "CreatedAt holds the value of the \"created_at\" field.",
|
"description": "CreatedAt holds the value of the \"created_at\" field.",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"default_group_id": {
|
||||||
|
"description": "DefaultGroupID holds the value of the \"default_group_id\" field.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"edges": {
|
"edges": {
|
||||||
"description": "Edges holds the relations/edges for other nodes in the graph.\nThe values are being populated by the UserQuery when eager-loading is set.",
|
"description": "Edges holds the relations/edges for other nodes in the graph.\nThe values are being populated by the UserQuery when eager-loading is set.",
|
||||||
"allOf": [
|
"allOf": [
|
||||||
@@ -3589,13 +3762,12 @@ const docTemplate = `{
|
|||||||
"$ref": "#/definitions/ent.AuthTokens"
|
"$ref": "#/definitions/ent.AuthTokens"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"group": {
|
"groups": {
|
||||||
"description": "Group holds the value of the group edge.",
|
"description": "Groups holds the value of the groups edge.",
|
||||||
"allOf": [
|
"type": "array",
|
||||||
{
|
"items": {
|
||||||
"$ref": "#/definitions/ent.Group"
|
"$ref": "#/definitions/ent.Group"
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"notifiers": {
|
"notifiers": {
|
||||||
"description": "Notifiers holds the value of the notifiers edge.",
|
"description": "Notifiers holds the value of the notifiers edge.",
|
||||||
@@ -3689,6 +3861,23 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"repo.GroupInvitation": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"expiresAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"$ref": "#/definitions/repo.Group"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"uses": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"repo.GroupStatistics": {
|
"repo.GroupStatistics": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -4906,14 +5095,17 @@ const docTemplate = `{
|
|||||||
"repo.UserOut": {
|
"repo.UserOut": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"defaultGroupId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"email": {
|
"email": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"groupId": {
|
"groupIds": {
|
||||||
"type": "string"
|
"type": "array",
|
||||||
},
|
"items": {
|
||||||
"groupName": {
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@@ -5134,6 +5326,17 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"v1.GroupMemberAdd": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"userId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"userId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"v1.ItemAttachmentToken": {
|
"v1.ItemAttachmentToken": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@@ -242,19 +242,22 @@
|
|||||||
"tags": [
|
"tags": [
|
||||||
"Group"
|
"Group"
|
||||||
],
|
],
|
||||||
"summary": "Get Group",
|
"summary": "Get All Groups",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
"$ref": "#/components/schemas/repo.Group"
|
"$ref": "#/components/schemas/repo.Group"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"put": {
|
"put": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -292,6 +295,32 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/v1/groups/invitations": {
|
"/v1/groups/invitations": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Get All Group Invitations",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/repo.GroupInvitation"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
@@ -451,6 +480,142 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/v1/groups/{id}": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Create Group",
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Group Name",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": "Created",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/repo.Group"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Delete Group",
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/v1/groups/{id}/members": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Get All Group Members",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/repo.UserOut"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Add User to Group",
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/v1.GroupMemberAdd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "User ID",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/v1/groups/{id}/members/{user_id}": {
|
||||||
|
"delete": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Remove User from Group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "User ID",
|
||||||
|
"name": "user_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/v1/items": {
|
"/v1/items": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -3727,6 +3892,10 @@
|
|||||||
"description": "CreatedAt holds the value of the \"created_at\" field.",
|
"description": "CreatedAt holds the value of the \"created_at\" field.",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"default_group_id": {
|
||||||
|
"description": "DefaultGroupID holds the value of the \"default_group_id\" field.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"edges": {
|
"edges": {
|
||||||
"description": "Edges holds the relations/edges for other nodes in the graph.\nThe values are being populated by the UserQuery when eager-loading is set.",
|
"description": "Edges holds the relations/edges for other nodes in the graph.\nThe values are being populated by the UserQuery when eager-loading is set.",
|
||||||
"allOf": [
|
"allOf": [
|
||||||
@@ -3787,13 +3956,12 @@
|
|||||||
"$ref": "#/components/schemas/ent.AuthTokens"
|
"$ref": "#/components/schemas/ent.AuthTokens"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"group": {
|
"groups": {
|
||||||
"description": "Group holds the value of the group edge.",
|
"description": "Groups holds the value of the groups edge.",
|
||||||
"allOf": [
|
"type": "array",
|
||||||
{
|
"items": {
|
||||||
"$ref": "#/components/schemas/ent.Group"
|
"$ref": "#/components/schemas/ent.Group"
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"notifiers": {
|
"notifiers": {
|
||||||
"description": "Notifiers holds the value of the notifiers edge.",
|
"description": "Notifiers holds the value of the notifiers edge.",
|
||||||
@@ -3887,6 +4055,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"repo.GroupInvitation": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"expiresAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"$ref": "#/components/schemas/repo.Group"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"uses": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"repo.GroupStatistics": {
|
"repo.GroupStatistics": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -5104,14 +5289,17 @@
|
|||||||
"repo.UserOut": {
|
"repo.UserOut": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"defaultGroupId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"email": {
|
"email": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"groupId": {
|
"groupIds": {
|
||||||
"type": "string"
|
"type": "array",
|
||||||
},
|
"items": {
|
||||||
"groupName": {
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@@ -5332,6 +5520,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"v1.GroupMemberAdd": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"userId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"userId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"v1.ItemAttachmentToken": {
|
"v1.ItemAttachmentToken": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@@ -142,13 +142,15 @@ paths:
|
|||||||
- Bearer: []
|
- Bearer: []
|
||||||
tags:
|
tags:
|
||||||
- Group
|
- Group
|
||||||
summary: Get Group
|
summary: Get All Groups
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
$ref: "#/components/schemas/repo.Group"
|
$ref: "#/components/schemas/repo.Group"
|
||||||
put:
|
put:
|
||||||
security:
|
security:
|
||||||
@@ -171,6 +173,21 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/repo.Group"
|
$ref: "#/components/schemas/repo.Group"
|
||||||
/v1/groups/invitations:
|
/v1/groups/invitations:
|
||||||
|
get:
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
summary: Get All Group Invitations
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/repo.GroupInvitation"
|
||||||
post:
|
post:
|
||||||
security:
|
security:
|
||||||
- Bearer: []
|
- Bearer: []
|
||||||
@@ -262,6 +279,85 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/repo.ValueOverTime"
|
$ref: "#/components/schemas/repo.ValueOverTime"
|
||||||
|
"/v1/groups/{id}":
|
||||||
|
post:
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
summary: Create Group
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: Group Name
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
"201":
|
||||||
|
description: Created
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/repo.Group"
|
||||||
|
delete:
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
summary: Delete Group
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
|
"/v1/groups/{id}/members":
|
||||||
|
get:
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
summary: Get All Group Members
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/repo.UserOut"
|
||||||
|
post:
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
summary: Add User to Group
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/v1.GroupMemberAdd"
|
||||||
|
description: User ID
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
|
"/v1/groups/{id}/members/{user_id}":
|
||||||
|
delete:
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
summary: Remove User from Group
|
||||||
|
parameters:
|
||||||
|
- description: User ID
|
||||||
|
name: user_id
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
/v1/items:
|
/v1/items:
|
||||||
get:
|
get:
|
||||||
security:
|
security:
|
||||||
@@ -2322,6 +2418,9 @@ components:
|
|||||||
created_at:
|
created_at:
|
||||||
description: CreatedAt holds the value of the "created_at" field.
|
description: CreatedAt holds the value of the "created_at" field.
|
||||||
type: string
|
type: string
|
||||||
|
default_group_id:
|
||||||
|
description: DefaultGroupID holds the value of the "default_group_id" field.
|
||||||
|
type: string
|
||||||
edges:
|
edges:
|
||||||
description: >-
|
description: >-
|
||||||
Edges holds the relations/edges for other nodes in the graph.
|
Edges holds the relations/edges for other nodes in the graph.
|
||||||
@@ -2365,10 +2464,11 @@ components:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/ent.AuthTokens"
|
$ref: "#/components/schemas/ent.AuthTokens"
|
||||||
group:
|
groups:
|
||||||
description: Group holds the value of the group edge.
|
description: Groups holds the value of the groups edge.
|
||||||
allOf:
|
type: array
|
||||||
- $ref: "#/components/schemas/ent.Group"
|
items:
|
||||||
|
$ref: "#/components/schemas/ent.Group"
|
||||||
notifiers:
|
notifiers:
|
||||||
description: Notifiers holds the value of the notifiers edge.
|
description: Notifiers holds the value of the notifiers edge.
|
||||||
type: array
|
type: array
|
||||||
@@ -2431,6 +2531,17 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
updatedAt:
|
updatedAt:
|
||||||
type: string
|
type: string
|
||||||
|
repo.GroupInvitation:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
expiresAt:
|
||||||
|
type: string
|
||||||
|
group:
|
||||||
|
$ref: "#/components/schemas/repo.Group"
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
uses:
|
||||||
|
type: integer
|
||||||
repo.GroupStatistics:
|
repo.GroupStatistics:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@@ -3264,11 +3375,13 @@ components:
|
|||||||
repo.UserOut:
|
repo.UserOut:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
defaultGroupId:
|
||||||
|
type: string
|
||||||
email:
|
email:
|
||||||
type: string
|
type: string
|
||||||
groupId:
|
groupIds:
|
||||||
type: string
|
type: array
|
||||||
groupName:
|
items:
|
||||||
type: string
|
type: string
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
@@ -3413,6 +3526,13 @@ components:
|
|||||||
type: integer
|
type: integer
|
||||||
maximum: 100
|
maximum: 100
|
||||||
minimum: 1
|
minimum: 1
|
||||||
|
v1.GroupMemberAdd:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- userId
|
||||||
|
properties:
|
||||||
|
userId:
|
||||||
|
type: string
|
||||||
v1.ItemAttachmentToken:
|
v1.ItemAttachmentToken:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|||||||
@@ -241,15 +241,18 @@
|
|||||||
"tags": [
|
"tags": [
|
||||||
"Group"
|
"Group"
|
||||||
],
|
],
|
||||||
"summary": "Get Group",
|
"summary": "Get All Groups",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
"$ref": "#/definitions/repo.Group"
|
"$ref": "#/definitions/repo.Group"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"put": {
|
"put": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -286,6 +289,31 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/v1/groups/invitations": {
|
"/v1/groups/invitations": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Get All Group Invitations",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/repo.GroupInvitation"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
@@ -436,6 +464,147 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/v1/groups/{id}": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Create Group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Group Name",
|
||||||
|
"name": "name",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": "Created",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/repo.Group"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Delete Group",
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/v1/groups/{id}/members": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Get All Group Members",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/repo.UserOut"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Add User to Group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "User ID",
|
||||||
|
"name": "payload",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1.GroupMemberAdd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/v1/groups/{id}/members/{user_id}": {
|
||||||
|
"delete": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Remove User from Group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "User ID",
|
||||||
|
"name": "user_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/v1/items": {
|
"/v1/items": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -3527,6 +3696,10 @@
|
|||||||
"description": "CreatedAt holds the value of the \"created_at\" field.",
|
"description": "CreatedAt holds the value of the \"created_at\" field.",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"default_group_id": {
|
||||||
|
"description": "DefaultGroupID holds the value of the \"default_group_id\" field.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"edges": {
|
"edges": {
|
||||||
"description": "Edges holds the relations/edges for other nodes in the graph.\nThe values are being populated by the UserQuery when eager-loading is set.",
|
"description": "Edges holds the relations/edges for other nodes in the graph.\nThe values are being populated by the UserQuery when eager-loading is set.",
|
||||||
"allOf": [
|
"allOf": [
|
||||||
@@ -3587,13 +3760,12 @@
|
|||||||
"$ref": "#/definitions/ent.AuthTokens"
|
"$ref": "#/definitions/ent.AuthTokens"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"group": {
|
"groups": {
|
||||||
"description": "Group holds the value of the group edge.",
|
"description": "Groups holds the value of the groups edge.",
|
||||||
"allOf": [
|
"type": "array",
|
||||||
{
|
"items": {
|
||||||
"$ref": "#/definitions/ent.Group"
|
"$ref": "#/definitions/ent.Group"
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"notifiers": {
|
"notifiers": {
|
||||||
"description": "Notifiers holds the value of the notifiers edge.",
|
"description": "Notifiers holds the value of the notifiers edge.",
|
||||||
@@ -3687,6 +3859,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"repo.GroupInvitation": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"expiresAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"$ref": "#/definitions/repo.Group"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"uses": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"repo.GroupStatistics": {
|
"repo.GroupStatistics": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -4904,14 +5093,17 @@
|
|||||||
"repo.UserOut": {
|
"repo.UserOut": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"defaultGroupId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"email": {
|
"email": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"groupId": {
|
"groupIds": {
|
||||||
"type": "string"
|
"type": "array",
|
||||||
},
|
"items": {
|
||||||
"groupName": {
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@@ -5132,6 +5324,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"v1.GroupMemberAdd": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"userId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"userId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"v1.ItemAttachmentToken": {
|
"v1.ItemAttachmentToken": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@@ -719,6 +719,9 @@ definitions:
|
|||||||
created_at:
|
created_at:
|
||||||
description: CreatedAt holds the value of the "created_at" field.
|
description: CreatedAt holds the value of the "created_at" field.
|
||||||
type: string
|
type: string
|
||||||
|
default_group_id:
|
||||||
|
description: DefaultGroupID holds the value of the "default_group_id" field.
|
||||||
|
type: string
|
||||||
edges:
|
edges:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/definitions/ent.UserEdges'
|
- $ref: '#/definitions/ent.UserEdges'
|
||||||
@@ -761,10 +764,11 @@ definitions:
|
|||||||
items:
|
items:
|
||||||
$ref: '#/definitions/ent.AuthTokens'
|
$ref: '#/definitions/ent.AuthTokens'
|
||||||
type: array
|
type: array
|
||||||
group:
|
groups:
|
||||||
allOf:
|
description: Groups holds the value of the groups edge.
|
||||||
- $ref: '#/definitions/ent.Group'
|
items:
|
||||||
description: Group holds the value of the group edge.
|
$ref: '#/definitions/ent.Group'
|
||||||
|
type: array
|
||||||
notifiers:
|
notifiers:
|
||||||
description: Notifiers holds the value of the notifiers edge.
|
description: Notifiers holds the value of the notifiers edge.
|
||||||
items:
|
items:
|
||||||
@@ -828,6 +832,17 @@ definitions:
|
|||||||
updatedAt:
|
updatedAt:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
repo.GroupInvitation:
|
||||||
|
properties:
|
||||||
|
expiresAt:
|
||||||
|
type: string
|
||||||
|
group:
|
||||||
|
$ref: '#/definitions/repo.Group'
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
uses:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
repo.GroupStatistics:
|
repo.GroupStatistics:
|
||||||
properties:
|
properties:
|
||||||
totalItemPrice:
|
totalItemPrice:
|
||||||
@@ -1660,12 +1675,14 @@ definitions:
|
|||||||
type: object
|
type: object
|
||||||
repo.UserOut:
|
repo.UserOut:
|
||||||
properties:
|
properties:
|
||||||
|
defaultGroupId:
|
||||||
|
type: string
|
||||||
email:
|
email:
|
||||||
type: string
|
type: string
|
||||||
groupId:
|
groupIds:
|
||||||
type: string
|
items:
|
||||||
groupName:
|
|
||||||
type: string
|
type: string
|
||||||
|
type: array
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
isOwner:
|
isOwner:
|
||||||
@@ -1810,6 +1827,13 @@ definitions:
|
|||||||
required:
|
required:
|
||||||
- uses
|
- uses
|
||||||
type: object
|
type: object
|
||||||
|
v1.GroupMemberAdd:
|
||||||
|
properties:
|
||||||
|
userId:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- userId
|
||||||
|
type: object
|
||||||
v1.ItemAttachmentToken:
|
v1.ItemAttachmentToken:
|
||||||
properties:
|
properties:
|
||||||
token:
|
token:
|
||||||
@@ -2032,10 +2056,12 @@ paths:
|
|||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
|
items:
|
||||||
$ref: '#/definitions/repo.Group'
|
$ref: '#/definitions/repo.Group'
|
||||||
|
type: array
|
||||||
security:
|
security:
|
||||||
- Bearer: []
|
- Bearer: []
|
||||||
summary: Get Group
|
summary: Get All Groups
|
||||||
tags:
|
tags:
|
||||||
- Group
|
- Group
|
||||||
put:
|
put:
|
||||||
@@ -2058,7 +2084,106 @@ paths:
|
|||||||
summary: Update Group
|
summary: Update Group
|
||||||
tags:
|
tags:
|
||||||
- Group
|
- Group
|
||||||
|
/v1/groups/{id}:
|
||||||
|
delete:
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Delete Group
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
post:
|
||||||
|
parameters:
|
||||||
|
- description: Group Name
|
||||||
|
in: body
|
||||||
|
name: name
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"201":
|
||||||
|
description: Created
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/repo.Group'
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Create Group
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
/v1/groups/{id}/members:
|
||||||
|
get:
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/repo.UserOut'
|
||||||
|
type: array
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Get All Group Members
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
post:
|
||||||
|
parameters:
|
||||||
|
- description: User ID
|
||||||
|
in: body
|
||||||
|
name: payload
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/v1.GroupMemberAdd'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Add User to Group
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
/v1/groups/{id}/members/{user_id}:
|
||||||
|
delete:
|
||||||
|
parameters:
|
||||||
|
- description: User ID
|
||||||
|
in: path
|
||||||
|
name: user_id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Remove User from Group
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
/v1/groups/invitations:
|
/v1/groups/invitations:
|
||||||
|
get:
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/repo.GroupInvitation'
|
||||||
|
type: array
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Get All Group Invitations
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
post:
|
post:
|
||||||
parameters:
|
parameters:
|
||||||
- description: User Data
|
- description: User Data
|
||||||
|
|||||||
@@ -325,6 +325,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.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs=
|
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/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY=
|
github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY=
|
||||||
@@ -347,6 +349,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/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 h1:Pa5SdeZL/zXPi1tJuMAPDbl4n3gQOThSL6G1p4qZ4SI=
|
||||||
github.com/olahol/melody v1.4.0/go.mod h1:GgkTl6Y7yWj/HtfD48Q5vLKPVoZOH+Qqgfa7CvJgJM4=
|
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 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=
|
||||||
@@ -389,6 +393,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/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 h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
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 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo=
|
||||||
github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs=
|
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=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ type contextKeys struct {
|
|||||||
var (
|
var (
|
||||||
ContextUser = &contextKeys{name: "User"}
|
ContextUser = &contextKeys{name: "User"}
|
||||||
ContextUserToken = &contextKeys{name: "UserToken"}
|
ContextUserToken = &contextKeys{name: "UserToken"}
|
||||||
|
ContextTenant = &contextKeys{name: "Tenant"}
|
||||||
)
|
)
|
||||||
|
|
||||||
type Context struct {
|
type Context struct {
|
||||||
@@ -33,10 +34,14 @@ type Context struct {
|
|||||||
// This extracts the users from the context and embeds it into the ServiceContext struct
|
// This extracts the users from the context and embeds it into the ServiceContext struct
|
||||||
func NewContext(ctx context.Context) Context {
|
func NewContext(ctx context.Context) Context {
|
||||||
user := UseUserCtx(ctx)
|
user := UseUserCtx(ctx)
|
||||||
|
gid := UseTenantCtx(ctx)
|
||||||
|
if gid == uuid.Nil && user != nil {
|
||||||
|
gid = user.DefaultGroupID
|
||||||
|
}
|
||||||
return Context{
|
return Context{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
UID: user.ID,
|
UID: user.ID,
|
||||||
GID: user.GroupID,
|
GID: gid,
|
||||||
User: user,
|
User: user,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,3 +69,17 @@ func UseTokenCtx(ctx context.Context) string {
|
|||||||
}
|
}
|
||||||
return ""
|
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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ package services
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/sysadminsmedia/homebox/backend/internal/sys/config"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/sysadminsmedia/homebox/backend/internal/sys/config"
|
||||||
|
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
"github.com/sysadminsmedia/homebox/backend/internal/core/currencies"
|
"github.com/sysadminsmedia/homebox/backend/internal/core/currencies"
|
||||||
"github.com/sysadminsmedia/homebox/backend/internal/core/services/reporting/eventbus"
|
"github.com/sysadminsmedia/homebox/backend/internal/core/services/reporting/eventbus"
|
||||||
@@ -33,7 +35,7 @@ func bootstrap() {
|
|||||||
ctx = context.Background()
|
ctx = context.Background()
|
||||||
)
|
)
|
||||||
|
|
||||||
tGroup, err = tRepos.Groups.GroupCreate(ctx, "test-group")
|
tGroup, err = tRepos.Groups.GroupCreate(ctx, "test-group", uuid.Nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -44,7 +46,7 @@ func bootstrap() {
|
|||||||
Email: fk.Email(),
|
Email: fk.Email(),
|
||||||
Password: &password,
|
Password: &password,
|
||||||
IsSuperuser: fk.Bool(),
|
IsSuperuser: fk.Bool(),
|
||||||
GroupID: tGroup.ID,
|
DefaultGroupID: tGroup.ID,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/sysadminsmedia/homebox/backend/internal/data/repo"
|
"github.com/sysadminsmedia/homebox/backend/internal/data/repo"
|
||||||
"github.com/sysadminsmedia/homebox/backend/pkgs/hasher"
|
"github.com/sysadminsmedia/homebox/backend/pkgs/hasher"
|
||||||
)
|
)
|
||||||
@@ -14,7 +15,7 @@ type GroupService struct {
|
|||||||
|
|
||||||
func (svc *GroupService) UpdateGroup(ctx Context, data repo.GroupUpdate) (repo.Group, error) {
|
func (svc *GroupService) UpdateGroup(ctx Context, data repo.GroupUpdate) (repo.Group, error) {
|
||||||
if data.Name == "" {
|
if data.Name == "" {
|
||||||
data.Name = ctx.User.GroupName
|
return repo.Group{}, errors.New("group name cannot be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.Currency == "" {
|
if data.Currency == "" {
|
||||||
@@ -24,6 +25,18 @@ func (svc *GroupService) UpdateGroup(ctx Context, data repo.GroupUpdate) (repo.G
|
|||||||
return svc.repos.Groups.GroupUpdate(ctx.Context, ctx.GID, data)
|
return svc.repos.Groups.GroupUpdate(ctx.Context, ctx.GID, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (svc *GroupService) CreateGroup(ctx Context, name string) (repo.Group, error) {
|
||||||
|
if name == "" {
|
||||||
|
return repo.Group{}, errors.New("group name cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
return svc.repos.Groups.GroupCreate(ctx.Context, name, ctx.UID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (svc *GroupService) DeleteGroup(ctx Context) error {
|
||||||
|
return svc.repos.Groups.GroupDelete(ctx.Context, ctx.GID)
|
||||||
|
}
|
||||||
|
|
||||||
func (svc *GroupService) NewInvitation(ctx Context, uses int, expiresAt time.Time) (string, error) {
|
func (svc *GroupService) NewInvitation(ctx Context, uses int, expiresAt time.Time) (string, error) {
|
||||||
token := hasher.GenerateToken()
|
token := hasher.GenerateToken()
|
||||||
|
|
||||||
@@ -38,3 +51,19 @@ func (svc *GroupService) NewInvitation(ctx Context, uses int, expiresAt time.Tim
|
|||||||
|
|
||||||
return token.Raw, nil
|
return token.Raw, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (svc *GroupService) AddMember(ctx Context, userID uuid.UUID) error {
|
||||||
|
if userID == uuid.Nil {
|
||||||
|
return errors.New("user ID cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
return svc.repos.Groups.AddMember(ctx.Context, ctx.GID, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (svc *GroupService) RemoveMember(ctx Context, userID uuid.UUID) error {
|
||||||
|
if userID == uuid.Nil {
|
||||||
|
return errors.New("user ID cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
return svc.repos.Groups.RemoveMember(ctx.Context, ctx.GID, userID)
|
||||||
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
|
|||||||
case "":
|
case "":
|
||||||
log.Debug().Msg("creating new group")
|
log.Debug().Msg("creating new group")
|
||||||
creatingGroup = true
|
creatingGroup = true
|
||||||
group, err = svc.repos.Groups.GroupCreate(ctx, "Home")
|
group, err = svc.repos.Groups.GroupCreate(ctx, "Home", uuid.Nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg("Failed to create group")
|
log.Err(err).Msg("Failed to create group")
|
||||||
return repo.UserOut{}, err
|
return repo.UserOut{}, err
|
||||||
@@ -85,7 +85,7 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
|
|||||||
Email: data.Email,
|
Email: data.Email,
|
||||||
Password: &hashed,
|
Password: &hashed,
|
||||||
IsSuperuser: false,
|
IsSuperuser: false,
|
||||||
GroupID: group.ID,
|
DefaultGroupID: group.ID,
|
||||||
IsOwner: creatingGroup,
|
IsOwner: creatingGroup,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
|
|||||||
if creatingGroup {
|
if creatingGroup {
|
||||||
log.Debug().Msg("creating default labels")
|
log.Debug().Msg("creating default labels")
|
||||||
for _, label := range defaultLabels() {
|
for _, label := range defaultLabels() {
|
||||||
_, err := svc.repos.Labels.Create(ctx, usr.GroupID, label)
|
_, err := svc.repos.Labels.Create(ctx, usr.DefaultGroupID, label)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return repo.UserOut{}, err
|
return repo.UserOut{}, err
|
||||||
}
|
}
|
||||||
@@ -107,7 +107,7 @@ func (svc *UserService) RegisterUser(ctx context.Context, data UserRegistration)
|
|||||||
|
|
||||||
log.Debug().Msg("creating default locations")
|
log.Debug().Msg("creating default locations")
|
||||||
for _, location := range defaultLocations() {
|
for _, location := range defaultLocations() {
|
||||||
_, err := svc.repos.Locations.Create(ctx, usr.GroupID, location)
|
_, err := svc.repos.Locations.Create(ctx, usr.DefaultGroupID, location)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return repo.UserOut{}, err
|
return repo.UserOut{}, err
|
||||||
}
|
}
|
||||||
@@ -280,7 +280,7 @@ func (svc *UserService) LoginOIDC(ctx context.Context, issuer, subject, email, n
|
|||||||
|
|
||||||
// registerOIDCUser creates a new user for OIDC authentication with issuer+subject identity.
|
// registerOIDCUser creates a new user for OIDC authentication with issuer+subject identity.
|
||||||
func (svc *UserService) registerOIDCUser(ctx context.Context, issuer, subject, email, name string) (repo.UserOut, error) {
|
func (svc *UserService) registerOIDCUser(ctx context.Context, issuer, subject, email, name string) (repo.UserOut, error) {
|
||||||
group, err := svc.repos.Groups.GroupCreate(ctx, "Home")
|
group, err := svc.repos.Groups.GroupCreate(ctx, "Home", uuid.Nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg("Failed to create group for OIDC user")
|
log.Err(err).Msg("Failed to create group for OIDC user")
|
||||||
return repo.UserOut{}, err
|
return repo.UserOut{}, err
|
||||||
@@ -291,7 +291,7 @@ func (svc *UserService) registerOIDCUser(ctx context.Context, issuer, subject, e
|
|||||||
Email: email,
|
Email: email,
|
||||||
Password: nil,
|
Password: nil,
|
||||||
IsSuperuser: false,
|
IsSuperuser: false,
|
||||||
GroupID: group.ID,
|
DefaultGroupID: group.ID,
|
||||||
IsOwner: true,
|
IsOwner: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,3 +369,30 @@ func (svc *UserService) ChangePassword(ctx Context, current string, new string)
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (svc *UserService) EnsureUserPassword(ctx context.Context, email, password string) error {
|
||||||
|
usr, err := svc.repos.Users.GetOneEmailNoEdges(ctx, email)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
match := false
|
||||||
|
if usr.PasswordHash != "" {
|
||||||
|
match, _ = hasher.CheckPasswordHash(password, usr.PasswordHash)
|
||||||
|
}
|
||||||
|
if !match {
|
||||||
|
hash, herr := hasher.HashPassword(password)
|
||||||
|
if herr != nil {
|
||||||
|
return herr
|
||||||
|
}
|
||||||
|
if cerr := svc.repos.Users.ChangePassword(ctx, usr.ID, hash); cerr != nil {
|
||||||
|
return cerr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExistsByEmail returns true if a user with the given email exists.
|
||||||
|
func (svc *UserService) ExistsByEmail(ctx context.Context, email string) bool {
|
||||||
|
_, err := svc.repos.Users.GetOneEmailNoEdges(ctx, email)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|||||||
8
backend/internal/data/ent/client.go
generated
8
backend/internal/data/ent/client.go
generated
@@ -909,7 +909,7 @@ func (c *GroupClient) QueryUsers(_m *Group) *UserQuery {
|
|||||||
step := sqlgraph.NewStep(
|
step := sqlgraph.NewStep(
|
||||||
sqlgraph.From(group.Table, group.FieldID, id),
|
sqlgraph.From(group.Table, group.FieldID, id),
|
||||||
sqlgraph.To(user.Table, user.FieldID),
|
sqlgraph.To(user.Table, user.FieldID),
|
||||||
sqlgraph.Edge(sqlgraph.O2M, false, group.UsersTable, group.UsersColumn),
|
sqlgraph.Edge(sqlgraph.M2M, true, group.UsersTable, group.UsersPrimaryKey...),
|
||||||
)
|
)
|
||||||
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
|
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
|
||||||
return fromV, nil
|
return fromV, nil
|
||||||
@@ -2711,15 +2711,15 @@ func (c *UserClient) GetX(ctx context.Context, id uuid.UUID) *User {
|
|||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryGroup queries the group edge of a User.
|
// QueryGroups queries the groups edge of a User.
|
||||||
func (c *UserClient) QueryGroup(_m *User) *GroupQuery {
|
func (c *UserClient) QueryGroups(_m *User) *GroupQuery {
|
||||||
query := (&GroupClient{config: c.config}).Query()
|
query := (&GroupClient{config: c.config}).Query()
|
||||||
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
|
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
|
||||||
id := _m.ID
|
id := _m.ID
|
||||||
step := sqlgraph.NewStep(
|
step := sqlgraph.NewStep(
|
||||||
sqlgraph.From(user.Table, user.FieldID, id),
|
sqlgraph.From(user.Table, user.FieldID, id),
|
||||||
sqlgraph.To(group.Table, group.FieldID),
|
sqlgraph.To(group.Table, group.FieldID),
|
||||||
sqlgraph.Edge(sqlgraph.M2O, true, user.GroupTable, user.GroupColumn),
|
sqlgraph.Edge(sqlgraph.M2M, false, user.GroupsTable, user.GroupsPrimaryKey...),
|
||||||
)
|
)
|
||||||
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
|
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
|
||||||
return fromV, nil
|
return fromV, nil
|
||||||
|
|||||||
14
backend/internal/data/ent/group/group.go
generated
14
backend/internal/data/ent/group/group.go
generated
@@ -39,13 +39,11 @@ const (
|
|||||||
EdgeItemTemplates = "item_templates"
|
EdgeItemTemplates = "item_templates"
|
||||||
// Table holds the table name of the group in the database.
|
// Table holds the table name of the group in the database.
|
||||||
Table = "groups"
|
Table = "groups"
|
||||||
// UsersTable is the table that holds the users relation/edge.
|
// UsersTable is the table that holds the users relation/edge. The primary key declared below.
|
||||||
UsersTable = "users"
|
UsersTable = "user_groups"
|
||||||
// UsersInverseTable is the table name for the User entity.
|
// UsersInverseTable is the table name for the User entity.
|
||||||
// It exists in this package in order to avoid circular dependency with the "user" package.
|
// It exists in this package in order to avoid circular dependency with the "user" package.
|
||||||
UsersInverseTable = "users"
|
UsersInverseTable = "users"
|
||||||
// UsersColumn is the table column denoting the users relation/edge.
|
|
||||||
UsersColumn = "group_users"
|
|
||||||
// LocationsTable is the table that holds the locations relation/edge.
|
// LocationsTable is the table that holds the locations relation/edge.
|
||||||
LocationsTable = "locations"
|
LocationsTable = "locations"
|
||||||
// LocationsInverseTable is the table name for the Location entity.
|
// LocationsInverseTable is the table name for the Location entity.
|
||||||
@@ -99,6 +97,12 @@ var Columns = []string{
|
|||||||
FieldCurrency,
|
FieldCurrency,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// UsersPrimaryKey and UsersColumn2 are the table columns denoting the
|
||||||
|
// primary key for the users relation (M2M).
|
||||||
|
UsersPrimaryKey = []string{"user_id", "group_id"}
|
||||||
|
)
|
||||||
|
|
||||||
// ValidColumn reports if the column name is valid (part of the table columns).
|
// ValidColumn reports if the column name is valid (part of the table columns).
|
||||||
func ValidColumn(column string) bool {
|
func ValidColumn(column string) bool {
|
||||||
for i := range Columns {
|
for i := range Columns {
|
||||||
@@ -253,7 +257,7 @@ func newUsersStep() *sqlgraph.Step {
|
|||||||
return sqlgraph.NewStep(
|
return sqlgraph.NewStep(
|
||||||
sqlgraph.From(Table, FieldID),
|
sqlgraph.From(Table, FieldID),
|
||||||
sqlgraph.To(UsersInverseTable, FieldID),
|
sqlgraph.To(UsersInverseTable, FieldID),
|
||||||
sqlgraph.Edge(sqlgraph.O2M, false, UsersTable, UsersColumn),
|
sqlgraph.Edge(sqlgraph.M2M, true, UsersTable, UsersPrimaryKey...),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
func newLocationsStep() *sqlgraph.Step {
|
func newLocationsStep() *sqlgraph.Step {
|
||||||
|
|||||||
2
backend/internal/data/ent/group/where.go
generated
2
backend/internal/data/ent/group/where.go
generated
@@ -291,7 +291,7 @@ func HasUsers() predicate.Group {
|
|||||||
return predicate.Group(func(s *sql.Selector) {
|
return predicate.Group(func(s *sql.Selector) {
|
||||||
step := sqlgraph.NewStep(
|
step := sqlgraph.NewStep(
|
||||||
sqlgraph.From(Table, FieldID),
|
sqlgraph.From(Table, FieldID),
|
||||||
sqlgraph.Edge(sqlgraph.O2M, false, UsersTable, UsersColumn),
|
sqlgraph.Edge(sqlgraph.M2M, true, UsersTable, UsersPrimaryKey...),
|
||||||
)
|
)
|
||||||
sqlgraph.HasNeighbors(s, step)
|
sqlgraph.HasNeighbors(s, step)
|
||||||
})
|
})
|
||||||
|
|||||||
6
backend/internal/data/ent/group_create.go
generated
6
backend/internal/data/ent/group_create.go
generated
@@ -320,10 +320,10 @@ func (_c *GroupCreate) createSpec() (*Group, *sqlgraph.CreateSpec) {
|
|||||||
}
|
}
|
||||||
if nodes := _c.mutation.UsersIDs(); len(nodes) > 0 {
|
if nodes := _c.mutation.UsersIDs(); len(nodes) > 0 {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.O2M,
|
Rel: sqlgraph.M2M,
|
||||||
Inverse: false,
|
Inverse: true,
|
||||||
Table: group.UsersTable,
|
Table: group.UsersTable,
|
||||||
Columns: []string{group.UsersColumn},
|
Columns: group.UsersPrimaryKey,
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
||||||
|
|||||||
68
backend/internal/data/ent/group_query.go
generated
68
backend/internal/data/ent/group_query.go
generated
@@ -88,7 +88,7 @@ func (_q *GroupQuery) QueryUsers() *UserQuery {
|
|||||||
step := sqlgraph.NewStep(
|
step := sqlgraph.NewStep(
|
||||||
sqlgraph.From(group.Table, group.FieldID, selector),
|
sqlgraph.From(group.Table, group.FieldID, selector),
|
||||||
sqlgraph.To(user.Table, user.FieldID),
|
sqlgraph.To(user.Table, user.FieldID),
|
||||||
sqlgraph.Edge(sqlgraph.O2M, false, group.UsersTable, group.UsersColumn),
|
sqlgraph.Edge(sqlgraph.M2M, true, group.UsersTable, group.UsersPrimaryKey...),
|
||||||
)
|
)
|
||||||
fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step)
|
fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step)
|
||||||
return fromU, nil
|
return fromU, nil
|
||||||
@@ -671,33 +671,63 @@ func (_q *GroupQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Group,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (_q *GroupQuery) loadUsers(ctx context.Context, query *UserQuery, nodes []*Group, init func(*Group), assign func(*Group, *User)) error {
|
func (_q *GroupQuery) loadUsers(ctx context.Context, query *UserQuery, nodes []*Group, init func(*Group), assign func(*Group, *User)) error {
|
||||||
fks := make([]driver.Value, 0, len(nodes))
|
edgeIDs := make([]driver.Value, len(nodes))
|
||||||
nodeids := make(map[uuid.UUID]*Group)
|
byID := make(map[uuid.UUID]*Group)
|
||||||
for i := range nodes {
|
nids := make(map[uuid.UUID]map[*Group]struct{})
|
||||||
fks = append(fks, nodes[i].ID)
|
for i, node := range nodes {
|
||||||
nodeids[nodes[i].ID] = nodes[i]
|
edgeIDs[i] = node.ID
|
||||||
|
byID[node.ID] = node
|
||||||
if init != nil {
|
if init != nil {
|
||||||
init(nodes[i])
|
init(node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
query.withFKs = true
|
query.Where(func(s *sql.Selector) {
|
||||||
query.Where(predicate.User(func(s *sql.Selector) {
|
joinT := sql.Table(group.UsersTable)
|
||||||
s.Where(sql.InValues(s.C(group.UsersColumn), fks...))
|
s.Join(joinT).On(s.C(user.FieldID), joinT.C(group.UsersPrimaryKey[0]))
|
||||||
}))
|
s.Where(sql.InValues(joinT.C(group.UsersPrimaryKey[1]), edgeIDs...))
|
||||||
neighbors, err := query.All(ctx)
|
columns := s.SelectedColumns()
|
||||||
|
s.Select(joinT.C(group.UsersPrimaryKey[1]))
|
||||||
|
s.AppendSelect(columns...)
|
||||||
|
s.SetDistinct(false)
|
||||||
|
})
|
||||||
|
if err := query.prepareQuery(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
qr := QuerierFunc(func(ctx context.Context, q Query) (Value, error) {
|
||||||
|
return query.sqlAll(ctx, func(_ context.Context, spec *sqlgraph.QuerySpec) {
|
||||||
|
assign := spec.Assign
|
||||||
|
values := spec.ScanValues
|
||||||
|
spec.ScanValues = func(columns []string) ([]any, error) {
|
||||||
|
values, err := values(columns[1:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return append([]any{new(uuid.UUID)}, values...), nil
|
||||||
|
}
|
||||||
|
spec.Assign = func(columns []string, values []any) error {
|
||||||
|
outValue := *values[0].(*uuid.UUID)
|
||||||
|
inValue := *values[1].(*uuid.UUID)
|
||||||
|
if nids[inValue] == nil {
|
||||||
|
nids[inValue] = map[*Group]struct{}{byID[outValue]: {}}
|
||||||
|
return assign(columns[1:], values[1:])
|
||||||
|
}
|
||||||
|
nids[inValue][byID[outValue]] = struct{}{}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
neighbors, err := withInterceptors[[]*User](ctx, query, qr, query.inters)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, n := range neighbors {
|
for _, n := range neighbors {
|
||||||
fk := n.group_users
|
nodes, ok := nids[n.ID]
|
||||||
if fk == nil {
|
|
||||||
return fmt.Errorf(`foreign-key "group_users" is nil for node %v`, n.ID)
|
|
||||||
}
|
|
||||||
node, ok := nodeids[*fk]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf(`unexpected referenced foreign-key "group_users" returned %v for node %v`, *fk, n.ID)
|
return fmt.Errorf(`unexpected "users" node returned %v`, n.ID)
|
||||||
|
}
|
||||||
|
for kn := range nodes {
|
||||||
|
assign(kn, n)
|
||||||
}
|
}
|
||||||
assign(node, n)
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
36
backend/internal/data/ent/group_update.go
generated
36
backend/internal/data/ent/group_update.go
generated
@@ -396,10 +396,10 @@ func (_u *GroupUpdate) sqlSave(ctx context.Context) (_node int, err error) {
|
|||||||
}
|
}
|
||||||
if _u.mutation.UsersCleared() {
|
if _u.mutation.UsersCleared() {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.O2M,
|
Rel: sqlgraph.M2M,
|
||||||
Inverse: false,
|
Inverse: true,
|
||||||
Table: group.UsersTable,
|
Table: group.UsersTable,
|
||||||
Columns: []string{group.UsersColumn},
|
Columns: group.UsersPrimaryKey,
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
||||||
@@ -409,10 +409,10 @@ func (_u *GroupUpdate) sqlSave(ctx context.Context) (_node int, err error) {
|
|||||||
}
|
}
|
||||||
if nodes := _u.mutation.RemovedUsersIDs(); len(nodes) > 0 && !_u.mutation.UsersCleared() {
|
if nodes := _u.mutation.RemovedUsersIDs(); len(nodes) > 0 && !_u.mutation.UsersCleared() {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.O2M,
|
Rel: sqlgraph.M2M,
|
||||||
Inverse: false,
|
Inverse: true,
|
||||||
Table: group.UsersTable,
|
Table: group.UsersTable,
|
||||||
Columns: []string{group.UsersColumn},
|
Columns: group.UsersPrimaryKey,
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
||||||
@@ -425,10 +425,10 @@ func (_u *GroupUpdate) sqlSave(ctx context.Context) (_node int, err error) {
|
|||||||
}
|
}
|
||||||
if nodes := _u.mutation.UsersIDs(); len(nodes) > 0 {
|
if nodes := _u.mutation.UsersIDs(); len(nodes) > 0 {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.O2M,
|
Rel: sqlgraph.M2M,
|
||||||
Inverse: false,
|
Inverse: true,
|
||||||
Table: group.UsersTable,
|
Table: group.UsersTable,
|
||||||
Columns: []string{group.UsersColumn},
|
Columns: group.UsersPrimaryKey,
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
||||||
@@ -1119,10 +1119,10 @@ func (_u *GroupUpdateOne) sqlSave(ctx context.Context) (_node *Group, err error)
|
|||||||
}
|
}
|
||||||
if _u.mutation.UsersCleared() {
|
if _u.mutation.UsersCleared() {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.O2M,
|
Rel: sqlgraph.M2M,
|
||||||
Inverse: false,
|
Inverse: true,
|
||||||
Table: group.UsersTable,
|
Table: group.UsersTable,
|
||||||
Columns: []string{group.UsersColumn},
|
Columns: group.UsersPrimaryKey,
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
||||||
@@ -1132,10 +1132,10 @@ func (_u *GroupUpdateOne) sqlSave(ctx context.Context) (_node *Group, err error)
|
|||||||
}
|
}
|
||||||
if nodes := _u.mutation.RemovedUsersIDs(); len(nodes) > 0 && !_u.mutation.UsersCleared() {
|
if nodes := _u.mutation.RemovedUsersIDs(); len(nodes) > 0 && !_u.mutation.UsersCleared() {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.O2M,
|
Rel: sqlgraph.M2M,
|
||||||
Inverse: false,
|
Inverse: true,
|
||||||
Table: group.UsersTable,
|
Table: group.UsersTable,
|
||||||
Columns: []string{group.UsersColumn},
|
Columns: group.UsersPrimaryKey,
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
||||||
@@ -1148,10 +1148,10 @@ func (_u *GroupUpdateOne) sqlSave(ctx context.Context) (_node *Group, err error)
|
|||||||
}
|
}
|
||||||
if nodes := _u.mutation.UsersIDs(); len(nodes) > 0 {
|
if nodes := _u.mutation.UsersIDs(); len(nodes) > 0 {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.O2M,
|
Rel: sqlgraph.M2M,
|
||||||
Inverse: false,
|
Inverse: true,
|
||||||
Table: group.UsersTable,
|
Table: group.UsersTable,
|
||||||
Columns: []string{group.UsersColumn},
|
Columns: group.UsersPrimaryKey,
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeUUID),
|
||||||
|
|||||||
39
backend/internal/data/ent/migrate/schema.go
generated
39
backend/internal/data/ent/migrate/schema.go
generated
@@ -468,21 +468,13 @@ var (
|
|||||||
{Name: "activated_on", Type: field.TypeTime, Nullable: true},
|
{Name: "activated_on", Type: field.TypeTime, Nullable: true},
|
||||||
{Name: "oidc_issuer", Type: field.TypeString, Nullable: true},
|
{Name: "oidc_issuer", Type: field.TypeString, Nullable: true},
|
||||||
{Name: "oidc_subject", 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},
|
||||||
}
|
}
|
||||||
// UsersTable holds the schema information for the "users" table.
|
// UsersTable holds the schema information for the "users" table.
|
||||||
UsersTable = &schema.Table{
|
UsersTable = &schema.Table{
|
||||||
Name: "users",
|
Name: "users",
|
||||||
Columns: UsersColumns,
|
Columns: UsersColumns,
|
||||||
PrimaryKey: []*schema.Column{UsersColumns[0]},
|
PrimaryKey: []*schema.Column{UsersColumns[0]},
|
||||||
ForeignKeys: []*schema.ForeignKey{
|
|
||||||
{
|
|
||||||
Symbol: "users_groups_users",
|
|
||||||
Columns: []*schema.Column{UsersColumns[12]},
|
|
||||||
RefColumns: []*schema.Column{GroupsColumns[0]},
|
|
||||||
OnDelete: schema.Cascade,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Indexes: []*schema.Index{
|
Indexes: []*schema.Index{
|
||||||
{
|
{
|
||||||
Name: "user_oidc_issuer_oidc_subject",
|
Name: "user_oidc_issuer_oidc_subject",
|
||||||
@@ -516,6 +508,31 @@ var (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
// UserGroupsColumns holds the columns for the "user_groups" table.
|
||||||
|
UserGroupsColumns = []*schema.Column{
|
||||||
|
{Name: "user_id", Type: field.TypeUUID},
|
||||||
|
{Name: "group_id", Type: field.TypeUUID},
|
||||||
|
}
|
||||||
|
// UserGroupsTable holds the schema information for the "user_groups" table.
|
||||||
|
UserGroupsTable = &schema.Table{
|
||||||
|
Name: "user_groups",
|
||||||
|
Columns: UserGroupsColumns,
|
||||||
|
PrimaryKey: []*schema.Column{UserGroupsColumns[0], UserGroupsColumns[1]},
|
||||||
|
ForeignKeys: []*schema.ForeignKey{
|
||||||
|
{
|
||||||
|
Symbol: "user_groups_user_id",
|
||||||
|
Columns: []*schema.Column{UserGroupsColumns[0]},
|
||||||
|
RefColumns: []*schema.Column{UsersColumns[0]},
|
||||||
|
OnDelete: schema.Cascade,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Symbol: "user_groups_group_id",
|
||||||
|
Columns: []*schema.Column{UserGroupsColumns[1]},
|
||||||
|
RefColumns: []*schema.Column{GroupsColumns[0]},
|
||||||
|
OnDelete: schema.Cascade,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
// Tables holds all the tables in the schema.
|
// Tables holds all the tables in the schema.
|
||||||
Tables = []*schema.Table{
|
Tables = []*schema.Table{
|
||||||
AttachmentsTable,
|
AttachmentsTable,
|
||||||
@@ -533,6 +550,7 @@ var (
|
|||||||
TemplateFieldsTable,
|
TemplateFieldsTable,
|
||||||
UsersTable,
|
UsersTable,
|
||||||
LabelItemsTable,
|
LabelItemsTable,
|
||||||
|
UserGroupsTable,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -555,7 +573,8 @@ func init() {
|
|||||||
NotifiersTable.ForeignKeys[0].RefTable = GroupsTable
|
NotifiersTable.ForeignKeys[0].RefTable = GroupsTable
|
||||||
NotifiersTable.ForeignKeys[1].RefTable = UsersTable
|
NotifiersTable.ForeignKeys[1].RefTable = UsersTable
|
||||||
TemplateFieldsTable.ForeignKeys[0].RefTable = ItemTemplatesTable
|
TemplateFieldsTable.ForeignKeys[0].RefTable = ItemTemplatesTable
|
||||||
UsersTable.ForeignKeys[0].RefTable = GroupsTable
|
|
||||||
LabelItemsTable.ForeignKeys[0].RefTable = LabelsTable
|
LabelItemsTable.ForeignKeys[0].RefTable = LabelsTable
|
||||||
LabelItemsTable.ForeignKeys[1].RefTable = ItemsTable
|
LabelItemsTable.ForeignKeys[1].RefTable = ItemsTable
|
||||||
|
UserGroupsTable.ForeignKeys[0].RefTable = UsersTable
|
||||||
|
UserGroupsTable.ForeignKeys[1].RefTable = GroupsTable
|
||||||
}
|
}
|
||||||
|
|||||||
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
|
activated_on *time.Time
|
||||||
oidc_issuer *string
|
oidc_issuer *string
|
||||||
oidc_subject *string
|
oidc_subject *string
|
||||||
|
default_group_id *uuid.UUID
|
||||||
clearedFields map[string]struct{}
|
clearedFields map[string]struct{}
|
||||||
group *uuid.UUID
|
groups map[uuid.UUID]struct{}
|
||||||
clearedgroup bool
|
removedgroups map[uuid.UUID]struct{}
|
||||||
|
clearedgroups 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
|
||||||
@@ -13149,43 +13151,107 @@ func (m *UserMutation) ResetOidcSubject() {
|
|||||||
delete(m.clearedFields, user.FieldOidcSubject)
|
delete(m.clearedFields, user.FieldOidcSubject)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetGroupID sets the "group" edge to the Group entity by id.
|
// SetDefaultGroupID sets the "default_group_id" field.
|
||||||
func (m *UserMutation) SetGroupID(id uuid.UUID) {
|
func (m *UserMutation) SetDefaultGroupID(u uuid.UUID) {
|
||||||
m.group = &id
|
m.default_group_id = &u
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearGroup clears the "group" edge to the Group entity.
|
// DefaultGroupID returns the value of the "default_group_id" field in the mutation.
|
||||||
func (m *UserMutation) ClearGroup() {
|
func (m *UserMutation) DefaultGroupID() (r uuid.UUID, exists bool) {
|
||||||
m.clearedgroup = true
|
v := m.default_group_id
|
||||||
|
if v == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return *v, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// GroupCleared reports if the "group" edge to the Group entity was cleared.
|
// OldDefaultGroupID returns the old "default_group_id" field's value of the User entity.
|
||||||
func (m *UserMutation) GroupCleared() bool {
|
// If the User object wasn't provided to the builder, the object is fetched from the database.
|
||||||
return m.clearedgroup
|
// 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.
|
// ClearDefaultGroupID clears the value of the "default_group_id" field.
|
||||||
func (m *UserMutation) GroupID() (id uuid.UUID, exists bool) {
|
func (m *UserMutation) ClearDefaultGroupID() {
|
||||||
if m.group != nil {
|
m.default_group_id = nil
|
||||||
return *m.group, true
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// GroupIDs returns the "group" edge IDs in the mutation.
|
// GroupsIDs returns the "groups" edge IDs in the mutation.
|
||||||
// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use
|
func (m *UserMutation) GroupsIDs() (ids []uuid.UUID) {
|
||||||
// GroupID instead. It exists only for internal usage by the builders.
|
for id := range m.groups {
|
||||||
func (m *UserMutation) GroupIDs() (ids []uuid.UUID) {
|
ids = append(ids, id)
|
||||||
if id := m.group; id != nil {
|
|
||||||
ids = append(ids, *id)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetGroup resets all changes to the "group" edge.
|
// ResetGroups resets all changes to the "groups" edge.
|
||||||
func (m *UserMutation) ResetGroup() {
|
func (m *UserMutation) ResetGroups() {
|
||||||
m.group = nil
|
m.groups = nil
|
||||||
m.clearedgroup = false
|
m.clearedgroups = false
|
||||||
|
m.removedgroups = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddAuthTokenIDs adds the "auth_tokens" edge to the AuthTokens entity by ids.
|
// 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
|
// order to get all numeric fields that were incremented/decremented, call
|
||||||
// AddedFields().
|
// AddedFields().
|
||||||
func (m *UserMutation) Fields() []string {
|
func (m *UserMutation) Fields() []string {
|
||||||
fields := make([]string, 0, 11)
|
fields := make([]string, 0, 12)
|
||||||
if m.created_at != nil {
|
if m.created_at != nil {
|
||||||
fields = append(fields, user.FieldCreatedAt)
|
fields = append(fields, user.FieldCreatedAt)
|
||||||
}
|
}
|
||||||
@@ -13364,6 +13430,9 @@ func (m *UserMutation) Fields() []string {
|
|||||||
if m.oidc_subject != nil {
|
if m.oidc_subject != nil {
|
||||||
fields = append(fields, user.FieldOidcSubject)
|
fields = append(fields, user.FieldOidcSubject)
|
||||||
}
|
}
|
||||||
|
if m.default_group_id != nil {
|
||||||
|
fields = append(fields, user.FieldDefaultGroupID)
|
||||||
|
}
|
||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13394,6 +13463,8 @@ func (m *UserMutation) Field(name string) (ent.Value, bool) {
|
|||||||
return m.OidcIssuer()
|
return m.OidcIssuer()
|
||||||
case user.FieldOidcSubject:
|
case user.FieldOidcSubject:
|
||||||
return m.OidcSubject()
|
return m.OidcSubject()
|
||||||
|
case user.FieldDefaultGroupID:
|
||||||
|
return m.DefaultGroupID()
|
||||||
}
|
}
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
@@ -13425,6 +13496,8 @@ func (m *UserMutation) OldField(ctx context.Context, name string) (ent.Value, er
|
|||||||
return m.OldOidcIssuer(ctx)
|
return m.OldOidcIssuer(ctx)
|
||||||
case user.FieldOidcSubject:
|
case user.FieldOidcSubject:
|
||||||
return m.OldOidcSubject(ctx)
|
return m.OldOidcSubject(ctx)
|
||||||
|
case user.FieldDefaultGroupID:
|
||||||
|
return m.OldDefaultGroupID(ctx)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("unknown User field %s", name)
|
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)
|
m.SetOidcSubject(v)
|
||||||
return nil
|
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)
|
return fmt.Errorf("unknown User field %s", name)
|
||||||
}
|
}
|
||||||
@@ -13553,6 +13633,9 @@ func (m *UserMutation) ClearedFields() []string {
|
|||||||
if m.FieldCleared(user.FieldOidcSubject) {
|
if m.FieldCleared(user.FieldOidcSubject) {
|
||||||
fields = append(fields, user.FieldOidcSubject)
|
fields = append(fields, user.FieldOidcSubject)
|
||||||
}
|
}
|
||||||
|
if m.FieldCleared(user.FieldDefaultGroupID) {
|
||||||
|
fields = append(fields, user.FieldDefaultGroupID)
|
||||||
|
}
|
||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13579,6 +13662,9 @@ func (m *UserMutation) ClearField(name string) error {
|
|||||||
case user.FieldOidcSubject:
|
case user.FieldOidcSubject:
|
||||||
m.ClearOidcSubject()
|
m.ClearOidcSubject()
|
||||||
return nil
|
return nil
|
||||||
|
case user.FieldDefaultGroupID:
|
||||||
|
m.ClearDefaultGroupID()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return fmt.Errorf("unknown User nullable field %s", name)
|
return fmt.Errorf("unknown User nullable field %s", name)
|
||||||
}
|
}
|
||||||
@@ -13620,6 +13706,9 @@ func (m *UserMutation) ResetField(name string) error {
|
|||||||
case user.FieldOidcSubject:
|
case user.FieldOidcSubject:
|
||||||
m.ResetOidcSubject()
|
m.ResetOidcSubject()
|
||||||
return nil
|
return nil
|
||||||
|
case user.FieldDefaultGroupID:
|
||||||
|
m.ResetDefaultGroupID()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return fmt.Errorf("unknown User field %s", name)
|
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.
|
// 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, 3)
|
||||||
if m.group != nil {
|
if m.groups != nil {
|
||||||
edges = append(edges, user.EdgeGroup)
|
edges = append(edges, user.EdgeGroups)
|
||||||
}
|
}
|
||||||
if m.auth_tokens != nil {
|
if m.auth_tokens != nil {
|
||||||
edges = append(edges, user.EdgeAuthTokens)
|
edges = append(edges, user.EdgeAuthTokens)
|
||||||
@@ -13643,10 +13732,12 @@ func (m *UserMutation) AddedEdges() []string {
|
|||||||
// name in this mutation.
|
// name in this mutation.
|
||||||
func (m *UserMutation) AddedIDs(name string) []ent.Value {
|
func (m *UserMutation) AddedIDs(name string) []ent.Value {
|
||||||
switch name {
|
switch name {
|
||||||
case user.EdgeGroup:
|
case user.EdgeGroups:
|
||||||
if id := m.group; id != nil {
|
ids := make([]ent.Value, 0, len(m.groups))
|
||||||
return []ent.Value{*id}
|
for id := range m.groups {
|
||||||
|
ids = append(ids, id)
|
||||||
}
|
}
|
||||||
|
return ids
|
||||||
case user.EdgeAuthTokens:
|
case user.EdgeAuthTokens:
|
||||||
ids := make([]ent.Value, 0, len(m.auth_tokens))
|
ids := make([]ent.Value, 0, len(m.auth_tokens))
|
||||||
for id := range 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.
|
// 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, 3)
|
||||||
|
if m.removedgroups != nil {
|
||||||
|
edges = append(edges, user.EdgeGroups)
|
||||||
|
}
|
||||||
if m.removedauth_tokens != nil {
|
if m.removedauth_tokens != nil {
|
||||||
edges = append(edges, user.EdgeAuthTokens)
|
edges = append(edges, user.EdgeAuthTokens)
|
||||||
}
|
}
|
||||||
@@ -13679,6 +13773,12 @@ func (m *UserMutation) RemovedEdges() []string {
|
|||||||
// the given name in this mutation.
|
// the given name in this mutation.
|
||||||
func (m *UserMutation) RemovedIDs(name string) []ent.Value {
|
func (m *UserMutation) RemovedIDs(name string) []ent.Value {
|
||||||
switch name {
|
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:
|
case user.EdgeAuthTokens:
|
||||||
ids := make([]ent.Value, 0, len(m.removedauth_tokens))
|
ids := make([]ent.Value, 0, len(m.removedauth_tokens))
|
||||||
for id := range 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.
|
// 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, 3)
|
||||||
if m.clearedgroup {
|
if m.clearedgroups {
|
||||||
edges = append(edges, user.EdgeGroup)
|
edges = append(edges, user.EdgeGroups)
|
||||||
}
|
}
|
||||||
if m.clearedauth_tokens {
|
if m.clearedauth_tokens {
|
||||||
edges = append(edges, user.EdgeAuthTokens)
|
edges = append(edges, user.EdgeAuthTokens)
|
||||||
@@ -13714,8 +13814,8 @@ func (m *UserMutation) ClearedEdges() []string {
|
|||||||
// was cleared in this mutation.
|
// was cleared in this mutation.
|
||||||
func (m *UserMutation) EdgeCleared(name string) bool {
|
func (m *UserMutation) EdgeCleared(name string) bool {
|
||||||
switch name {
|
switch name {
|
||||||
case user.EdgeGroup:
|
case user.EdgeGroups:
|
||||||
return m.clearedgroup
|
return m.clearedgroups
|
||||||
case user.EdgeAuthTokens:
|
case user.EdgeAuthTokens:
|
||||||
return m.clearedauth_tokens
|
return m.clearedauth_tokens
|
||||||
case user.EdgeNotifiers:
|
case user.EdgeNotifiers:
|
||||||
@@ -13728,9 +13828,6 @@ func (m *UserMutation) EdgeCleared(name string) bool {
|
|||||||
// if that edge is not defined in the schema.
|
// if that edge is not defined in the schema.
|
||||||
func (m *UserMutation) ClearEdge(name string) error {
|
func (m *UserMutation) ClearEdge(name string) error {
|
||||||
switch name {
|
switch name {
|
||||||
case user.EdgeGroup:
|
|
||||||
m.ClearGroup()
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
return fmt.Errorf("unknown User unique edge %s", name)
|
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.
|
// It returns an error if the edge is not defined in the schema.
|
||||||
func (m *UserMutation) ResetEdge(name string) error {
|
func (m *UserMutation) ResetEdge(name string) error {
|
||||||
switch name {
|
switch name {
|
||||||
case user.EdgeGroup:
|
case user.EdgeGroups:
|
||||||
m.ResetGroup()
|
m.ResetGroups()
|
||||||
return nil
|
return nil
|
||||||
case user.EdgeAuthTokens:
|
case user.EdgeAuthTokens:
|
||||||
m.ResetAuthTokens()
|
m.ResetAuthTokens()
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ func (Group) Edges() []ent.Edge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return []ent.Edge{
|
return []ent.Edge{
|
||||||
owned("users", User.Type),
|
// Use edge.From + Ref("groups") to model M:M between users and groups via junction table
|
||||||
|
edge.From("users", User.Type).Ref("groups"),
|
||||||
owned("locations", Location.Type),
|
owned("locations", Location.Type),
|
||||||
owned("items", Item.Type),
|
owned("items", Item.Type),
|
||||||
owned("labels", Label.Type),
|
owned("labels", Label.Type),
|
||||||
@@ -72,14 +73,14 @@ func (g GroupMixin) Fields() []ent.Field {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g GroupMixin) Edges() []ent.Edge {
|
func (g GroupMixin) Edges() []ent.Edge {
|
||||||
edge := edge.From("group", Group.Type).
|
e := edge.From("group", Group.Type).
|
||||||
Ref(g.ref).
|
Ref(g.ref).
|
||||||
Unique().
|
Unique().
|
||||||
Required()
|
Required()
|
||||||
|
|
||||||
if g.field != "" {
|
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 {
|
func (User) Mixin() []ent.Mixin {
|
||||||
return []ent.Mixin{
|
return []ent.Mixin{
|
||||||
mixins.BaseMixin{},
|
mixins.BaseMixin{},
|
||||||
GroupMixin{ref: "users"},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,6 +53,10 @@ func (User) Fields() []ent.Field {
|
|||||||
field.String("oidc_subject").
|
field.String("oidc_subject").
|
||||||
Optional().
|
Optional().
|
||||||
Nillable(),
|
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.
|
// Edges of the User.
|
||||||
func (User) Edges() []ent.Edge {
|
func (User) Edges() []ent.Edge {
|
||||||
return []ent.Edge{
|
return []ent.Edge{
|
||||||
|
edge.To("groups", Group.Type),
|
||||||
edge.To("auth_tokens", AuthTokens.Type).
|
edge.To("auth_tokens", AuthTokens.Type).
|
||||||
Annotations(entsql.Annotation{
|
Annotations(entsql.Annotation{
|
||||||
OnDelete: entsql.Cascade,
|
OnDelete: entsql.Cascade,
|
||||||
|
|||||||
45
backend/internal/data/ent/user.go
generated
45
backend/internal/data/ent/user.go
generated
@@ -10,7 +10,6 @@ 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/sysadminsmedia/homebox/backend/internal/data/ent/group"
|
|
||||||
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/user"
|
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -41,17 +40,18 @@ type User struct {
|
|||||||
OidcIssuer *string `json:"oidc_issuer,omitempty"`
|
OidcIssuer *string `json:"oidc_issuer,omitempty"`
|
||||||
// OidcSubject holds the value of the "oidc_subject" field.
|
// OidcSubject holds the value of the "oidc_subject" field.
|
||||||
OidcSubject *string `json:"oidc_subject,omitempty"`
|
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.
|
// Edges holds the relations/edges for other nodes in the graph.
|
||||||
// The values are being populated by the UserQuery when eager-loading is set.
|
// The values are being populated by the UserQuery when eager-loading is set.
|
||||||
Edges UserEdges `json:"edges"`
|
Edges UserEdges `json:"edges"`
|
||||||
group_users *uuid.UUID
|
|
||||||
selectValues sql.SelectValues
|
selectValues sql.SelectValues
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserEdges holds the relations/edges for other nodes in the graph.
|
// UserEdges holds the relations/edges for other nodes in the graph.
|
||||||
type UserEdges struct {
|
type UserEdges struct {
|
||||||
// Group holds the value of the group edge.
|
// Groups holds the value of the groups edge.
|
||||||
Group *Group `json:"group,omitempty"`
|
Groups []*Group `json:"groups,omitempty"`
|
||||||
// AuthTokens holds the value of the auth_tokens edge.
|
// AuthTokens holds the value of the auth_tokens edge.
|
||||||
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.
|
||||||
@@ -61,15 +61,13 @@ type UserEdges struct {
|
|||||||
loadedTypes [3]bool
|
loadedTypes [3]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// GroupOrErr returns the Group value or an error if the edge
|
// GroupsOrErr returns the Groups value or an error if the edge
|
||||||
// was not loaded in eager-loading, or loaded but was not found.
|
// was not loaded in eager-loading.
|
||||||
func (e UserEdges) GroupOrErr() (*Group, error) {
|
func (e UserEdges) GroupsOrErr() ([]*Group, error) {
|
||||||
if e.Group != nil {
|
if e.loadedTypes[0] {
|
||||||
return e.Group, nil
|
return e.Groups, nil
|
||||||
} else if e.loadedTypes[0] {
|
|
||||||
return nil, &NotFoundError{label: group.Label}
|
|
||||||
}
|
}
|
||||||
return nil, &NotLoadedError{edge: "group"}
|
return nil, &NotLoadedError{edge: "groups"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthTokensOrErr returns the AuthTokens value or an error if the edge
|
// AuthTokensOrErr returns the AuthTokens value or an error if the edge
|
||||||
@@ -95,6 +93,8 @@ func (*User) scanValues(columns []string) ([]any, error) {
|
|||||||
values := make([]any, len(columns))
|
values := make([]any, len(columns))
|
||||||
for i := range columns {
|
for i := range columns {
|
||||||
switch columns[i] {
|
switch columns[i] {
|
||||||
|
case user.FieldDefaultGroupID:
|
||||||
|
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
|
||||||
case user.FieldIsSuperuser, user.FieldSuperuser:
|
case user.FieldIsSuperuser, user.FieldSuperuser:
|
||||||
values[i] = new(sql.NullBool)
|
values[i] = new(sql.NullBool)
|
||||||
case user.FieldName, user.FieldEmail, user.FieldPassword, user.FieldRole, user.FieldOidcIssuer, user.FieldOidcSubject:
|
case user.FieldName, user.FieldEmail, user.FieldPassword, user.FieldRole, user.FieldOidcIssuer, user.FieldOidcSubject:
|
||||||
@@ -103,8 +103,6 @@ func (*User) scanValues(columns []string) ([]any, error) {
|
|||||||
values[i] = new(sql.NullTime)
|
values[i] = new(sql.NullTime)
|
||||||
case user.FieldID:
|
case user.FieldID:
|
||||||
values[i] = new(uuid.UUID)
|
values[i] = new(uuid.UUID)
|
||||||
case user.ForeignKeys[0]: // group_users
|
|
||||||
values[i] = &sql.NullScanner{S: new(uuid.UUID)}
|
|
||||||
default:
|
default:
|
||||||
values[i] = new(sql.UnknownType)
|
values[i] = new(sql.UnknownType)
|
||||||
}
|
}
|
||||||
@@ -195,12 +193,12 @@ func (_m *User) assignValues(columns []string, values []any) error {
|
|||||||
_m.OidcSubject = new(string)
|
_m.OidcSubject = new(string)
|
||||||
*_m.OidcSubject = value.String
|
*_m.OidcSubject = value.String
|
||||||
}
|
}
|
||||||
case user.ForeignKeys[0]:
|
case user.FieldDefaultGroupID:
|
||||||
if value, ok := values[i].(*sql.NullScanner); !ok {
|
if value, ok := values[i].(*sql.NullScanner); !ok {
|
||||||
return fmt.Errorf("unexpected type %T for field group_users", values[i])
|
return fmt.Errorf("unexpected type %T for field default_group_id", values[i])
|
||||||
} else if value.Valid {
|
} else if value.Valid {
|
||||||
_m.group_users = new(uuid.UUID)
|
_m.DefaultGroupID = new(uuid.UUID)
|
||||||
*_m.group_users = *value.S.(*uuid.UUID)
|
*_m.DefaultGroupID = *value.S.(*uuid.UUID)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
_m.selectValues.Set(columns[i], values[i])
|
_m.selectValues.Set(columns[i], values[i])
|
||||||
@@ -215,9 +213,9 @@ func (_m *User) Value(name string) (ent.Value, error) {
|
|||||||
return _m.selectValues.Get(name)
|
return _m.selectValues.Get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryGroup queries the "group" edge of the User entity.
|
// QueryGroups queries the "groups" edge of the User entity.
|
||||||
func (_m *User) QueryGroup() *GroupQuery {
|
func (_m *User) QueryGroups() *GroupQuery {
|
||||||
return NewUserClient(_m.config).QueryGroup(_m)
|
return NewUserClient(_m.config).QueryGroups(_m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryAuthTokens queries the "auth_tokens" edge of the User entity.
|
// QueryAuthTokens queries the "auth_tokens" edge of the User entity.
|
||||||
@@ -288,6 +286,11 @@ func (_m *User) String() string {
|
|||||||
builder.WriteString("oidc_subject=")
|
builder.WriteString("oidc_subject=")
|
||||||
builder.WriteString(*v)
|
builder.WriteString(*v)
|
||||||
}
|
}
|
||||||
|
builder.WriteString(", ")
|
||||||
|
if v := _m.DefaultGroupID; v != nil {
|
||||||
|
builder.WriteString("default_group_id=")
|
||||||
|
builder.WriteString(fmt.Sprintf("%v", *v))
|
||||||
|
}
|
||||||
builder.WriteByte(')')
|
builder.WriteByte(')')
|
||||||
return builder.String()
|
return builder.String()
|
||||||
}
|
}
|
||||||
|
|||||||
56
backend/internal/data/ent/user/user.go
generated
56
backend/internal/data/ent/user/user.go
generated
@@ -38,21 +38,21 @@ const (
|
|||||||
FieldOidcIssuer = "oidc_issuer"
|
FieldOidcIssuer = "oidc_issuer"
|
||||||
// FieldOidcSubject holds the string denoting the oidc_subject field in the database.
|
// FieldOidcSubject holds the string denoting the oidc_subject field in the database.
|
||||||
FieldOidcSubject = "oidc_subject"
|
FieldOidcSubject = "oidc_subject"
|
||||||
// EdgeGroup holds the string denoting the group edge name in mutations.
|
// FieldDefaultGroupID holds the string denoting the default_group_id field in the database.
|
||||||
EdgeGroup = "group"
|
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 holds the string denoting the auth_tokens edge name in mutations.
|
||||||
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"
|
||||||
// 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.
|
// GroupsTable is the table that holds the groups relation/edge. The primary key declared below.
|
||||||
GroupTable = "users"
|
GroupsTable = "user_groups"
|
||||||
// GroupInverseTable is the table name for the Group entity.
|
// GroupsInverseTable is the table name for the Group entity.
|
||||||
// It exists in this package in order to avoid circular dependency with the "group" package.
|
// It exists in this package in order to avoid circular dependency with the "group" package.
|
||||||
GroupInverseTable = "groups"
|
GroupsInverseTable = "groups"
|
||||||
// GroupColumn is the table column denoting the group relation/edge.
|
|
||||||
GroupColumn = "group_users"
|
|
||||||
// AuthTokensTable is the table that holds the auth_tokens relation/edge.
|
// AuthTokensTable is the table that holds the auth_tokens relation/edge.
|
||||||
AuthTokensTable = "auth_tokens"
|
AuthTokensTable = "auth_tokens"
|
||||||
// AuthTokensInverseTable is the table name for the AuthTokens entity.
|
// AuthTokensInverseTable is the table name for the AuthTokens entity.
|
||||||
@@ -83,13 +83,14 @@ var Columns = []string{
|
|||||||
FieldActivatedOn,
|
FieldActivatedOn,
|
||||||
FieldOidcIssuer,
|
FieldOidcIssuer,
|
||||||
FieldOidcSubject,
|
FieldOidcSubject,
|
||||||
|
FieldDefaultGroupID,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForeignKeys holds the SQL foreign-keys that are owned by the "users"
|
var (
|
||||||
// table and are not defined as standalone fields in the schema.
|
// GroupsPrimaryKey and GroupsColumn2 are the table columns denoting the
|
||||||
var ForeignKeys = []string{
|
// primary key for the groups relation (M2M).
|
||||||
"group_users",
|
GroupsPrimaryKey = []string{"user_id", "group_id"}
|
||||||
}
|
)
|
||||||
|
|
||||||
// ValidColumn reports if the column name is valid (part of the table columns).
|
// ValidColumn reports if the column name is valid (part of the table columns).
|
||||||
func ValidColumn(column string) bool {
|
func ValidColumn(column string) bool {
|
||||||
@@ -98,11 +99,6 @@ func ValidColumn(column string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := range ForeignKeys {
|
|
||||||
if column == ForeignKeys[i] {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,10 +212,22 @@ func ByOidcSubject(opts ...sql.OrderTermOption) OrderOption {
|
|||||||
return sql.OrderByField(FieldOidcSubject, opts...).ToFunc()
|
return sql.OrderByField(FieldOidcSubject, opts...).ToFunc()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ByGroupField orders the results by group field.
|
// ByDefaultGroupID orders the results by the default_group_id field.
|
||||||
func ByGroupField(field string, opts ...sql.OrderTermOption) OrderOption {
|
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) {
|
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 +258,11 @@ 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...)...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func newGroupStep() *sqlgraph.Step {
|
func newGroupsStep() *sqlgraph.Step {
|
||||||
return sqlgraph.NewStep(
|
return sqlgraph.NewStep(
|
||||||
sqlgraph.From(Table, FieldID),
|
sqlgraph.From(Table, FieldID),
|
||||||
sqlgraph.To(GroupInverseTable, FieldID),
|
sqlgraph.To(GroupsInverseTable, FieldID),
|
||||||
sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn),
|
sqlgraph.Edge(sqlgraph.M2M, false, GroupsTable, GroupsPrimaryKey...),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
func newAuthTokensStep() *sqlgraph.Step {
|
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))
|
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.
|
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
||||||
func CreatedAtEQ(v time.Time) predicate.User {
|
func CreatedAtEQ(v time.Time) predicate.User {
|
||||||
return predicate.User(sql.FieldEQ(FieldCreatedAt, v))
|
return predicate.User(sql.FieldEQ(FieldCreatedAt, v))
|
||||||
@@ -631,21 +636,71 @@ func OidcSubjectContainsFold(v string) predicate.User {
|
|||||||
return predicate.User(sql.FieldContainsFold(FieldOidcSubject, v))
|
return predicate.User(sql.FieldContainsFold(FieldOidcSubject, v))
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasGroup applies the HasEdge predicate on the "group" edge.
|
// DefaultGroupIDEQ applies the EQ predicate on the "default_group_id" field.
|
||||||
func HasGroup() predicate.User {
|
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) {
|
return predicate.User(func(s *sql.Selector) {
|
||||||
step := sqlgraph.NewStep(
|
step := sqlgraph.NewStep(
|
||||||
sqlgraph.From(Table, FieldID),
|
sqlgraph.From(Table, FieldID),
|
||||||
sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn),
|
sqlgraph.Edge(sqlgraph.M2M, false, GroupsTable, GroupsPrimaryKey...),
|
||||||
)
|
)
|
||||||
sqlgraph.HasNeighbors(s, step)
|
sqlgraph.HasNeighbors(s, step)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasGroupWith applies the HasEdge predicate on the "group" edge with a given conditions (other predicates).
|
// HasGroupsWith applies the HasEdge predicate on the "groups" edge with a given conditions (other predicates).
|
||||||
func HasGroupWith(preds ...predicate.Group) predicate.User {
|
func HasGroupsWith(preds ...predicate.Group) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(func(s *sql.Selector) {
|
||||||
step := newGroupStep()
|
step := newGroupsStep()
|
||||||
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
||||||
for _, p := range preds {
|
for _, p := range preds {
|
||||||
p(s)
|
p(s)
|
||||||
|
|||||||
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
|
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.
|
// SetID sets the "id" field.
|
||||||
func (_c *UserCreate) SetID(v uuid.UUID) *UserCreate {
|
func (_c *UserCreate) SetID(v uuid.UUID) *UserCreate {
|
||||||
_c.mutation.SetID(v)
|
_c.mutation.SetID(v)
|
||||||
@@ -176,15 +190,19 @@ func (_c *UserCreate) SetNillableID(v *uuid.UUID) *UserCreate {
|
|||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetGroupID sets the "group" edge to the Group entity by ID.
|
// AddGroupIDs adds the "groups" edge to the Group entity by IDs.
|
||||||
func (_c *UserCreate) SetGroupID(id uuid.UUID) *UserCreate {
|
func (_c *UserCreate) AddGroupIDs(ids ...uuid.UUID) *UserCreate {
|
||||||
_c.mutation.SetGroupID(id)
|
_c.mutation.AddGroupIDs(ids...)
|
||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetGroup sets the "group" edge to the Group entity.
|
// AddGroups adds the "groups" edges to the Group entity.
|
||||||
func (_c *UserCreate) SetGroup(v *Group) *UserCreate {
|
func (_c *UserCreate) AddGroups(v ...*Group) *UserCreate {
|
||||||
return _c.SetGroupID(v.ID)
|
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.
|
// 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)}
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,12 +418,16 @@ func (_c *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) {
|
|||||||
_spec.SetField(user.FieldOidcSubject, field.TypeString, value)
|
_spec.SetField(user.FieldOidcSubject, field.TypeString, value)
|
||||||
_node.OidcSubject = &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{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.M2O,
|
Rel: sqlgraph.M2M,
|
||||||
Inverse: true,
|
Inverse: false,
|
||||||
Table: user.GroupTable,
|
Table: user.GroupsTable,
|
||||||
Columns: []string{user.GroupColumn},
|
Columns: user.GroupsPrimaryKey,
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
|
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
|
||||||
@@ -417,7 +436,6 @@ func (_c *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) {
|
|||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||||
}
|
}
|
||||||
_node.group_users = &nodes[0]
|
|
||||||
_spec.Edges = append(_spec.Edges, edge)
|
_spec.Edges = append(_spec.Edges, edge)
|
||||||
}
|
}
|
||||||
if nodes := _c.mutation.AuthTokensIDs(); len(nodes) > 0 {
|
if nodes := _c.mutation.AuthTokensIDs(); len(nodes) > 0 {
|
||||||
|
|||||||
98
backend/internal/data/ent/user_query.go
generated
98
backend/internal/data/ent/user_query.go
generated
@@ -27,10 +27,9 @@ type UserQuery struct {
|
|||||||
order []user.OrderOption
|
order []user.OrderOption
|
||||||
inters []Interceptor
|
inters []Interceptor
|
||||||
predicates []predicate.User
|
predicates []predicate.User
|
||||||
withGroup *GroupQuery
|
withGroups *GroupQuery
|
||||||
withAuthTokens *AuthTokensQuery
|
withAuthTokens *AuthTokensQuery
|
||||||
withNotifiers *NotifierQuery
|
withNotifiers *NotifierQuery
|
||||||
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)
|
||||||
@@ -67,8 +66,8 @@ func (_q *UserQuery) Order(o ...user.OrderOption) *UserQuery {
|
|||||||
return _q
|
return _q
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryGroup chains the current query on the "group" edge.
|
// QueryGroups chains the current query on the "groups" edge.
|
||||||
func (_q *UserQuery) QueryGroup() *GroupQuery {
|
func (_q *UserQuery) QueryGroups() *GroupQuery {
|
||||||
query := (&GroupClient{config: _q.config}).Query()
|
query := (&GroupClient{config: _q.config}).Query()
|
||||||
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
|
||||||
if err := _q.prepareQuery(ctx); err != nil {
|
if err := _q.prepareQuery(ctx); err != nil {
|
||||||
@@ -81,7 +80,7 @@ func (_q *UserQuery) QueryGroup() *GroupQuery {
|
|||||||
step := sqlgraph.NewStep(
|
step := sqlgraph.NewStep(
|
||||||
sqlgraph.From(user.Table, user.FieldID, selector),
|
sqlgraph.From(user.Table, user.FieldID, selector),
|
||||||
sqlgraph.To(group.Table, group.FieldID),
|
sqlgraph.To(group.Table, group.FieldID),
|
||||||
sqlgraph.Edge(sqlgraph.M2O, true, user.GroupTable, user.GroupColumn),
|
sqlgraph.Edge(sqlgraph.M2M, false, user.GroupsTable, user.GroupsPrimaryKey...),
|
||||||
)
|
)
|
||||||
fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step)
|
fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step)
|
||||||
return fromU, nil
|
return fromU, nil
|
||||||
@@ -325,7 +324,7 @@ func (_q *UserQuery) Clone() *UserQuery {
|
|||||||
order: append([]user.OrderOption{}, _q.order...),
|
order: append([]user.OrderOption{}, _q.order...),
|
||||||
inters: append([]Interceptor{}, _q.inters...),
|
inters: append([]Interceptor{}, _q.inters...),
|
||||||
predicates: append([]predicate.User{}, _q.predicates...),
|
predicates: append([]predicate.User{}, _q.predicates...),
|
||||||
withGroup: _q.withGroup.Clone(),
|
withGroups: _q.withGroups.Clone(),
|
||||||
withAuthTokens: _q.withAuthTokens.Clone(),
|
withAuthTokens: _q.withAuthTokens.Clone(),
|
||||||
withNotifiers: _q.withNotifiers.Clone(),
|
withNotifiers: _q.withNotifiers.Clone(),
|
||||||
// clone intermediate query.
|
// clone intermediate query.
|
||||||
@@ -334,14 +333,14 @@ func (_q *UserQuery) Clone() *UserQuery {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithGroup tells the query-builder to eager-load the nodes that are connected to
|
// WithGroups 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.
|
// the "groups" edge. The optional arguments are used to configure the query builder of the edge.
|
||||||
func (_q *UserQuery) WithGroup(opts ...func(*GroupQuery)) *UserQuery {
|
func (_q *UserQuery) WithGroups(opts ...func(*GroupQuery)) *UserQuery {
|
||||||
query := (&GroupClient{config: _q.config}).Query()
|
query := (&GroupClient{config: _q.config}).Query()
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(query)
|
opt(query)
|
||||||
}
|
}
|
||||||
_q.withGroup = query
|
_q.withGroups = query
|
||||||
return _q
|
return _q
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,20 +443,13 @@ func (_q *UserQuery) prepareQuery(ctx context.Context) error {
|
|||||||
func (_q *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, error) {
|
func (_q *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, error) {
|
||||||
var (
|
var (
|
||||||
nodes = []*User{}
|
nodes = []*User{}
|
||||||
withFKs = _q.withFKs
|
|
||||||
_spec = _q.querySpec()
|
_spec = _q.querySpec()
|
||||||
loadedTypes = [3]bool{
|
loadedTypes = [3]bool{
|
||||||
_q.withGroup != nil,
|
_q.withGroups != nil,
|
||||||
_q.withAuthTokens != nil,
|
_q.withAuthTokens != nil,
|
||||||
_q.withNotifiers != nil,
|
_q.withNotifiers != nil,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if _q.withGroup != nil {
|
|
||||||
withFKs = true
|
|
||||||
}
|
|
||||||
if withFKs {
|
|
||||||
_spec.Node.Columns = append(_spec.Node.Columns, user.ForeignKeys...)
|
|
||||||
}
|
|
||||||
_spec.ScanValues = func(columns []string) ([]any, error) {
|
_spec.ScanValues = func(columns []string) ([]any, error) {
|
||||||
return (*User).scanValues(nil, columns)
|
return (*User).scanValues(nil, columns)
|
||||||
}
|
}
|
||||||
@@ -476,9 +468,10 @@ func (_q *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
|
|||||||
if len(nodes) == 0 {
|
if len(nodes) == 0 {
|
||||||
return nodes, nil
|
return nodes, nil
|
||||||
}
|
}
|
||||||
if query := _q.withGroup; query != nil {
|
if query := _q.withGroups; query != nil {
|
||||||
if err := _q.loadGroup(ctx, query, nodes, nil,
|
if err := _q.loadGroups(ctx, query, nodes,
|
||||||
func(n *User, e *Group) { n.Edges.Group = e }); err != nil {
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -499,34 +492,63 @@ func (_q *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
|
|||||||
return nodes, nil
|
return nodes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_q *UserQuery) loadGroup(ctx context.Context, query *GroupQuery, nodes []*User, init func(*User), assign func(*User, *Group)) error {
|
func (_q *UserQuery) loadGroups(ctx context.Context, query *GroupQuery, nodes []*User, init func(*User), assign func(*User, *Group)) error {
|
||||||
ids := make([]uuid.UUID, 0, len(nodes))
|
edgeIDs := make([]driver.Value, len(nodes))
|
||||||
nodeids := make(map[uuid.UUID][]*User)
|
byID := make(map[uuid.UUID]*User)
|
||||||
for i := range nodes {
|
nids := make(map[uuid.UUID]map[*User]struct{})
|
||||||
if nodes[i].group_users == nil {
|
for i, node := range nodes {
|
||||||
continue
|
edgeIDs[i] = node.ID
|
||||||
|
byID[node.ID] = node
|
||||||
|
if init != nil {
|
||||||
|
init(node)
|
||||||
}
|
}
|
||||||
fk := *nodes[i].group_users
|
|
||||||
if _, ok := nodeids[fk]; !ok {
|
|
||||||
ids = append(ids, fk)
|
|
||||||
}
|
}
|
||||||
nodeids[fk] = append(nodeids[fk], nodes[i])
|
query.Where(func(s *sql.Selector) {
|
||||||
|
joinT := sql.Table(user.GroupsTable)
|
||||||
|
s.Join(joinT).On(s.C(group.FieldID), joinT.C(user.GroupsPrimaryKey[1]))
|
||||||
|
s.Where(sql.InValues(joinT.C(user.GroupsPrimaryKey[0]), edgeIDs...))
|
||||||
|
columns := s.SelectedColumns()
|
||||||
|
s.Select(joinT.C(user.GroupsPrimaryKey[0]))
|
||||||
|
s.AppendSelect(columns...)
|
||||||
|
s.SetDistinct(false)
|
||||||
|
})
|
||||||
|
if err := query.prepareQuery(ctx); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
if len(ids) == 0 {
|
qr := QuerierFunc(func(ctx context.Context, q Query) (Value, error) {
|
||||||
|
return query.sqlAll(ctx, func(_ context.Context, spec *sqlgraph.QuerySpec) {
|
||||||
|
assign := spec.Assign
|
||||||
|
values := spec.ScanValues
|
||||||
|
spec.ScanValues = func(columns []string) ([]any, error) {
|
||||||
|
values, err := values(columns[1:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return append([]any{new(uuid.UUID)}, values...), nil
|
||||||
|
}
|
||||||
|
spec.Assign = func(columns []string, values []any) error {
|
||||||
|
outValue := *values[0].(*uuid.UUID)
|
||||||
|
inValue := *values[1].(*uuid.UUID)
|
||||||
|
if nids[inValue] == nil {
|
||||||
|
nids[inValue] = map[*User]struct{}{byID[outValue]: {}}
|
||||||
|
return assign(columns[1:], values[1:])
|
||||||
|
}
|
||||||
|
nids[inValue][byID[outValue]] = struct{}{}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
query.Where(group.IDIn(ids...))
|
})
|
||||||
neighbors, err := query.All(ctx)
|
})
|
||||||
|
neighbors, err := withInterceptors[[]*Group](ctx, query, qr, query.inters)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, n := range neighbors {
|
for _, n := range neighbors {
|
||||||
nodes, ok := nodeids[n.ID]
|
nodes, ok := nids[n.ID]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf(`unexpected foreign-key "group_users" returned %v`, n.ID)
|
return fmt.Errorf(`unexpected "groups" node returned %v`, n.ID)
|
||||||
}
|
}
|
||||||
for i := range nodes {
|
for kn := range nodes {
|
||||||
assign(nodes[i], n)
|
assign(kn, n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
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
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetGroupID sets the "group" edge to the Group entity by ID.
|
// SetDefaultGroupID sets the "default_group_id" field.
|
||||||
func (_u *UserUpdate) SetGroupID(id uuid.UUID) *UserUpdate {
|
func (_u *UserUpdate) SetDefaultGroupID(v uuid.UUID) *UserUpdate {
|
||||||
_u.mutation.SetGroupID(id)
|
_u.mutation.SetDefaultGroupID(v)
|
||||||
return _u
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetGroup sets the "group" edge to the Group entity.
|
// SetNillableDefaultGroupID sets the "default_group_id" field if the given value is not nil.
|
||||||
func (_u *UserUpdate) SetGroup(v *Group) *UserUpdate {
|
func (_u *UserUpdate) SetNillableDefaultGroupID(v *uuid.UUID) *UserUpdate {
|
||||||
return _u.SetGroupID(v.ID)
|
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.
|
// AddAuthTokenIDs adds the "auth_tokens" edge to the AuthTokens entity by IDs.
|
||||||
@@ -234,12 +258,27 @@ func (_u *UserUpdate) Mutation() *UserMutation {
|
|||||||
return _u.mutation
|
return _u.mutation
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearGroup clears the "group" edge to the Group entity.
|
// ClearGroups clears all "groups" edges to the Group entity.
|
||||||
func (_u *UserUpdate) ClearGroup() *UserUpdate {
|
func (_u *UserUpdate) ClearGroups() *UserUpdate {
|
||||||
_u.mutation.ClearGroup()
|
_u.mutation.ClearGroups()
|
||||||
return _u
|
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.
|
// ClearAuthTokens clears all "auth_tokens" edges to the AuthTokens entity.
|
||||||
func (_u *UserUpdate) ClearAuthTokens() *UserUpdate {
|
func (_u *UserUpdate) ClearAuthTokens() *UserUpdate {
|
||||||
_u.mutation.ClearAuthTokens()
|
_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)}
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,12 +436,18 @@ func (_u *UserUpdate) sqlSave(ctx context.Context) (_node int, err error) {
|
|||||||
if _u.mutation.OidcSubjectCleared() {
|
if _u.mutation.OidcSubjectCleared() {
|
||||||
_spec.ClearField(user.FieldOidcSubject, field.TypeString)
|
_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{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.M2O,
|
Rel: sqlgraph.M2M,
|
||||||
Inverse: true,
|
Inverse: false,
|
||||||
Table: user.GroupTable,
|
Table: user.GroupsTable,
|
||||||
Columns: []string{user.GroupColumn},
|
Columns: user.GroupsPrimaryKey,
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
|
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)
|
_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{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.M2O,
|
Rel: sqlgraph.M2M,
|
||||||
Inverse: true,
|
Inverse: false,
|
||||||
Table: user.GroupTable,
|
Table: user.GroupsTable,
|
||||||
Columns: []string{user.GroupColumn},
|
Columns: user.GroupsPrimaryKey,
|
||||||
|
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.M2M,
|
||||||
|
Inverse: false,
|
||||||
|
Table: user.GroupsTable,
|
||||||
|
Columns: user.GroupsPrimaryKey,
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
|
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
|
||||||
@@ -695,15 +753,39 @@ func (_u *UserUpdateOne) ClearOidcSubject() *UserUpdateOne {
|
|||||||
return _u
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetGroupID sets the "group" edge to the Group entity by ID.
|
// SetDefaultGroupID sets the "default_group_id" field.
|
||||||
func (_u *UserUpdateOne) SetGroupID(id uuid.UUID) *UserUpdateOne {
|
func (_u *UserUpdateOne) SetDefaultGroupID(v uuid.UUID) *UserUpdateOne {
|
||||||
_u.mutation.SetGroupID(id)
|
_u.mutation.SetDefaultGroupID(v)
|
||||||
return _u
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetGroup sets the "group" edge to the Group entity.
|
// SetNillableDefaultGroupID sets the "default_group_id" field if the given value is not nil.
|
||||||
func (_u *UserUpdateOne) SetGroup(v *Group) *UserUpdateOne {
|
func (_u *UserUpdateOne) SetNillableDefaultGroupID(v *uuid.UUID) *UserUpdateOne {
|
||||||
return _u.SetGroupID(v.ID)
|
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.
|
// AddAuthTokenIDs adds the "auth_tokens" edge to the AuthTokens entity by IDs.
|
||||||
@@ -741,12 +823,27 @@ func (_u *UserUpdateOne) Mutation() *UserMutation {
|
|||||||
return _u.mutation
|
return _u.mutation
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearGroup clears the "group" edge to the Group entity.
|
// ClearGroups clears all "groups" edges to the Group entity.
|
||||||
func (_u *UserUpdateOne) ClearGroup() *UserUpdateOne {
|
func (_u *UserUpdateOne) ClearGroups() *UserUpdateOne {
|
||||||
_u.mutation.ClearGroup()
|
_u.mutation.ClearGroups()
|
||||||
return _u
|
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.
|
// ClearAuthTokens clears all "auth_tokens" edges to the AuthTokens entity.
|
||||||
func (_u *UserUpdateOne) ClearAuthTokens() *UserUpdateOne {
|
func (_u *UserUpdateOne) ClearAuthTokens() *UserUpdateOne {
|
||||||
_u.mutation.ClearAuthTokens()
|
_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)}
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -937,12 +1031,18 @@ func (_u *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) {
|
|||||||
if _u.mutation.OidcSubjectCleared() {
|
if _u.mutation.OidcSubjectCleared() {
|
||||||
_spec.ClearField(user.FieldOidcSubject, field.TypeString)
|
_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{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.M2O,
|
Rel: sqlgraph.M2M,
|
||||||
Inverse: true,
|
Inverse: false,
|
||||||
Table: user.GroupTable,
|
Table: user.GroupsTable,
|
||||||
Columns: []string{user.GroupColumn},
|
Columns: user.GroupsPrimaryKey,
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
|
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)
|
_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{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.M2O,
|
Rel: sqlgraph.M2M,
|
||||||
Inverse: true,
|
Inverse: false,
|
||||||
Table: user.GroupTable,
|
Table: user.GroupsTable,
|
||||||
Columns: []string{user.GroupColumn},
|
Columns: user.GroupsPrimaryKey,
|
||||||
|
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.M2M,
|
||||||
|
Inverse: false,
|
||||||
|
Table: user.GroupsTable,
|
||||||
|
Columns: user.GroupsPrimaryKey,
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
|
IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeUUID),
|
||||||
|
|||||||
@@ -31,5 +31,4 @@ func Migrations(dialect string) (embed.FS, error) {
|
|||||||
return embed.FS{}, fmt.Errorf("unknown sql dialect: %s", dialect)
|
return embed.FS{}, fmt.Errorf("unknown sql dialect: %s", dialect)
|
||||||
}
|
}
|
||||||
// This should never get hit, but just in case
|
// This should never get hit, but just in case
|
||||||
return sqliteFiles, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,68 @@
|
|||||||
|
-- +goose Up
|
||||||
|
-- +goose no transaction
|
||||||
|
-- Turn off foreign key constraints because otherwise we'll wipe notifiers out of the database when dropping the older users table
|
||||||
|
PRAGMA foreign_keys=OFF;
|
||||||
|
-- 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);
|
||||||
|
|
||||||
|
PRAGMA foreign_keys=ON;
|
||||||
@@ -2,6 +2,7 @@ package repo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/sysadminsmedia/homebox/backend/internal/sys/config"
|
"github.com/sysadminsmedia/homebox/backend/internal/sys/config"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
@@ -29,7 +30,7 @@ func bootstrap() {
|
|||||||
ctx = context.Background()
|
ctx = context.Background()
|
||||||
)
|
)
|
||||||
|
|
||||||
tGroup, err = tRepos.Groups.GroupCreate(ctx, "test-group")
|
tGroup, err = tRepos.Groups.GroupCreate(ctx, "test-group", uuid.Nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ func (r *GroupRepository) StatsPurchasePrice(ctx context.Context, gid uuid.UUID,
|
|||||||
func (r *GroupRepository) StatsGroup(ctx context.Context, gid uuid.UUID) (GroupStatistics, error) {
|
func (r *GroupRepository) StatsGroup(ctx context.Context, gid uuid.UUID) (GroupStatistics, error) {
|
||||||
q := `
|
q := `
|
||||||
SELECT
|
SELECT
|
||||||
(SELECT COUNT(*) FROM users WHERE group_users = $2) AS total_users,
|
(SELECT COUNT(*) FROM user_groups WHERE group_id = $2) AS total_users,
|
||||||
(SELECT COUNT(*) FROM items WHERE group_items = $2 AND items.archived = false) AS total_items,
|
(SELECT COUNT(*) FROM items WHERE group_items = $2 AND items.archived = false) AS total_items,
|
||||||
(SELECT COUNT(*) FROM locations WHERE group_locations = $2) AS total_locations,
|
(SELECT COUNT(*) FROM locations WHERE group_locations = $2) AS total_locations,
|
||||||
(SELECT COUNT(*) FROM labels WHERE group_labels = $2) AS total_labels,
|
(SELECT COUNT(*) FROM labels WHERE group_labels = $2) AS total_labels,
|
||||||
@@ -252,10 +252,15 @@ func (r *GroupRepository) StatsGroup(ctx context.Context, gid uuid.UUID) (GroupS
|
|||||||
return stats, nil
|
return stats, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *GroupRepository) GroupCreate(ctx context.Context, name string) (Group, error) {
|
func (r *GroupRepository) GroupCreate(ctx context.Context, name string, userID uuid.UUID) (Group, error) {
|
||||||
return r.groupMapper.MapErr(r.db.Group.Create().
|
createQuery := r.db.Group.Create().SetName(name)
|
||||||
SetName(name).
|
|
||||||
Save(ctx))
|
// Only link user if a valid user ID is provided
|
||||||
|
if userID != uuid.Nil {
|
||||||
|
createQuery = createQuery.AddUserIDs(userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.groupMapper.MapErr(createQuery.Save(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *GroupRepository) GroupUpdate(ctx context.Context, id uuid.UUID, data GroupUpdate) (Group, error) {
|
func (r *GroupRepository) GroupUpdate(ctx context.Context, id uuid.UUID, data GroupUpdate) (Group, error) {
|
||||||
@@ -271,6 +276,10 @@ func (r *GroupRepository) GroupByID(ctx context.Context, id uuid.UUID) (Group, e
|
|||||||
return r.groupMapper.MapErr(r.db.Group.Get(ctx, id))
|
return r.groupMapper.MapErr(r.db.Group.Get(ctx, id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *GroupRepository) GroupDelete(ctx context.Context, id uuid.UUID) error {
|
||||||
|
return r.db.Group.DeleteOneID(id).Exec(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
func (r *GroupRepository) InvitationGet(ctx context.Context, token []byte) (GroupInvitation, error) {
|
func (r *GroupRepository) InvitationGet(ctx context.Context, token []byte) (GroupInvitation, error) {
|
||||||
return r.invitationMapper.MapErr(r.db.GroupInvitationToken.Query().
|
return r.invitationMapper.MapErr(r.db.GroupInvitationToken.Query().
|
||||||
Where(groupinvitationtoken.Token(token)).
|
Where(groupinvitationtoken.Token(token)).
|
||||||
@@ -278,6 +287,18 @@ func (r *GroupRepository) InvitationGet(ctx context.Context, token []byte) (Grou
|
|||||||
Only(ctx))
|
Only(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *GroupRepository) InvitationGetAll(ctx context.Context, groupID uuid.UUID) ([]GroupInvitation, error) {
|
||||||
|
invitations, err := r.db.GroupInvitationToken.Query().
|
||||||
|
Where(groupinvitationtoken.HasGroupWith(group.ID(groupID))).
|
||||||
|
WithGroup().
|
||||||
|
All(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.invitationMapper.MapEach(invitations), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *GroupRepository) InvitationCreate(ctx context.Context, groupID uuid.UUID, invite GroupInvitationCreate) (GroupInvitation, error) {
|
func (r *GroupRepository) InvitationCreate(ctx context.Context, groupID uuid.UUID, invite GroupInvitationCreate) (GroupInvitation, error) {
|
||||||
entity, err := r.db.GroupInvitationToken.Create().
|
entity, err := r.db.GroupInvitationToken.Create().
|
||||||
SetGroupID(groupID).
|
SetGroupID(groupID).
|
||||||
@@ -308,3 +329,11 @@ func (r *GroupRepository) InvitationPurge(ctx context.Context) (amount int, err
|
|||||||
|
|
||||||
return q.Exec(ctx)
|
return q.Exec(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *GroupRepository) AddMember(ctx context.Context, groupID, userID uuid.UUID) error {
|
||||||
|
return r.db.Group.UpdateOneID(groupID).AddUserIDs(userID).Exec(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *GroupRepository) RemoveMember(ctx context.Context, groupID, userID uuid.UUID) error {
|
||||||
|
return r.db.Group.UpdateOneID(groupID).RemoveUserIDs(userID).Exec(ctx)
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,12 +4,13 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_Group_Create(t *testing.T) {
|
func Test_Group_Create(t *testing.T) {
|
||||||
g, err := tRepos.Groups.GroupCreate(context.Background(), "test")
|
g, err := tRepos.Groups.GroupCreate(context.Background(), "test", uuid.Nil)
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, "test", g.Name)
|
assert.Equal(t, "test", g.Name)
|
||||||
@@ -21,7 +22,7 @@ func Test_Group_Create(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Test_Group_Update(t *testing.T) {
|
func Test_Group_Update(t *testing.T) {
|
||||||
g, err := tRepos.Groups.GroupCreate(context.Background(), "test")
|
g, err := tRepos.Groups.GroupCreate(context.Background(), "test", uuid.Nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
g, err = tRepos.Groups.GroupUpdate(context.Background(), g.ID, GroupUpdate{
|
g, err = tRepos.Groups.GroupUpdate(context.Background(), g.ID, GroupUpdate{
|
||||||
|
|||||||
@@ -45,12 +45,12 @@ type (
|
|||||||
// Default values for items
|
// Default values for items
|
||||||
DefaultQuantity *int `json:"defaultQuantity,omitempty" extensions:"x-nullable"`
|
DefaultQuantity *int `json:"defaultQuantity,omitempty" extensions:"x-nullable"`
|
||||||
DefaultInsured bool `json:"defaultInsured"`
|
DefaultInsured bool `json:"defaultInsured"`
|
||||||
DefaultName *string `json:"defaultName,omitempty" extensions:"x-nullable" validate:"omitempty,max=255"`
|
DefaultName *string `json:"defaultName,omitempty" validate:"omitempty,max=255" extensions:"x-nullable"`
|
||||||
DefaultDescription *string `json:"defaultDescription,omitempty" extensions:"x-nullable" validate:"omitempty,max=1000"`
|
DefaultDescription *string `json:"defaultDescription,omitempty" validate:"omitempty,max=1000" extensions:"x-nullable"`
|
||||||
DefaultManufacturer *string `json:"defaultManufacturer,omitempty" extensions:"x-nullable" validate:"omitempty,max=255"`
|
DefaultManufacturer *string `json:"defaultManufacturer,omitempty" validate:"omitempty,max=255" extensions:"x-nullable"`
|
||||||
DefaultModelNumber *string `json:"defaultModelNumber,omitempty" extensions:"x-nullable" validate:"omitempty,max=255"`
|
DefaultModelNumber *string `json:"defaultModelNumber,omitempty" validate:"omitempty,max=255" extensions:"x-nullable"`
|
||||||
DefaultLifetimeWarranty bool `json:"defaultLifetimeWarranty"`
|
DefaultLifetimeWarranty bool `json:"defaultLifetimeWarranty"`
|
||||||
DefaultWarrantyDetails *string `json:"defaultWarrantyDetails,omitempty" extensions:"x-nullable" validate:"omitempty,max=1000"`
|
DefaultWarrantyDetails *string `json:"defaultWarrantyDetails,omitempty" validate:"omitempty,max=1000" extensions:"x-nullable"`
|
||||||
|
|
||||||
// Default location and labels
|
// Default location and labels
|
||||||
DefaultLocationID uuid.UUID `json:"defaultLocationId,omitempty" extensions:"x-nullable"`
|
DefaultLocationID uuid.UUID `json:"defaultLocationId,omitempty" extensions:"x-nullable"`
|
||||||
@@ -74,12 +74,12 @@ type (
|
|||||||
// Default values for items
|
// Default values for items
|
||||||
DefaultQuantity *int `json:"defaultQuantity,omitempty" extensions:"x-nullable"`
|
DefaultQuantity *int `json:"defaultQuantity,omitempty" extensions:"x-nullable"`
|
||||||
DefaultInsured bool `json:"defaultInsured"`
|
DefaultInsured bool `json:"defaultInsured"`
|
||||||
DefaultName *string `json:"defaultName,omitempty" extensions:"x-nullable" validate:"omitempty,max=255"`
|
DefaultName *string `json:"defaultName,omitempty" validate:"omitempty,max=255" extensions:"x-nullable"`
|
||||||
DefaultDescription *string `json:"defaultDescription,omitempty" extensions:"x-nullable" validate:"omitempty,max=1000"`
|
DefaultDescription *string `json:"defaultDescription,omitempty" validate:"omitempty,max=1000" extensions:"x-nullable"`
|
||||||
DefaultManufacturer *string `json:"defaultManufacturer,omitempty" extensions:"x-nullable" validate:"omitempty,max=255"`
|
DefaultManufacturer *string `json:"defaultManufacturer,omitempty" validate:"omitempty,max=255" extensions:"x-nullable"`
|
||||||
DefaultModelNumber *string `json:"defaultModelNumber,omitempty" extensions:"x-nullable" validate:"omitempty,max=255"`
|
DefaultModelNumber *string `json:"defaultModelNumber,omitempty" validate:"omitempty,max=255" extensions:"x-nullable"`
|
||||||
DefaultLifetimeWarranty bool `json:"defaultLifetimeWarranty"`
|
DefaultLifetimeWarranty bool `json:"defaultLifetimeWarranty"`
|
||||||
DefaultWarrantyDetails *string `json:"defaultWarrantyDetails,omitempty" extensions:"x-nullable" validate:"omitempty,max=1000"`
|
DefaultWarrantyDetails *string `json:"defaultWarrantyDetails,omitempty" validate:"omitempty,max=1000" extensions:"x-nullable"`
|
||||||
|
|
||||||
// Default location and labels
|
// Default location and labels
|
||||||
DefaultLocationID uuid.UUID `json:"defaultLocationId,omitempty" extensions:"x-nullable"`
|
DefaultLocationID uuid.UUID `json:"defaultLocationId,omitempty" extensions:"x-nullable"`
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ func TestItemsRepository_AccentInsensitiveSearch(t *testing.T) {
|
|||||||
if tc.shouldMatch {
|
if tc.shouldMatch {
|
||||||
// If it should match, then either the original query should match
|
// If it should match, then either the original query should match
|
||||||
// or the normalized query should match when applied to the stored data
|
// or the normalized query should match when applied to the stored data
|
||||||
assert.NotEqual(t, "", normalizedSearch, "Normalized search should not be empty")
|
assert.NotEmpty(t, normalizedSearch, "Normalized search should not be empty")
|
||||||
|
|
||||||
// The key insight is that we're searching with both the original and normalized queries
|
// The key insight is that we're searching with both the original and normalized queries
|
||||||
// So "electrónica" will be found when searching for "electronica" because:
|
// So "electrónica" will be found when searching for "electronica" because:
|
||||||
|
|||||||
@@ -313,7 +313,7 @@ func TestItemRepository_GetAllCustomFields(t *testing.T) {
|
|||||||
|
|
||||||
// Test getting all values from field
|
// 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)
|
require.NoError(t, err)
|
||||||
assert.ElementsMatch(t, values[:1], results)
|
assert.ElementsMatch(t, values[:1], results)
|
||||||
@@ -465,7 +465,7 @@ func TestItemsRepository_WipeInventory(t *testing.T) {
|
|||||||
t.Run("wipe all including labels, locations, and maintenance", func(t *testing.T) {
|
t.Run("wipe all including labels, locations, and maintenance", func(t *testing.T) {
|
||||||
deleted, err := tRepos.Items.WipeInventory(context.Background(), tGroup.ID, true, true, true)
|
deleted, err := tRepos.Items.WipeInventory(context.Background(), tGroup.ID, true, true, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Greater(t, deleted, 0, "Should have deleted at least some entities")
|
assert.Positive(t, deleted, "Should have deleted at least some entities")
|
||||||
|
|
||||||
// Verify items are deleted
|
// Verify items are deleted
|
||||||
_, err = tRepos.Items.GetOneByGroup(context.Background(), tGroup.ID, item1.ID)
|
_, err = tRepos.Items.GetOneByGroup(context.Background(), tGroup.ID, item1.ID)
|
||||||
@@ -532,7 +532,7 @@ func TestItemsRepository_WipeInventory_OnlyItems(t *testing.T) {
|
|||||||
// Test: Wipe inventory with only items (no labels, locations, or maintenance)
|
// Test: Wipe inventory with only items (no labels, locations, or maintenance)
|
||||||
deleted, err := tRepos.Items.WipeInventory(context.Background(), tGroup.ID, false, false, false)
|
deleted, err := tRepos.Items.WipeInventory(context.Background(), tGroup.ID, false, false, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Greater(t, deleted, 0, "Should have deleted at least the item")
|
assert.Positive(t, deleted, "Should have deleted at least the item")
|
||||||
|
|
||||||
// Verify item is deleted
|
// Verify item is deleted
|
||||||
_, err = tRepos.Items.GetOneByGroup(context.Background(), tGroup.ID, item.ID)
|
_, err = tRepos.Items.GetOneByGroup(context.Background(), tGroup.ID, item.ID)
|
||||||
@@ -555,4 +555,3 @@ func TestItemsRepository_WipeInventory_OnlyItems(t *testing.T) {
|
|||||||
_ = tRepos.Labels.DeleteByGroup(context.Background(), tGroup.ID, label.ID)
|
_ = tRepos.Labels.DeleteByGroup(context.Background(), tGroup.ID, label.ID)
|
||||||
_ = tRepos.Locations.delete(context.Background(), loc.ID)
|
_ = tRepos.Locations.delete(context.Background(), loc.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ func (r *TokenRepository) GetUserFromToken(ctx context.Context, token []byte) (U
|
|||||||
Where(authtokens.ExpiresAtGTE(time.Now())).
|
Where(authtokens.ExpiresAtGTE(time.Now())).
|
||||||
WithUser().
|
WithUser().
|
||||||
QueryUser().
|
QueryUser().
|
||||||
WithGroup().
|
WithGroups().
|
||||||
Only(ctx)
|
Only(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return UserOut{}, err
|
return UserOut{}, err
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/sysadminsmedia/homebox/backend/internal/data/ent"
|
"github.com/sysadminsmedia/homebox/backend/internal/data/ent"
|
||||||
|
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/group"
|
||||||
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/user"
|
"github.com/sysadminsmedia/homebox/backend/internal/data/ent/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,8 +21,8 @@ type (
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Password *string `json:"password"`
|
Password *string `json:"password"`
|
||||||
IsSuperuser bool `json:"isSuperuser"`
|
IsSuperuser bool `json:"isSuperUser"`
|
||||||
GroupID uuid.UUID `json:"groupID"`
|
DefaultGroupID uuid.UUID `json:"defaultGroupID"`
|
||||||
IsOwner bool `json:"isOwner"`
|
IsOwner bool `json:"isOwner"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,8 +36,8 @@ type (
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
IsSuperuser bool `json:"isSuperuser"`
|
IsSuperuser bool `json:"isSuperuser"`
|
||||||
GroupID uuid.UUID `json:"groupId"`
|
DefaultGroupID uuid.UUID `json:"defaultGroupId"`
|
||||||
GroupName string `json:"groupName"`
|
GroupIDs []uuid.UUID `json:"groupIds"`
|
||||||
PasswordHash string `json:"-"`
|
PasswordHash string `json:"-"`
|
||||||
IsOwner bool `json:"isOwner"`
|
IsOwner bool `json:"isOwner"`
|
||||||
OidcIssuer *string `json:"oidcIssuer"`
|
OidcIssuer *string `json:"oidcIssuer"`
|
||||||
@@ -55,13 +56,24 @@ func mapUserOut(user *ent.User) UserOut {
|
|||||||
passwordHash = *user.Password
|
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{
|
return UserOut{
|
||||||
ID: user.ID,
|
ID: user.ID,
|
||||||
Name: user.Name,
|
Name: user.Name,
|
||||||
Email: user.Email,
|
Email: user.Email,
|
||||||
IsSuperuser: user.IsSuperuser,
|
IsSuperuser: user.IsSuperuser,
|
||||||
GroupID: user.Edges.Group.ID,
|
DefaultGroupID: defaultGroupID,
|
||||||
GroupName: user.Edges.Group.Name,
|
GroupIDs: groupIDs,
|
||||||
PasswordHash: passwordHash,
|
PasswordHash: passwordHash,
|
||||||
IsOwner: user.Role == "owner",
|
IsOwner: user.Role == "owner",
|
||||||
OidcIssuer: user.OidcIssuer,
|
OidcIssuer: user.OidcIssuer,
|
||||||
@@ -72,20 +84,27 @@ func mapUserOut(user *ent.User) UserOut {
|
|||||||
func (r *UserRepository) GetOneID(ctx context.Context, id uuid.UUID) (UserOut, error) {
|
func (r *UserRepository) GetOneID(ctx context.Context, id uuid.UUID) (UserOut, error) {
|
||||||
return mapUserOutErr(r.db.User.Query().
|
return mapUserOutErr(r.db.User.Query().
|
||||||
Where(user.ID(id)).
|
Where(user.ID(id)).
|
||||||
WithGroup().
|
WithGroups().
|
||||||
Only(ctx))
|
Only(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *UserRepository) GetOneEmail(ctx context.Context, email string) (UserOut, error) {
|
func (r *UserRepository) GetOneEmail(ctx context.Context, email string) (UserOut, error) {
|
||||||
return mapUserOutErr(r.db.User.Query().
|
return mapUserOutErr(r.db.User.Query().
|
||||||
Where(user.EmailEqualFold(email)).
|
Where(user.EmailEqualFold(email)).
|
||||||
WithGroup().
|
WithGroups().
|
||||||
|
Only(ctx),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *UserRepository) GetOneEmailNoEdges(ctx context.Context, email string) (UserOut, error) {
|
||||||
|
return mapUserOutErr(r.db.User.Query().
|
||||||
|
Where(user.EmailEqualFold(email)).
|
||||||
Only(ctx),
|
Only(ctx),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *UserRepository) GetAll(ctx context.Context) ([]UserOut, error) {
|
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) {
|
func (r *UserRepository) Create(ctx context.Context, usr UserCreate) (UserOut, error) {
|
||||||
@@ -99,8 +118,9 @@ func (r *UserRepository) Create(ctx context.Context, usr UserCreate) (UserOut, e
|
|||||||
SetName(usr.Name).
|
SetName(usr.Name).
|
||||||
SetEmail(usr.Email).
|
SetEmail(usr.Email).
|
||||||
SetIsSuperuser(usr.IsSuperuser).
|
SetIsSuperuser(usr.IsSuperuser).
|
||||||
SetGroupID(usr.GroupID).
|
SetDefaultGroupID(usr.DefaultGroupID).
|
||||||
SetRole(role)
|
SetRole(role).
|
||||||
|
AddGroupIDs(usr.DefaultGroupID)
|
||||||
|
|
||||||
// Only set password if provided (non-nil)
|
// Only set password if provided (non-nil)
|
||||||
if usr.Password != nil {
|
if usr.Password != nil {
|
||||||
@@ -126,10 +146,11 @@ func (r *UserRepository) CreateWithOIDC(ctx context.Context, usr UserCreate, iss
|
|||||||
SetName(usr.Name).
|
SetName(usr.Name).
|
||||||
SetEmail(usr.Email).
|
SetEmail(usr.Email).
|
||||||
SetIsSuperuser(usr.IsSuperuser).
|
SetIsSuperuser(usr.IsSuperuser).
|
||||||
SetGroupID(usr.GroupID).
|
SetDefaultGroupID(usr.DefaultGroupID).
|
||||||
SetRole(role).
|
SetRole(role).
|
||||||
SetOidcIssuer(issuer).
|
SetOidcIssuer(issuer).
|
||||||
SetOidcSubject(subject)
|
SetOidcSubject(subject).
|
||||||
|
AddGroupIDs(usr.DefaultGroupID)
|
||||||
|
|
||||||
if usr.Password != nil {
|
if usr.Password != nil {
|
||||||
createQuery = createQuery.SetPassword(*usr.Password)
|
createQuery = createQuery.SetPassword(*usr.Password)
|
||||||
@@ -183,6 +204,13 @@ func (r *UserRepository) SetOIDCIdentity(ctx context.Context, uid uuid.UUID, iss
|
|||||||
func (r *UserRepository) GetOneOIDC(ctx context.Context, issuer, subject string) (UserOut, error) {
|
func (r *UserRepository) GetOneOIDC(ctx context.Context, issuer, subject string) (UserOut, error) {
|
||||||
return mapUserOutErr(r.db.User.Query().
|
return mapUserOutErr(r.db.User.Query().
|
||||||
Where(user.OidcIssuerEQ(issuer), user.OidcSubjectEQ(subject)).
|
Where(user.OidcIssuerEQ(issuer), user.OidcSubjectEQ(subject)).
|
||||||
WithGroup().
|
WithGroups().
|
||||||
Only(ctx))
|
Only(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *UserRepository) GetUsersByGroupID(ctx context.Context, gid uuid.UUID) ([]UserOut, error) {
|
||||||
|
return mapUsersOutErr(r.db.User.Query().
|
||||||
|
WithGroups().
|
||||||
|
Where(user.HasGroupsWith(group.ID(gid))).
|
||||||
|
All(ctx))
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@@ -15,7 +16,7 @@ func userFactory() UserCreate {
|
|||||||
Email: fk.Email(),
|
Email: fk.Email(),
|
||||||
Password: &password,
|
Password: &password,
|
||||||
IsSuperuser: fk.Bool(),
|
IsSuperuser: fk.Bool(),
|
||||||
GroupID: tGroup.ID,
|
DefaultGroupID: tGroup.ID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +88,8 @@ func TestUserRepo_GetAll(t *testing.T) {
|
|||||||
assert.Equal(t, usr.Email, usr2.Email)
|
assert.Equal(t, usr.Email, usr2.Email)
|
||||||
|
|
||||||
// Check groups are loaded
|
// Check groups are loaded
|
||||||
assert.NotNil(t, usr2.GroupID)
|
assert.NotEqual(t, uuid.Nil, usr2.DefaultGroupID)
|
||||||
|
assert.NotEmpty(t, usr2.GroupIDs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,12 +108,12 @@ func TestWipeInventory_Integration(t *testing.T) {
|
|||||||
// 7. Test wipe inventory with all options enabled
|
// 7. Test wipe inventory with all options enabled
|
||||||
deleted, err := tRepos.Items.WipeInventory(context.Background(), tGroup.ID, true, true, true)
|
deleted, err := tRepos.Items.WipeInventory(context.Background(), tGroup.ID, true, true, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Greater(t, deleted, 0, "Should have deleted entities")
|
assert.Positive(t, deleted, "Should have deleted entities")
|
||||||
|
|
||||||
// 8. Verify all items are deleted
|
// 8. Verify all items are deleted
|
||||||
allItemsAfter, err := tRepos.Items.GetAll(context.Background(), tGroup.ID)
|
allItemsAfter, err := tRepos.Items.GetAll(context.Background(), tGroup.ID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, 0, len(allItemsAfter), "All items should be deleted")
|
assert.Empty(t, allItemsAfter, "All items should be deleted")
|
||||||
|
|
||||||
// 9. Verify maintenance entries are deleted
|
// 9. Verify maintenance entries are deleted
|
||||||
maint1After, err := tRepos.MaintEntry.GetMaintenanceByItemID(context.Background(), tGroup.ID, item1.ID, MaintenanceFilters{})
|
maint1After, err := tRepos.MaintEntry.GetMaintenanceByItemID(context.Background(), tGroup.ID, item1.ID, MaintenanceFilters{})
|
||||||
@@ -169,7 +169,7 @@ func TestWipeInventory_SelectiveWipe(t *testing.T) {
|
|||||||
// Test: Wipe only items (keep labels and locations)
|
// Test: Wipe only items (keep labels and locations)
|
||||||
deleted, err := tRepos.Items.WipeInventory(context.Background(), tGroup.ID, false, false, false)
|
deleted, err := tRepos.Items.WipeInventory(context.Background(), tGroup.ID, false, false, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Greater(t, deleted, 0, "Should have deleted at least items")
|
assert.Positive(t, deleted, "Should have deleted at least items")
|
||||||
|
|
||||||
// Verify item is deleted
|
// Verify item is deleted
|
||||||
_, err = tRepos.Items.GetOneByGroup(context.Background(), tGroup.ID, item.ID)
|
_, err = tRepos.Items.GetOneByGroup(context.Background(), tGroup.ID, item.ID)
|
||||||
|
|||||||
@@ -241,15 +241,18 @@
|
|||||||
"tags": [
|
"tags": [
|
||||||
"Group"
|
"Group"
|
||||||
],
|
],
|
||||||
"summary": "Get Group",
|
"summary": "Get All Groups",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
"$ref": "#/definitions/repo.Group"
|
"$ref": "#/definitions/repo.Group"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"put": {
|
"put": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -286,6 +289,31 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/v1/groups/invitations": {
|
"/v1/groups/invitations": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Get All Group Invitations",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/repo.GroupInvitation"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
@@ -436,6 +464,147 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/v1/groups/{id}": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Create Group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Group Name",
|
||||||
|
"name": "name",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": "Created",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/repo.Group"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Delete Group",
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/v1/groups/{id}/members": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Get All Group Members",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/repo.UserOut"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Add User to Group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "User ID",
|
||||||
|
"name": "payload",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1.GroupMemberAdd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/v1/groups/{id}/members/{user_id}": {
|
||||||
|
"delete": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Remove User from Group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "User ID",
|
||||||
|
"name": "user_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/v1/items": {
|
"/v1/items": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -3527,6 +3696,10 @@
|
|||||||
"description": "CreatedAt holds the value of the \"created_at\" field.",
|
"description": "CreatedAt holds the value of the \"created_at\" field.",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"default_group_id": {
|
||||||
|
"description": "DefaultGroupID holds the value of the \"default_group_id\" field.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"edges": {
|
"edges": {
|
||||||
"description": "Edges holds the relations/edges for other nodes in the graph.\nThe values are being populated by the UserQuery when eager-loading is set.",
|
"description": "Edges holds the relations/edges for other nodes in the graph.\nThe values are being populated by the UserQuery when eager-loading is set.",
|
||||||
"allOf": [
|
"allOf": [
|
||||||
@@ -3587,13 +3760,12 @@
|
|||||||
"$ref": "#/definitions/ent.AuthTokens"
|
"$ref": "#/definitions/ent.AuthTokens"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"group": {
|
"groups": {
|
||||||
"description": "Group holds the value of the group edge.",
|
"description": "Groups holds the value of the groups edge.",
|
||||||
"allOf": [
|
"type": "array",
|
||||||
{
|
"items": {
|
||||||
"$ref": "#/definitions/ent.Group"
|
"$ref": "#/definitions/ent.Group"
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"notifiers": {
|
"notifiers": {
|
||||||
"description": "Notifiers holds the value of the notifiers edge.",
|
"description": "Notifiers holds the value of the notifiers edge.",
|
||||||
@@ -3687,6 +3859,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"repo.GroupInvitation": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"expiresAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"$ref": "#/definitions/repo.Group"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"uses": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"repo.GroupStatistics": {
|
"repo.GroupStatistics": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -4904,14 +5093,17 @@
|
|||||||
"repo.UserOut": {
|
"repo.UserOut": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"defaultGroupId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"email": {
|
"email": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"groupId": {
|
"groupIds": {
|
||||||
"type": "string"
|
"type": "array",
|
||||||
},
|
"items": {
|
||||||
"groupName": {
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@@ -5132,6 +5324,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"v1.GroupMemberAdd": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"userId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"userId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"v1.ItemAttachmentToken": {
|
"v1.ItemAttachmentToken": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@@ -719,6 +719,9 @@ definitions:
|
|||||||
created_at:
|
created_at:
|
||||||
description: CreatedAt holds the value of the "created_at" field.
|
description: CreatedAt holds the value of the "created_at" field.
|
||||||
type: string
|
type: string
|
||||||
|
default_group_id:
|
||||||
|
description: DefaultGroupID holds the value of the "default_group_id" field.
|
||||||
|
type: string
|
||||||
edges:
|
edges:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/definitions/ent.UserEdges'
|
- $ref: '#/definitions/ent.UserEdges'
|
||||||
@@ -761,10 +764,11 @@ definitions:
|
|||||||
items:
|
items:
|
||||||
$ref: '#/definitions/ent.AuthTokens'
|
$ref: '#/definitions/ent.AuthTokens'
|
||||||
type: array
|
type: array
|
||||||
group:
|
groups:
|
||||||
allOf:
|
description: Groups holds the value of the groups edge.
|
||||||
- $ref: '#/definitions/ent.Group'
|
items:
|
||||||
description: Group holds the value of the group edge.
|
$ref: '#/definitions/ent.Group'
|
||||||
|
type: array
|
||||||
notifiers:
|
notifiers:
|
||||||
description: Notifiers holds the value of the notifiers edge.
|
description: Notifiers holds the value of the notifiers edge.
|
||||||
items:
|
items:
|
||||||
@@ -828,6 +832,17 @@ definitions:
|
|||||||
updatedAt:
|
updatedAt:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
repo.GroupInvitation:
|
||||||
|
properties:
|
||||||
|
expiresAt:
|
||||||
|
type: string
|
||||||
|
group:
|
||||||
|
$ref: '#/definitions/repo.Group'
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
uses:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
repo.GroupStatistics:
|
repo.GroupStatistics:
|
||||||
properties:
|
properties:
|
||||||
totalItemPrice:
|
totalItemPrice:
|
||||||
@@ -1660,12 +1675,14 @@ definitions:
|
|||||||
type: object
|
type: object
|
||||||
repo.UserOut:
|
repo.UserOut:
|
||||||
properties:
|
properties:
|
||||||
|
defaultGroupId:
|
||||||
|
type: string
|
||||||
email:
|
email:
|
||||||
type: string
|
type: string
|
||||||
groupId:
|
groupIds:
|
||||||
type: string
|
items:
|
||||||
groupName:
|
|
||||||
type: string
|
type: string
|
||||||
|
type: array
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
isOwner:
|
isOwner:
|
||||||
@@ -1810,6 +1827,13 @@ definitions:
|
|||||||
required:
|
required:
|
||||||
- uses
|
- uses
|
||||||
type: object
|
type: object
|
||||||
|
v1.GroupMemberAdd:
|
||||||
|
properties:
|
||||||
|
userId:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- userId
|
||||||
|
type: object
|
||||||
v1.ItemAttachmentToken:
|
v1.ItemAttachmentToken:
|
||||||
properties:
|
properties:
|
||||||
token:
|
token:
|
||||||
@@ -2032,10 +2056,12 @@ paths:
|
|||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
|
items:
|
||||||
$ref: '#/definitions/repo.Group'
|
$ref: '#/definitions/repo.Group'
|
||||||
|
type: array
|
||||||
security:
|
security:
|
||||||
- Bearer: []
|
- Bearer: []
|
||||||
summary: Get Group
|
summary: Get All Groups
|
||||||
tags:
|
tags:
|
||||||
- Group
|
- Group
|
||||||
put:
|
put:
|
||||||
@@ -2058,7 +2084,106 @@ paths:
|
|||||||
summary: Update Group
|
summary: Update Group
|
||||||
tags:
|
tags:
|
||||||
- Group
|
- Group
|
||||||
|
/v1/groups/{id}:
|
||||||
|
delete:
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Delete Group
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
post:
|
||||||
|
parameters:
|
||||||
|
- description: Group Name
|
||||||
|
in: body
|
||||||
|
name: name
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"201":
|
||||||
|
description: Created
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/repo.Group'
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Create Group
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
/v1/groups/{id}/members:
|
||||||
|
get:
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/repo.UserOut'
|
||||||
|
type: array
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Get All Group Members
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
post:
|
||||||
|
parameters:
|
||||||
|
- description: User ID
|
||||||
|
in: body
|
||||||
|
name: payload
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/v1.GroupMemberAdd'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Add User to Group
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
/v1/groups/{id}/members/{user_id}:
|
||||||
|
delete:
|
||||||
|
parameters:
|
||||||
|
- description: User ID
|
||||||
|
in: path
|
||||||
|
name: user_id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Remove User from Group
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
/v1/groups/invitations:
|
/v1/groups/invitations:
|
||||||
|
get:
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/repo.GroupInvitation'
|
||||||
|
type: array
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Get All Group Invitations
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
post:
|
post:
|
||||||
parameters:
|
parameters:
|
||||||
- description: User Data
|
- description: User Data
|
||||||
|
|||||||
@@ -242,19 +242,22 @@
|
|||||||
"tags": [
|
"tags": [
|
||||||
"Group"
|
"Group"
|
||||||
],
|
],
|
||||||
"summary": "Get Group",
|
"summary": "Get All Groups",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
"$ref": "#/components/schemas/repo.Group"
|
"$ref": "#/components/schemas/repo.Group"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"put": {
|
"put": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -292,6 +295,32 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/v1/groups/invitations": {
|
"/v1/groups/invitations": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Get All Group Invitations",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/repo.GroupInvitation"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
@@ -451,6 +480,142 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/v1/groups/{id}": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Create Group",
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Group Name",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": "Created",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/repo.Group"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Delete Group",
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/v1/groups/{id}/members": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Get All Group Members",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/repo.UserOut"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Add User to Group",
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/v1.GroupMemberAdd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "User ID",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/v1/groups/{id}/members/{user_id}": {
|
||||||
|
"delete": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Remove User from Group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "User ID",
|
||||||
|
"name": "user_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/v1/items": {
|
"/v1/items": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -3727,6 +3892,10 @@
|
|||||||
"description": "CreatedAt holds the value of the \"created_at\" field.",
|
"description": "CreatedAt holds the value of the \"created_at\" field.",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"default_group_id": {
|
||||||
|
"description": "DefaultGroupID holds the value of the \"default_group_id\" field.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"edges": {
|
"edges": {
|
||||||
"description": "Edges holds the relations/edges for other nodes in the graph.\nThe values are being populated by the UserQuery when eager-loading is set.",
|
"description": "Edges holds the relations/edges for other nodes in the graph.\nThe values are being populated by the UserQuery when eager-loading is set.",
|
||||||
"allOf": [
|
"allOf": [
|
||||||
@@ -3787,13 +3956,12 @@
|
|||||||
"$ref": "#/components/schemas/ent.AuthTokens"
|
"$ref": "#/components/schemas/ent.AuthTokens"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"group": {
|
"groups": {
|
||||||
"description": "Group holds the value of the group edge.",
|
"description": "Groups holds the value of the groups edge.",
|
||||||
"allOf": [
|
"type": "array",
|
||||||
{
|
"items": {
|
||||||
"$ref": "#/components/schemas/ent.Group"
|
"$ref": "#/components/schemas/ent.Group"
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"notifiers": {
|
"notifiers": {
|
||||||
"description": "Notifiers holds the value of the notifiers edge.",
|
"description": "Notifiers holds the value of the notifiers edge.",
|
||||||
@@ -3887,6 +4055,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"repo.GroupInvitation": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"expiresAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"$ref": "#/components/schemas/repo.Group"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"uses": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"repo.GroupStatistics": {
|
"repo.GroupStatistics": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -5104,14 +5289,17 @@
|
|||||||
"repo.UserOut": {
|
"repo.UserOut": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"defaultGroupId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"email": {
|
"email": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"groupId": {
|
"groupIds": {
|
||||||
"type": "string"
|
"type": "array",
|
||||||
},
|
"items": {
|
||||||
"groupName": {
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@@ -5332,6 +5520,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"v1.GroupMemberAdd": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"userId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"userId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"v1.ItemAttachmentToken": {
|
"v1.ItemAttachmentToken": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@@ -142,13 +142,15 @@ paths:
|
|||||||
- Bearer: []
|
- Bearer: []
|
||||||
tags:
|
tags:
|
||||||
- Group
|
- Group
|
||||||
summary: Get Group
|
summary: Get All Groups
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
$ref: "#/components/schemas/repo.Group"
|
$ref: "#/components/schemas/repo.Group"
|
||||||
put:
|
put:
|
||||||
security:
|
security:
|
||||||
@@ -171,6 +173,21 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/repo.Group"
|
$ref: "#/components/schemas/repo.Group"
|
||||||
/v1/groups/invitations:
|
/v1/groups/invitations:
|
||||||
|
get:
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
summary: Get All Group Invitations
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/repo.GroupInvitation"
|
||||||
post:
|
post:
|
||||||
security:
|
security:
|
||||||
- Bearer: []
|
- Bearer: []
|
||||||
@@ -262,6 +279,85 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/repo.ValueOverTime"
|
$ref: "#/components/schemas/repo.ValueOverTime"
|
||||||
|
"/v1/groups/{id}":
|
||||||
|
post:
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
summary: Create Group
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: Group Name
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
"201":
|
||||||
|
description: Created
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/repo.Group"
|
||||||
|
delete:
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
summary: Delete Group
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
|
"/v1/groups/{id}/members":
|
||||||
|
get:
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
summary: Get All Group Members
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/repo.UserOut"
|
||||||
|
post:
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
summary: Add User to Group
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/v1.GroupMemberAdd"
|
||||||
|
description: User ID
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
|
"/v1/groups/{id}/members/{user_id}":
|
||||||
|
delete:
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
summary: Remove User from Group
|
||||||
|
parameters:
|
||||||
|
- description: User ID
|
||||||
|
name: user_id
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
/v1/items:
|
/v1/items:
|
||||||
get:
|
get:
|
||||||
security:
|
security:
|
||||||
@@ -2322,6 +2418,9 @@ components:
|
|||||||
created_at:
|
created_at:
|
||||||
description: CreatedAt holds the value of the "created_at" field.
|
description: CreatedAt holds the value of the "created_at" field.
|
||||||
type: string
|
type: string
|
||||||
|
default_group_id:
|
||||||
|
description: DefaultGroupID holds the value of the "default_group_id" field.
|
||||||
|
type: string
|
||||||
edges:
|
edges:
|
||||||
description: >-
|
description: >-
|
||||||
Edges holds the relations/edges for other nodes in the graph.
|
Edges holds the relations/edges for other nodes in the graph.
|
||||||
@@ -2365,10 +2464,11 @@ components:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/ent.AuthTokens"
|
$ref: "#/components/schemas/ent.AuthTokens"
|
||||||
group:
|
groups:
|
||||||
description: Group holds the value of the group edge.
|
description: Groups holds the value of the groups edge.
|
||||||
allOf:
|
type: array
|
||||||
- $ref: "#/components/schemas/ent.Group"
|
items:
|
||||||
|
$ref: "#/components/schemas/ent.Group"
|
||||||
notifiers:
|
notifiers:
|
||||||
description: Notifiers holds the value of the notifiers edge.
|
description: Notifiers holds the value of the notifiers edge.
|
||||||
type: array
|
type: array
|
||||||
@@ -2431,6 +2531,17 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
updatedAt:
|
updatedAt:
|
||||||
type: string
|
type: string
|
||||||
|
repo.GroupInvitation:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
expiresAt:
|
||||||
|
type: string
|
||||||
|
group:
|
||||||
|
$ref: "#/components/schemas/repo.Group"
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
uses:
|
||||||
|
type: integer
|
||||||
repo.GroupStatistics:
|
repo.GroupStatistics:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@@ -3264,11 +3375,13 @@ components:
|
|||||||
repo.UserOut:
|
repo.UserOut:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
defaultGroupId:
|
||||||
|
type: string
|
||||||
email:
|
email:
|
||||||
type: string
|
type: string
|
||||||
groupId:
|
groupIds:
|
||||||
type: string
|
type: array
|
||||||
groupName:
|
items:
|
||||||
type: string
|
type: string
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
@@ -3413,6 +3526,13 @@ components:
|
|||||||
type: integer
|
type: integer
|
||||||
maximum: 100
|
maximum: 100
|
||||||
minimum: 1
|
minimum: 1
|
||||||
|
v1.GroupMemberAdd:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- userId
|
||||||
|
properties:
|
||||||
|
userId:
|
||||||
|
type: string
|
||||||
v1.ItemAttachmentToken:
|
v1.ItemAttachmentToken:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|||||||
@@ -241,15 +241,18 @@
|
|||||||
"tags": [
|
"tags": [
|
||||||
"Group"
|
"Group"
|
||||||
],
|
],
|
||||||
"summary": "Get Group",
|
"summary": "Get All Groups",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
"$ref": "#/definitions/repo.Group"
|
"$ref": "#/definitions/repo.Group"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"put": {
|
"put": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -286,6 +289,31 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/v1/groups/invitations": {
|
"/v1/groups/invitations": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Get All Group Invitations",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/repo.GroupInvitation"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
@@ -436,6 +464,147 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/v1/groups/{id}": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Create Group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Group Name",
|
||||||
|
"name": "name",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"201": {
|
||||||
|
"description": "Created",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/repo.Group"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Delete Group",
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/v1/groups/{id}/members": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Get All Group Members",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/repo.UserOut"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Add User to Group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "User ID",
|
||||||
|
"name": "payload",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1.GroupMemberAdd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/v1/groups/{id}/members/{user_id}": {
|
||||||
|
"delete": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Group"
|
||||||
|
],
|
||||||
|
"summary": "Remove User from Group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "User ID",
|
||||||
|
"name": "user_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "No Content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/v1/items": {
|
"/v1/items": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
@@ -3527,6 +3696,10 @@
|
|||||||
"description": "CreatedAt holds the value of the \"created_at\" field.",
|
"description": "CreatedAt holds the value of the \"created_at\" field.",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"default_group_id": {
|
||||||
|
"description": "DefaultGroupID holds the value of the \"default_group_id\" field.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"edges": {
|
"edges": {
|
||||||
"description": "Edges holds the relations/edges for other nodes in the graph.\nThe values are being populated by the UserQuery when eager-loading is set.",
|
"description": "Edges holds the relations/edges for other nodes in the graph.\nThe values are being populated by the UserQuery when eager-loading is set.",
|
||||||
"allOf": [
|
"allOf": [
|
||||||
@@ -3587,13 +3760,12 @@
|
|||||||
"$ref": "#/definitions/ent.AuthTokens"
|
"$ref": "#/definitions/ent.AuthTokens"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"group": {
|
"groups": {
|
||||||
"description": "Group holds the value of the group edge.",
|
"description": "Groups holds the value of the groups edge.",
|
||||||
"allOf": [
|
"type": "array",
|
||||||
{
|
"items": {
|
||||||
"$ref": "#/definitions/ent.Group"
|
"$ref": "#/definitions/ent.Group"
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"notifiers": {
|
"notifiers": {
|
||||||
"description": "Notifiers holds the value of the notifiers edge.",
|
"description": "Notifiers holds the value of the notifiers edge.",
|
||||||
@@ -3687,6 +3859,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"repo.GroupInvitation": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"expiresAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"$ref": "#/definitions/repo.Group"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"uses": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"repo.GroupStatistics": {
|
"repo.GroupStatistics": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -4904,14 +5093,17 @@
|
|||||||
"repo.UserOut": {
|
"repo.UserOut": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"defaultGroupId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"email": {
|
"email": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"groupId": {
|
"groupIds": {
|
||||||
"type": "string"
|
"type": "array",
|
||||||
},
|
"items": {
|
||||||
"groupName": {
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@@ -5132,6 +5324,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"v1.GroupMemberAdd": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"userId"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"userId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"v1.ItemAttachmentToken": {
|
"v1.ItemAttachmentToken": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@@ -719,6 +719,9 @@ definitions:
|
|||||||
created_at:
|
created_at:
|
||||||
description: CreatedAt holds the value of the "created_at" field.
|
description: CreatedAt holds the value of the "created_at" field.
|
||||||
type: string
|
type: string
|
||||||
|
default_group_id:
|
||||||
|
description: DefaultGroupID holds the value of the "default_group_id" field.
|
||||||
|
type: string
|
||||||
edges:
|
edges:
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: '#/definitions/ent.UserEdges'
|
- $ref: '#/definitions/ent.UserEdges'
|
||||||
@@ -761,10 +764,11 @@ definitions:
|
|||||||
items:
|
items:
|
||||||
$ref: '#/definitions/ent.AuthTokens'
|
$ref: '#/definitions/ent.AuthTokens'
|
||||||
type: array
|
type: array
|
||||||
group:
|
groups:
|
||||||
allOf:
|
description: Groups holds the value of the groups edge.
|
||||||
- $ref: '#/definitions/ent.Group'
|
items:
|
||||||
description: Group holds the value of the group edge.
|
$ref: '#/definitions/ent.Group'
|
||||||
|
type: array
|
||||||
notifiers:
|
notifiers:
|
||||||
description: Notifiers holds the value of the notifiers edge.
|
description: Notifiers holds the value of the notifiers edge.
|
||||||
items:
|
items:
|
||||||
@@ -828,6 +832,17 @@ definitions:
|
|||||||
updatedAt:
|
updatedAt:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
repo.GroupInvitation:
|
||||||
|
properties:
|
||||||
|
expiresAt:
|
||||||
|
type: string
|
||||||
|
group:
|
||||||
|
$ref: '#/definitions/repo.Group'
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
uses:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
repo.GroupStatistics:
|
repo.GroupStatistics:
|
||||||
properties:
|
properties:
|
||||||
totalItemPrice:
|
totalItemPrice:
|
||||||
@@ -1660,12 +1675,14 @@ definitions:
|
|||||||
type: object
|
type: object
|
||||||
repo.UserOut:
|
repo.UserOut:
|
||||||
properties:
|
properties:
|
||||||
|
defaultGroupId:
|
||||||
|
type: string
|
||||||
email:
|
email:
|
||||||
type: string
|
type: string
|
||||||
groupId:
|
groupIds:
|
||||||
type: string
|
items:
|
||||||
groupName:
|
|
||||||
type: string
|
type: string
|
||||||
|
type: array
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
isOwner:
|
isOwner:
|
||||||
@@ -1810,6 +1827,13 @@ definitions:
|
|||||||
required:
|
required:
|
||||||
- uses
|
- uses
|
||||||
type: object
|
type: object
|
||||||
|
v1.GroupMemberAdd:
|
||||||
|
properties:
|
||||||
|
userId:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- userId
|
||||||
|
type: object
|
||||||
v1.ItemAttachmentToken:
|
v1.ItemAttachmentToken:
|
||||||
properties:
|
properties:
|
||||||
token:
|
token:
|
||||||
@@ -2032,10 +2056,12 @@ paths:
|
|||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
|
items:
|
||||||
$ref: '#/definitions/repo.Group'
|
$ref: '#/definitions/repo.Group'
|
||||||
|
type: array
|
||||||
security:
|
security:
|
||||||
- Bearer: []
|
- Bearer: []
|
||||||
summary: Get Group
|
summary: Get All Groups
|
||||||
tags:
|
tags:
|
||||||
- Group
|
- Group
|
||||||
put:
|
put:
|
||||||
@@ -2058,7 +2084,106 @@ paths:
|
|||||||
summary: Update Group
|
summary: Update Group
|
||||||
tags:
|
tags:
|
||||||
- Group
|
- Group
|
||||||
|
/v1/groups/{id}:
|
||||||
|
delete:
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Delete Group
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
post:
|
||||||
|
parameters:
|
||||||
|
- description: Group Name
|
||||||
|
in: body
|
||||||
|
name: name
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"201":
|
||||||
|
description: Created
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/repo.Group'
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Create Group
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
/v1/groups/{id}/members:
|
||||||
|
get:
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/repo.UserOut'
|
||||||
|
type: array
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Get All Group Members
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
post:
|
||||||
|
parameters:
|
||||||
|
- description: User ID
|
||||||
|
in: body
|
||||||
|
name: payload
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/v1.GroupMemberAdd'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Add User to Group
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
|
/v1/groups/{id}/members/{user_id}:
|
||||||
|
delete:
|
||||||
|
parameters:
|
||||||
|
- description: User ID
|
||||||
|
in: path
|
||||||
|
name: user_id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: No Content
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Remove User from Group
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
/v1/groups/invitations:
|
/v1/groups/invitations:
|
||||||
|
get:
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/repo.GroupInvitation'
|
||||||
|
type: array
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Get All Group Invitations
|
||||||
|
tags:
|
||||||
|
- Group
|
||||||
post:
|
post:
|
||||||
parameters:
|
parameters:
|
||||||
- description: User Data
|
- description: User Data
|
||||||
|
|||||||
@@ -7,12 +7,16 @@ describe("first time user workflow (register, login, join group)", () => {
|
|||||||
test("user should be able to update group", async () => {
|
test("user should be able to update group", async () => {
|
||||||
const { client } = await factories.client.singleUse();
|
const { client } = await factories.client.singleUse();
|
||||||
|
|
||||||
|
const { data: user } = await client.user.self();
|
||||||
const name = faker.person.firstName();
|
const name = faker.person.firstName();
|
||||||
|
|
||||||
const { response, data: group } = await client.group.update({
|
const { response, data: group } = await client.group.update(
|
||||||
|
{
|
||||||
name,
|
name,
|
||||||
currency: "eur",
|
currency: "eur",
|
||||||
});
|
},
|
||||||
|
user.item.defaultGroupId
|
||||||
|
);
|
||||||
|
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
expect(group.name).toBe(name);
|
expect(group.name).toBe(name);
|
||||||
@@ -21,7 +25,8 @@ describe("first time user workflow (register, login, join group)", () => {
|
|||||||
test("user should be able to get own group", async () => {
|
test("user should be able to get own group", async () => {
|
||||||
const { client } = await factories.client.singleUse();
|
const { client } = await factories.client.singleUse();
|
||||||
|
|
||||||
const { response, data: group } = await client.group.get();
|
const { data: user } = await client.user.self();
|
||||||
|
const { response, data: group } = await client.group.get(user.item.defaultGroupId);
|
||||||
|
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
expect(group.name).toBeTruthy();
|
expect(group.name).toBeTruthy();
|
||||||
@@ -57,7 +62,7 @@ describe("first time user workflow (register, login, join group)", () => {
|
|||||||
const client2 = factories.client.user(loginData.token);
|
const client2 = factories.client.user(loginData.token);
|
||||||
const { data: user2 } = await client2.user.self();
|
const { data: user2 } = await client2.user.self();
|
||||||
|
|
||||||
user2.item.groupName = user1.item.groupName;
|
expect(user2.item.defaultGroupId).toBe(user1.item.defaultGroupId);
|
||||||
|
|
||||||
// Cleanup User 2
|
// Cleanup User 2
|
||||||
const { response: deleteResp } = await client2.user.delete();
|
const { response: deleteResp } = await client2.user.delete();
|
||||||
|
|||||||
@@ -15,16 +15,16 @@ export class GroupApi extends BaseAPI {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
update(data: GroupUpdate) {
|
update(data: GroupUpdate, groupId?: string) {
|
||||||
return this.http.put<GroupUpdate, Group>({
|
return this.http.put<GroupUpdate, Group>({
|
||||||
url: route("/groups"),
|
url: route(`/groups/${groupId || ""}`),
|
||||||
body: data,
|
body: data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get() {
|
get(groupId?: string) {
|
||||||
return this.http.get<Group>({
|
return this.http.get<Group>({
|
||||||
url: route("/groups"),
|
url: route(`/groups/${groupId || ""}`),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
21
frontend/lib/api/types/data-contracts.ts
generated
21
frontend/lib/api/types/data-contracts.ts
generated
@@ -508,6 +508,8 @@ export interface EntUser {
|
|||||||
activated_on: string;
|
activated_on: string;
|
||||||
/** CreatedAt holds the value of the "created_at" field. */
|
/** CreatedAt holds the value of the "created_at" field. */
|
||||||
created_at: string;
|
created_at: string;
|
||||||
|
/** DefaultGroupID holds the value of the "default_group_id" field. */
|
||||||
|
default_group_id: string;
|
||||||
/**
|
/**
|
||||||
* Edges holds the relations/edges for other nodes in the graph.
|
* Edges holds the relations/edges for other nodes in the graph.
|
||||||
* The values are being populated by the UserQuery when eager-loading is set.
|
* The values are being populated by the UserQuery when eager-loading is set.
|
||||||
@@ -536,8 +538,8 @@ export interface EntUser {
|
|||||||
export interface EntUserEdges {
|
export interface EntUserEdges {
|
||||||
/** AuthTokens holds the value of the auth_tokens edge. */
|
/** AuthTokens holds the value of the auth_tokens edge. */
|
||||||
auth_tokens: EntAuthTokens[];
|
auth_tokens: EntAuthTokens[];
|
||||||
/** Group holds the value of the group edge. */
|
/** Groups holds the value of the groups edge. */
|
||||||
group: EntGroup;
|
groups: EntGroup[];
|
||||||
/** Notifiers holds the value of the notifiers edge. */
|
/** Notifiers holds the value of the notifiers edge. */
|
||||||
notifiers: EntNotifier[];
|
notifiers: EntNotifier[];
|
||||||
}
|
}
|
||||||
@@ -570,6 +572,13 @@ export interface Group {
|
|||||||
updatedAt: Date | string;
|
updatedAt: Date | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GroupInvitation {
|
||||||
|
expiresAt: Date | string;
|
||||||
|
group: Group;
|
||||||
|
id: string;
|
||||||
|
uses: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface GroupStatistics {
|
export interface GroupStatistics {
|
||||||
totalItemPrice: number;
|
totalItemPrice: number;
|
||||||
totalItems: number;
|
totalItems: number;
|
||||||
@@ -1027,9 +1036,9 @@ export interface TreeItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface UserOut {
|
export interface UserOut {
|
||||||
|
defaultGroupId: string;
|
||||||
email: string;
|
email: string;
|
||||||
groupId: string;
|
groupIds: string[];
|
||||||
groupName: string;
|
|
||||||
id: string;
|
id: string;
|
||||||
isOwner: boolean;
|
isOwner: boolean;
|
||||||
isSuperuser: boolean;
|
isSuperuser: boolean;
|
||||||
@@ -1112,6 +1121,10 @@ export interface GroupInvitationCreate {
|
|||||||
uses: number;
|
uses: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GroupMemberAdd {
|
||||||
|
userId: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ItemAttachmentToken {
|
export interface ItemAttachmentToken {
|
||||||
token: string;
|
token: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user