diff --git a/ROADMAP.md b/ROADMAP.md index 0eb9285f..765a5b16 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -183,7 +183,7 @@ Order = user-visible value first; each ships with backend + UI + tests. - [ ] Multi-account switcher UI — N-token session store, avatar-menu switch + signed-out badges (frontend-only, backend already supports) - [ ] QQ Connect (non-OIDC protocol, separate integration), account linking UI for existing local accounts, group/role claim mapping 4. **VAS/monetization-free** — credits + redemption codes as *free* features (gift codes for admin use), storage/membership SKU definitions; payment processors stay out of scope (fixes #3231). See §1.3a for the SKU/credits/gift-code spec. - - [ ] `sku` entity (storage-capacity + group-upgrade types, duration, cash+points price, label, bullets); Shop page (Memberships/Storage/Redeem tabs) + - [x] `sku` entity (storage-capacity + group-upgrade types, duration, cash+points price, label, bullets); points purchase → atomic debit+grant; admin SKU tables; `/shop` page (Memberships/Storage/Redeem tabs) + nav entry - [x] `user.credits` + `credit_txn` ledger (guarded atomic adjust); Finance settings tab (balance + grants + redeem + ledger); admin manual adjust (#183) - [x] `gift_code` entity (points/storage/group × amount × duration) + `user_grant` expiring grants + `grant_expire` cron; admin generate/list/revoke + user redeem (#183) - [ ] Paid-share `price_points` wired to the ledger + purchase/resume-ticket flow diff --git a/ent/client.go b/ent/client.go index d0cc1d68..bdc0a5d7 100644 --- a/ent/client.go +++ b/ent/client.go @@ -34,6 +34,7 @@ import ( "github.com/cloudreve/Cloudreve/v4/ent/passkey" "github.com/cloudreve/Cloudreve/v4/ent/setting" "github.com/cloudreve/Cloudreve/v4/ent/share" + "github.com/cloudreve/Cloudreve/v4/ent/sku" "github.com/cloudreve/Cloudreve/v4/ent/storagepolicy" "github.com/cloudreve/Cloudreve/v4/ent/task" "github.com/cloudreve/Cloudreve/v4/ent/user" @@ -85,6 +86,8 @@ type Client struct { Setting *SettingClient // Share is the client for interacting with the Share builders. Share *ShareClient + // Sku is the client for interacting with the Sku builders. + Sku *SkuClient // StoragePolicy is the client for interacting with the StoragePolicy builders. StoragePolicy *StoragePolicyClient // Task is the client for interacting with the Task builders. @@ -123,6 +126,7 @@ func (c *Client) init() { c.Passkey = NewPasskeyClient(c.config) c.Setting = NewSettingClient(c.config) c.Share = NewShareClient(c.config) + c.Sku = NewSkuClient(c.config) c.StoragePolicy = NewStoragePolicyClient(c.config) c.Task = NewTaskClient(c.config) c.User = NewUserClient(c.config) @@ -238,6 +242,7 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) { Passkey: NewPasskeyClient(cfg), Setting: NewSettingClient(cfg), Share: NewShareClient(cfg), + Sku: NewSkuClient(cfg), StoragePolicy: NewStoragePolicyClient(cfg), Task: NewTaskClient(cfg), User: NewUserClient(cfg), @@ -280,6 +285,7 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) Passkey: NewPasskeyClient(cfg), Setting: NewSettingClient(cfg), Share: NewShareClient(cfg), + Sku: NewSkuClient(cfg), StoragePolicy: NewStoragePolicyClient(cfg), Task: NewTaskClient(cfg), User: NewUserClient(cfg), @@ -316,7 +322,7 @@ func (c *Client) Use(hooks ...Hook) { c.AbuseReport, c.AclEntry, c.ActivityEvent, c.CreditTxn, c.DavAccount, c.DirectLink, c.Entity, c.File, c.FsEvent, c.GiftCode, c.Group, c.InvitationCode, c.Metadata, c.Node, c.OAuthClient, c.OAuthGrant, c.Passkey, - c.Setting, c.Share, c.StoragePolicy, c.Task, c.User, c.UserGrant, + c.Setting, c.Share, c.Sku, c.StoragePolicy, c.Task, c.User, c.UserGrant, } { n.Use(hooks...) } @@ -329,7 +335,7 @@ func (c *Client) Intercept(interceptors ...Interceptor) { c.AbuseReport, c.AclEntry, c.ActivityEvent, c.CreditTxn, c.DavAccount, c.DirectLink, c.Entity, c.File, c.FsEvent, c.GiftCode, c.Group, c.InvitationCode, c.Metadata, c.Node, c.OAuthClient, c.OAuthGrant, c.Passkey, - c.Setting, c.Share, c.StoragePolicy, c.Task, c.User, c.UserGrant, + c.Setting, c.Share, c.Sku, c.StoragePolicy, c.Task, c.User, c.UserGrant, } { n.Intercept(interceptors...) } @@ -376,6 +382,8 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) { return c.Setting.mutate(ctx, m) case *ShareMutation: return c.Share.mutate(ctx, m) + case *SkuMutation: + return c.Sku.mutate(ctx, m) case *StoragePolicyMutation: return c.StoragePolicy.mutate(ctx, m) case *TaskMutation: @@ -3417,6 +3425,141 @@ func (c *ShareClient) mutate(ctx context.Context, m *ShareMutation) (Value, erro } } +// SkuClient is a client for the Sku schema. +type SkuClient struct { + config +} + +// NewSkuClient returns a client for the Sku from the given config. +func NewSkuClient(c config) *SkuClient { + return &SkuClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `sku.Hooks(f(g(h())))`. +func (c *SkuClient) Use(hooks ...Hook) { + c.hooks.Sku = append(c.hooks.Sku, hooks...) +} + +// Intercept adds a list of query interceptors to the interceptors stack. +// A call to `Intercept(f, g, h)` equals to `sku.Intercept(f(g(h())))`. +func (c *SkuClient) Intercept(interceptors ...Interceptor) { + c.inters.Sku = append(c.inters.Sku, interceptors...) +} + +// Create returns a builder for creating a Sku entity. +func (c *SkuClient) Create() *SkuCreate { + mutation := newSkuMutation(c.config, OpCreate) + return &SkuCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of Sku entities. +func (c *SkuClient) CreateBulk(builders ...*SkuCreate) *SkuCreateBulk { + return &SkuCreateBulk{config: c.config, builders: builders} +} + +// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates +// a builder and applies setFunc on it. +func (c *SkuClient) MapCreateBulk(slice any, setFunc func(*SkuCreate, int)) *SkuCreateBulk { + rv := reflect.ValueOf(slice) + if rv.Kind() != reflect.Slice { + return &SkuCreateBulk{err: fmt.Errorf("calling to SkuClient.MapCreateBulk with wrong type %T, need slice", slice)} + } + builders := make([]*SkuCreate, rv.Len()) + for i := 0; i < rv.Len(); i++ { + builders[i] = c.Create() + setFunc(builders[i], i) + } + return &SkuCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for Sku. +func (c *SkuClient) Update() *SkuUpdate { + mutation := newSkuMutation(c.config, OpUpdate) + return &SkuUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *SkuClient) UpdateOne(s *Sku) *SkuUpdateOne { + mutation := newSkuMutation(c.config, OpUpdateOne, withSku(s)) + return &SkuUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *SkuClient) UpdateOneID(id int) *SkuUpdateOne { + mutation := newSkuMutation(c.config, OpUpdateOne, withSkuID(id)) + return &SkuUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for Sku. +func (c *SkuClient) Delete() *SkuDelete { + mutation := newSkuMutation(c.config, OpDelete) + return &SkuDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a builder for deleting the given entity. +func (c *SkuClient) DeleteOne(s *Sku) *SkuDeleteOne { + return c.DeleteOneID(s.ID) +} + +// DeleteOneID returns a builder for deleting the given entity by its id. +func (c *SkuClient) DeleteOneID(id int) *SkuDeleteOne { + builder := c.Delete().Where(sku.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &SkuDeleteOne{builder} +} + +// Query returns a query builder for Sku. +func (c *SkuClient) Query() *SkuQuery { + return &SkuQuery{ + config: c.config, + ctx: &QueryContext{Type: TypeSku}, + inters: c.Interceptors(), + } +} + +// Get returns a Sku entity by its id. +func (c *SkuClient) Get(ctx context.Context, id int) (*Sku, error) { + return c.Query().Where(sku.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *SkuClient) GetX(ctx context.Context, id int) *Sku { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// Hooks returns the client hooks. +func (c *SkuClient) Hooks() []Hook { + hooks := c.hooks.Sku + return append(hooks[:len(hooks):len(hooks)], sku.Hooks[:]...) +} + +// Interceptors returns the client interceptors. +func (c *SkuClient) Interceptors() []Interceptor { + inters := c.inters.Sku + return append(inters[:len(inters):len(inters)], sku.Interceptors[:]...) +} + +func (c *SkuClient) mutate(ctx context.Context, m *SkuMutation) (Value, error) { + switch m.Op() { + case OpCreate: + return (&SkuCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdate: + return (&SkuUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdateOne: + return (&SkuUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpDelete, OpDeleteOne: + return (&SkuDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx) + default: + return nil, fmt.Errorf("ent: unknown Sku mutation op: %q", m.Op()) + } +} + // StoragePolicyClient is a client for the StoragePolicy schema. type StoragePolicyClient struct { config @@ -4266,13 +4409,13 @@ type ( hooks struct { AbuseReport, AclEntry, ActivityEvent, CreditTxn, DavAccount, DirectLink, Entity, File, FsEvent, GiftCode, Group, InvitationCode, Metadata, Node, OAuthClient, - OAuthGrant, Passkey, Setting, Share, StoragePolicy, Task, User, + OAuthGrant, Passkey, Setting, Share, Sku, StoragePolicy, Task, User, UserGrant []ent.Hook } inters struct { AbuseReport, AclEntry, ActivityEvent, CreditTxn, DavAccount, DirectLink, Entity, File, FsEvent, GiftCode, Group, InvitationCode, Metadata, Node, OAuthClient, - OAuthGrant, Passkey, Setting, Share, StoragePolicy, Task, User, + OAuthGrant, Passkey, Setting, Share, Sku, StoragePolicy, Task, User, UserGrant []ent.Interceptor } ) diff --git a/ent/ent.go b/ent/ent.go index d9e3adb3..fe12586b 100644 --- a/ent/ent.go +++ b/ent/ent.go @@ -31,6 +31,7 @@ import ( "github.com/cloudreve/Cloudreve/v4/ent/passkey" "github.com/cloudreve/Cloudreve/v4/ent/setting" "github.com/cloudreve/Cloudreve/v4/ent/share" + "github.com/cloudreve/Cloudreve/v4/ent/sku" "github.com/cloudreve/Cloudreve/v4/ent/storagepolicy" "github.com/cloudreve/Cloudreve/v4/ent/task" "github.com/cloudreve/Cloudreve/v4/ent/user" @@ -114,6 +115,7 @@ func checkColumn(table, column string) error { passkey.Table: passkey.ValidColumn, setting.Table: setting.ValidColumn, share.Table: share.ValidColumn, + sku.Table: sku.ValidColumn, storagepolicy.Table: storagepolicy.ValidColumn, task.Table: task.ValidColumn, user.Table: user.ValidColumn, diff --git a/ent/hook/hook.go b/ent/hook/hook.go index a9a93cb3..6a4118d9 100644 --- a/ent/hook/hook.go +++ b/ent/hook/hook.go @@ -237,6 +237,18 @@ func (f ShareFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ShareMutation", m) } +// The SkuFunc type is an adapter to allow the use of ordinary +// function as Sku mutator. +type SkuFunc func(context.Context, *ent.SkuMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f SkuFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if mv, ok := m.(*ent.SkuMutation); ok { + return f(ctx, mv) + } + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.SkuMutation", m) +} + // The StoragePolicyFunc type is an adapter to allow the use of ordinary // function as StoragePolicy mutator. type StoragePolicyFunc func(context.Context, *ent.StoragePolicyMutation) (ent.Value, error) diff --git a/ent/intercept/intercept.go b/ent/intercept/intercept.go index 6b0a71d2..7237abb6 100644 --- a/ent/intercept/intercept.go +++ b/ent/intercept/intercept.go @@ -28,6 +28,7 @@ import ( "github.com/cloudreve/Cloudreve/v4/ent/predicate" "github.com/cloudreve/Cloudreve/v4/ent/setting" "github.com/cloudreve/Cloudreve/v4/ent/share" + "github.com/cloudreve/Cloudreve/v4/ent/sku" "github.com/cloudreve/Cloudreve/v4/ent/storagepolicy" "github.com/cloudreve/Cloudreve/v4/ent/task" "github.com/cloudreve/Cloudreve/v4/ent/user" @@ -603,6 +604,33 @@ func (f TraverseShare) Traverse(ctx context.Context, q ent.Query) error { return fmt.Errorf("unexpected query type %T. expect *ent.ShareQuery", q) } +// The SkuFunc type is an adapter to allow the use of ordinary function as a Querier. +type SkuFunc func(context.Context, *ent.SkuQuery) (ent.Value, error) + +// Query calls f(ctx, q). +func (f SkuFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) { + if q, ok := q.(*ent.SkuQuery); ok { + return f(ctx, q) + } + return nil, fmt.Errorf("unexpected query type %T. expect *ent.SkuQuery", q) +} + +// The TraverseSku type is an adapter to allow the use of ordinary function as Traverser. +type TraverseSku func(context.Context, *ent.SkuQuery) error + +// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline. +func (f TraverseSku) Intercept(next ent.Querier) ent.Querier { + return next +} + +// Traverse calls f(ctx, q). +func (f TraverseSku) Traverse(ctx context.Context, q ent.Query) error { + if q, ok := q.(*ent.SkuQuery); ok { + return f(ctx, q) + } + return fmt.Errorf("unexpected query type %T. expect *ent.SkuQuery", q) +} + // The StoragePolicyFunc type is an adapter to allow the use of ordinary function as a Querier. type StoragePolicyFunc func(context.Context, *ent.StoragePolicyQuery) (ent.Value, error) @@ -752,6 +780,8 @@ func NewQuery(q ent.Query) (Query, error) { return &query[*ent.SettingQuery, predicate.Setting, setting.OrderOption]{typ: ent.TypeSetting, tq: q}, nil case *ent.ShareQuery: return &query[*ent.ShareQuery, predicate.Share, share.OrderOption]{typ: ent.TypeShare, tq: q}, nil + case *ent.SkuQuery: + return &query[*ent.SkuQuery, predicate.Sku, sku.OrderOption]{typ: ent.TypeSku, tq: q}, nil case *ent.StoragePolicyQuery: return &query[*ent.StoragePolicyQuery, predicate.StoragePolicy, storagepolicy.OrderOption]{typ: ent.TypeStoragePolicy, tq: q}, nil case *ent.TaskQuery: diff --git a/ent/internal/schema.go b/ent/internal/schema.go index 967b89e1..e9f067c2 100644 --- a/ent/internal/schema.go +++ b/ent/internal/schema.go @@ -6,4 +6,4 @@ // Package internal holds a loadable version of the latest schema. package internal -const Schema = "{\"Schema\":\"github.com/cloudreve/Cloudreve/v4/ent/schema\",\"Package\":\"github.com/cloudreve/Cloudreve/v4/ent\",\"Schemas\":[{\"name\":\"AbuseReport\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"reporter_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"reporter_email\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"target_type\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"target_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"reason\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"description\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"status\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":\"open\",\"default_kind\":24,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"admin_note\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"status\",\"created_at\"]},{\"fields\":[\"target_type\",\"target_id\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"AclEntry\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"file\",\"type\":\"File\",\"field\":\"file_id\",\"ref_name\":\"acl_entries\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"file_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"subject_type\",\"type\":{\"Type\":6,\"Ident\":\"aclentry.SubjectType\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"user\",\"V\":\"user\"},{\"N\":\"group\",\"V\":\"group\"},{\"N\":\"anonymous\",\"V\":\"anonymous\"},{\"N\":\"everyone\",\"V\":\"everyone\"}],\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"subject_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"permissions\",\"type\":{\"Type\":5,\"Ident\":\"*boolset.BooleanSet\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"PkgName\":\"boolset\",\"Nillable\":true,\"RType\":{\"Name\":\"BooleanSet\",\"Ident\":\"boolset.BooleanSet\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"Methods\":{\"Enabled\":{\"In\":[{\"Name\":\"int\",\"Ident\":\"int\",\"Kind\":2,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"unique\":true,\"fields\":[\"file_id\",\"subject_type\",\"subject_id\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"ActivityEvent\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"type\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"actor_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"ip\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"cid\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"share_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"extra\",\"type\":{\"Type\":3,\"Ident\":\"map[string]interface {}\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":true,\"RType\":{\"Name\":\"\",\"Ident\":\"map[string]interface {}\",\"Kind\":21,\"PkgPath\":\"\",\"Methods\":{}}},\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"created_at\"]},{\"fields\":[\"type\",\"created_at\"]},{\"fields\":[\"file_id\",\"created_at\"]},{\"fields\":[\"actor_id\",\"created_at\"]},{\"fields\":[\"share_id\",\"created_at\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"CreditTxn\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_id\",\"ref_name\":\"credit_txns\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"user_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"amount\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"type\",\"type\":{\"Type\":6,\"Ident\":\"credittxn.Type\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"purchase\",\"V\":\"purchase\"},{\"N\":\"gift\",\"V\":\"gift\"},{\"N\":\"share_income\",\"V\":\"share_income\"},{\"N\":\"adjust\",\"V\":\"adjust\"}],\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"ref\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"des\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"user_id\",\"created_at\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"DavAccount\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"owner\",\"type\":\"User\",\"field\":\"owner_id\",\"ref_name\":\"dav_accounts\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"uri\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"password\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"options\",\"type\":{\"Type\":5,\"Ident\":\"*boolset.BooleanSet\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"PkgName\":\"boolset\",\"Nillable\":true,\"RType\":{\"Name\":\"BooleanSet\",\"Ident\":\"boolset.BooleanSet\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"Methods\":{\"Enabled\":{\"In\":[{\"Name\":\"int\",\"Ident\":\"int\",\"Kind\":2,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"props\",\"type\":{\"Type\":3,\"Ident\":\"*types.DavAccountProps\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"DavAccountProps\",\"Ident\":\"types.DavAccountProps\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"owner_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"unique\":true,\"fields\":[\"owner_id\",\"password\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"DirectLink\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"file\",\"type\":\"File\",\"field\":\"file_id\",\"ref_name\":\"direct_links\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"downloads\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"speed\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Entity\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"file\",\"type\":\"File\",\"ref_name\":\"entities\",\"inverse\":true},{\"name\":\"user\",\"type\":\"User\",\"field\":\"created_by\",\"ref_name\":\"entities\",\"unique\":true,\"inverse\":true},{\"name\":\"storage_policy\",\"type\":\"StoragePolicy\",\"field\":\"storage_policy_entities\",\"ref_name\":\"entities\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"type\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"source\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"size\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"reference_count\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":1,\"default_kind\":2,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"storage_policy_entities\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"created_by\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"upload_session_id\",\"type\":{\"Type\":4,\"Ident\":\"uuid.UUID\",\"PkgPath\":\"github.com/gofrs/uuid\",\"PkgName\":\"uuid\",\"Nillable\":false,\"RType\":{\"Name\":\"UUID\",\"Ident\":\"uuid.UUID\",\"Kind\":17,\"PkgPath\":\"github.com/gofrs/uuid\",\"Methods\":{\"Bytes\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}]},\"Format\":{\"In\":[{\"Name\":\"State\",\"Ident\":\"fmt.State\",\"Kind\":20,\"PkgPath\":\"fmt\",\"Methods\":null},{\"Name\":\"int32\",\"Ident\":\"int32\",\"Kind\":5,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalText\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"SetVariant\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"SetVersion\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalText\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Variant\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]},\"Version\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"props\",\"type\":{\"Type\":3,\"Ident\":\"*types.EntityProps\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"EntityProps\",\"Ident\":\"types.EntityProps\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"storage_key\":\"recycle_options\",\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"File\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"owner\",\"type\":\"User\",\"field\":\"owner_id\",\"ref_name\":\"files\",\"unique\":true,\"inverse\":true,\"required\":true},{\"name\":\"storage_policies\",\"type\":\"StoragePolicy\",\"field\":\"storage_policy_files\",\"ref_name\":\"files\",\"unique\":true,\"inverse\":true},{\"name\":\"parent\",\"type\":\"File\",\"field\":\"file_children\",\"ref\":{\"name\":\"children\",\"type\":\"File\"},\"unique\":true,\"inverse\":true},{\"name\":\"metadata\",\"type\":\"Metadata\"},{\"name\":\"entities\",\"type\":\"Entity\"},{\"name\":\"shares\",\"type\":\"Share\"},{\"name\":\"acl_entries\",\"type\":\"AclEntry\"},{\"name\":\"direct_links\",\"type\":\"DirectLink\"}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"type\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"owner_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"size\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":6,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"primary_entity\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_children\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"is_symbolic\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"props\",\"type\":{\"Type\":3,\"Ident\":\"*types.FileProps\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"FileProps\",\"Ident\":\"types.FileProps\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"position\":{\"Index\":9,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"storage_policy_files\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":10,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"unique\":true,\"fields\":[\"file_children\",\"name\"]},{\"fields\":[\"file_children\",\"type\",\"updated_at\"]},{\"fields\":[\"file_children\",\"type\",\"created_at\"]},{\"fields\":[\"file_children\",\"type\",\"size\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}]},{\"name\":\"FsEvent\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_fsevent\",\"ref_name\":\"fsevents\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"event\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"subscriber\",\"type\":{\"Type\":4,\"Ident\":\"uuid.UUID\",\"PkgPath\":\"github.com/gofrs/uuid\",\"PkgName\":\"uuid\",\"Nillable\":false,\"RType\":{\"Name\":\"UUID\",\"Ident\":\"uuid.UUID\",\"Kind\":17,\"PkgPath\":\"github.com/gofrs/uuid\",\"Methods\":{\"Bytes\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}]},\"Format\":{\"In\":[{\"Name\":\"State\",\"Ident\":\"fmt.State\",\"Kind\":20,\"PkgPath\":\"fmt\",\"Methods\":null},{\"Name\":\"int32\",\"Ident\":\"int32\",\"Kind\":5,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalText\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"SetVariant\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"SetVersion\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalText\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Variant\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]},\"Version\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"user_fsevent\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"GiftCode\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"redeemer\",\"type\":\"User\",\"field\":\"used_by_id\",\"ref_name\":\"redeemed_codes\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"code\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"unique\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"type\",\"type\":{\"Type\":6,\"Ident\":\"giftcode.Type\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"points\",\"V\":\"points\"},{\"N\":\"storage\",\"V\":\"storage\"},{\"N\":\"group\",\"V\":\"group\"}],\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"amount\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"duration\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"used_by_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"used_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"des\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Group\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"users\",\"type\":\"User\"},{\"name\":\"storage_policies\",\"type\":\"StoragePolicy\",\"field\":\"storage_policy_id\",\"ref_name\":\"groups\",\"unique\":true,\"inverse\":true},{\"name\":\"allowed_policies\",\"type\":\"StoragePolicy\"}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"max_storage\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"speed_limit\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"permissions\",\"type\":{\"Type\":5,\"Ident\":\"*boolset.BooleanSet\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"PkgName\":\"boolset\",\"Nillable\":true,\"RType\":{\"Name\":\"BooleanSet\",\"Ident\":\"boolset.BooleanSet\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"Methods\":{\"Enabled\":{\"In\":[{\"Name\":\"int\",\"Ident\":\"int\",\"Kind\":2,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"settings\",\"type\":{\"Type\":3,\"Ident\":\"*types.GroupSetting\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"GroupSetting\",\"Ident\":\"types.GroupSetting\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"default\":true,\"default_value\":{},\"default_kind\":22,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"storage_policy_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"InvitationCode\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"code\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":64,\"unique\":true,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"group_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":2,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"max_uses\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":1,\"default_kind\":2,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"used_count\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":2,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"expires_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Metadata\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"file\",\"type\":\"File\",\"field\":\"file_id\",\"ref_name\":\"metadata\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"value\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"is_public\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"unique\":true,\"fields\":[\"file_id\",\"name\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Node\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"storage_policy\",\"type\":\"StoragePolicy\"}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"status\",\"type\":{\"Type\":6,\"Ident\":\"node.Status\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"active\",\"V\":\"active\"},{\"N\":\"suspended\",\"V\":\"suspended\"}],\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"type\",\"type\":{\"Type\":6,\"Ident\":\"node.Type\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"master\",\"V\":\"master\"},{\"N\":\"slave\",\"V\":\"slave\"}],\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"server\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"slave_key\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"capabilities\",\"type\":{\"Type\":5,\"Ident\":\"*boolset.BooleanSet\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"PkgName\":\"boolset\",\"Nillable\":true,\"RType\":{\"Name\":\"BooleanSet\",\"Ident\":\"boolset.BooleanSet\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"Methods\":{\"Enabled\":{\"In\":[{\"Name\":\"int\",\"Ident\":\"int\",\"Kind\":2,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"settings\",\"type\":{\"Type\":3,\"Ident\":\"*types.NodeSetting\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"NodeSetting\",\"Ident\":\"types.NodeSetting\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"default\":true,\"default_value\":{},\"default_kind\":22,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"weight\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":2,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"OAuthClient\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"grants\",\"type\":\"OAuthGrant\"}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"guid\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":255,\"unique\":true,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"secret\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":255,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":255,\"validators\":1,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"homepage_url\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2048,\"optional\":true,\"validators\":1,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"redirect_uris\",\"type\":{\"Type\":3,\"Ident\":\"[]string\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":true,\"RType\":{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":{}}},\"default\":true,\"default_value\":[],\"default_kind\":23,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"scopes\",\"type\":{\"Type\":3,\"Ident\":\"[]string\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":true,\"RType\":{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":{}}},\"default\":true,\"default_value\":[],\"default_kind\":23,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"props\",\"type\":{\"Type\":3,\"Ident\":\"*types.OAuthClientProps\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"OAuthClientProps\",\"Ident\":\"types.OAuthClientProps\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"default\":true,\"default_value\":{},\"default_kind\":22,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"is_enabled\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":true,\"default_kind\":1,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"OAuthGrant\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_id\",\"ref_name\":\"oauth_grants\",\"unique\":true,\"inverse\":true,\"required\":true},{\"name\":\"client\",\"type\":\"OAuthClient\",\"field\":\"client_id\",\"ref_name\":\"grants\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"user_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"client_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"scopes\",\"type\":{\"Type\":3,\"Ident\":\"[]string\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":true,\"RType\":{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":{}}},\"default\":true,\"default_value\":[],\"default_kind\":23,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"last_used_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}}],\"indexes\":[{\"unique\":true,\"fields\":[\"user_id\",\"client_id\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Passkey\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_id\",\"ref_name\":\"passkey\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"user_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"credential_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"credential\",\"type\":{\"Type\":3,\"Ident\":\"*webauthn.Credential\",\"PkgPath\":\"github.com/go-webauthn/webauthn/webauthn\",\"PkgName\":\"webauthn\",\"Nillable\":true,\"RType\":{\"Name\":\"Credential\",\"Ident\":\"webauthn.Credential\",\"Kind\":22,\"PkgPath\":\"github.com/go-webauthn/webauthn/webauthn\",\"Methods\":{\"Descriptor\":{\"In\":[],\"Out\":[{\"Name\":\"CredentialDescriptor\",\"Ident\":\"protocol.CredentialDescriptor\",\"Kind\":25,\"PkgPath\":\"github.com/go-webauthn/webauthn/protocol\",\"Methods\":null}]},\"Verify\":{\"In\":[{\"Name\":\"Provider\",\"Ident\":\"metadata.Provider\",\"Kind\":20,\"PkgPath\":\"github.com/go-webauthn/webauthn/metadata\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"used_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}}],\"indexes\":[{\"unique\":true,\"fields\":[\"user_id\",\"credential_id\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Setting\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"unique\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"value\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"optional\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Share\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"ref_name\":\"shares\",\"unique\":true,\"inverse\":true},{\"name\":\"file\",\"type\":\"File\",\"ref_name\":\"shares\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"password\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"views\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":2,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"downloads\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":2,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"expires\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"remain_downloads\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"props\",\"type\":{\"Type\":3,\"Ident\":\"*types.ShareProps\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"ShareProps\",\"Ident\":\"types.ShareProps\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"StoragePolicy\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"groups\",\"type\":\"Group\"},{\"name\":\"files\",\"type\":\"File\"},{\"name\":\"entities\",\"type\":\"Entity\"},{\"name\":\"allowed_groups\",\"type\":\"Group\",\"ref_name\":\"allowed_policies\",\"inverse\":true},{\"name\":\"node\",\"type\":\"Node\",\"field\":\"node_id\",\"ref_name\":\"storage_policy\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"type\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"status\",\"type\":{\"Type\":6,\"Ident\":\"storagepolicy.Status\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"active\",\"V\":\"active\"},{\"N\":\"suspended\",\"V\":\"suspended\"}],\"default\":true,\"default_value\":\"active\",\"default_kind\":24,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"server\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"bucket_name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"is_private\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"access_key\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"secret_key\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"optional\":true,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"max_size\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"dir_name_rule\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":9,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_name_rule\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":10,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"settings\",\"type\":{\"Type\":3,\"Ident\":\"*types.PolicySetting\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"PolicySetting\",\"Ident\":\"types.PolicySetting\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"default\":true,\"default_value\":{\"file_type\":null,\"native_media_processing\":false,\"s3_path_style\":false,\"token\":\"\"},\"default_kind\":22,\"position\":{\"Index\":11,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"node_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":12,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Task\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_tasks\",\"ref_name\":\"tasks\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"type\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"status\",\"type\":{\"Type\":6,\"Ident\":\"task.Status\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"queued\",\"V\":\"queued\"},{\"N\":\"processing\",\"V\":\"processing\"},{\"N\":\"suspending\",\"V\":\"suspending\"},{\"N\":\"error\",\"V\":\"error\"},{\"N\":\"canceled\",\"V\":\"canceled\"},{\"N\":\"completed\",\"V\":\"completed\"}],\"default\":true,\"default_value\":\"queued\",\"default_kind\":24,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"public_state\",\"type\":{\"Type\":3,\"Ident\":\"*types.TaskPublicState\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"TaskPublicState\",\"Ident\":\"types.TaskPublicState\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"private_state\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"correlation_id\",\"type\":{\"Type\":4,\"Ident\":\"uuid.UUID\",\"PkgPath\":\"github.com/gofrs/uuid\",\"PkgName\":\"uuid\",\"Nillable\":false,\"RType\":{\"Name\":\"UUID\",\"Ident\":\"uuid.UUID\",\"Kind\":17,\"PkgPath\":\"github.com/gofrs/uuid\",\"Methods\":{\"Bytes\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}]},\"Format\":{\"In\":[{\"Name\":\"State\",\"Ident\":\"fmt.State\",\"Kind\":20,\"PkgPath\":\"fmt\",\"Methods\":null},{\"Name\":\"int32\",\"Ident\":\"int32\",\"Kind\":5,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalText\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"SetVariant\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"SetVersion\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalText\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Variant\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]},\"Version\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"optional\":true,\"immutable\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"user_tasks\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"creator_ip\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":45,\"optional\":true,\"validators\":1,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"hidden\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"User\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"group\",\"type\":\"Group\",\"field\":\"group_users\",\"ref_name\":\"users\",\"unique\":true,\"inverse\":true,\"required\":true},{\"name\":\"files\",\"type\":\"File\"},{\"name\":\"dav_accounts\",\"type\":\"DavAccount\"},{\"name\":\"shares\",\"type\":\"Share\"},{\"name\":\"passkey\",\"type\":\"Passkey\"},{\"name\":\"tasks\",\"type\":\"Task\"},{\"name\":\"fsevents\",\"type\":\"FsEvent\"},{\"name\":\"entities\",\"type\":\"Entity\"},{\"name\":\"oauth_grants\",\"type\":\"OAuthGrant\"},{\"name\":\"credit_txns\",\"type\":\"CreditTxn\"},{\"name\":\"redeemed_codes\",\"type\":\"GiftCode\"},{\"name\":\"grants\",\"type\":\"UserGrant\"}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"email\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":100,\"unique\":true,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"nick\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":100,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"password\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"status\",\"type\":{\"Type\":6,\"Ident\":\"user.Status\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"active\",\"V\":\"active\"},{\"N\":\"inactive\",\"V\":\"inactive\"},{\"N\":\"manual_banned\",\"V\":\"manual_banned\"},{\"N\":\"sys_banned\",\"V\":\"sys_banned\"}],\"default\":true,\"default_value\":\"active\",\"default_kind\":24,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"ban_expires\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"ban_reason\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"last_login\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0},\"comment\":\"Time of the last successful sign-in\"},{\"name\":\"storage\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":6,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"credits\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":6,\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"two_factor_secret\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":9,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"avatar\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":10,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"settings\",\"type\":{\"Type\":3,\"Ident\":\"*types.UserSetting\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"UserSetting\",\"Ident\":\"types.UserSetting\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"default\":true,\"default_value\":{},\"default_kind\":22,\"position\":{\"Index\":11,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"group_users\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":12,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"UserGrant\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_id\",\"ref_name\":\"grants\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"user_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"type\",\"type\":{\"Type\":6,\"Ident\":\"usergrant.Type\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"storage\",\"V\":\"storage\"},{\"N\":\"group\",\"V\":\"group\"}],\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"amount\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"prev_group_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"expires_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"user_id\",\"type\"]},{\"fields\":[\"expires_at\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]}],\"Features\":[\"intercept\",\"schema/snapshot\",\"sql/upsert\",\"sql/upsert\",\"sql/execquery\"]}" +const Schema = "{\"Schema\":\"github.com/cloudreve/Cloudreve/v4/ent/schema\",\"Package\":\"github.com/cloudreve/Cloudreve/v4/ent\",\"Schemas\":[{\"name\":\"AbuseReport\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"reporter_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"reporter_email\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"target_type\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"target_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"reason\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"description\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"status\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":\"open\",\"default_kind\":24,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"admin_note\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"status\",\"created_at\"]},{\"fields\":[\"target_type\",\"target_id\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"AclEntry\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"file\",\"type\":\"File\",\"field\":\"file_id\",\"ref_name\":\"acl_entries\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"file_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"subject_type\",\"type\":{\"Type\":6,\"Ident\":\"aclentry.SubjectType\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"user\",\"V\":\"user\"},{\"N\":\"group\",\"V\":\"group\"},{\"N\":\"anonymous\",\"V\":\"anonymous\"},{\"N\":\"everyone\",\"V\":\"everyone\"}],\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"subject_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"permissions\",\"type\":{\"Type\":5,\"Ident\":\"*boolset.BooleanSet\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"PkgName\":\"boolset\",\"Nillable\":true,\"RType\":{\"Name\":\"BooleanSet\",\"Ident\":\"boolset.BooleanSet\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"Methods\":{\"Enabled\":{\"In\":[{\"Name\":\"int\",\"Ident\":\"int\",\"Kind\":2,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"unique\":true,\"fields\":[\"file_id\",\"subject_type\",\"subject_id\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"ActivityEvent\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"type\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"actor_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"ip\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"cid\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"share_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"extra\",\"type\":{\"Type\":3,\"Ident\":\"map[string]interface {}\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":true,\"RType\":{\"Name\":\"\",\"Ident\":\"map[string]interface {}\",\"Kind\":21,\"PkgPath\":\"\",\"Methods\":{}}},\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"created_at\"]},{\"fields\":[\"type\",\"created_at\"]},{\"fields\":[\"file_id\",\"created_at\"]},{\"fields\":[\"actor_id\",\"created_at\"]},{\"fields\":[\"share_id\",\"created_at\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"CreditTxn\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_id\",\"ref_name\":\"credit_txns\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"user_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"amount\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"type\",\"type\":{\"Type\":6,\"Ident\":\"credittxn.Type\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"purchase\",\"V\":\"purchase\"},{\"N\":\"gift\",\"V\":\"gift\"},{\"N\":\"share_income\",\"V\":\"share_income\"},{\"N\":\"adjust\",\"V\":\"adjust\"}],\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"ref\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"des\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"user_id\",\"created_at\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"DavAccount\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"owner\",\"type\":\"User\",\"field\":\"owner_id\",\"ref_name\":\"dav_accounts\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"uri\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"password\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"options\",\"type\":{\"Type\":5,\"Ident\":\"*boolset.BooleanSet\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"PkgName\":\"boolset\",\"Nillable\":true,\"RType\":{\"Name\":\"BooleanSet\",\"Ident\":\"boolset.BooleanSet\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"Methods\":{\"Enabled\":{\"In\":[{\"Name\":\"int\",\"Ident\":\"int\",\"Kind\":2,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"props\",\"type\":{\"Type\":3,\"Ident\":\"*types.DavAccountProps\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"DavAccountProps\",\"Ident\":\"types.DavAccountProps\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"owner_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"unique\":true,\"fields\":[\"owner_id\",\"password\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"DirectLink\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"file\",\"type\":\"File\",\"field\":\"file_id\",\"ref_name\":\"direct_links\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"downloads\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"speed\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Entity\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"file\",\"type\":\"File\",\"ref_name\":\"entities\",\"inverse\":true},{\"name\":\"user\",\"type\":\"User\",\"field\":\"created_by\",\"ref_name\":\"entities\",\"unique\":true,\"inverse\":true},{\"name\":\"storage_policy\",\"type\":\"StoragePolicy\",\"field\":\"storage_policy_entities\",\"ref_name\":\"entities\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"type\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"source\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"size\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"reference_count\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":1,\"default_kind\":2,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"storage_policy_entities\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"created_by\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"upload_session_id\",\"type\":{\"Type\":4,\"Ident\":\"uuid.UUID\",\"PkgPath\":\"github.com/gofrs/uuid\",\"PkgName\":\"uuid\",\"Nillable\":false,\"RType\":{\"Name\":\"UUID\",\"Ident\":\"uuid.UUID\",\"Kind\":17,\"PkgPath\":\"github.com/gofrs/uuid\",\"Methods\":{\"Bytes\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}]},\"Format\":{\"In\":[{\"Name\":\"State\",\"Ident\":\"fmt.State\",\"Kind\":20,\"PkgPath\":\"fmt\",\"Methods\":null},{\"Name\":\"int32\",\"Ident\":\"int32\",\"Kind\":5,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalText\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"SetVariant\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"SetVersion\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalText\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Variant\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]},\"Version\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"props\",\"type\":{\"Type\":3,\"Ident\":\"*types.EntityProps\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"EntityProps\",\"Ident\":\"types.EntityProps\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"storage_key\":\"recycle_options\",\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"File\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"owner\",\"type\":\"User\",\"field\":\"owner_id\",\"ref_name\":\"files\",\"unique\":true,\"inverse\":true,\"required\":true},{\"name\":\"storage_policies\",\"type\":\"StoragePolicy\",\"field\":\"storage_policy_files\",\"ref_name\":\"files\",\"unique\":true,\"inverse\":true},{\"name\":\"parent\",\"type\":\"File\",\"field\":\"file_children\",\"ref\":{\"name\":\"children\",\"type\":\"File\"},\"unique\":true,\"inverse\":true},{\"name\":\"metadata\",\"type\":\"Metadata\"},{\"name\":\"entities\",\"type\":\"Entity\"},{\"name\":\"shares\",\"type\":\"Share\"},{\"name\":\"acl_entries\",\"type\":\"AclEntry\"},{\"name\":\"direct_links\",\"type\":\"DirectLink\"}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"type\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"owner_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"size\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":6,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"primary_entity\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_children\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"is_symbolic\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"props\",\"type\":{\"Type\":3,\"Ident\":\"*types.FileProps\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"FileProps\",\"Ident\":\"types.FileProps\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"position\":{\"Index\":9,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"storage_policy_files\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":10,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"unique\":true,\"fields\":[\"file_children\",\"name\"]},{\"fields\":[\"file_children\",\"type\",\"updated_at\"]},{\"fields\":[\"file_children\",\"type\",\"created_at\"]},{\"fields\":[\"file_children\",\"type\",\"size\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}]},{\"name\":\"FsEvent\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_fsevent\",\"ref_name\":\"fsevents\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"event\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"subscriber\",\"type\":{\"Type\":4,\"Ident\":\"uuid.UUID\",\"PkgPath\":\"github.com/gofrs/uuid\",\"PkgName\":\"uuid\",\"Nillable\":false,\"RType\":{\"Name\":\"UUID\",\"Ident\":\"uuid.UUID\",\"Kind\":17,\"PkgPath\":\"github.com/gofrs/uuid\",\"Methods\":{\"Bytes\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}]},\"Format\":{\"In\":[{\"Name\":\"State\",\"Ident\":\"fmt.State\",\"Kind\":20,\"PkgPath\":\"fmt\",\"Methods\":null},{\"Name\":\"int32\",\"Ident\":\"int32\",\"Kind\":5,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalText\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"SetVariant\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"SetVersion\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalText\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Variant\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]},\"Version\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"user_fsevent\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"GiftCode\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"redeemer\",\"type\":\"User\",\"field\":\"used_by_id\",\"ref_name\":\"redeemed_codes\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"code\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"unique\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"type\",\"type\":{\"Type\":6,\"Ident\":\"giftcode.Type\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"points\",\"V\":\"points\"},{\"N\":\"storage\",\"V\":\"storage\"},{\"N\":\"group\",\"V\":\"group\"}],\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"amount\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"duration\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"used_by_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"used_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"des\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Group\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"users\",\"type\":\"User\"},{\"name\":\"storage_policies\",\"type\":\"StoragePolicy\",\"field\":\"storage_policy_id\",\"ref_name\":\"groups\",\"unique\":true,\"inverse\":true},{\"name\":\"allowed_policies\",\"type\":\"StoragePolicy\"}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"max_storage\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"speed_limit\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"permissions\",\"type\":{\"Type\":5,\"Ident\":\"*boolset.BooleanSet\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"PkgName\":\"boolset\",\"Nillable\":true,\"RType\":{\"Name\":\"BooleanSet\",\"Ident\":\"boolset.BooleanSet\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"Methods\":{\"Enabled\":{\"In\":[{\"Name\":\"int\",\"Ident\":\"int\",\"Kind\":2,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"settings\",\"type\":{\"Type\":3,\"Ident\":\"*types.GroupSetting\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"GroupSetting\",\"Ident\":\"types.GroupSetting\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"default\":true,\"default_value\":{},\"default_kind\":22,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"storage_policy_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"InvitationCode\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"code\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":64,\"unique\":true,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"group_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":2,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"max_uses\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":1,\"default_kind\":2,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"used_count\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":2,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"expires_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Metadata\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"file\",\"type\":\"File\",\"field\":\"file_id\",\"ref_name\":\"metadata\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"value\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"is_public\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"unique\":true,\"fields\":[\"file_id\",\"name\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Node\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"storage_policy\",\"type\":\"StoragePolicy\"}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"status\",\"type\":{\"Type\":6,\"Ident\":\"node.Status\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"active\",\"V\":\"active\"},{\"N\":\"suspended\",\"V\":\"suspended\"}],\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"type\",\"type\":{\"Type\":6,\"Ident\":\"node.Type\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"master\",\"V\":\"master\"},{\"N\":\"slave\",\"V\":\"slave\"}],\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"server\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"slave_key\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"capabilities\",\"type\":{\"Type\":5,\"Ident\":\"*boolset.BooleanSet\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"PkgName\":\"boolset\",\"Nillable\":true,\"RType\":{\"Name\":\"BooleanSet\",\"Ident\":\"boolset.BooleanSet\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"Methods\":{\"Enabled\":{\"In\":[{\"Name\":\"int\",\"Ident\":\"int\",\"Kind\":2,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"settings\",\"type\":{\"Type\":3,\"Ident\":\"*types.NodeSetting\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"NodeSetting\",\"Ident\":\"types.NodeSetting\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"default\":true,\"default_value\":{},\"default_kind\":22,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"weight\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":2,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"OAuthClient\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"grants\",\"type\":\"OAuthGrant\"}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"guid\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":255,\"unique\":true,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"secret\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":255,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":255,\"validators\":1,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"homepage_url\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2048,\"optional\":true,\"validators\":1,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"redirect_uris\",\"type\":{\"Type\":3,\"Ident\":\"[]string\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":true,\"RType\":{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":{}}},\"default\":true,\"default_value\":[],\"default_kind\":23,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"scopes\",\"type\":{\"Type\":3,\"Ident\":\"[]string\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":true,\"RType\":{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":{}}},\"default\":true,\"default_value\":[],\"default_kind\":23,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"props\",\"type\":{\"Type\":3,\"Ident\":\"*types.OAuthClientProps\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"OAuthClientProps\",\"Ident\":\"types.OAuthClientProps\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"default\":true,\"default_value\":{},\"default_kind\":22,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"is_enabled\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":true,\"default_kind\":1,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"OAuthGrant\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_id\",\"ref_name\":\"oauth_grants\",\"unique\":true,\"inverse\":true,\"required\":true},{\"name\":\"client\",\"type\":\"OAuthClient\",\"field\":\"client_id\",\"ref_name\":\"grants\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"user_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"client_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"scopes\",\"type\":{\"Type\":3,\"Ident\":\"[]string\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":true,\"RType\":{\"Name\":\"\",\"Ident\":\"[]string\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":{}}},\"default\":true,\"default_value\":[],\"default_kind\":23,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"last_used_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}}],\"indexes\":[{\"unique\":true,\"fields\":[\"user_id\",\"client_id\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Passkey\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_id\",\"ref_name\":\"passkey\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"user_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"credential_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"credential\",\"type\":{\"Type\":3,\"Ident\":\"*webauthn.Credential\",\"PkgPath\":\"github.com/go-webauthn/webauthn/webauthn\",\"PkgName\":\"webauthn\",\"Nillable\":true,\"RType\":{\"Name\":\"Credential\",\"Ident\":\"webauthn.Credential\",\"Kind\":22,\"PkgPath\":\"github.com/go-webauthn/webauthn/webauthn\",\"Methods\":{\"Descriptor\":{\"In\":[],\"Out\":[{\"Name\":\"CredentialDescriptor\",\"Ident\":\"protocol.CredentialDescriptor\",\"Kind\":25,\"PkgPath\":\"github.com/go-webauthn/webauthn/protocol\",\"Methods\":null}]},\"Verify\":{\"In\":[{\"Name\":\"Provider\",\"Ident\":\"metadata.Provider\",\"Kind\":20,\"PkgPath\":\"github.com/go-webauthn/webauthn/metadata\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"used_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}}],\"indexes\":[{\"unique\":true,\"fields\":[\"user_id\",\"credential_id\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Setting\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"unique\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"value\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"optional\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Share\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"ref_name\":\"shares\",\"unique\":true,\"inverse\":true},{\"name\":\"file\",\"type\":\"File\",\"ref_name\":\"shares\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"password\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"views\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":2,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"downloads\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":2,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"expires\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"remain_downloads\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"props\",\"type\":{\"Type\":3,\"Ident\":\"*types.ShareProps\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"ShareProps\",\"Ident\":\"types.ShareProps\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Sku\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"type\",\"type\":{\"Type\":6,\"Ident\":\"sku.Type\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"storage\",\"V\":\"storage\"},{\"N\":\"group\",\"V\":\"group\"}],\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"amount\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"duration\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"price\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"points\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"label\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"des\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"enabled\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":true,\"default_kind\":1,\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"weight\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":2,\"position\":{\"Index\":9,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"StoragePolicy\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"groups\",\"type\":\"Group\"},{\"name\":\"files\",\"type\":\"File\"},{\"name\":\"entities\",\"type\":\"Entity\"},{\"name\":\"allowed_groups\",\"type\":\"Group\",\"ref_name\":\"allowed_policies\",\"inverse\":true},{\"name\":\"node\",\"type\":\"Node\",\"field\":\"node_id\",\"ref_name\":\"storage_policy\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"type\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"status\",\"type\":{\"Type\":6,\"Ident\":\"storagepolicy.Status\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"active\",\"V\":\"active\"},{\"N\":\"suspended\",\"V\":\"suspended\"}],\"default\":true,\"default_value\":\"active\",\"default_kind\":24,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"server\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"bucket_name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"is_private\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"access_key\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"secret_key\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"optional\":true,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"max_size\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"dir_name_rule\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":9,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_name_rule\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":10,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"settings\",\"type\":{\"Type\":3,\"Ident\":\"*types.PolicySetting\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"PolicySetting\",\"Ident\":\"types.PolicySetting\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"default\":true,\"default_value\":{\"file_type\":null,\"native_media_processing\":false,\"s3_path_style\":false,\"token\":\"\"},\"default_kind\":22,\"position\":{\"Index\":11,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"node_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":12,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Task\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_tasks\",\"ref_name\":\"tasks\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"type\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"status\",\"type\":{\"Type\":6,\"Ident\":\"task.Status\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"queued\",\"V\":\"queued\"},{\"N\":\"processing\",\"V\":\"processing\"},{\"N\":\"suspending\",\"V\":\"suspending\"},{\"N\":\"error\",\"V\":\"error\"},{\"N\":\"canceled\",\"V\":\"canceled\"},{\"N\":\"completed\",\"V\":\"completed\"}],\"default\":true,\"default_value\":\"queued\",\"default_kind\":24,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"public_state\",\"type\":{\"Type\":3,\"Ident\":\"*types.TaskPublicState\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"TaskPublicState\",\"Ident\":\"types.TaskPublicState\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"private_state\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"correlation_id\",\"type\":{\"Type\":4,\"Ident\":\"uuid.UUID\",\"PkgPath\":\"github.com/gofrs/uuid\",\"PkgName\":\"uuid\",\"Nillable\":false,\"RType\":{\"Name\":\"UUID\",\"Ident\":\"uuid.UUID\",\"Kind\":17,\"PkgPath\":\"github.com/gofrs/uuid\",\"Methods\":{\"Bytes\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}]},\"Format\":{\"In\":[{\"Name\":\"State\",\"Ident\":\"fmt.State\",\"Kind\":20,\"PkgPath\":\"fmt\",\"Methods\":null},{\"Name\":\"int32\",\"Ident\":\"int32\",\"Kind\":5,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalText\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"SetVariant\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"SetVersion\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalText\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Variant\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]},\"Version\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"optional\":true,\"immutable\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"user_tasks\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"creator_ip\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":45,\"optional\":true,\"validators\":1,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"hidden\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"User\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"group\",\"type\":\"Group\",\"field\":\"group_users\",\"ref_name\":\"users\",\"unique\":true,\"inverse\":true,\"required\":true},{\"name\":\"files\",\"type\":\"File\"},{\"name\":\"dav_accounts\",\"type\":\"DavAccount\"},{\"name\":\"shares\",\"type\":\"Share\"},{\"name\":\"passkey\",\"type\":\"Passkey\"},{\"name\":\"tasks\",\"type\":\"Task\"},{\"name\":\"fsevents\",\"type\":\"FsEvent\"},{\"name\":\"entities\",\"type\":\"Entity\"},{\"name\":\"oauth_grants\",\"type\":\"OAuthGrant\"},{\"name\":\"credit_txns\",\"type\":\"CreditTxn\"},{\"name\":\"redeemed_codes\",\"type\":\"GiftCode\"},{\"name\":\"grants\",\"type\":\"UserGrant\"}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"email\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":100,\"unique\":true,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"nick\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":100,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"password\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"status\",\"type\":{\"Type\":6,\"Ident\":\"user.Status\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"active\",\"V\":\"active\"},{\"N\":\"inactive\",\"V\":\"inactive\"},{\"N\":\"manual_banned\",\"V\":\"manual_banned\"},{\"N\":\"sys_banned\",\"V\":\"sys_banned\"}],\"default\":true,\"default_value\":\"active\",\"default_kind\":24,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"ban_expires\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"ban_reason\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"last_login\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0},\"comment\":\"Time of the last successful sign-in\"},{\"name\":\"storage\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":6,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"credits\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":6,\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"two_factor_secret\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":9,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"avatar\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":10,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"settings\",\"type\":{\"Type\":3,\"Ident\":\"*types.UserSetting\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"UserSetting\",\"Ident\":\"types.UserSetting\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"default\":true,\"default_value\":{},\"default_kind\":22,\"position\":{\"Index\":11,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"group_users\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":12,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"UserGrant\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_id\",\"ref_name\":\"grants\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"user_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"type\",\"type\":{\"Type\":6,\"Ident\":\"usergrant.Type\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"storage\",\"V\":\"storage\"},{\"N\":\"group\",\"V\":\"group\"}],\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"amount\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"prev_group_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"expires_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"fields\":[\"user_id\",\"type\"]},{\"fields\":[\"expires_at\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]}],\"Features\":[\"intercept\",\"schema/snapshot\",\"sql/upsert\",\"sql/upsert\",\"sql/execquery\"]}" diff --git a/ent/migrate/schema.go b/ent/migrate/schema.go index 83095b96..43abc9b9 100644 --- a/ent/migrate/schema.go +++ b/ent/migrate/schema.go @@ -602,6 +602,29 @@ var ( }, }, } + // SkusColumns holds the columns for the "skus" table. + SkusColumns = []*schema.Column{ + {Name: "id", Type: field.TypeInt, Increment: true}, + {Name: "created_at", Type: field.TypeTime, SchemaType: map[string]string{"mysql": "datetime"}}, + {Name: "updated_at", Type: field.TypeTime, SchemaType: map[string]string{"mysql": "datetime"}}, + {Name: "deleted_at", Type: field.TypeTime, Nullable: true, SchemaType: map[string]string{"mysql": "datetime"}}, + {Name: "name", Type: field.TypeString}, + {Name: "type", Type: field.TypeEnum, Enums: []string{"storage", "group"}}, + {Name: "amount", Type: field.TypeInt64}, + {Name: "duration", Type: field.TypeInt64, Nullable: true}, + {Name: "price", Type: field.TypeInt64, Nullable: true}, + {Name: "points", Type: field.TypeInt64, Nullable: true}, + {Name: "label", Type: field.TypeString, Nullable: true}, + {Name: "des", Type: field.TypeString, Nullable: true}, + {Name: "enabled", Type: field.TypeBool, Default: true}, + {Name: "weight", Type: field.TypeInt, Default: 0}, + } + // SkusTable holds the schema information for the "skus" table. + SkusTable = &schema.Table{ + Name: "skus", + Columns: SkusColumns, + PrimaryKey: []*schema.Column{SkusColumns[0]}, + } // StoragePoliciesColumns holds the columns for the "storage_policies" table. StoragePoliciesColumns = []*schema.Column{ {Name: "id", Type: field.TypeInt, Increment: true}, @@ -808,6 +831,7 @@ var ( PasskeysTable, SettingsTable, SharesTable, + SkusTable, StoragePoliciesTable, TasksTable, UsersTable, diff --git a/ent/mutation.go b/ent/mutation.go index 6a17493a..e8944012 100644 --- a/ent/mutation.go +++ b/ent/mutation.go @@ -31,6 +31,7 @@ import ( "github.com/cloudreve/Cloudreve/v4/ent/predicate" "github.com/cloudreve/Cloudreve/v4/ent/setting" "github.com/cloudreve/Cloudreve/v4/ent/share" + "github.com/cloudreve/Cloudreve/v4/ent/sku" "github.com/cloudreve/Cloudreve/v4/ent/storagepolicy" "github.com/cloudreve/Cloudreve/v4/ent/task" "github.com/cloudreve/Cloudreve/v4/ent/user" @@ -69,6 +70,7 @@ const ( TypePasskey = "Passkey" TypeSetting = "Setting" TypeShare = "Share" + TypeSku = "Sku" TypeStoragePolicy = "StoragePolicy" TypeTask = "Task" TypeUser = "User" @@ -18371,6 +18373,1268 @@ func (m *ShareMutation) ResetEdge(name string) error { return fmt.Errorf("unknown Share edge %s", name) } +// SkuMutation represents an operation that mutates the Sku nodes in the graph. +type SkuMutation struct { + config + op Op + typ string + id *int + created_at *time.Time + updated_at *time.Time + deleted_at *time.Time + name *string + _type *sku.Type + amount *int64 + addamount *int64 + duration *int64 + addduration *int64 + price *int64 + addprice *int64 + points *int64 + addpoints *int64 + label *string + des *string + enabled *bool + weight *int + addweight *int + clearedFields map[string]struct{} + done bool + oldValue func(context.Context) (*Sku, error) + predicates []predicate.Sku +} + +var _ ent.Mutation = (*SkuMutation)(nil) + +// skuOption allows management of the mutation configuration using functional options. +type skuOption func(*SkuMutation) + +// newSkuMutation creates new mutation for the Sku entity. +func newSkuMutation(c config, op Op, opts ...skuOption) *SkuMutation { + m := &SkuMutation{ + config: c, + op: op, + typ: TypeSku, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withSkuID sets the ID field of the mutation. +func withSkuID(id int) skuOption { + return func(m *SkuMutation) { + var ( + err error + once sync.Once + value *Sku + ) + m.oldValue = func(ctx context.Context) (*Sku, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().Sku.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withSku sets the old Sku of the mutation. +func withSku(node *Sku) skuOption { + return func(m *SkuMutation) { + m.oldValue = func(context.Context) (*Sku, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m SkuMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m SkuMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *SkuMutation) ID() (id int, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// IDs queries the database and returns the entity ids that match the mutation's predicate. +// That means, if the mutation is applied within a transaction with an isolation level such +// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated +// or updated by the mutation. +func (m *SkuMutation) IDs(ctx context.Context) ([]int, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []int{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().Sku.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetCreatedAt sets the "created_at" field. +func (m *SkuMutation) SetCreatedAt(t time.Time) { + m.created_at = &t +} + +// CreatedAt returns the value of the "created_at" field in the mutation. +func (m *SkuMutation) CreatedAt() (r time.Time, exists bool) { + v := m.created_at + if v == nil { + return + } + return *v, true +} + +// OldCreatedAt returns the old "created_at" field's value of the Sku entity. +// If the Sku object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SkuMutation) OldCreatedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCreatedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCreatedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCreatedAt: %w", err) + } + return oldValue.CreatedAt, nil +} + +// ResetCreatedAt resets all changes to the "created_at" field. +func (m *SkuMutation) ResetCreatedAt() { + m.created_at = nil +} + +// SetUpdatedAt sets the "updated_at" field. +func (m *SkuMutation) SetUpdatedAt(t time.Time) { + m.updated_at = &t +} + +// UpdatedAt returns the value of the "updated_at" field in the mutation. +func (m *SkuMutation) UpdatedAt() (r time.Time, exists bool) { + v := m.updated_at + if v == nil { + return + } + return *v, true +} + +// OldUpdatedAt returns the old "updated_at" field's value of the Sku entity. +// If the Sku object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SkuMutation) OldUpdatedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldUpdatedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldUpdatedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldUpdatedAt: %w", err) + } + return oldValue.UpdatedAt, nil +} + +// ResetUpdatedAt resets all changes to the "updated_at" field. +func (m *SkuMutation) ResetUpdatedAt() { + m.updated_at = nil +} + +// SetDeletedAt sets the "deleted_at" field. +func (m *SkuMutation) SetDeletedAt(t time.Time) { + m.deleted_at = &t +} + +// DeletedAt returns the value of the "deleted_at" field in the mutation. +func (m *SkuMutation) DeletedAt() (r time.Time, exists bool) { + v := m.deleted_at + if v == nil { + return + } + return *v, true +} + +// OldDeletedAt returns the old "deleted_at" field's value of the Sku entity. +// If the Sku object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SkuMutation) OldDeletedAt(ctx context.Context) (v *time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldDeletedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldDeletedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldDeletedAt: %w", err) + } + return oldValue.DeletedAt, nil +} + +// ClearDeletedAt clears the value of the "deleted_at" field. +func (m *SkuMutation) ClearDeletedAt() { + m.deleted_at = nil + m.clearedFields[sku.FieldDeletedAt] = struct{}{} +} + +// DeletedAtCleared returns if the "deleted_at" field was cleared in this mutation. +func (m *SkuMutation) DeletedAtCleared() bool { + _, ok := m.clearedFields[sku.FieldDeletedAt] + return ok +} + +// ResetDeletedAt resets all changes to the "deleted_at" field. +func (m *SkuMutation) ResetDeletedAt() { + m.deleted_at = nil + delete(m.clearedFields, sku.FieldDeletedAt) +} + +// SetName sets the "name" field. +func (m *SkuMutation) SetName(s string) { + m.name = &s +} + +// Name returns the value of the "name" field in the mutation. +func (m *SkuMutation) Name() (r string, exists bool) { + v := m.name + if v == nil { + return + } + return *v, true +} + +// OldName returns the old "name" field's value of the Sku entity. +// If the Sku object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SkuMutation) OldName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldName: %w", err) + } + return oldValue.Name, nil +} + +// ResetName resets all changes to the "name" field. +func (m *SkuMutation) ResetName() { + m.name = nil +} + +// SetType sets the "type" field. +func (m *SkuMutation) SetType(s sku.Type) { + m._type = &s +} + +// GetType returns the value of the "type" field in the mutation. +func (m *SkuMutation) GetType() (r sku.Type, exists bool) { + v := m._type + if v == nil { + return + } + return *v, true +} + +// OldType returns the old "type" field's value of the Sku entity. +// If the Sku object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SkuMutation) OldType(ctx context.Context) (v sku.Type, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldType is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldType requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldType: %w", err) + } + return oldValue.Type, nil +} + +// ResetType resets all changes to the "type" field. +func (m *SkuMutation) ResetType() { + m._type = nil +} + +// SetAmount sets the "amount" field. +func (m *SkuMutation) SetAmount(i int64) { + m.amount = &i + m.addamount = nil +} + +// Amount returns the value of the "amount" field in the mutation. +func (m *SkuMutation) Amount() (r int64, exists bool) { + v := m.amount + if v == nil { + return + } + return *v, true +} + +// OldAmount returns the old "amount" field's value of the Sku entity. +// If the Sku object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SkuMutation) OldAmount(ctx context.Context) (v int64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldAmount is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldAmount requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldAmount: %w", err) + } + return oldValue.Amount, nil +} + +// AddAmount adds i to the "amount" field. +func (m *SkuMutation) AddAmount(i int64) { + if m.addamount != nil { + *m.addamount += i + } else { + m.addamount = &i + } +} + +// AddedAmount returns the value that was added to the "amount" field in this mutation. +func (m *SkuMutation) AddedAmount() (r int64, exists bool) { + v := m.addamount + if v == nil { + return + } + return *v, true +} + +// ResetAmount resets all changes to the "amount" field. +func (m *SkuMutation) ResetAmount() { + m.amount = nil + m.addamount = nil +} + +// SetDuration sets the "duration" field. +func (m *SkuMutation) SetDuration(i int64) { + m.duration = &i + m.addduration = nil +} + +// Duration returns the value of the "duration" field in the mutation. +func (m *SkuMutation) Duration() (r int64, exists bool) { + v := m.duration + if v == nil { + return + } + return *v, true +} + +// OldDuration returns the old "duration" field's value of the Sku entity. +// If the Sku object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SkuMutation) OldDuration(ctx context.Context) (v int64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldDuration is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldDuration requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldDuration: %w", err) + } + return oldValue.Duration, nil +} + +// AddDuration adds i to the "duration" field. +func (m *SkuMutation) AddDuration(i int64) { + if m.addduration != nil { + *m.addduration += i + } else { + m.addduration = &i + } +} + +// AddedDuration returns the value that was added to the "duration" field in this mutation. +func (m *SkuMutation) AddedDuration() (r int64, exists bool) { + v := m.addduration + if v == nil { + return + } + return *v, true +} + +// ClearDuration clears the value of the "duration" field. +func (m *SkuMutation) ClearDuration() { + m.duration = nil + m.addduration = nil + m.clearedFields[sku.FieldDuration] = struct{}{} +} + +// DurationCleared returns if the "duration" field was cleared in this mutation. +func (m *SkuMutation) DurationCleared() bool { + _, ok := m.clearedFields[sku.FieldDuration] + return ok +} + +// ResetDuration resets all changes to the "duration" field. +func (m *SkuMutation) ResetDuration() { + m.duration = nil + m.addduration = nil + delete(m.clearedFields, sku.FieldDuration) +} + +// SetPrice sets the "price" field. +func (m *SkuMutation) SetPrice(i int64) { + m.price = &i + m.addprice = nil +} + +// Price returns the value of the "price" field in the mutation. +func (m *SkuMutation) Price() (r int64, exists bool) { + v := m.price + if v == nil { + return + } + return *v, true +} + +// OldPrice returns the old "price" field's value of the Sku entity. +// If the Sku object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SkuMutation) OldPrice(ctx context.Context) (v int64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldPrice is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldPrice requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPrice: %w", err) + } + return oldValue.Price, nil +} + +// AddPrice adds i to the "price" field. +func (m *SkuMutation) AddPrice(i int64) { + if m.addprice != nil { + *m.addprice += i + } else { + m.addprice = &i + } +} + +// AddedPrice returns the value that was added to the "price" field in this mutation. +func (m *SkuMutation) AddedPrice() (r int64, exists bool) { + v := m.addprice + if v == nil { + return + } + return *v, true +} + +// ClearPrice clears the value of the "price" field. +func (m *SkuMutation) ClearPrice() { + m.price = nil + m.addprice = nil + m.clearedFields[sku.FieldPrice] = struct{}{} +} + +// PriceCleared returns if the "price" field was cleared in this mutation. +func (m *SkuMutation) PriceCleared() bool { + _, ok := m.clearedFields[sku.FieldPrice] + return ok +} + +// ResetPrice resets all changes to the "price" field. +func (m *SkuMutation) ResetPrice() { + m.price = nil + m.addprice = nil + delete(m.clearedFields, sku.FieldPrice) +} + +// SetPoints sets the "points" field. +func (m *SkuMutation) SetPoints(i int64) { + m.points = &i + m.addpoints = nil +} + +// Points returns the value of the "points" field in the mutation. +func (m *SkuMutation) Points() (r int64, exists bool) { + v := m.points + if v == nil { + return + } + return *v, true +} + +// OldPoints returns the old "points" field's value of the Sku entity. +// If the Sku object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SkuMutation) OldPoints(ctx context.Context) (v *int64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldPoints is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldPoints requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPoints: %w", err) + } + return oldValue.Points, nil +} + +// AddPoints adds i to the "points" field. +func (m *SkuMutation) AddPoints(i int64) { + if m.addpoints != nil { + *m.addpoints += i + } else { + m.addpoints = &i + } +} + +// AddedPoints returns the value that was added to the "points" field in this mutation. +func (m *SkuMutation) AddedPoints() (r int64, exists bool) { + v := m.addpoints + if v == nil { + return + } + return *v, true +} + +// ClearPoints clears the value of the "points" field. +func (m *SkuMutation) ClearPoints() { + m.points = nil + m.addpoints = nil + m.clearedFields[sku.FieldPoints] = struct{}{} +} + +// PointsCleared returns if the "points" field was cleared in this mutation. +func (m *SkuMutation) PointsCleared() bool { + _, ok := m.clearedFields[sku.FieldPoints] + return ok +} + +// ResetPoints resets all changes to the "points" field. +func (m *SkuMutation) ResetPoints() { + m.points = nil + m.addpoints = nil + delete(m.clearedFields, sku.FieldPoints) +} + +// SetLabel sets the "label" field. +func (m *SkuMutation) SetLabel(s string) { + m.label = &s +} + +// Label returns the value of the "label" field in the mutation. +func (m *SkuMutation) Label() (r string, exists bool) { + v := m.label + if v == nil { + return + } + return *v, true +} + +// OldLabel returns the old "label" field's value of the Sku entity. +// If the Sku object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SkuMutation) OldLabel(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldLabel is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldLabel requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldLabel: %w", err) + } + return oldValue.Label, nil +} + +// ClearLabel clears the value of the "label" field. +func (m *SkuMutation) ClearLabel() { + m.label = nil + m.clearedFields[sku.FieldLabel] = struct{}{} +} + +// LabelCleared returns if the "label" field was cleared in this mutation. +func (m *SkuMutation) LabelCleared() bool { + _, ok := m.clearedFields[sku.FieldLabel] + return ok +} + +// ResetLabel resets all changes to the "label" field. +func (m *SkuMutation) ResetLabel() { + m.label = nil + delete(m.clearedFields, sku.FieldLabel) +} + +// SetDes sets the "des" field. +func (m *SkuMutation) SetDes(s string) { + m.des = &s +} + +// Des returns the value of the "des" field in the mutation. +func (m *SkuMutation) Des() (r string, exists bool) { + v := m.des + if v == nil { + return + } + return *v, true +} + +// OldDes returns the old "des" field's value of the Sku entity. +// If the Sku object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SkuMutation) OldDes(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldDes is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldDes requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldDes: %w", err) + } + return oldValue.Des, nil +} + +// ClearDes clears the value of the "des" field. +func (m *SkuMutation) ClearDes() { + m.des = nil + m.clearedFields[sku.FieldDes] = struct{}{} +} + +// DesCleared returns if the "des" field was cleared in this mutation. +func (m *SkuMutation) DesCleared() bool { + _, ok := m.clearedFields[sku.FieldDes] + return ok +} + +// ResetDes resets all changes to the "des" field. +func (m *SkuMutation) ResetDes() { + m.des = nil + delete(m.clearedFields, sku.FieldDes) +} + +// SetEnabled sets the "enabled" field. +func (m *SkuMutation) SetEnabled(b bool) { + m.enabled = &b +} + +// Enabled returns the value of the "enabled" field in the mutation. +func (m *SkuMutation) Enabled() (r bool, exists bool) { + v := m.enabled + if v == nil { + return + } + return *v, true +} + +// OldEnabled returns the old "enabled" field's value of the Sku entity. +// If the Sku object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SkuMutation) OldEnabled(ctx context.Context) (v bool, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldEnabled is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldEnabled requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldEnabled: %w", err) + } + return oldValue.Enabled, nil +} + +// ResetEnabled resets all changes to the "enabled" field. +func (m *SkuMutation) ResetEnabled() { + m.enabled = nil +} + +// SetWeight sets the "weight" field. +func (m *SkuMutation) SetWeight(i int) { + m.weight = &i + m.addweight = nil +} + +// Weight returns the value of the "weight" field in the mutation. +func (m *SkuMutation) Weight() (r int, exists bool) { + v := m.weight + if v == nil { + return + } + return *v, true +} + +// OldWeight returns the old "weight" field's value of the Sku entity. +// If the Sku object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *SkuMutation) OldWeight(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldWeight is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldWeight requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldWeight: %w", err) + } + return oldValue.Weight, nil +} + +// AddWeight adds i to the "weight" field. +func (m *SkuMutation) AddWeight(i int) { + if m.addweight != nil { + *m.addweight += i + } else { + m.addweight = &i + } +} + +// AddedWeight returns the value that was added to the "weight" field in this mutation. +func (m *SkuMutation) AddedWeight() (r int, exists bool) { + v := m.addweight + if v == nil { + return + } + return *v, true +} + +// ResetWeight resets all changes to the "weight" field. +func (m *SkuMutation) ResetWeight() { + m.weight = nil + m.addweight = nil +} + +// Where appends a list predicates to the SkuMutation builder. +func (m *SkuMutation) Where(ps ...predicate.Sku) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the SkuMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *SkuMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.Sku, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *SkuMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *SkuMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (Sku). +func (m *SkuMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *SkuMutation) Fields() []string { + fields := make([]string, 0, 13) + if m.created_at != nil { + fields = append(fields, sku.FieldCreatedAt) + } + if m.updated_at != nil { + fields = append(fields, sku.FieldUpdatedAt) + } + if m.deleted_at != nil { + fields = append(fields, sku.FieldDeletedAt) + } + if m.name != nil { + fields = append(fields, sku.FieldName) + } + if m._type != nil { + fields = append(fields, sku.FieldType) + } + if m.amount != nil { + fields = append(fields, sku.FieldAmount) + } + if m.duration != nil { + fields = append(fields, sku.FieldDuration) + } + if m.price != nil { + fields = append(fields, sku.FieldPrice) + } + if m.points != nil { + fields = append(fields, sku.FieldPoints) + } + if m.label != nil { + fields = append(fields, sku.FieldLabel) + } + if m.des != nil { + fields = append(fields, sku.FieldDes) + } + if m.enabled != nil { + fields = append(fields, sku.FieldEnabled) + } + if m.weight != nil { + fields = append(fields, sku.FieldWeight) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *SkuMutation) Field(name string) (ent.Value, bool) { + switch name { + case sku.FieldCreatedAt: + return m.CreatedAt() + case sku.FieldUpdatedAt: + return m.UpdatedAt() + case sku.FieldDeletedAt: + return m.DeletedAt() + case sku.FieldName: + return m.Name() + case sku.FieldType: + return m.GetType() + case sku.FieldAmount: + return m.Amount() + case sku.FieldDuration: + return m.Duration() + case sku.FieldPrice: + return m.Price() + case sku.FieldPoints: + return m.Points() + case sku.FieldLabel: + return m.Label() + case sku.FieldDes: + return m.Des() + case sku.FieldEnabled: + return m.Enabled() + case sku.FieldWeight: + return m.Weight() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *SkuMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case sku.FieldCreatedAt: + return m.OldCreatedAt(ctx) + case sku.FieldUpdatedAt: + return m.OldUpdatedAt(ctx) + case sku.FieldDeletedAt: + return m.OldDeletedAt(ctx) + case sku.FieldName: + return m.OldName(ctx) + case sku.FieldType: + return m.OldType(ctx) + case sku.FieldAmount: + return m.OldAmount(ctx) + case sku.FieldDuration: + return m.OldDuration(ctx) + case sku.FieldPrice: + return m.OldPrice(ctx) + case sku.FieldPoints: + return m.OldPoints(ctx) + case sku.FieldLabel: + return m.OldLabel(ctx) + case sku.FieldDes: + return m.OldDes(ctx) + case sku.FieldEnabled: + return m.OldEnabled(ctx) + case sku.FieldWeight: + return m.OldWeight(ctx) + } + return nil, fmt.Errorf("unknown Sku field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *SkuMutation) SetField(name string, value ent.Value) error { + switch name { + case sku.FieldCreatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCreatedAt(v) + return nil + case sku.FieldUpdatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUpdatedAt(v) + return nil + case sku.FieldDeletedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetDeletedAt(v) + return nil + case sku.FieldName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetName(v) + return nil + case sku.FieldType: + v, ok := value.(sku.Type) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetType(v) + return nil + case sku.FieldAmount: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetAmount(v) + return nil + case sku.FieldDuration: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetDuration(v) + return nil + case sku.FieldPrice: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPrice(v) + return nil + case sku.FieldPoints: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPoints(v) + return nil + case sku.FieldLabel: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetLabel(v) + return nil + case sku.FieldDes: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetDes(v) + return nil + case sku.FieldEnabled: + v, ok := value.(bool) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetEnabled(v) + return nil + case sku.FieldWeight: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetWeight(v) + return nil + } + return fmt.Errorf("unknown Sku field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *SkuMutation) AddedFields() []string { + var fields []string + if m.addamount != nil { + fields = append(fields, sku.FieldAmount) + } + if m.addduration != nil { + fields = append(fields, sku.FieldDuration) + } + if m.addprice != nil { + fields = append(fields, sku.FieldPrice) + } + if m.addpoints != nil { + fields = append(fields, sku.FieldPoints) + } + if m.addweight != nil { + fields = append(fields, sku.FieldWeight) + } + return fields +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *SkuMutation) AddedField(name string) (ent.Value, bool) { + switch name { + case sku.FieldAmount: + return m.AddedAmount() + case sku.FieldDuration: + return m.AddedDuration() + case sku.FieldPrice: + return m.AddedPrice() + case sku.FieldPoints: + return m.AddedPoints() + case sku.FieldWeight: + return m.AddedWeight() + } + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *SkuMutation) AddField(name string, value ent.Value) error { + switch name { + case sku.FieldAmount: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddAmount(v) + return nil + case sku.FieldDuration: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddDuration(v) + return nil + case sku.FieldPrice: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddPrice(v) + return nil + case sku.FieldPoints: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddPoints(v) + return nil + case sku.FieldWeight: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddWeight(v) + return nil + } + return fmt.Errorf("unknown Sku numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *SkuMutation) ClearedFields() []string { + var fields []string + if m.FieldCleared(sku.FieldDeletedAt) { + fields = append(fields, sku.FieldDeletedAt) + } + if m.FieldCleared(sku.FieldDuration) { + fields = append(fields, sku.FieldDuration) + } + if m.FieldCleared(sku.FieldPrice) { + fields = append(fields, sku.FieldPrice) + } + if m.FieldCleared(sku.FieldPoints) { + fields = append(fields, sku.FieldPoints) + } + if m.FieldCleared(sku.FieldLabel) { + fields = append(fields, sku.FieldLabel) + } + if m.FieldCleared(sku.FieldDes) { + fields = append(fields, sku.FieldDes) + } + return fields +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *SkuMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *SkuMutation) ClearField(name string) error { + switch name { + case sku.FieldDeletedAt: + m.ClearDeletedAt() + return nil + case sku.FieldDuration: + m.ClearDuration() + return nil + case sku.FieldPrice: + m.ClearPrice() + return nil + case sku.FieldPoints: + m.ClearPoints() + return nil + case sku.FieldLabel: + m.ClearLabel() + return nil + case sku.FieldDes: + m.ClearDes() + return nil + } + return fmt.Errorf("unknown Sku nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *SkuMutation) ResetField(name string) error { + switch name { + case sku.FieldCreatedAt: + m.ResetCreatedAt() + return nil + case sku.FieldUpdatedAt: + m.ResetUpdatedAt() + return nil + case sku.FieldDeletedAt: + m.ResetDeletedAt() + return nil + case sku.FieldName: + m.ResetName() + return nil + case sku.FieldType: + m.ResetType() + return nil + case sku.FieldAmount: + m.ResetAmount() + return nil + case sku.FieldDuration: + m.ResetDuration() + return nil + case sku.FieldPrice: + m.ResetPrice() + return nil + case sku.FieldPoints: + m.ResetPoints() + return nil + case sku.FieldLabel: + m.ResetLabel() + return nil + case sku.FieldDes: + m.ResetDes() + return nil + case sku.FieldEnabled: + m.ResetEnabled() + return nil + case sku.FieldWeight: + m.ResetWeight() + return nil + } + return fmt.Errorf("unknown Sku field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *SkuMutation) AddedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *SkuMutation) AddedIDs(name string) []ent.Value { + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *SkuMutation) RemovedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *SkuMutation) RemovedIDs(name string) []ent.Value { + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *SkuMutation) ClearedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *SkuMutation) EdgeCleared(name string) bool { + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *SkuMutation) ClearEdge(name string) error { + return fmt.Errorf("unknown Sku unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *SkuMutation) ResetEdge(name string) error { + return fmt.Errorf("unknown Sku edge %s", name) +} + // StoragePolicyMutation represents an operation that mutates the StoragePolicy nodes in the graph. type StoragePolicyMutation struct { config diff --git a/ent/mutationhelper.go b/ent/mutationhelper.go index 535d2fed..5d8da380 100644 --- a/ent/mutationhelper.go +++ b/ent/mutationhelper.go @@ -118,6 +118,12 @@ func (m *ShareMutation) SetRawID(t int) { // SetUpdatedAt sets the "updated_at" field. +func (m *SkuMutation) SetRawID(t int) { + m.id = &t +} + +// SetUpdatedAt sets the "updated_at" field. + func (m *StoragePolicyMutation) SetRawID(t int) { m.id = &t } diff --git a/ent/predicate/predicate.go b/ent/predicate/predicate.go index 98ec45fb..97226947 100644 --- a/ent/predicate/predicate.go +++ b/ent/predicate/predicate.go @@ -63,6 +63,9 @@ type Setting func(*sql.Selector) // Share is the predicate function for share builders. type Share func(*sql.Selector) +// Sku is the predicate function for sku builders. +type Sku func(*sql.Selector) + // StoragePolicy is the predicate function for storagepolicy builders. type StoragePolicy func(*sql.Selector) diff --git a/ent/runtime/runtime.go b/ent/runtime/runtime.go index b2c1ba07..09964c5b 100644 --- a/ent/runtime/runtime.go +++ b/ent/runtime/runtime.go @@ -25,6 +25,7 @@ import ( "github.com/cloudreve/Cloudreve/v4/ent/schema" "github.com/cloudreve/Cloudreve/v4/ent/setting" "github.com/cloudreve/Cloudreve/v4/ent/share" + "github.com/cloudreve/Cloudreve/v4/ent/sku" "github.com/cloudreve/Cloudreve/v4/ent/storagepolicy" "github.com/cloudreve/Cloudreve/v4/ent/task" "github.com/cloudreve/Cloudreve/v4/ent/user" @@ -482,6 +483,33 @@ func init() { shareDescDownloads := shareFields[2].Descriptor() // share.DefaultDownloads holds the default value on creation for the downloads field. share.DefaultDownloads = shareDescDownloads.Default.(int) + skuMixin := schema.Sku{}.Mixin() + skuMixinHooks0 := skuMixin[0].Hooks() + sku.Hooks[0] = skuMixinHooks0[0] + skuMixinInters0 := skuMixin[0].Interceptors() + sku.Interceptors[0] = skuMixinInters0[0] + skuMixinFields0 := skuMixin[0].Fields() + _ = skuMixinFields0 + skuFields := schema.Sku{}.Fields() + _ = skuFields + // skuDescCreatedAt is the schema descriptor for created_at field. + skuDescCreatedAt := skuMixinFields0[0].Descriptor() + // sku.DefaultCreatedAt holds the default value on creation for the created_at field. + sku.DefaultCreatedAt = skuDescCreatedAt.Default.(func() time.Time) + // skuDescUpdatedAt is the schema descriptor for updated_at field. + skuDescUpdatedAt := skuMixinFields0[1].Descriptor() + // sku.DefaultUpdatedAt holds the default value on creation for the updated_at field. + sku.DefaultUpdatedAt = skuDescUpdatedAt.Default.(func() time.Time) + // sku.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field. + sku.UpdateDefaultUpdatedAt = skuDescUpdatedAt.UpdateDefault.(func() time.Time) + // skuDescEnabled is the schema descriptor for enabled field. + skuDescEnabled := skuFields[8].Descriptor() + // sku.DefaultEnabled holds the default value on creation for the enabled field. + sku.DefaultEnabled = skuDescEnabled.Default.(bool) + // skuDescWeight is the schema descriptor for weight field. + skuDescWeight := skuFields[9].Descriptor() + // sku.DefaultWeight holds the default value on creation for the weight field. + sku.DefaultWeight = skuDescWeight.Default.(int) storagepolicyMixin := schema.StoragePolicy{}.Mixin() storagepolicyMixinHooks0 := storagepolicyMixin[0].Hooks() storagepolicy.Hooks[0] = storagepolicyMixinHooks0[0] diff --git a/ent/schema/sku.go b/ent/schema/sku.go new file mode 100644 index 00000000..6f09631a --- /dev/null +++ b/ent/schema/sku.go @@ -0,0 +1,52 @@ +package schema + +import ( + "entgo.io/ent" + "entgo.io/ent/schema/field" +) + +// Sku holds the schema definition for purchasable products: a storage +// capacity pack (amount = bytes) or a membership upgrade (amount = target +// group id). duration is seconds; 0 means the grant never expires. points +// is the credit price; NULL means the product cannot be bought with +// points. price is the display cash price in the smallest currency unit — +// cash payment processors are intentionally out of scope. +type Sku struct { + ent.Schema +} + +// Fields of the Sku. +func (Sku) Fields() []ent.Field { + return []ent.Field{ + field.String("name"), + field.Enum("type"). + Values("storage", "group"), + field.Int64("amount"), + field.Int64("duration"). + Optional(), + field.Int64("price"). + Optional(), + field.Int64("points"). + Optional(). + Nillable(), + field.String("label"). + Optional(), + field.String("des"). + Optional(), + field.Bool("enabled"). + Default(true), + field.Int("weight"). + Default(0), + } +} + +// Edges of the Sku. +func (Sku) Edges() []ent.Edge { + return nil +} + +func (Sku) Mixin() []ent.Mixin { + return []ent.Mixin{ + CommonMixin{}, + } +} diff --git a/ent/sku.go b/ent/sku.go new file mode 100644 index 00000000..b522dcbb --- /dev/null +++ b/ent/sku.go @@ -0,0 +1,246 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "fmt" + "strings" + "time" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "github.com/cloudreve/Cloudreve/v4/ent/sku" +) + +// Sku is the model entity for the Sku schema. +type Sku struct { + config `json:"-"` + // ID of the ent. + ID int `json:"id,omitempty"` + // CreatedAt holds the value of the "created_at" field. + CreatedAt time.Time `json:"created_at,omitempty"` + // UpdatedAt holds the value of the "updated_at" field. + UpdatedAt time.Time `json:"updated_at,omitempty"` + // DeletedAt holds the value of the "deleted_at" field. + DeletedAt *time.Time `json:"deleted_at,omitempty"` + // Name holds the value of the "name" field. + Name string `json:"name,omitempty"` + // Type holds the value of the "type" field. + Type sku.Type `json:"type,omitempty"` + // Amount holds the value of the "amount" field. + Amount int64 `json:"amount,omitempty"` + // Duration holds the value of the "duration" field. + Duration int64 `json:"duration,omitempty"` + // Price holds the value of the "price" field. + Price int64 `json:"price,omitempty"` + // Points holds the value of the "points" field. + Points *int64 `json:"points,omitempty"` + // Label holds the value of the "label" field. + Label string `json:"label,omitempty"` + // Des holds the value of the "des" field. + Des string `json:"des,omitempty"` + // Enabled holds the value of the "enabled" field. + Enabled bool `json:"enabled,omitempty"` + // Weight holds the value of the "weight" field. + Weight int `json:"weight,omitempty"` + selectValues sql.SelectValues +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*Sku) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case sku.FieldEnabled: + values[i] = new(sql.NullBool) + case sku.FieldID, sku.FieldAmount, sku.FieldDuration, sku.FieldPrice, sku.FieldPoints, sku.FieldWeight: + values[i] = new(sql.NullInt64) + case sku.FieldName, sku.FieldType, sku.FieldLabel, sku.FieldDes: + values[i] = new(sql.NullString) + case sku.FieldCreatedAt, sku.FieldUpdatedAt, sku.FieldDeletedAt: + values[i] = new(sql.NullTime) + default: + values[i] = new(sql.UnknownType) + } + } + return values, nil +} + +// assignValues assigns the values that were returned from sql.Rows (after scanning) +// to the Sku fields. +func (s *Sku) assignValues(columns []string, values []any) error { + if m, n := len(values), len(columns); m < n { + return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) + } + for i := range columns { + switch columns[i] { + case sku.FieldID: + value, ok := values[i].(*sql.NullInt64) + if !ok { + return fmt.Errorf("unexpected type %T for field id", value) + } + s.ID = int(value.Int64) + case sku.FieldCreatedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field created_at", values[i]) + } else if value.Valid { + s.CreatedAt = value.Time + } + case sku.FieldUpdatedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field updated_at", values[i]) + } else if value.Valid { + s.UpdatedAt = value.Time + } + case sku.FieldDeletedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field deleted_at", values[i]) + } else if value.Valid { + s.DeletedAt = new(time.Time) + *s.DeletedAt = value.Time + } + case sku.FieldName: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field name", values[i]) + } else if value.Valid { + s.Name = value.String + } + case sku.FieldType: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field type", values[i]) + } else if value.Valid { + s.Type = sku.Type(value.String) + } + case sku.FieldAmount: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field amount", values[i]) + } else if value.Valid { + s.Amount = value.Int64 + } + case sku.FieldDuration: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field duration", values[i]) + } else if value.Valid { + s.Duration = value.Int64 + } + case sku.FieldPrice: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field price", values[i]) + } else if value.Valid { + s.Price = value.Int64 + } + case sku.FieldPoints: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field points", values[i]) + } else if value.Valid { + s.Points = new(int64) + *s.Points = value.Int64 + } + case sku.FieldLabel: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field label", values[i]) + } else if value.Valid { + s.Label = value.String + } + case sku.FieldDes: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field des", values[i]) + } else if value.Valid { + s.Des = value.String + } + case sku.FieldEnabled: + if value, ok := values[i].(*sql.NullBool); !ok { + return fmt.Errorf("unexpected type %T for field enabled", values[i]) + } else if value.Valid { + s.Enabled = value.Bool + } + case sku.FieldWeight: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field weight", values[i]) + } else if value.Valid { + s.Weight = int(value.Int64) + } + default: + s.selectValues.Set(columns[i], values[i]) + } + } + return nil +} + +// Value returns the ent.Value that was dynamically selected and assigned to the Sku. +// This includes values selected through modifiers, order, etc. +func (s *Sku) Value(name string) (ent.Value, error) { + return s.selectValues.Get(name) +} + +// Update returns a builder for updating this Sku. +// Note that you need to call Sku.Unwrap() before calling this method if this Sku +// was returned from a transaction, and the transaction was committed or rolled back. +func (s *Sku) Update() *SkuUpdateOne { + return NewSkuClient(s.config).UpdateOne(s) +} + +// Unwrap unwraps the Sku entity that was returned from a transaction after it was closed, +// so that all future queries will be executed through the driver which created the transaction. +func (s *Sku) Unwrap() *Sku { + _tx, ok := s.config.driver.(*txDriver) + if !ok { + panic("ent: Sku is not a transactional entity") + } + s.config.driver = _tx.drv + return s +} + +// String implements the fmt.Stringer. +func (s *Sku) String() string { + var builder strings.Builder + builder.WriteString("Sku(") + builder.WriteString(fmt.Sprintf("id=%v, ", s.ID)) + builder.WriteString("created_at=") + builder.WriteString(s.CreatedAt.Format(time.ANSIC)) + builder.WriteString(", ") + builder.WriteString("updated_at=") + builder.WriteString(s.UpdatedAt.Format(time.ANSIC)) + builder.WriteString(", ") + if v := s.DeletedAt; v != nil { + builder.WriteString("deleted_at=") + builder.WriteString(v.Format(time.ANSIC)) + } + builder.WriteString(", ") + builder.WriteString("name=") + builder.WriteString(s.Name) + builder.WriteString(", ") + builder.WriteString("type=") + builder.WriteString(fmt.Sprintf("%v", s.Type)) + builder.WriteString(", ") + builder.WriteString("amount=") + builder.WriteString(fmt.Sprintf("%v", s.Amount)) + builder.WriteString(", ") + builder.WriteString("duration=") + builder.WriteString(fmt.Sprintf("%v", s.Duration)) + builder.WriteString(", ") + builder.WriteString("price=") + builder.WriteString(fmt.Sprintf("%v", s.Price)) + builder.WriteString(", ") + if v := s.Points; v != nil { + builder.WriteString("points=") + builder.WriteString(fmt.Sprintf("%v", *v)) + } + builder.WriteString(", ") + builder.WriteString("label=") + builder.WriteString(s.Label) + builder.WriteString(", ") + builder.WriteString("des=") + builder.WriteString(s.Des) + builder.WriteString(", ") + builder.WriteString("enabled=") + builder.WriteString(fmt.Sprintf("%v", s.Enabled)) + builder.WriteString(", ") + builder.WriteString("weight=") + builder.WriteString(fmt.Sprintf("%v", s.Weight)) + builder.WriteByte(')') + return builder.String() +} + +// Skus is a parsable slice of Sku. +type Skus []*Sku diff --git a/ent/sku/sku.go b/ent/sku/sku.go new file mode 100644 index 00000000..232778e1 --- /dev/null +++ b/ent/sku/sku.go @@ -0,0 +1,190 @@ +// Code generated by ent, DO NOT EDIT. + +package sku + +import ( + "fmt" + "time" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" +) + +const ( + // Label holds the string label denoting the sku type in the database. + Label = "sku" + // FieldID holds the string denoting the id field in the database. + FieldID = "id" + // FieldCreatedAt holds the string denoting the created_at field in the database. + FieldCreatedAt = "created_at" + // FieldUpdatedAt holds the string denoting the updated_at field in the database. + FieldUpdatedAt = "updated_at" + // FieldDeletedAt holds the string denoting the deleted_at field in the database. + FieldDeletedAt = "deleted_at" + // FieldName holds the string denoting the name field in the database. + FieldName = "name" + // FieldType holds the string denoting the type field in the database. + FieldType = "type" + // FieldAmount holds the string denoting the amount field in the database. + FieldAmount = "amount" + // FieldDuration holds the string denoting the duration field in the database. + FieldDuration = "duration" + // FieldPrice holds the string denoting the price field in the database. + FieldPrice = "price" + // FieldPoints holds the string denoting the points field in the database. + FieldPoints = "points" + // FieldLabel holds the string denoting the label field in the database. + FieldLabel = "label" + // FieldDes holds the string denoting the des field in the database. + FieldDes = "des" + // FieldEnabled holds the string denoting the enabled field in the database. + FieldEnabled = "enabled" + // FieldWeight holds the string denoting the weight field in the database. + FieldWeight = "weight" + // Table holds the table name of the sku in the database. + Table = "skus" +) + +// Columns holds all SQL columns for sku fields. +var Columns = []string{ + FieldID, + FieldCreatedAt, + FieldUpdatedAt, + FieldDeletedAt, + FieldName, + FieldType, + FieldAmount, + FieldDuration, + FieldPrice, + FieldPoints, + FieldLabel, + FieldDes, + FieldEnabled, + FieldWeight, +} + +// ValidColumn reports if the column name is valid (part of the table columns). +func ValidColumn(column string) bool { + for i := range Columns { + if column == Columns[i] { + return true + } + } + return false +} + +// Note that the variables below are initialized by the runtime +// package on the initialization of the application. Therefore, +// it should be imported in the main as follows: +// +// import _ "github.com/cloudreve/Cloudreve/v4/ent/runtime" +var ( + Hooks [1]ent.Hook + Interceptors [1]ent.Interceptor + // DefaultCreatedAt holds the default value on creation for the "created_at" field. + DefaultCreatedAt func() time.Time + // DefaultUpdatedAt holds the default value on creation for the "updated_at" field. + DefaultUpdatedAt func() time.Time + // UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field. + UpdateDefaultUpdatedAt func() time.Time + // DefaultEnabled holds the default value on creation for the "enabled" field. + DefaultEnabled bool + // DefaultWeight holds the default value on creation for the "weight" field. + DefaultWeight int +) + +// Type defines the type for the "type" enum field. +type Type string + +// Type values. +const ( + TypeStorage Type = "storage" + TypeGroup Type = "group" +) + +func (_type Type) String() string { + return string(_type) +} + +// TypeValidator is a validator for the "type" field enum values. It is called by the builders before save. +func TypeValidator(_type Type) error { + switch _type { + case TypeStorage, TypeGroup: + return nil + default: + return fmt.Errorf("sku: invalid enum value for type field: %q", _type) + } +} + +// OrderOption defines the ordering options for the Sku queries. +type OrderOption func(*sql.Selector) + +// ByID orders the results by the id field. +func ByID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldID, opts...).ToFunc() +} + +// ByCreatedAt orders the results by the created_at field. +func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() +} + +// ByUpdatedAt orders the results by the updated_at field. +func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc() +} + +// ByDeletedAt orders the results by the deleted_at field. +func ByDeletedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldDeletedAt, opts...).ToFunc() +} + +// ByName orders the results by the name field. +func ByName(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldName, opts...).ToFunc() +} + +// ByType orders the results by the type field. +func ByType(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldType, opts...).ToFunc() +} + +// ByAmount orders the results by the amount field. +func ByAmount(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldAmount, opts...).ToFunc() +} + +// ByDuration orders the results by the duration field. +func ByDuration(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldDuration, opts...).ToFunc() +} + +// ByPrice orders the results by the price field. +func ByPrice(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldPrice, opts...).ToFunc() +} + +// ByPoints orders the results by the points field. +func ByPoints(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldPoints, opts...).ToFunc() +} + +// ByLabel orders the results by the label field. +func ByLabel(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldLabel, opts...).ToFunc() +} + +// ByDes orders the results by the des field. +func ByDes(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldDes, opts...).ToFunc() +} + +// ByEnabled orders the results by the enabled field. +func ByEnabled(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldEnabled, opts...).ToFunc() +} + +// ByWeight orders the results by the weight field. +func ByWeight(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldWeight, opts...).ToFunc() +} diff --git a/ent/sku/where.go b/ent/sku/where.go new file mode 100644 index 00000000..f40d3941 --- /dev/null +++ b/ent/sku/where.go @@ -0,0 +1,730 @@ +// Code generated by ent, DO NOT EDIT. + +package sku + +import ( + "time" + + "entgo.io/ent/dialect/sql" + "github.com/cloudreve/Cloudreve/v4/ent/predicate" +) + +// ID filters vertices based on their ID field. +func ID(id int) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldID, id)) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id int) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldID, id)) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id int) predicate.Sku { + return predicate.Sku(sql.FieldNEQ(FieldID, id)) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...int) predicate.Sku { + return predicate.Sku(sql.FieldIn(FieldID, ids...)) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...int) predicate.Sku { + return predicate.Sku(sql.FieldNotIn(FieldID, ids...)) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id int) predicate.Sku { + return predicate.Sku(sql.FieldGT(FieldID, id)) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id int) predicate.Sku { + return predicate.Sku(sql.FieldGTE(FieldID, id)) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id int) predicate.Sku { + return predicate.Sku(sql.FieldLT(FieldID, id)) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id int) predicate.Sku { + return predicate.Sku(sql.FieldLTE(FieldID, id)) +} + +// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ. +func CreatedAt(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldCreatedAt, v)) +} + +// UpdatedAt applies equality check predicate on the "updated_at" field. It's identical to UpdatedAtEQ. +func UpdatedAt(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldUpdatedAt, v)) +} + +// DeletedAt applies equality check predicate on the "deleted_at" field. It's identical to DeletedAtEQ. +func DeletedAt(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldDeletedAt, v)) +} + +// Name applies equality check predicate on the "name" field. It's identical to NameEQ. +func Name(v string) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldName, v)) +} + +// Amount applies equality check predicate on the "amount" field. It's identical to AmountEQ. +func Amount(v int64) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldAmount, v)) +} + +// Duration applies equality check predicate on the "duration" field. It's identical to DurationEQ. +func Duration(v int64) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldDuration, v)) +} + +// Price applies equality check predicate on the "price" field. It's identical to PriceEQ. +func Price(v int64) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldPrice, v)) +} + +// Points applies equality check predicate on the "points" field. It's identical to PointsEQ. +func Points(v int64) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldPoints, v)) +} + +// Des applies equality check predicate on the "des" field. It's identical to DesEQ. +func Des(v string) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldDes, v)) +} + +// Enabled applies equality check predicate on the "enabled" field. It's identical to EnabledEQ. +func Enabled(v bool) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldEnabled, v)) +} + +// Weight applies equality check predicate on the "weight" field. It's identical to WeightEQ. +func Weight(v int) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldWeight, v)) +} + +// CreatedAtEQ applies the EQ predicate on the "created_at" field. +func CreatedAtEQ(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldCreatedAt, v)) +} + +// CreatedAtNEQ applies the NEQ predicate on the "created_at" field. +func CreatedAtNEQ(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldNEQ(FieldCreatedAt, v)) +} + +// CreatedAtIn applies the In predicate on the "created_at" field. +func CreatedAtIn(vs ...time.Time) predicate.Sku { + return predicate.Sku(sql.FieldIn(FieldCreatedAt, vs...)) +} + +// CreatedAtNotIn applies the NotIn predicate on the "created_at" field. +func CreatedAtNotIn(vs ...time.Time) predicate.Sku { + return predicate.Sku(sql.FieldNotIn(FieldCreatedAt, vs...)) +} + +// CreatedAtGT applies the GT predicate on the "created_at" field. +func CreatedAtGT(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldGT(FieldCreatedAt, v)) +} + +// CreatedAtGTE applies the GTE predicate on the "created_at" field. +func CreatedAtGTE(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldGTE(FieldCreatedAt, v)) +} + +// CreatedAtLT applies the LT predicate on the "created_at" field. +func CreatedAtLT(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldLT(FieldCreatedAt, v)) +} + +// CreatedAtLTE applies the LTE predicate on the "created_at" field. +func CreatedAtLTE(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldLTE(FieldCreatedAt, v)) +} + +// UpdatedAtEQ applies the EQ predicate on the "updated_at" field. +func UpdatedAtEQ(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldUpdatedAt, v)) +} + +// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field. +func UpdatedAtNEQ(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldNEQ(FieldUpdatedAt, v)) +} + +// UpdatedAtIn applies the In predicate on the "updated_at" field. +func UpdatedAtIn(vs ...time.Time) predicate.Sku { + return predicate.Sku(sql.FieldIn(FieldUpdatedAt, vs...)) +} + +// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field. +func UpdatedAtNotIn(vs ...time.Time) predicate.Sku { + return predicate.Sku(sql.FieldNotIn(FieldUpdatedAt, vs...)) +} + +// UpdatedAtGT applies the GT predicate on the "updated_at" field. +func UpdatedAtGT(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldGT(FieldUpdatedAt, v)) +} + +// UpdatedAtGTE applies the GTE predicate on the "updated_at" field. +func UpdatedAtGTE(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldGTE(FieldUpdatedAt, v)) +} + +// UpdatedAtLT applies the LT predicate on the "updated_at" field. +func UpdatedAtLT(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldLT(FieldUpdatedAt, v)) +} + +// UpdatedAtLTE applies the LTE predicate on the "updated_at" field. +func UpdatedAtLTE(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldLTE(FieldUpdatedAt, v)) +} + +// DeletedAtEQ applies the EQ predicate on the "deleted_at" field. +func DeletedAtEQ(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldDeletedAt, v)) +} + +// DeletedAtNEQ applies the NEQ predicate on the "deleted_at" field. +func DeletedAtNEQ(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldNEQ(FieldDeletedAt, v)) +} + +// DeletedAtIn applies the In predicate on the "deleted_at" field. +func DeletedAtIn(vs ...time.Time) predicate.Sku { + return predicate.Sku(sql.FieldIn(FieldDeletedAt, vs...)) +} + +// DeletedAtNotIn applies the NotIn predicate on the "deleted_at" field. +func DeletedAtNotIn(vs ...time.Time) predicate.Sku { + return predicate.Sku(sql.FieldNotIn(FieldDeletedAt, vs...)) +} + +// DeletedAtGT applies the GT predicate on the "deleted_at" field. +func DeletedAtGT(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldGT(FieldDeletedAt, v)) +} + +// DeletedAtGTE applies the GTE predicate on the "deleted_at" field. +func DeletedAtGTE(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldGTE(FieldDeletedAt, v)) +} + +// DeletedAtLT applies the LT predicate on the "deleted_at" field. +func DeletedAtLT(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldLT(FieldDeletedAt, v)) +} + +// DeletedAtLTE applies the LTE predicate on the "deleted_at" field. +func DeletedAtLTE(v time.Time) predicate.Sku { + return predicate.Sku(sql.FieldLTE(FieldDeletedAt, v)) +} + +// DeletedAtIsNil applies the IsNil predicate on the "deleted_at" field. +func DeletedAtIsNil() predicate.Sku { + return predicate.Sku(sql.FieldIsNull(FieldDeletedAt)) +} + +// DeletedAtNotNil applies the NotNil predicate on the "deleted_at" field. +func DeletedAtNotNil() predicate.Sku { + return predicate.Sku(sql.FieldNotNull(FieldDeletedAt)) +} + +// NameEQ applies the EQ predicate on the "name" field. +func NameEQ(v string) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldName, v)) +} + +// NameNEQ applies the NEQ predicate on the "name" field. +func NameNEQ(v string) predicate.Sku { + return predicate.Sku(sql.FieldNEQ(FieldName, v)) +} + +// NameIn applies the In predicate on the "name" field. +func NameIn(vs ...string) predicate.Sku { + return predicate.Sku(sql.FieldIn(FieldName, vs...)) +} + +// NameNotIn applies the NotIn predicate on the "name" field. +func NameNotIn(vs ...string) predicate.Sku { + return predicate.Sku(sql.FieldNotIn(FieldName, vs...)) +} + +// NameGT applies the GT predicate on the "name" field. +func NameGT(v string) predicate.Sku { + return predicate.Sku(sql.FieldGT(FieldName, v)) +} + +// NameGTE applies the GTE predicate on the "name" field. +func NameGTE(v string) predicate.Sku { + return predicate.Sku(sql.FieldGTE(FieldName, v)) +} + +// NameLT applies the LT predicate on the "name" field. +func NameLT(v string) predicate.Sku { + return predicate.Sku(sql.FieldLT(FieldName, v)) +} + +// NameLTE applies the LTE predicate on the "name" field. +func NameLTE(v string) predicate.Sku { + return predicate.Sku(sql.FieldLTE(FieldName, v)) +} + +// NameContains applies the Contains predicate on the "name" field. +func NameContains(v string) predicate.Sku { + return predicate.Sku(sql.FieldContains(FieldName, v)) +} + +// NameHasPrefix applies the HasPrefix predicate on the "name" field. +func NameHasPrefix(v string) predicate.Sku { + return predicate.Sku(sql.FieldHasPrefix(FieldName, v)) +} + +// NameHasSuffix applies the HasSuffix predicate on the "name" field. +func NameHasSuffix(v string) predicate.Sku { + return predicate.Sku(sql.FieldHasSuffix(FieldName, v)) +} + +// NameEqualFold applies the EqualFold predicate on the "name" field. +func NameEqualFold(v string) predicate.Sku { + return predicate.Sku(sql.FieldEqualFold(FieldName, v)) +} + +// NameContainsFold applies the ContainsFold predicate on the "name" field. +func NameContainsFold(v string) predicate.Sku { + return predicate.Sku(sql.FieldContainsFold(FieldName, v)) +} + +// TypeEQ applies the EQ predicate on the "type" field. +func TypeEQ(v Type) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldType, v)) +} + +// TypeNEQ applies the NEQ predicate on the "type" field. +func TypeNEQ(v Type) predicate.Sku { + return predicate.Sku(sql.FieldNEQ(FieldType, v)) +} + +// TypeIn applies the In predicate on the "type" field. +func TypeIn(vs ...Type) predicate.Sku { + return predicate.Sku(sql.FieldIn(FieldType, vs...)) +} + +// TypeNotIn applies the NotIn predicate on the "type" field. +func TypeNotIn(vs ...Type) predicate.Sku { + return predicate.Sku(sql.FieldNotIn(FieldType, vs...)) +} + +// AmountEQ applies the EQ predicate on the "amount" field. +func AmountEQ(v int64) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldAmount, v)) +} + +// AmountNEQ applies the NEQ predicate on the "amount" field. +func AmountNEQ(v int64) predicate.Sku { + return predicate.Sku(sql.FieldNEQ(FieldAmount, v)) +} + +// AmountIn applies the In predicate on the "amount" field. +func AmountIn(vs ...int64) predicate.Sku { + return predicate.Sku(sql.FieldIn(FieldAmount, vs...)) +} + +// AmountNotIn applies the NotIn predicate on the "amount" field. +func AmountNotIn(vs ...int64) predicate.Sku { + return predicate.Sku(sql.FieldNotIn(FieldAmount, vs...)) +} + +// AmountGT applies the GT predicate on the "amount" field. +func AmountGT(v int64) predicate.Sku { + return predicate.Sku(sql.FieldGT(FieldAmount, v)) +} + +// AmountGTE applies the GTE predicate on the "amount" field. +func AmountGTE(v int64) predicate.Sku { + return predicate.Sku(sql.FieldGTE(FieldAmount, v)) +} + +// AmountLT applies the LT predicate on the "amount" field. +func AmountLT(v int64) predicate.Sku { + return predicate.Sku(sql.FieldLT(FieldAmount, v)) +} + +// AmountLTE applies the LTE predicate on the "amount" field. +func AmountLTE(v int64) predicate.Sku { + return predicate.Sku(sql.FieldLTE(FieldAmount, v)) +} + +// DurationEQ applies the EQ predicate on the "duration" field. +func DurationEQ(v int64) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldDuration, v)) +} + +// DurationNEQ applies the NEQ predicate on the "duration" field. +func DurationNEQ(v int64) predicate.Sku { + return predicate.Sku(sql.FieldNEQ(FieldDuration, v)) +} + +// DurationIn applies the In predicate on the "duration" field. +func DurationIn(vs ...int64) predicate.Sku { + return predicate.Sku(sql.FieldIn(FieldDuration, vs...)) +} + +// DurationNotIn applies the NotIn predicate on the "duration" field. +func DurationNotIn(vs ...int64) predicate.Sku { + return predicate.Sku(sql.FieldNotIn(FieldDuration, vs...)) +} + +// DurationGT applies the GT predicate on the "duration" field. +func DurationGT(v int64) predicate.Sku { + return predicate.Sku(sql.FieldGT(FieldDuration, v)) +} + +// DurationGTE applies the GTE predicate on the "duration" field. +func DurationGTE(v int64) predicate.Sku { + return predicate.Sku(sql.FieldGTE(FieldDuration, v)) +} + +// DurationLT applies the LT predicate on the "duration" field. +func DurationLT(v int64) predicate.Sku { + return predicate.Sku(sql.FieldLT(FieldDuration, v)) +} + +// DurationLTE applies the LTE predicate on the "duration" field. +func DurationLTE(v int64) predicate.Sku { + return predicate.Sku(sql.FieldLTE(FieldDuration, v)) +} + +// DurationIsNil applies the IsNil predicate on the "duration" field. +func DurationIsNil() predicate.Sku { + return predicate.Sku(sql.FieldIsNull(FieldDuration)) +} + +// DurationNotNil applies the NotNil predicate on the "duration" field. +func DurationNotNil() predicate.Sku { + return predicate.Sku(sql.FieldNotNull(FieldDuration)) +} + +// PriceEQ applies the EQ predicate on the "price" field. +func PriceEQ(v int64) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldPrice, v)) +} + +// PriceNEQ applies the NEQ predicate on the "price" field. +func PriceNEQ(v int64) predicate.Sku { + return predicate.Sku(sql.FieldNEQ(FieldPrice, v)) +} + +// PriceIn applies the In predicate on the "price" field. +func PriceIn(vs ...int64) predicate.Sku { + return predicate.Sku(sql.FieldIn(FieldPrice, vs...)) +} + +// PriceNotIn applies the NotIn predicate on the "price" field. +func PriceNotIn(vs ...int64) predicate.Sku { + return predicate.Sku(sql.FieldNotIn(FieldPrice, vs...)) +} + +// PriceGT applies the GT predicate on the "price" field. +func PriceGT(v int64) predicate.Sku { + return predicate.Sku(sql.FieldGT(FieldPrice, v)) +} + +// PriceGTE applies the GTE predicate on the "price" field. +func PriceGTE(v int64) predicate.Sku { + return predicate.Sku(sql.FieldGTE(FieldPrice, v)) +} + +// PriceLT applies the LT predicate on the "price" field. +func PriceLT(v int64) predicate.Sku { + return predicate.Sku(sql.FieldLT(FieldPrice, v)) +} + +// PriceLTE applies the LTE predicate on the "price" field. +func PriceLTE(v int64) predicate.Sku { + return predicate.Sku(sql.FieldLTE(FieldPrice, v)) +} + +// PriceIsNil applies the IsNil predicate on the "price" field. +func PriceIsNil() predicate.Sku { + return predicate.Sku(sql.FieldIsNull(FieldPrice)) +} + +// PriceNotNil applies the NotNil predicate on the "price" field. +func PriceNotNil() predicate.Sku { + return predicate.Sku(sql.FieldNotNull(FieldPrice)) +} + +// PointsEQ applies the EQ predicate on the "points" field. +func PointsEQ(v int64) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldPoints, v)) +} + +// PointsNEQ applies the NEQ predicate on the "points" field. +func PointsNEQ(v int64) predicate.Sku { + return predicate.Sku(sql.FieldNEQ(FieldPoints, v)) +} + +// PointsIn applies the In predicate on the "points" field. +func PointsIn(vs ...int64) predicate.Sku { + return predicate.Sku(sql.FieldIn(FieldPoints, vs...)) +} + +// PointsNotIn applies the NotIn predicate on the "points" field. +func PointsNotIn(vs ...int64) predicate.Sku { + return predicate.Sku(sql.FieldNotIn(FieldPoints, vs...)) +} + +// PointsGT applies the GT predicate on the "points" field. +func PointsGT(v int64) predicate.Sku { + return predicate.Sku(sql.FieldGT(FieldPoints, v)) +} + +// PointsGTE applies the GTE predicate on the "points" field. +func PointsGTE(v int64) predicate.Sku { + return predicate.Sku(sql.FieldGTE(FieldPoints, v)) +} + +// PointsLT applies the LT predicate on the "points" field. +func PointsLT(v int64) predicate.Sku { + return predicate.Sku(sql.FieldLT(FieldPoints, v)) +} + +// PointsLTE applies the LTE predicate on the "points" field. +func PointsLTE(v int64) predicate.Sku { + return predicate.Sku(sql.FieldLTE(FieldPoints, v)) +} + +// PointsIsNil applies the IsNil predicate on the "points" field. +func PointsIsNil() predicate.Sku { + return predicate.Sku(sql.FieldIsNull(FieldPoints)) +} + +// PointsNotNil applies the NotNil predicate on the "points" field. +func PointsNotNil() predicate.Sku { + return predicate.Sku(sql.FieldNotNull(FieldPoints)) +} + +// LabelEQ applies the EQ predicate on the "label" field. +func LabelEQ(v string) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldLabel, v)) +} + +// LabelNEQ applies the NEQ predicate on the "label" field. +func LabelNEQ(v string) predicate.Sku { + return predicate.Sku(sql.FieldNEQ(FieldLabel, v)) +} + +// LabelIn applies the In predicate on the "label" field. +func LabelIn(vs ...string) predicate.Sku { + return predicate.Sku(sql.FieldIn(FieldLabel, vs...)) +} + +// LabelNotIn applies the NotIn predicate on the "label" field. +func LabelNotIn(vs ...string) predicate.Sku { + return predicate.Sku(sql.FieldNotIn(FieldLabel, vs...)) +} + +// LabelGT applies the GT predicate on the "label" field. +func LabelGT(v string) predicate.Sku { + return predicate.Sku(sql.FieldGT(FieldLabel, v)) +} + +// LabelGTE applies the GTE predicate on the "label" field. +func LabelGTE(v string) predicate.Sku { + return predicate.Sku(sql.FieldGTE(FieldLabel, v)) +} + +// LabelLT applies the LT predicate on the "label" field. +func LabelLT(v string) predicate.Sku { + return predicate.Sku(sql.FieldLT(FieldLabel, v)) +} + +// LabelLTE applies the LTE predicate on the "label" field. +func LabelLTE(v string) predicate.Sku { + return predicate.Sku(sql.FieldLTE(FieldLabel, v)) +} + +// LabelContains applies the Contains predicate on the "label" field. +func LabelContains(v string) predicate.Sku { + return predicate.Sku(sql.FieldContains(FieldLabel, v)) +} + +// LabelHasPrefix applies the HasPrefix predicate on the "label" field. +func LabelHasPrefix(v string) predicate.Sku { + return predicate.Sku(sql.FieldHasPrefix(FieldLabel, v)) +} + +// LabelHasSuffix applies the HasSuffix predicate on the "label" field. +func LabelHasSuffix(v string) predicate.Sku { + return predicate.Sku(sql.FieldHasSuffix(FieldLabel, v)) +} + +// LabelIsNil applies the IsNil predicate on the "label" field. +func LabelIsNil() predicate.Sku { + return predicate.Sku(sql.FieldIsNull(FieldLabel)) +} + +// LabelNotNil applies the NotNil predicate on the "label" field. +func LabelNotNil() predicate.Sku { + return predicate.Sku(sql.FieldNotNull(FieldLabel)) +} + +// LabelEqualFold applies the EqualFold predicate on the "label" field. +func LabelEqualFold(v string) predicate.Sku { + return predicate.Sku(sql.FieldEqualFold(FieldLabel, v)) +} + +// LabelContainsFold applies the ContainsFold predicate on the "label" field. +func LabelContainsFold(v string) predicate.Sku { + return predicate.Sku(sql.FieldContainsFold(FieldLabel, v)) +} + +// DesEQ applies the EQ predicate on the "des" field. +func DesEQ(v string) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldDes, v)) +} + +// DesNEQ applies the NEQ predicate on the "des" field. +func DesNEQ(v string) predicate.Sku { + return predicate.Sku(sql.FieldNEQ(FieldDes, v)) +} + +// DesIn applies the In predicate on the "des" field. +func DesIn(vs ...string) predicate.Sku { + return predicate.Sku(sql.FieldIn(FieldDes, vs...)) +} + +// DesNotIn applies the NotIn predicate on the "des" field. +func DesNotIn(vs ...string) predicate.Sku { + return predicate.Sku(sql.FieldNotIn(FieldDes, vs...)) +} + +// DesGT applies the GT predicate on the "des" field. +func DesGT(v string) predicate.Sku { + return predicate.Sku(sql.FieldGT(FieldDes, v)) +} + +// DesGTE applies the GTE predicate on the "des" field. +func DesGTE(v string) predicate.Sku { + return predicate.Sku(sql.FieldGTE(FieldDes, v)) +} + +// DesLT applies the LT predicate on the "des" field. +func DesLT(v string) predicate.Sku { + return predicate.Sku(sql.FieldLT(FieldDes, v)) +} + +// DesLTE applies the LTE predicate on the "des" field. +func DesLTE(v string) predicate.Sku { + return predicate.Sku(sql.FieldLTE(FieldDes, v)) +} + +// DesContains applies the Contains predicate on the "des" field. +func DesContains(v string) predicate.Sku { + return predicate.Sku(sql.FieldContains(FieldDes, v)) +} + +// DesHasPrefix applies the HasPrefix predicate on the "des" field. +func DesHasPrefix(v string) predicate.Sku { + return predicate.Sku(sql.FieldHasPrefix(FieldDes, v)) +} + +// DesHasSuffix applies the HasSuffix predicate on the "des" field. +func DesHasSuffix(v string) predicate.Sku { + return predicate.Sku(sql.FieldHasSuffix(FieldDes, v)) +} + +// DesIsNil applies the IsNil predicate on the "des" field. +func DesIsNil() predicate.Sku { + return predicate.Sku(sql.FieldIsNull(FieldDes)) +} + +// DesNotNil applies the NotNil predicate on the "des" field. +func DesNotNil() predicate.Sku { + return predicate.Sku(sql.FieldNotNull(FieldDes)) +} + +// DesEqualFold applies the EqualFold predicate on the "des" field. +func DesEqualFold(v string) predicate.Sku { + return predicate.Sku(sql.FieldEqualFold(FieldDes, v)) +} + +// DesContainsFold applies the ContainsFold predicate on the "des" field. +func DesContainsFold(v string) predicate.Sku { + return predicate.Sku(sql.FieldContainsFold(FieldDes, v)) +} + +// EnabledEQ applies the EQ predicate on the "enabled" field. +func EnabledEQ(v bool) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldEnabled, v)) +} + +// EnabledNEQ applies the NEQ predicate on the "enabled" field. +func EnabledNEQ(v bool) predicate.Sku { + return predicate.Sku(sql.FieldNEQ(FieldEnabled, v)) +} + +// WeightEQ applies the EQ predicate on the "weight" field. +func WeightEQ(v int) predicate.Sku { + return predicate.Sku(sql.FieldEQ(FieldWeight, v)) +} + +// WeightNEQ applies the NEQ predicate on the "weight" field. +func WeightNEQ(v int) predicate.Sku { + return predicate.Sku(sql.FieldNEQ(FieldWeight, v)) +} + +// WeightIn applies the In predicate on the "weight" field. +func WeightIn(vs ...int) predicate.Sku { + return predicate.Sku(sql.FieldIn(FieldWeight, vs...)) +} + +// WeightNotIn applies the NotIn predicate on the "weight" field. +func WeightNotIn(vs ...int) predicate.Sku { + return predicate.Sku(sql.FieldNotIn(FieldWeight, vs...)) +} + +// WeightGT applies the GT predicate on the "weight" field. +func WeightGT(v int) predicate.Sku { + return predicate.Sku(sql.FieldGT(FieldWeight, v)) +} + +// WeightGTE applies the GTE predicate on the "weight" field. +func WeightGTE(v int) predicate.Sku { + return predicate.Sku(sql.FieldGTE(FieldWeight, v)) +} + +// WeightLT applies the LT predicate on the "weight" field. +func WeightLT(v int) predicate.Sku { + return predicate.Sku(sql.FieldLT(FieldWeight, v)) +} + +// WeightLTE applies the LTE predicate on the "weight" field. +func WeightLTE(v int) predicate.Sku { + return predicate.Sku(sql.FieldLTE(FieldWeight, v)) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.Sku) predicate.Sku { + return predicate.Sku(sql.AndPredicates(predicates...)) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.Sku) predicate.Sku { + return predicate.Sku(sql.OrPredicates(predicates...)) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.Sku) predicate.Sku { + return predicate.Sku(sql.NotPredicates(p)) +} diff --git a/ent/sku_create.go b/ent/sku_create.go new file mode 100644 index 00000000..93cbcde5 --- /dev/null +++ b/ent/sku_create.go @@ -0,0 +1,1393 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/cloudreve/Cloudreve/v4/ent/sku" +) + +// SkuCreate is the builder for creating a Sku entity. +type SkuCreate struct { + config + mutation *SkuMutation + hooks []Hook + conflict []sql.ConflictOption +} + +// SetCreatedAt sets the "created_at" field. +func (sc *SkuCreate) SetCreatedAt(t time.Time) *SkuCreate { + sc.mutation.SetCreatedAt(t) + return sc +} + +// SetNillableCreatedAt sets the "created_at" field if the given value is not nil. +func (sc *SkuCreate) SetNillableCreatedAt(t *time.Time) *SkuCreate { + if t != nil { + sc.SetCreatedAt(*t) + } + return sc +} + +// SetUpdatedAt sets the "updated_at" field. +func (sc *SkuCreate) SetUpdatedAt(t time.Time) *SkuCreate { + sc.mutation.SetUpdatedAt(t) + return sc +} + +// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil. +func (sc *SkuCreate) SetNillableUpdatedAt(t *time.Time) *SkuCreate { + if t != nil { + sc.SetUpdatedAt(*t) + } + return sc +} + +// SetDeletedAt sets the "deleted_at" field. +func (sc *SkuCreate) SetDeletedAt(t time.Time) *SkuCreate { + sc.mutation.SetDeletedAt(t) + return sc +} + +// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil. +func (sc *SkuCreate) SetNillableDeletedAt(t *time.Time) *SkuCreate { + if t != nil { + sc.SetDeletedAt(*t) + } + return sc +} + +// SetName sets the "name" field. +func (sc *SkuCreate) SetName(s string) *SkuCreate { + sc.mutation.SetName(s) + return sc +} + +// SetType sets the "type" field. +func (sc *SkuCreate) SetType(s sku.Type) *SkuCreate { + sc.mutation.SetType(s) + return sc +} + +// SetAmount sets the "amount" field. +func (sc *SkuCreate) SetAmount(i int64) *SkuCreate { + sc.mutation.SetAmount(i) + return sc +} + +// SetDuration sets the "duration" field. +func (sc *SkuCreate) SetDuration(i int64) *SkuCreate { + sc.mutation.SetDuration(i) + return sc +} + +// SetNillableDuration sets the "duration" field if the given value is not nil. +func (sc *SkuCreate) SetNillableDuration(i *int64) *SkuCreate { + if i != nil { + sc.SetDuration(*i) + } + return sc +} + +// SetPrice sets the "price" field. +func (sc *SkuCreate) SetPrice(i int64) *SkuCreate { + sc.mutation.SetPrice(i) + return sc +} + +// SetNillablePrice sets the "price" field if the given value is not nil. +func (sc *SkuCreate) SetNillablePrice(i *int64) *SkuCreate { + if i != nil { + sc.SetPrice(*i) + } + return sc +} + +// SetPoints sets the "points" field. +func (sc *SkuCreate) SetPoints(i int64) *SkuCreate { + sc.mutation.SetPoints(i) + return sc +} + +// SetNillablePoints sets the "points" field if the given value is not nil. +func (sc *SkuCreate) SetNillablePoints(i *int64) *SkuCreate { + if i != nil { + sc.SetPoints(*i) + } + return sc +} + +// SetLabel sets the "label" field. +func (sc *SkuCreate) SetLabel(s string) *SkuCreate { + sc.mutation.SetLabel(s) + return sc +} + +// SetNillableLabel sets the "label" field if the given value is not nil. +func (sc *SkuCreate) SetNillableLabel(s *string) *SkuCreate { + if s != nil { + sc.SetLabel(*s) + } + return sc +} + +// SetDes sets the "des" field. +func (sc *SkuCreate) SetDes(s string) *SkuCreate { + sc.mutation.SetDes(s) + return sc +} + +// SetNillableDes sets the "des" field if the given value is not nil. +func (sc *SkuCreate) SetNillableDes(s *string) *SkuCreate { + if s != nil { + sc.SetDes(*s) + } + return sc +} + +// SetEnabled sets the "enabled" field. +func (sc *SkuCreate) SetEnabled(b bool) *SkuCreate { + sc.mutation.SetEnabled(b) + return sc +} + +// SetNillableEnabled sets the "enabled" field if the given value is not nil. +func (sc *SkuCreate) SetNillableEnabled(b *bool) *SkuCreate { + if b != nil { + sc.SetEnabled(*b) + } + return sc +} + +// SetWeight sets the "weight" field. +func (sc *SkuCreate) SetWeight(i int) *SkuCreate { + sc.mutation.SetWeight(i) + return sc +} + +// SetNillableWeight sets the "weight" field if the given value is not nil. +func (sc *SkuCreate) SetNillableWeight(i *int) *SkuCreate { + if i != nil { + sc.SetWeight(*i) + } + return sc +} + +// Mutation returns the SkuMutation object of the builder. +func (sc *SkuCreate) Mutation() *SkuMutation { + return sc.mutation +} + +// Save creates the Sku in the database. +func (sc *SkuCreate) Save(ctx context.Context) (*Sku, error) { + if err := sc.defaults(); err != nil { + return nil, err + } + return withHooks(ctx, sc.sqlSave, sc.mutation, sc.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (sc *SkuCreate) SaveX(ctx context.Context) *Sku { + v, err := sc.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (sc *SkuCreate) Exec(ctx context.Context) error { + _, err := sc.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (sc *SkuCreate) ExecX(ctx context.Context) { + if err := sc.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (sc *SkuCreate) defaults() error { + if _, ok := sc.mutation.CreatedAt(); !ok { + if sku.DefaultCreatedAt == nil { + return fmt.Errorf("ent: uninitialized sku.DefaultCreatedAt (forgotten import ent/runtime?)") + } + v := sku.DefaultCreatedAt() + sc.mutation.SetCreatedAt(v) + } + if _, ok := sc.mutation.UpdatedAt(); !ok { + if sku.DefaultUpdatedAt == nil { + return fmt.Errorf("ent: uninitialized sku.DefaultUpdatedAt (forgotten import ent/runtime?)") + } + v := sku.DefaultUpdatedAt() + sc.mutation.SetUpdatedAt(v) + } + if _, ok := sc.mutation.Enabled(); !ok { + v := sku.DefaultEnabled + sc.mutation.SetEnabled(v) + } + if _, ok := sc.mutation.Weight(); !ok { + v := sku.DefaultWeight + sc.mutation.SetWeight(v) + } + return nil +} + +// check runs all checks and user-defined validators on the builder. +func (sc *SkuCreate) check() error { + if _, ok := sc.mutation.CreatedAt(); !ok { + return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "Sku.created_at"`)} + } + if _, ok := sc.mutation.UpdatedAt(); !ok { + return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "Sku.updated_at"`)} + } + if _, ok := sc.mutation.Name(); !ok { + return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "Sku.name"`)} + } + if _, ok := sc.mutation.GetType(); !ok { + return &ValidationError{Name: "type", err: errors.New(`ent: missing required field "Sku.type"`)} + } + if v, ok := sc.mutation.GetType(); ok { + if err := sku.TypeValidator(v); err != nil { + return &ValidationError{Name: "type", err: fmt.Errorf(`ent: validator failed for field "Sku.type": %w`, err)} + } + } + if _, ok := sc.mutation.Amount(); !ok { + return &ValidationError{Name: "amount", err: errors.New(`ent: missing required field "Sku.amount"`)} + } + if _, ok := sc.mutation.Enabled(); !ok { + return &ValidationError{Name: "enabled", err: errors.New(`ent: missing required field "Sku.enabled"`)} + } + if _, ok := sc.mutation.Weight(); !ok { + return &ValidationError{Name: "weight", err: errors.New(`ent: missing required field "Sku.weight"`)} + } + return nil +} + +func (sc *SkuCreate) sqlSave(ctx context.Context) (*Sku, error) { + if err := sc.check(); err != nil { + return nil, err + } + _node, _spec := sc.createSpec() + if err := sqlgraph.CreateNode(ctx, sc.driver, _spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + id := _spec.ID.Value.(int64) + _node.ID = int(id) + sc.mutation.id = &_node.ID + sc.mutation.done = true + return _node, nil +} + +func (sc *SkuCreate) createSpec() (*Sku, *sqlgraph.CreateSpec) { + var ( + _node = &Sku{config: sc.config} + _spec = sqlgraph.NewCreateSpec(sku.Table, sqlgraph.NewFieldSpec(sku.FieldID, field.TypeInt)) + ) + + if id, ok := sc.mutation.ID(); ok { + _node.ID = id + id64 := int64(id) + _spec.ID.Value = id64 + } + + _spec.OnConflict = sc.conflict + if value, ok := sc.mutation.CreatedAt(); ok { + _spec.SetField(sku.FieldCreatedAt, field.TypeTime, value) + _node.CreatedAt = value + } + if value, ok := sc.mutation.UpdatedAt(); ok { + _spec.SetField(sku.FieldUpdatedAt, field.TypeTime, value) + _node.UpdatedAt = value + } + if value, ok := sc.mutation.DeletedAt(); ok { + _spec.SetField(sku.FieldDeletedAt, field.TypeTime, value) + _node.DeletedAt = &value + } + if value, ok := sc.mutation.Name(); ok { + _spec.SetField(sku.FieldName, field.TypeString, value) + _node.Name = value + } + if value, ok := sc.mutation.GetType(); ok { + _spec.SetField(sku.FieldType, field.TypeEnum, value) + _node.Type = value + } + if value, ok := sc.mutation.Amount(); ok { + _spec.SetField(sku.FieldAmount, field.TypeInt64, value) + _node.Amount = value + } + if value, ok := sc.mutation.Duration(); ok { + _spec.SetField(sku.FieldDuration, field.TypeInt64, value) + _node.Duration = value + } + if value, ok := sc.mutation.Price(); ok { + _spec.SetField(sku.FieldPrice, field.TypeInt64, value) + _node.Price = value + } + if value, ok := sc.mutation.Points(); ok { + _spec.SetField(sku.FieldPoints, field.TypeInt64, value) + _node.Points = &value + } + if value, ok := sc.mutation.Label(); ok { + _spec.SetField(sku.FieldLabel, field.TypeString, value) + _node.Label = value + } + if value, ok := sc.mutation.Des(); ok { + _spec.SetField(sku.FieldDes, field.TypeString, value) + _node.Des = value + } + if value, ok := sc.mutation.Enabled(); ok { + _spec.SetField(sku.FieldEnabled, field.TypeBool, value) + _node.Enabled = value + } + if value, ok := sc.mutation.Weight(); ok { + _spec.SetField(sku.FieldWeight, field.TypeInt, value) + _node.Weight = value + } + return _node, _spec +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.Sku.Create(). +// SetCreatedAt(v). +// OnConflict( +// // Update the row with the new values +// // the was proposed for insertion. +// sql.ResolveWithNewValues(), +// ). +// // Override some of the fields with custom +// // update values. +// Update(func(u *ent.SkuUpsert) { +// SetCreatedAt(v+v). +// }). +// Exec(ctx) +func (sc *SkuCreate) OnConflict(opts ...sql.ConflictOption) *SkuUpsertOne { + sc.conflict = opts + return &SkuUpsertOne{ + create: sc, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.Sku.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (sc *SkuCreate) OnConflictColumns(columns ...string) *SkuUpsertOne { + sc.conflict = append(sc.conflict, sql.ConflictColumns(columns...)) + return &SkuUpsertOne{ + create: sc, + } +} + +type ( + // SkuUpsertOne is the builder for "upsert"-ing + // one Sku node. + SkuUpsertOne struct { + create *SkuCreate + } + + // SkuUpsert is the "OnConflict" setter. + SkuUpsert struct { + *sql.UpdateSet + } +) + +// SetUpdatedAt sets the "updated_at" field. +func (u *SkuUpsert) SetUpdatedAt(v time.Time) *SkuUpsert { + u.Set(sku.FieldUpdatedAt, v) + return u +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *SkuUpsert) UpdateUpdatedAt() *SkuUpsert { + u.SetExcluded(sku.FieldUpdatedAt) + return u +} + +// SetDeletedAt sets the "deleted_at" field. +func (u *SkuUpsert) SetDeletedAt(v time.Time) *SkuUpsert { + u.Set(sku.FieldDeletedAt, v) + return u +} + +// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create. +func (u *SkuUpsert) UpdateDeletedAt() *SkuUpsert { + u.SetExcluded(sku.FieldDeletedAt) + return u +} + +// ClearDeletedAt clears the value of the "deleted_at" field. +func (u *SkuUpsert) ClearDeletedAt() *SkuUpsert { + u.SetNull(sku.FieldDeletedAt) + return u +} + +// SetName sets the "name" field. +func (u *SkuUpsert) SetName(v string) *SkuUpsert { + u.Set(sku.FieldName, v) + return u +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *SkuUpsert) UpdateName() *SkuUpsert { + u.SetExcluded(sku.FieldName) + return u +} + +// SetType sets the "type" field. +func (u *SkuUpsert) SetType(v sku.Type) *SkuUpsert { + u.Set(sku.FieldType, v) + return u +} + +// UpdateType sets the "type" field to the value that was provided on create. +func (u *SkuUpsert) UpdateType() *SkuUpsert { + u.SetExcluded(sku.FieldType) + return u +} + +// SetAmount sets the "amount" field. +func (u *SkuUpsert) SetAmount(v int64) *SkuUpsert { + u.Set(sku.FieldAmount, v) + return u +} + +// UpdateAmount sets the "amount" field to the value that was provided on create. +func (u *SkuUpsert) UpdateAmount() *SkuUpsert { + u.SetExcluded(sku.FieldAmount) + return u +} + +// AddAmount adds v to the "amount" field. +func (u *SkuUpsert) AddAmount(v int64) *SkuUpsert { + u.Add(sku.FieldAmount, v) + return u +} + +// SetDuration sets the "duration" field. +func (u *SkuUpsert) SetDuration(v int64) *SkuUpsert { + u.Set(sku.FieldDuration, v) + return u +} + +// UpdateDuration sets the "duration" field to the value that was provided on create. +func (u *SkuUpsert) UpdateDuration() *SkuUpsert { + u.SetExcluded(sku.FieldDuration) + return u +} + +// AddDuration adds v to the "duration" field. +func (u *SkuUpsert) AddDuration(v int64) *SkuUpsert { + u.Add(sku.FieldDuration, v) + return u +} + +// ClearDuration clears the value of the "duration" field. +func (u *SkuUpsert) ClearDuration() *SkuUpsert { + u.SetNull(sku.FieldDuration) + return u +} + +// SetPrice sets the "price" field. +func (u *SkuUpsert) SetPrice(v int64) *SkuUpsert { + u.Set(sku.FieldPrice, v) + return u +} + +// UpdatePrice sets the "price" field to the value that was provided on create. +func (u *SkuUpsert) UpdatePrice() *SkuUpsert { + u.SetExcluded(sku.FieldPrice) + return u +} + +// AddPrice adds v to the "price" field. +func (u *SkuUpsert) AddPrice(v int64) *SkuUpsert { + u.Add(sku.FieldPrice, v) + return u +} + +// ClearPrice clears the value of the "price" field. +func (u *SkuUpsert) ClearPrice() *SkuUpsert { + u.SetNull(sku.FieldPrice) + return u +} + +// SetPoints sets the "points" field. +func (u *SkuUpsert) SetPoints(v int64) *SkuUpsert { + u.Set(sku.FieldPoints, v) + return u +} + +// UpdatePoints sets the "points" field to the value that was provided on create. +func (u *SkuUpsert) UpdatePoints() *SkuUpsert { + u.SetExcluded(sku.FieldPoints) + return u +} + +// AddPoints adds v to the "points" field. +func (u *SkuUpsert) AddPoints(v int64) *SkuUpsert { + u.Add(sku.FieldPoints, v) + return u +} + +// ClearPoints clears the value of the "points" field. +func (u *SkuUpsert) ClearPoints() *SkuUpsert { + u.SetNull(sku.FieldPoints) + return u +} + +// SetLabel sets the "label" field. +func (u *SkuUpsert) SetLabel(v string) *SkuUpsert { + u.Set(sku.FieldLabel, v) + return u +} + +// UpdateLabel sets the "label" field to the value that was provided on create. +func (u *SkuUpsert) UpdateLabel() *SkuUpsert { + u.SetExcluded(sku.FieldLabel) + return u +} + +// ClearLabel clears the value of the "label" field. +func (u *SkuUpsert) ClearLabel() *SkuUpsert { + u.SetNull(sku.FieldLabel) + return u +} + +// SetDes sets the "des" field. +func (u *SkuUpsert) SetDes(v string) *SkuUpsert { + u.Set(sku.FieldDes, v) + return u +} + +// UpdateDes sets the "des" field to the value that was provided on create. +func (u *SkuUpsert) UpdateDes() *SkuUpsert { + u.SetExcluded(sku.FieldDes) + return u +} + +// ClearDes clears the value of the "des" field. +func (u *SkuUpsert) ClearDes() *SkuUpsert { + u.SetNull(sku.FieldDes) + return u +} + +// SetEnabled sets the "enabled" field. +func (u *SkuUpsert) SetEnabled(v bool) *SkuUpsert { + u.Set(sku.FieldEnabled, v) + return u +} + +// UpdateEnabled sets the "enabled" field to the value that was provided on create. +func (u *SkuUpsert) UpdateEnabled() *SkuUpsert { + u.SetExcluded(sku.FieldEnabled) + return u +} + +// SetWeight sets the "weight" field. +func (u *SkuUpsert) SetWeight(v int) *SkuUpsert { + u.Set(sku.FieldWeight, v) + return u +} + +// UpdateWeight sets the "weight" field to the value that was provided on create. +func (u *SkuUpsert) UpdateWeight() *SkuUpsert { + u.SetExcluded(sku.FieldWeight) + return u +} + +// AddWeight adds v to the "weight" field. +func (u *SkuUpsert) AddWeight(v int) *SkuUpsert { + u.Add(sku.FieldWeight, v) + return u +} + +// UpdateNewValues updates the mutable fields using the new values that were set on create. +// Using this option is equivalent to using: +// +// client.Sku.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *SkuUpsertOne) UpdateNewValues() *SkuUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) { + if _, exists := u.create.mutation.CreatedAt(); exists { + s.SetIgnore(sku.FieldCreatedAt) + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.Sku.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *SkuUpsertOne) Ignore() *SkuUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore()) + return u +} + +// DoNothing configures the conflict_action to `DO NOTHING`. +// Supported only by SQLite and PostgreSQL. +func (u *SkuUpsertOne) DoNothing() *SkuUpsertOne { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the SkuCreate.OnConflict +// documentation for more info. +func (u *SkuUpsertOne) Update(set func(*SkuUpsert)) *SkuUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&SkuUpsert{UpdateSet: update}) + })) + return u +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *SkuUpsertOne) SetUpdatedAt(v time.Time) *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.SetUpdatedAt(v) + }) +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *SkuUpsertOne) UpdateUpdatedAt() *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.UpdateUpdatedAt() + }) +} + +// SetDeletedAt sets the "deleted_at" field. +func (u *SkuUpsertOne) SetDeletedAt(v time.Time) *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.SetDeletedAt(v) + }) +} + +// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create. +func (u *SkuUpsertOne) UpdateDeletedAt() *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.UpdateDeletedAt() + }) +} + +// ClearDeletedAt clears the value of the "deleted_at" field. +func (u *SkuUpsertOne) ClearDeletedAt() *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.ClearDeletedAt() + }) +} + +// SetName sets the "name" field. +func (u *SkuUpsertOne) SetName(v string) *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.SetName(v) + }) +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *SkuUpsertOne) UpdateName() *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.UpdateName() + }) +} + +// SetType sets the "type" field. +func (u *SkuUpsertOne) SetType(v sku.Type) *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.SetType(v) + }) +} + +// UpdateType sets the "type" field to the value that was provided on create. +func (u *SkuUpsertOne) UpdateType() *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.UpdateType() + }) +} + +// SetAmount sets the "amount" field. +func (u *SkuUpsertOne) SetAmount(v int64) *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.SetAmount(v) + }) +} + +// AddAmount adds v to the "amount" field. +func (u *SkuUpsertOne) AddAmount(v int64) *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.AddAmount(v) + }) +} + +// UpdateAmount sets the "amount" field to the value that was provided on create. +func (u *SkuUpsertOne) UpdateAmount() *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.UpdateAmount() + }) +} + +// SetDuration sets the "duration" field. +func (u *SkuUpsertOne) SetDuration(v int64) *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.SetDuration(v) + }) +} + +// AddDuration adds v to the "duration" field. +func (u *SkuUpsertOne) AddDuration(v int64) *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.AddDuration(v) + }) +} + +// UpdateDuration sets the "duration" field to the value that was provided on create. +func (u *SkuUpsertOne) UpdateDuration() *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.UpdateDuration() + }) +} + +// ClearDuration clears the value of the "duration" field. +func (u *SkuUpsertOne) ClearDuration() *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.ClearDuration() + }) +} + +// SetPrice sets the "price" field. +func (u *SkuUpsertOne) SetPrice(v int64) *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.SetPrice(v) + }) +} + +// AddPrice adds v to the "price" field. +func (u *SkuUpsertOne) AddPrice(v int64) *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.AddPrice(v) + }) +} + +// UpdatePrice sets the "price" field to the value that was provided on create. +func (u *SkuUpsertOne) UpdatePrice() *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.UpdatePrice() + }) +} + +// ClearPrice clears the value of the "price" field. +func (u *SkuUpsertOne) ClearPrice() *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.ClearPrice() + }) +} + +// SetPoints sets the "points" field. +func (u *SkuUpsertOne) SetPoints(v int64) *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.SetPoints(v) + }) +} + +// AddPoints adds v to the "points" field. +func (u *SkuUpsertOne) AddPoints(v int64) *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.AddPoints(v) + }) +} + +// UpdatePoints sets the "points" field to the value that was provided on create. +func (u *SkuUpsertOne) UpdatePoints() *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.UpdatePoints() + }) +} + +// ClearPoints clears the value of the "points" field. +func (u *SkuUpsertOne) ClearPoints() *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.ClearPoints() + }) +} + +// SetLabel sets the "label" field. +func (u *SkuUpsertOne) SetLabel(v string) *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.SetLabel(v) + }) +} + +// UpdateLabel sets the "label" field to the value that was provided on create. +func (u *SkuUpsertOne) UpdateLabel() *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.UpdateLabel() + }) +} + +// ClearLabel clears the value of the "label" field. +func (u *SkuUpsertOne) ClearLabel() *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.ClearLabel() + }) +} + +// SetDes sets the "des" field. +func (u *SkuUpsertOne) SetDes(v string) *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.SetDes(v) + }) +} + +// UpdateDes sets the "des" field to the value that was provided on create. +func (u *SkuUpsertOne) UpdateDes() *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.UpdateDes() + }) +} + +// ClearDes clears the value of the "des" field. +func (u *SkuUpsertOne) ClearDes() *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.ClearDes() + }) +} + +// SetEnabled sets the "enabled" field. +func (u *SkuUpsertOne) SetEnabled(v bool) *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.SetEnabled(v) + }) +} + +// UpdateEnabled sets the "enabled" field to the value that was provided on create. +func (u *SkuUpsertOne) UpdateEnabled() *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.UpdateEnabled() + }) +} + +// SetWeight sets the "weight" field. +func (u *SkuUpsertOne) SetWeight(v int) *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.SetWeight(v) + }) +} + +// AddWeight adds v to the "weight" field. +func (u *SkuUpsertOne) AddWeight(v int) *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.AddWeight(v) + }) +} + +// UpdateWeight sets the "weight" field to the value that was provided on create. +func (u *SkuUpsertOne) UpdateWeight() *SkuUpsertOne { + return u.Update(func(s *SkuUpsert) { + s.UpdateWeight() + }) +} + +// Exec executes the query. +func (u *SkuUpsertOne) Exec(ctx context.Context) error { + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for SkuCreate.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *SkuUpsertOne) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} + +// Exec executes the UPSERT query and returns the inserted/updated ID. +func (u *SkuUpsertOne) ID(ctx context.Context) (id int, err error) { + node, err := u.create.Save(ctx) + if err != nil { + return id, err + } + return node.ID, nil +} + +// IDX is like ID, but panics if an error occurs. +func (u *SkuUpsertOne) IDX(ctx context.Context) int { + id, err := u.ID(ctx) + if err != nil { + panic(err) + } + return id +} + +func (m *SkuCreate) SetRawID(t int) *SkuCreate { + m.mutation.SetRawID(t) + return m +} + +// SkuCreateBulk is the builder for creating many Sku entities in bulk. +type SkuCreateBulk struct { + config + err error + builders []*SkuCreate + conflict []sql.ConflictOption +} + +// Save creates the Sku entities in the database. +func (scb *SkuCreateBulk) Save(ctx context.Context) ([]*Sku, error) { + if scb.err != nil { + return nil, scb.err + } + specs := make([]*sqlgraph.CreateSpec, len(scb.builders)) + nodes := make([]*Sku, len(scb.builders)) + mutators := make([]Mutator, len(scb.builders)) + for i := range scb.builders { + func(i int, root context.Context) { + builder := scb.builders[i] + builder.defaults() + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*SkuMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err := builder.check(); err != nil { + return nil, err + } + builder.mutation = mutation + var err error + nodes[i], specs[i] = builder.createSpec() + if i < len(mutators)-1 { + _, err = mutators[i+1].Mutate(root, scb.builders[i+1].mutation) + } else { + spec := &sqlgraph.BatchCreateSpec{Nodes: specs} + spec.OnConflict = scb.conflict + // Invoke the actual operation on the latest mutation in the chain. + if err = sqlgraph.BatchCreate(ctx, scb.driver, spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + } + } + if err != nil { + return nil, err + } + mutation.id = &nodes[i].ID + if specs[i].ID.Value != nil { + id := specs[i].ID.Value.(int64) + nodes[i].ID = int(id) + } + mutation.done = true + return nodes[i], nil + }) + for i := len(builder.hooks) - 1; i >= 0; i-- { + mut = builder.hooks[i](mut) + } + mutators[i] = mut + }(i, ctx) + } + if len(mutators) > 0 { + if _, err := mutators[0].Mutate(ctx, scb.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (scb *SkuCreateBulk) SaveX(ctx context.Context) []*Sku { + v, err := scb.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (scb *SkuCreateBulk) Exec(ctx context.Context) error { + _, err := scb.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (scb *SkuCreateBulk) ExecX(ctx context.Context) { + if err := scb.Exec(ctx); err != nil { + panic(err) + } +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.Sku.CreateBulk(builders...). +// OnConflict( +// // Update the row with the new values +// // the was proposed for insertion. +// sql.ResolveWithNewValues(), +// ). +// // Override some of the fields with custom +// // update values. +// Update(func(u *ent.SkuUpsert) { +// SetCreatedAt(v+v). +// }). +// Exec(ctx) +func (scb *SkuCreateBulk) OnConflict(opts ...sql.ConflictOption) *SkuUpsertBulk { + scb.conflict = opts + return &SkuUpsertBulk{ + create: scb, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.Sku.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (scb *SkuCreateBulk) OnConflictColumns(columns ...string) *SkuUpsertBulk { + scb.conflict = append(scb.conflict, sql.ConflictColumns(columns...)) + return &SkuUpsertBulk{ + create: scb, + } +} + +// SkuUpsertBulk is the builder for "upsert"-ing +// a bulk of Sku nodes. +type SkuUpsertBulk struct { + create *SkuCreateBulk +} + +// UpdateNewValues updates the mutable fields using the new values that +// were set on create. Using this option is equivalent to using: +// +// client.Sku.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *SkuUpsertBulk) UpdateNewValues() *SkuUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) { + for _, b := range u.create.builders { + if _, exists := b.mutation.CreatedAt(); exists { + s.SetIgnore(sku.FieldCreatedAt) + } + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.Sku.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *SkuUpsertBulk) Ignore() *SkuUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore()) + return u +} + +// DoNothing configures the conflict_action to `DO NOTHING`. +// Supported only by SQLite and PostgreSQL. +func (u *SkuUpsertBulk) DoNothing() *SkuUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the SkuCreateBulk.OnConflict +// documentation for more info. +func (u *SkuUpsertBulk) Update(set func(*SkuUpsert)) *SkuUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&SkuUpsert{UpdateSet: update}) + })) + return u +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *SkuUpsertBulk) SetUpdatedAt(v time.Time) *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.SetUpdatedAt(v) + }) +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *SkuUpsertBulk) UpdateUpdatedAt() *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.UpdateUpdatedAt() + }) +} + +// SetDeletedAt sets the "deleted_at" field. +func (u *SkuUpsertBulk) SetDeletedAt(v time.Time) *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.SetDeletedAt(v) + }) +} + +// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create. +func (u *SkuUpsertBulk) UpdateDeletedAt() *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.UpdateDeletedAt() + }) +} + +// ClearDeletedAt clears the value of the "deleted_at" field. +func (u *SkuUpsertBulk) ClearDeletedAt() *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.ClearDeletedAt() + }) +} + +// SetName sets the "name" field. +func (u *SkuUpsertBulk) SetName(v string) *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.SetName(v) + }) +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *SkuUpsertBulk) UpdateName() *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.UpdateName() + }) +} + +// SetType sets the "type" field. +func (u *SkuUpsertBulk) SetType(v sku.Type) *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.SetType(v) + }) +} + +// UpdateType sets the "type" field to the value that was provided on create. +func (u *SkuUpsertBulk) UpdateType() *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.UpdateType() + }) +} + +// SetAmount sets the "amount" field. +func (u *SkuUpsertBulk) SetAmount(v int64) *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.SetAmount(v) + }) +} + +// AddAmount adds v to the "amount" field. +func (u *SkuUpsertBulk) AddAmount(v int64) *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.AddAmount(v) + }) +} + +// UpdateAmount sets the "amount" field to the value that was provided on create. +func (u *SkuUpsertBulk) UpdateAmount() *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.UpdateAmount() + }) +} + +// SetDuration sets the "duration" field. +func (u *SkuUpsertBulk) SetDuration(v int64) *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.SetDuration(v) + }) +} + +// AddDuration adds v to the "duration" field. +func (u *SkuUpsertBulk) AddDuration(v int64) *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.AddDuration(v) + }) +} + +// UpdateDuration sets the "duration" field to the value that was provided on create. +func (u *SkuUpsertBulk) UpdateDuration() *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.UpdateDuration() + }) +} + +// ClearDuration clears the value of the "duration" field. +func (u *SkuUpsertBulk) ClearDuration() *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.ClearDuration() + }) +} + +// SetPrice sets the "price" field. +func (u *SkuUpsertBulk) SetPrice(v int64) *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.SetPrice(v) + }) +} + +// AddPrice adds v to the "price" field. +func (u *SkuUpsertBulk) AddPrice(v int64) *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.AddPrice(v) + }) +} + +// UpdatePrice sets the "price" field to the value that was provided on create. +func (u *SkuUpsertBulk) UpdatePrice() *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.UpdatePrice() + }) +} + +// ClearPrice clears the value of the "price" field. +func (u *SkuUpsertBulk) ClearPrice() *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.ClearPrice() + }) +} + +// SetPoints sets the "points" field. +func (u *SkuUpsertBulk) SetPoints(v int64) *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.SetPoints(v) + }) +} + +// AddPoints adds v to the "points" field. +func (u *SkuUpsertBulk) AddPoints(v int64) *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.AddPoints(v) + }) +} + +// UpdatePoints sets the "points" field to the value that was provided on create. +func (u *SkuUpsertBulk) UpdatePoints() *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.UpdatePoints() + }) +} + +// ClearPoints clears the value of the "points" field. +func (u *SkuUpsertBulk) ClearPoints() *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.ClearPoints() + }) +} + +// SetLabel sets the "label" field. +func (u *SkuUpsertBulk) SetLabel(v string) *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.SetLabel(v) + }) +} + +// UpdateLabel sets the "label" field to the value that was provided on create. +func (u *SkuUpsertBulk) UpdateLabel() *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.UpdateLabel() + }) +} + +// ClearLabel clears the value of the "label" field. +func (u *SkuUpsertBulk) ClearLabel() *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.ClearLabel() + }) +} + +// SetDes sets the "des" field. +func (u *SkuUpsertBulk) SetDes(v string) *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.SetDes(v) + }) +} + +// UpdateDes sets the "des" field to the value that was provided on create. +func (u *SkuUpsertBulk) UpdateDes() *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.UpdateDes() + }) +} + +// ClearDes clears the value of the "des" field. +func (u *SkuUpsertBulk) ClearDes() *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.ClearDes() + }) +} + +// SetEnabled sets the "enabled" field. +func (u *SkuUpsertBulk) SetEnabled(v bool) *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.SetEnabled(v) + }) +} + +// UpdateEnabled sets the "enabled" field to the value that was provided on create. +func (u *SkuUpsertBulk) UpdateEnabled() *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.UpdateEnabled() + }) +} + +// SetWeight sets the "weight" field. +func (u *SkuUpsertBulk) SetWeight(v int) *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.SetWeight(v) + }) +} + +// AddWeight adds v to the "weight" field. +func (u *SkuUpsertBulk) AddWeight(v int) *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.AddWeight(v) + }) +} + +// UpdateWeight sets the "weight" field to the value that was provided on create. +func (u *SkuUpsertBulk) UpdateWeight() *SkuUpsertBulk { + return u.Update(func(s *SkuUpsert) { + s.UpdateWeight() + }) +} + +// Exec executes the query. +func (u *SkuUpsertBulk) Exec(ctx context.Context) error { + if u.create.err != nil { + return u.create.err + } + for i, b := range u.create.builders { + if len(b.conflict) != 0 { + return fmt.Errorf("ent: OnConflict was set for builder %d. Set it on the SkuCreateBulk instead", i) + } + } + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for SkuCreateBulk.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *SkuUpsertBulk) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/ent/sku_delete.go b/ent/sku_delete.go new file mode 100644 index 00000000..16c5492c --- /dev/null +++ b/ent/sku_delete.go @@ -0,0 +1,88 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/cloudreve/Cloudreve/v4/ent/predicate" + "github.com/cloudreve/Cloudreve/v4/ent/sku" +) + +// SkuDelete is the builder for deleting a Sku entity. +type SkuDelete struct { + config + hooks []Hook + mutation *SkuMutation +} + +// Where appends a list predicates to the SkuDelete builder. +func (sd *SkuDelete) Where(ps ...predicate.Sku) *SkuDelete { + sd.mutation.Where(ps...) + return sd +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (sd *SkuDelete) Exec(ctx context.Context) (int, error) { + return withHooks(ctx, sd.sqlExec, sd.mutation, sd.hooks) +} + +// ExecX is like Exec, but panics if an error occurs. +func (sd *SkuDelete) ExecX(ctx context.Context) int { + n, err := sd.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (sd *SkuDelete) sqlExec(ctx context.Context) (int, error) { + _spec := sqlgraph.NewDeleteSpec(sku.Table, sqlgraph.NewFieldSpec(sku.FieldID, field.TypeInt)) + if ps := sd.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + affected, err := sqlgraph.DeleteNodes(ctx, sd.driver, _spec) + if err != nil && sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + sd.mutation.done = true + return affected, err +} + +// SkuDeleteOne is the builder for deleting a single Sku entity. +type SkuDeleteOne struct { + sd *SkuDelete +} + +// Where appends a list predicates to the SkuDelete builder. +func (sdo *SkuDeleteOne) Where(ps ...predicate.Sku) *SkuDeleteOne { + sdo.sd.mutation.Where(ps...) + return sdo +} + +// Exec executes the deletion query. +func (sdo *SkuDeleteOne) Exec(ctx context.Context) error { + n, err := sdo.sd.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{sku.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (sdo *SkuDeleteOne) ExecX(ctx context.Context) { + if err := sdo.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/ent/sku_query.go b/ent/sku_query.go new file mode 100644 index 00000000..921efb37 --- /dev/null +++ b/ent/sku_query.go @@ -0,0 +1,526 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + "math" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/cloudreve/Cloudreve/v4/ent/predicate" + "github.com/cloudreve/Cloudreve/v4/ent/sku" +) + +// SkuQuery is the builder for querying Sku entities. +type SkuQuery struct { + config + ctx *QueryContext + order []sku.OrderOption + inters []Interceptor + predicates []predicate.Sku + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the SkuQuery builder. +func (sq *SkuQuery) Where(ps ...predicate.Sku) *SkuQuery { + sq.predicates = append(sq.predicates, ps...) + return sq +} + +// Limit the number of records to be returned by this query. +func (sq *SkuQuery) Limit(limit int) *SkuQuery { + sq.ctx.Limit = &limit + return sq +} + +// Offset to start from. +func (sq *SkuQuery) Offset(offset int) *SkuQuery { + sq.ctx.Offset = &offset + return sq +} + +// Unique configures the query builder to filter duplicate records on query. +// By default, unique is set to true, and can be disabled using this method. +func (sq *SkuQuery) Unique(unique bool) *SkuQuery { + sq.ctx.Unique = &unique + return sq +} + +// Order specifies how the records should be ordered. +func (sq *SkuQuery) Order(o ...sku.OrderOption) *SkuQuery { + sq.order = append(sq.order, o...) + return sq +} + +// First returns the first Sku entity from the query. +// Returns a *NotFoundError when no Sku was found. +func (sq *SkuQuery) First(ctx context.Context) (*Sku, error) { + nodes, err := sq.Limit(1).All(setContextOp(ctx, sq.ctx, "First")) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{sku.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (sq *SkuQuery) FirstX(ctx context.Context) *Sku { + node, err := sq.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first Sku ID from the query. +// Returns a *NotFoundError when no Sku ID was found. +func (sq *SkuQuery) FirstID(ctx context.Context) (id int, err error) { + var ids []int + if ids, err = sq.Limit(1).IDs(setContextOp(ctx, sq.ctx, "FirstID")); err != nil { + return + } + if len(ids) == 0 { + err = &NotFoundError{sku.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (sq *SkuQuery) FirstIDX(ctx context.Context) int { + id, err := sq.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single Sku entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one Sku entity is found. +// Returns a *NotFoundError when no Sku entities are found. +func (sq *SkuQuery) Only(ctx context.Context) (*Sku, error) { + nodes, err := sq.Limit(2).All(setContextOp(ctx, sq.ctx, "Only")) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{sku.Label} + default: + return nil, &NotSingularError{sku.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (sq *SkuQuery) OnlyX(ctx context.Context) *Sku { + node, err := sq.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only Sku ID in the query. +// Returns a *NotSingularError when more than one Sku ID is found. +// Returns a *NotFoundError when no entities are found. +func (sq *SkuQuery) OnlyID(ctx context.Context) (id int, err error) { + var ids []int + if ids, err = sq.Limit(2).IDs(setContextOp(ctx, sq.ctx, "OnlyID")); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &NotFoundError{sku.Label} + default: + err = &NotSingularError{sku.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (sq *SkuQuery) OnlyIDX(ctx context.Context) int { + id, err := sq.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of Skus. +func (sq *SkuQuery) All(ctx context.Context) ([]*Sku, error) { + ctx = setContextOp(ctx, sq.ctx, "All") + if err := sq.prepareQuery(ctx); err != nil { + return nil, err + } + qr := querierAll[[]*Sku, *SkuQuery]() + return withInterceptors[[]*Sku](ctx, sq, qr, sq.inters) +} + +// AllX is like All, but panics if an error occurs. +func (sq *SkuQuery) AllX(ctx context.Context) []*Sku { + nodes, err := sq.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of Sku IDs. +func (sq *SkuQuery) IDs(ctx context.Context) (ids []int, err error) { + if sq.ctx.Unique == nil && sq.path != nil { + sq.Unique(true) + } + ctx = setContextOp(ctx, sq.ctx, "IDs") + if err = sq.Select(sku.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (sq *SkuQuery) IDsX(ctx context.Context) []int { + ids, err := sq.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (sq *SkuQuery) Count(ctx context.Context) (int, error) { + ctx = setContextOp(ctx, sq.ctx, "Count") + if err := sq.prepareQuery(ctx); err != nil { + return 0, err + } + return withInterceptors[int](ctx, sq, querierCount[*SkuQuery](), sq.inters) +} + +// CountX is like Count, but panics if an error occurs. +func (sq *SkuQuery) CountX(ctx context.Context) int { + count, err := sq.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (sq *SkuQuery) Exist(ctx context.Context) (bool, error) { + ctx = setContextOp(ctx, sq.ctx, "Exist") + switch _, err := sq.FirstID(ctx); { + case IsNotFound(err): + return false, nil + case err != nil: + return false, fmt.Errorf("ent: check existence: %w", err) + default: + return true, nil + } +} + +// ExistX is like Exist, but panics if an error occurs. +func (sq *SkuQuery) ExistX(ctx context.Context) bool { + exist, err := sq.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the SkuQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (sq *SkuQuery) Clone() *SkuQuery { + if sq == nil { + return nil + } + return &SkuQuery{ + config: sq.config, + ctx: sq.ctx.Clone(), + order: append([]sku.OrderOption{}, sq.order...), + inters: append([]Interceptor{}, sq.inters...), + predicates: append([]predicate.Sku{}, sq.predicates...), + // clone intermediate query. + sql: sq.sql.Clone(), + path: sq.path, + } +} + +// GroupBy is used to group vertices by one or more fields/columns. +// It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// CreatedAt time.Time `json:"created_at,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.Sku.Query(). +// GroupBy(sku.FieldCreatedAt). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (sq *SkuQuery) GroupBy(field string, fields ...string) *SkuGroupBy { + sq.ctx.Fields = append([]string{field}, fields...) + grbuild := &SkuGroupBy{build: sq} + grbuild.flds = &sq.ctx.Fields + grbuild.label = sku.Label + grbuild.scan = grbuild.Scan + return grbuild +} + +// Select allows the selection one or more fields/columns for the given query, +// instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// CreatedAt time.Time `json:"created_at,omitempty"` +// } +// +// client.Sku.Query(). +// Select(sku.FieldCreatedAt). +// Scan(ctx, &v) +func (sq *SkuQuery) Select(fields ...string) *SkuSelect { + sq.ctx.Fields = append(sq.ctx.Fields, fields...) + sbuild := &SkuSelect{SkuQuery: sq} + sbuild.label = sku.Label + sbuild.flds, sbuild.scan = &sq.ctx.Fields, sbuild.Scan + return sbuild +} + +// Aggregate returns a SkuSelect configured with the given aggregations. +func (sq *SkuQuery) Aggregate(fns ...AggregateFunc) *SkuSelect { + return sq.Select().Aggregate(fns...) +} + +func (sq *SkuQuery) prepareQuery(ctx context.Context) error { + for _, inter := range sq.inters { + if inter == nil { + return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)") + } + if trv, ok := inter.(Traverser); ok { + if err := trv.Traverse(ctx, sq); err != nil { + return err + } + } + } + for _, f := range sq.ctx.Fields { + if !sku.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if sq.path != nil { + prev, err := sq.path(ctx) + if err != nil { + return err + } + sq.sql = prev + } + return nil +} + +func (sq *SkuQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Sku, error) { + var ( + nodes = []*Sku{} + _spec = sq.querySpec() + ) + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*Sku).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &Sku{config: sq.config} + nodes = append(nodes, node) + return node.assignValues(columns, values) + } + for i := range hooks { + hooks[i](ctx, _spec) + } + if err := sqlgraph.QueryNodes(ctx, sq.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + return nodes, nil +} + +func (sq *SkuQuery) sqlCount(ctx context.Context) (int, error) { + _spec := sq.querySpec() + _spec.Node.Columns = sq.ctx.Fields + if len(sq.ctx.Fields) > 0 { + _spec.Unique = sq.ctx.Unique != nil && *sq.ctx.Unique + } + return sqlgraph.CountNodes(ctx, sq.driver, _spec) +} + +func (sq *SkuQuery) querySpec() *sqlgraph.QuerySpec { + _spec := sqlgraph.NewQuerySpec(sku.Table, sku.Columns, sqlgraph.NewFieldSpec(sku.FieldID, field.TypeInt)) + _spec.From = sq.sql + if unique := sq.ctx.Unique; unique != nil { + _spec.Unique = *unique + } else if sq.path != nil { + _spec.Unique = true + } + if fields := sq.ctx.Fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, sku.FieldID) + for i := range fields { + if fields[i] != sku.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + } + } + if ps := sq.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := sq.ctx.Limit; limit != nil { + _spec.Limit = *limit + } + if offset := sq.ctx.Offset; offset != nil { + _spec.Offset = *offset + } + if ps := sq.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return _spec +} + +func (sq *SkuQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(sq.driver.Dialect()) + t1 := builder.Table(sku.Table) + columns := sq.ctx.Fields + if len(columns) == 0 { + columns = sku.Columns + } + selector := builder.Select(t1.Columns(columns...)...).From(t1) + if sq.sql != nil { + selector = sq.sql + selector.Select(selector.Columns(columns...)...) + } + if sq.ctx.Unique != nil && *sq.ctx.Unique { + selector.Distinct() + } + for _, p := range sq.predicates { + p(selector) + } + for _, p := range sq.order { + p(selector) + } + if offset := sq.ctx.Offset; offset != nil { + // limit is mandatory for offset clause. We start + // with default value, and override it below if needed. + selector.Offset(*offset).Limit(math.MaxInt32) + } + if limit := sq.ctx.Limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// SkuGroupBy is the group-by builder for Sku entities. +type SkuGroupBy struct { + selector + build *SkuQuery +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (sgb *SkuGroupBy) Aggregate(fns ...AggregateFunc) *SkuGroupBy { + sgb.fns = append(sgb.fns, fns...) + return sgb +} + +// Scan applies the selector query and scans the result into the given value. +func (sgb *SkuGroupBy) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, sgb.build.ctx, "GroupBy") + if err := sgb.build.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*SkuQuery, *SkuGroupBy](ctx, sgb.build, sgb, sgb.build.inters, v) +} + +func (sgb *SkuGroupBy) sqlScan(ctx context.Context, root *SkuQuery, v any) error { + selector := root.sqlQuery(ctx).Select() + aggregation := make([]string, 0, len(sgb.fns)) + for _, fn := range sgb.fns { + aggregation = append(aggregation, fn(selector)) + } + if len(selector.SelectedColumns()) == 0 { + columns := make([]string, 0, len(*sgb.flds)+len(sgb.fns)) + for _, f := range *sgb.flds { + columns = append(columns, selector.C(f)) + } + columns = append(columns, aggregation...) + selector.Select(columns...) + } + selector.GroupBy(selector.Columns(*sgb.flds...)...) + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := sgb.build.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +// SkuSelect is the builder for selecting fields of Sku entities. +type SkuSelect struct { + *SkuQuery + selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (ss *SkuSelect) Aggregate(fns ...AggregateFunc) *SkuSelect { + ss.fns = append(ss.fns, fns...) + return ss +} + +// Scan applies the selector query and scans the result into the given value. +func (ss *SkuSelect) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, ss.ctx, "Select") + if err := ss.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*SkuQuery, *SkuSelect](ctx, ss.SkuQuery, ss, ss.inters, v) +} + +func (ss *SkuSelect) sqlScan(ctx context.Context, root *SkuQuery, v any) error { + selector := root.sqlQuery(ctx) + aggregation := make([]string, 0, len(ss.fns)) + for _, fn := range ss.fns { + aggregation = append(aggregation, fn(selector)) + } + switch n := len(*ss.selector.flds); { + case n == 0 && len(aggregation) > 0: + selector.Select(aggregation...) + case n != 0 && len(aggregation) > 0: + selector.AppendSelect(aggregation...) + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := ss.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} diff --git a/ent/sku_update.go b/ent/sku_update.go new file mode 100644 index 00000000..f37361c1 --- /dev/null +++ b/ent/sku_update.go @@ -0,0 +1,832 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/cloudreve/Cloudreve/v4/ent/predicate" + "github.com/cloudreve/Cloudreve/v4/ent/sku" +) + +// SkuUpdate is the builder for updating Sku entities. +type SkuUpdate struct { + config + hooks []Hook + mutation *SkuMutation +} + +// Where appends a list predicates to the SkuUpdate builder. +func (su *SkuUpdate) Where(ps ...predicate.Sku) *SkuUpdate { + su.mutation.Where(ps...) + return su +} + +// SetUpdatedAt sets the "updated_at" field. +func (su *SkuUpdate) SetUpdatedAt(t time.Time) *SkuUpdate { + su.mutation.SetUpdatedAt(t) + return su +} + +// SetDeletedAt sets the "deleted_at" field. +func (su *SkuUpdate) SetDeletedAt(t time.Time) *SkuUpdate { + su.mutation.SetDeletedAt(t) + return su +} + +// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil. +func (su *SkuUpdate) SetNillableDeletedAt(t *time.Time) *SkuUpdate { + if t != nil { + su.SetDeletedAt(*t) + } + return su +} + +// ClearDeletedAt clears the value of the "deleted_at" field. +func (su *SkuUpdate) ClearDeletedAt() *SkuUpdate { + su.mutation.ClearDeletedAt() + return su +} + +// SetName sets the "name" field. +func (su *SkuUpdate) SetName(s string) *SkuUpdate { + su.mutation.SetName(s) + return su +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (su *SkuUpdate) SetNillableName(s *string) *SkuUpdate { + if s != nil { + su.SetName(*s) + } + return su +} + +// SetType sets the "type" field. +func (su *SkuUpdate) SetType(s sku.Type) *SkuUpdate { + su.mutation.SetType(s) + return su +} + +// SetNillableType sets the "type" field if the given value is not nil. +func (su *SkuUpdate) SetNillableType(s *sku.Type) *SkuUpdate { + if s != nil { + su.SetType(*s) + } + return su +} + +// SetAmount sets the "amount" field. +func (su *SkuUpdate) SetAmount(i int64) *SkuUpdate { + su.mutation.ResetAmount() + su.mutation.SetAmount(i) + return su +} + +// SetNillableAmount sets the "amount" field if the given value is not nil. +func (su *SkuUpdate) SetNillableAmount(i *int64) *SkuUpdate { + if i != nil { + su.SetAmount(*i) + } + return su +} + +// AddAmount adds i to the "amount" field. +func (su *SkuUpdate) AddAmount(i int64) *SkuUpdate { + su.mutation.AddAmount(i) + return su +} + +// SetDuration sets the "duration" field. +func (su *SkuUpdate) SetDuration(i int64) *SkuUpdate { + su.mutation.ResetDuration() + su.mutation.SetDuration(i) + return su +} + +// SetNillableDuration sets the "duration" field if the given value is not nil. +func (su *SkuUpdate) SetNillableDuration(i *int64) *SkuUpdate { + if i != nil { + su.SetDuration(*i) + } + return su +} + +// AddDuration adds i to the "duration" field. +func (su *SkuUpdate) AddDuration(i int64) *SkuUpdate { + su.mutation.AddDuration(i) + return su +} + +// ClearDuration clears the value of the "duration" field. +func (su *SkuUpdate) ClearDuration() *SkuUpdate { + su.mutation.ClearDuration() + return su +} + +// SetPrice sets the "price" field. +func (su *SkuUpdate) SetPrice(i int64) *SkuUpdate { + su.mutation.ResetPrice() + su.mutation.SetPrice(i) + return su +} + +// SetNillablePrice sets the "price" field if the given value is not nil. +func (su *SkuUpdate) SetNillablePrice(i *int64) *SkuUpdate { + if i != nil { + su.SetPrice(*i) + } + return su +} + +// AddPrice adds i to the "price" field. +func (su *SkuUpdate) AddPrice(i int64) *SkuUpdate { + su.mutation.AddPrice(i) + return su +} + +// ClearPrice clears the value of the "price" field. +func (su *SkuUpdate) ClearPrice() *SkuUpdate { + su.mutation.ClearPrice() + return su +} + +// SetPoints sets the "points" field. +func (su *SkuUpdate) SetPoints(i int64) *SkuUpdate { + su.mutation.ResetPoints() + su.mutation.SetPoints(i) + return su +} + +// SetNillablePoints sets the "points" field if the given value is not nil. +func (su *SkuUpdate) SetNillablePoints(i *int64) *SkuUpdate { + if i != nil { + su.SetPoints(*i) + } + return su +} + +// AddPoints adds i to the "points" field. +func (su *SkuUpdate) AddPoints(i int64) *SkuUpdate { + su.mutation.AddPoints(i) + return su +} + +// ClearPoints clears the value of the "points" field. +func (su *SkuUpdate) ClearPoints() *SkuUpdate { + su.mutation.ClearPoints() + return su +} + +// SetLabel sets the "label" field. +func (su *SkuUpdate) SetLabel(s string) *SkuUpdate { + su.mutation.SetLabel(s) + return su +} + +// SetNillableLabel sets the "label" field if the given value is not nil. +func (su *SkuUpdate) SetNillableLabel(s *string) *SkuUpdate { + if s != nil { + su.SetLabel(*s) + } + return su +} + +// ClearLabel clears the value of the "label" field. +func (su *SkuUpdate) ClearLabel() *SkuUpdate { + su.mutation.ClearLabel() + return su +} + +// SetDes sets the "des" field. +func (su *SkuUpdate) SetDes(s string) *SkuUpdate { + su.mutation.SetDes(s) + return su +} + +// SetNillableDes sets the "des" field if the given value is not nil. +func (su *SkuUpdate) SetNillableDes(s *string) *SkuUpdate { + if s != nil { + su.SetDes(*s) + } + return su +} + +// ClearDes clears the value of the "des" field. +func (su *SkuUpdate) ClearDes() *SkuUpdate { + su.mutation.ClearDes() + return su +} + +// SetEnabled sets the "enabled" field. +func (su *SkuUpdate) SetEnabled(b bool) *SkuUpdate { + su.mutation.SetEnabled(b) + return su +} + +// SetNillableEnabled sets the "enabled" field if the given value is not nil. +func (su *SkuUpdate) SetNillableEnabled(b *bool) *SkuUpdate { + if b != nil { + su.SetEnabled(*b) + } + return su +} + +// SetWeight sets the "weight" field. +func (su *SkuUpdate) SetWeight(i int) *SkuUpdate { + su.mutation.ResetWeight() + su.mutation.SetWeight(i) + return su +} + +// SetNillableWeight sets the "weight" field if the given value is not nil. +func (su *SkuUpdate) SetNillableWeight(i *int) *SkuUpdate { + if i != nil { + su.SetWeight(*i) + } + return su +} + +// AddWeight adds i to the "weight" field. +func (su *SkuUpdate) AddWeight(i int) *SkuUpdate { + su.mutation.AddWeight(i) + return su +} + +// Mutation returns the SkuMutation object of the builder. +func (su *SkuUpdate) Mutation() *SkuMutation { + return su.mutation +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (su *SkuUpdate) Save(ctx context.Context) (int, error) { + if err := su.defaults(); err != nil { + return 0, err + } + return withHooks(ctx, su.sqlSave, su.mutation, su.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (su *SkuUpdate) SaveX(ctx context.Context) int { + affected, err := su.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (su *SkuUpdate) Exec(ctx context.Context) error { + _, err := su.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (su *SkuUpdate) ExecX(ctx context.Context) { + if err := su.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (su *SkuUpdate) defaults() error { + if _, ok := su.mutation.UpdatedAt(); !ok { + if sku.UpdateDefaultUpdatedAt == nil { + return fmt.Errorf("ent: uninitialized sku.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)") + } + v := sku.UpdateDefaultUpdatedAt() + su.mutation.SetUpdatedAt(v) + } + return nil +} + +// check runs all checks and user-defined validators on the builder. +func (su *SkuUpdate) check() error { + if v, ok := su.mutation.GetType(); ok { + if err := sku.TypeValidator(v); err != nil { + return &ValidationError{Name: "type", err: fmt.Errorf(`ent: validator failed for field "Sku.type": %w`, err)} + } + } + return nil +} + +func (su *SkuUpdate) sqlSave(ctx context.Context) (n int, err error) { + if err := su.check(); err != nil { + return n, err + } + _spec := sqlgraph.NewUpdateSpec(sku.Table, sku.Columns, sqlgraph.NewFieldSpec(sku.FieldID, field.TypeInt)) + if ps := su.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := su.mutation.UpdatedAt(); ok { + _spec.SetField(sku.FieldUpdatedAt, field.TypeTime, value) + } + if value, ok := su.mutation.DeletedAt(); ok { + _spec.SetField(sku.FieldDeletedAt, field.TypeTime, value) + } + if su.mutation.DeletedAtCleared() { + _spec.ClearField(sku.FieldDeletedAt, field.TypeTime) + } + if value, ok := su.mutation.Name(); ok { + _spec.SetField(sku.FieldName, field.TypeString, value) + } + if value, ok := su.mutation.GetType(); ok { + _spec.SetField(sku.FieldType, field.TypeEnum, value) + } + if value, ok := su.mutation.Amount(); ok { + _spec.SetField(sku.FieldAmount, field.TypeInt64, value) + } + if value, ok := su.mutation.AddedAmount(); ok { + _spec.AddField(sku.FieldAmount, field.TypeInt64, value) + } + if value, ok := su.mutation.Duration(); ok { + _spec.SetField(sku.FieldDuration, field.TypeInt64, value) + } + if value, ok := su.mutation.AddedDuration(); ok { + _spec.AddField(sku.FieldDuration, field.TypeInt64, value) + } + if su.mutation.DurationCleared() { + _spec.ClearField(sku.FieldDuration, field.TypeInt64) + } + if value, ok := su.mutation.Price(); ok { + _spec.SetField(sku.FieldPrice, field.TypeInt64, value) + } + if value, ok := su.mutation.AddedPrice(); ok { + _spec.AddField(sku.FieldPrice, field.TypeInt64, value) + } + if su.mutation.PriceCleared() { + _spec.ClearField(sku.FieldPrice, field.TypeInt64) + } + if value, ok := su.mutation.Points(); ok { + _spec.SetField(sku.FieldPoints, field.TypeInt64, value) + } + if value, ok := su.mutation.AddedPoints(); ok { + _spec.AddField(sku.FieldPoints, field.TypeInt64, value) + } + if su.mutation.PointsCleared() { + _spec.ClearField(sku.FieldPoints, field.TypeInt64) + } + if value, ok := su.mutation.Label(); ok { + _spec.SetField(sku.FieldLabel, field.TypeString, value) + } + if su.mutation.LabelCleared() { + _spec.ClearField(sku.FieldLabel, field.TypeString) + } + if value, ok := su.mutation.Des(); ok { + _spec.SetField(sku.FieldDes, field.TypeString, value) + } + if su.mutation.DesCleared() { + _spec.ClearField(sku.FieldDes, field.TypeString) + } + if value, ok := su.mutation.Enabled(); ok { + _spec.SetField(sku.FieldEnabled, field.TypeBool, value) + } + if value, ok := su.mutation.Weight(); ok { + _spec.SetField(sku.FieldWeight, field.TypeInt, value) + } + if value, ok := su.mutation.AddedWeight(); ok { + _spec.AddField(sku.FieldWeight, field.TypeInt, value) + } + if n, err = sqlgraph.UpdateNodes(ctx, su.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{sku.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + su.mutation.done = true + return n, nil +} + +// SkuUpdateOne is the builder for updating a single Sku entity. +type SkuUpdateOne struct { + config + fields []string + hooks []Hook + mutation *SkuMutation +} + +// SetUpdatedAt sets the "updated_at" field. +func (suo *SkuUpdateOne) SetUpdatedAt(t time.Time) *SkuUpdateOne { + suo.mutation.SetUpdatedAt(t) + return suo +} + +// SetDeletedAt sets the "deleted_at" field. +func (suo *SkuUpdateOne) SetDeletedAt(t time.Time) *SkuUpdateOne { + suo.mutation.SetDeletedAt(t) + return suo +} + +// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil. +func (suo *SkuUpdateOne) SetNillableDeletedAt(t *time.Time) *SkuUpdateOne { + if t != nil { + suo.SetDeletedAt(*t) + } + return suo +} + +// ClearDeletedAt clears the value of the "deleted_at" field. +func (suo *SkuUpdateOne) ClearDeletedAt() *SkuUpdateOne { + suo.mutation.ClearDeletedAt() + return suo +} + +// SetName sets the "name" field. +func (suo *SkuUpdateOne) SetName(s string) *SkuUpdateOne { + suo.mutation.SetName(s) + return suo +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (suo *SkuUpdateOne) SetNillableName(s *string) *SkuUpdateOne { + if s != nil { + suo.SetName(*s) + } + return suo +} + +// SetType sets the "type" field. +func (suo *SkuUpdateOne) SetType(s sku.Type) *SkuUpdateOne { + suo.mutation.SetType(s) + return suo +} + +// SetNillableType sets the "type" field if the given value is not nil. +func (suo *SkuUpdateOne) SetNillableType(s *sku.Type) *SkuUpdateOne { + if s != nil { + suo.SetType(*s) + } + return suo +} + +// SetAmount sets the "amount" field. +func (suo *SkuUpdateOne) SetAmount(i int64) *SkuUpdateOne { + suo.mutation.ResetAmount() + suo.mutation.SetAmount(i) + return suo +} + +// SetNillableAmount sets the "amount" field if the given value is not nil. +func (suo *SkuUpdateOne) SetNillableAmount(i *int64) *SkuUpdateOne { + if i != nil { + suo.SetAmount(*i) + } + return suo +} + +// AddAmount adds i to the "amount" field. +func (suo *SkuUpdateOne) AddAmount(i int64) *SkuUpdateOne { + suo.mutation.AddAmount(i) + return suo +} + +// SetDuration sets the "duration" field. +func (suo *SkuUpdateOne) SetDuration(i int64) *SkuUpdateOne { + suo.mutation.ResetDuration() + suo.mutation.SetDuration(i) + return suo +} + +// SetNillableDuration sets the "duration" field if the given value is not nil. +func (suo *SkuUpdateOne) SetNillableDuration(i *int64) *SkuUpdateOne { + if i != nil { + suo.SetDuration(*i) + } + return suo +} + +// AddDuration adds i to the "duration" field. +func (suo *SkuUpdateOne) AddDuration(i int64) *SkuUpdateOne { + suo.mutation.AddDuration(i) + return suo +} + +// ClearDuration clears the value of the "duration" field. +func (suo *SkuUpdateOne) ClearDuration() *SkuUpdateOne { + suo.mutation.ClearDuration() + return suo +} + +// SetPrice sets the "price" field. +func (suo *SkuUpdateOne) SetPrice(i int64) *SkuUpdateOne { + suo.mutation.ResetPrice() + suo.mutation.SetPrice(i) + return suo +} + +// SetNillablePrice sets the "price" field if the given value is not nil. +func (suo *SkuUpdateOne) SetNillablePrice(i *int64) *SkuUpdateOne { + if i != nil { + suo.SetPrice(*i) + } + return suo +} + +// AddPrice adds i to the "price" field. +func (suo *SkuUpdateOne) AddPrice(i int64) *SkuUpdateOne { + suo.mutation.AddPrice(i) + return suo +} + +// ClearPrice clears the value of the "price" field. +func (suo *SkuUpdateOne) ClearPrice() *SkuUpdateOne { + suo.mutation.ClearPrice() + return suo +} + +// SetPoints sets the "points" field. +func (suo *SkuUpdateOne) SetPoints(i int64) *SkuUpdateOne { + suo.mutation.ResetPoints() + suo.mutation.SetPoints(i) + return suo +} + +// SetNillablePoints sets the "points" field if the given value is not nil. +func (suo *SkuUpdateOne) SetNillablePoints(i *int64) *SkuUpdateOne { + if i != nil { + suo.SetPoints(*i) + } + return suo +} + +// AddPoints adds i to the "points" field. +func (suo *SkuUpdateOne) AddPoints(i int64) *SkuUpdateOne { + suo.mutation.AddPoints(i) + return suo +} + +// ClearPoints clears the value of the "points" field. +func (suo *SkuUpdateOne) ClearPoints() *SkuUpdateOne { + suo.mutation.ClearPoints() + return suo +} + +// SetLabel sets the "label" field. +func (suo *SkuUpdateOne) SetLabel(s string) *SkuUpdateOne { + suo.mutation.SetLabel(s) + return suo +} + +// SetNillableLabel sets the "label" field if the given value is not nil. +func (suo *SkuUpdateOne) SetNillableLabel(s *string) *SkuUpdateOne { + if s != nil { + suo.SetLabel(*s) + } + return suo +} + +// ClearLabel clears the value of the "label" field. +func (suo *SkuUpdateOne) ClearLabel() *SkuUpdateOne { + suo.mutation.ClearLabel() + return suo +} + +// SetDes sets the "des" field. +func (suo *SkuUpdateOne) SetDes(s string) *SkuUpdateOne { + suo.mutation.SetDes(s) + return suo +} + +// SetNillableDes sets the "des" field if the given value is not nil. +func (suo *SkuUpdateOne) SetNillableDes(s *string) *SkuUpdateOne { + if s != nil { + suo.SetDes(*s) + } + return suo +} + +// ClearDes clears the value of the "des" field. +func (suo *SkuUpdateOne) ClearDes() *SkuUpdateOne { + suo.mutation.ClearDes() + return suo +} + +// SetEnabled sets the "enabled" field. +func (suo *SkuUpdateOne) SetEnabled(b bool) *SkuUpdateOne { + suo.mutation.SetEnabled(b) + return suo +} + +// SetNillableEnabled sets the "enabled" field if the given value is not nil. +func (suo *SkuUpdateOne) SetNillableEnabled(b *bool) *SkuUpdateOne { + if b != nil { + suo.SetEnabled(*b) + } + return suo +} + +// SetWeight sets the "weight" field. +func (suo *SkuUpdateOne) SetWeight(i int) *SkuUpdateOne { + suo.mutation.ResetWeight() + suo.mutation.SetWeight(i) + return suo +} + +// SetNillableWeight sets the "weight" field if the given value is not nil. +func (suo *SkuUpdateOne) SetNillableWeight(i *int) *SkuUpdateOne { + if i != nil { + suo.SetWeight(*i) + } + return suo +} + +// AddWeight adds i to the "weight" field. +func (suo *SkuUpdateOne) AddWeight(i int) *SkuUpdateOne { + suo.mutation.AddWeight(i) + return suo +} + +// Mutation returns the SkuMutation object of the builder. +func (suo *SkuUpdateOne) Mutation() *SkuMutation { + return suo.mutation +} + +// Where appends a list predicates to the SkuUpdate builder. +func (suo *SkuUpdateOne) Where(ps ...predicate.Sku) *SkuUpdateOne { + suo.mutation.Where(ps...) + return suo +} + +// Select allows selecting one or more fields (columns) of the returned entity. +// The default is selecting all fields defined in the entity schema. +func (suo *SkuUpdateOne) Select(field string, fields ...string) *SkuUpdateOne { + suo.fields = append([]string{field}, fields...) + return suo +} + +// Save executes the query and returns the updated Sku entity. +func (suo *SkuUpdateOne) Save(ctx context.Context) (*Sku, error) { + if err := suo.defaults(); err != nil { + return nil, err + } + return withHooks(ctx, suo.sqlSave, suo.mutation, suo.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (suo *SkuUpdateOne) SaveX(ctx context.Context) *Sku { + node, err := suo.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (suo *SkuUpdateOne) Exec(ctx context.Context) error { + _, err := suo.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (suo *SkuUpdateOne) ExecX(ctx context.Context) { + if err := suo.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (suo *SkuUpdateOne) defaults() error { + if _, ok := suo.mutation.UpdatedAt(); !ok { + if sku.UpdateDefaultUpdatedAt == nil { + return fmt.Errorf("ent: uninitialized sku.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)") + } + v := sku.UpdateDefaultUpdatedAt() + suo.mutation.SetUpdatedAt(v) + } + return nil +} + +// check runs all checks and user-defined validators on the builder. +func (suo *SkuUpdateOne) check() error { + if v, ok := suo.mutation.GetType(); ok { + if err := sku.TypeValidator(v); err != nil { + return &ValidationError{Name: "type", err: fmt.Errorf(`ent: validator failed for field "Sku.type": %w`, err)} + } + } + return nil +} + +func (suo *SkuUpdateOne) sqlSave(ctx context.Context) (_node *Sku, err error) { + if err := suo.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(sku.Table, sku.Columns, sqlgraph.NewFieldSpec(sku.FieldID, field.TypeInt)) + id, ok := suo.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "Sku.id" for update`)} + } + _spec.Node.ID.Value = id + if fields := suo.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, sku.FieldID) + for _, f := range fields { + if !sku.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != sku.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, f) + } + } + } + if ps := suo.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := suo.mutation.UpdatedAt(); ok { + _spec.SetField(sku.FieldUpdatedAt, field.TypeTime, value) + } + if value, ok := suo.mutation.DeletedAt(); ok { + _spec.SetField(sku.FieldDeletedAt, field.TypeTime, value) + } + if suo.mutation.DeletedAtCleared() { + _spec.ClearField(sku.FieldDeletedAt, field.TypeTime) + } + if value, ok := suo.mutation.Name(); ok { + _spec.SetField(sku.FieldName, field.TypeString, value) + } + if value, ok := suo.mutation.GetType(); ok { + _spec.SetField(sku.FieldType, field.TypeEnum, value) + } + if value, ok := suo.mutation.Amount(); ok { + _spec.SetField(sku.FieldAmount, field.TypeInt64, value) + } + if value, ok := suo.mutation.AddedAmount(); ok { + _spec.AddField(sku.FieldAmount, field.TypeInt64, value) + } + if value, ok := suo.mutation.Duration(); ok { + _spec.SetField(sku.FieldDuration, field.TypeInt64, value) + } + if value, ok := suo.mutation.AddedDuration(); ok { + _spec.AddField(sku.FieldDuration, field.TypeInt64, value) + } + if suo.mutation.DurationCleared() { + _spec.ClearField(sku.FieldDuration, field.TypeInt64) + } + if value, ok := suo.mutation.Price(); ok { + _spec.SetField(sku.FieldPrice, field.TypeInt64, value) + } + if value, ok := suo.mutation.AddedPrice(); ok { + _spec.AddField(sku.FieldPrice, field.TypeInt64, value) + } + if suo.mutation.PriceCleared() { + _spec.ClearField(sku.FieldPrice, field.TypeInt64) + } + if value, ok := suo.mutation.Points(); ok { + _spec.SetField(sku.FieldPoints, field.TypeInt64, value) + } + if value, ok := suo.mutation.AddedPoints(); ok { + _spec.AddField(sku.FieldPoints, field.TypeInt64, value) + } + if suo.mutation.PointsCleared() { + _spec.ClearField(sku.FieldPoints, field.TypeInt64) + } + if value, ok := suo.mutation.Label(); ok { + _spec.SetField(sku.FieldLabel, field.TypeString, value) + } + if suo.mutation.LabelCleared() { + _spec.ClearField(sku.FieldLabel, field.TypeString) + } + if value, ok := suo.mutation.Des(); ok { + _spec.SetField(sku.FieldDes, field.TypeString, value) + } + if suo.mutation.DesCleared() { + _spec.ClearField(sku.FieldDes, field.TypeString) + } + if value, ok := suo.mutation.Enabled(); ok { + _spec.SetField(sku.FieldEnabled, field.TypeBool, value) + } + if value, ok := suo.mutation.Weight(); ok { + _spec.SetField(sku.FieldWeight, field.TypeInt, value) + } + if value, ok := suo.mutation.AddedWeight(); ok { + _spec.AddField(sku.FieldWeight, field.TypeInt, value) + } + _node = &Sku{config: suo.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, suo.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{sku.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + suo.mutation.done = true + return _node, nil +} diff --git a/ent/tx.go b/ent/tx.go index 8455fdac..7ec81c18 100644 --- a/ent/tx.go +++ b/ent/tx.go @@ -52,6 +52,8 @@ type Tx struct { Setting *SettingClient // Share is the client for interacting with the Share builders. Share *ShareClient + // Sku is the client for interacting with the Sku builders. + Sku *SkuClient // StoragePolicy is the client for interacting with the StoragePolicy builders. StoragePolicy *StoragePolicyClient // Task is the client for interacting with the Task builders. @@ -210,6 +212,7 @@ func (tx *Tx) init() { tx.Passkey = NewPasskeyClient(tx.config) tx.Setting = NewSettingClient(tx.config) tx.Share = NewShareClient(tx.config) + tx.Sku = NewSkuClient(tx.config) tx.StoragePolicy = NewStoragePolicyClient(tx.config) tx.Task = NewTaskClient(tx.config) tx.User = NewUserClient(tx.config) diff --git a/frontend/public/locales/en-US/application.json b/frontend/public/locales/en-US/application.json index 25789c2c..258ee73e 100644 --- a/frontend/public/locales/en-US/application.json +++ b/frontend/public/locales/en-US/application.json @@ -134,6 +134,7 @@ "remoteDownload": "Remote Download", "connect": "Connect & Mount", "taskQueue": "Background Tasks", + "shop": "Shop", "setting": "Settings", "videos": "Videos", "photos": "Photos", @@ -1113,6 +1114,17 @@ "reportDescription": "Additional description", "reportAbuseSuccess": "Report submitted." }, + "shop": { + "memberships": "Memberships", + "storagePacks": "Storage packs", + "redeem": "Redeem", + "balance": "Balance: {{credits}} pts", + "purchased": "Purchased {{name}}", + "permanent": "Permanent", + "noProducts": "No products available", + "buyWithPoints": "Buy for {{points}} pts", + "pointsUnavailable": "Not purchasable with points" + }, "announcement": { "title": "Announcement", "dontShowAgain": "Don't show this again" diff --git a/frontend/public/locales/zh-CN/application.json b/frontend/public/locales/zh-CN/application.json index 03f406e2..eca26b8b 100644 --- a/frontend/public/locales/zh-CN/application.json +++ b/frontend/public/locales/zh-CN/application.json @@ -134,6 +134,7 @@ "remoteDownload": "离线下载", "connect": "连接与挂载", "taskQueue": "后台任务", + "shop": "商城", "setting": "设置", "videos": "视频", "photos": "图片", @@ -1113,6 +1114,17 @@ "reportDescription": "补充说明", "reportAbuseSuccess": "举报已提交" }, + "shop": { + "memberships": "会员", + "storagePacks": "容量包", + "redeem": "兑换", + "balance": "余额:{{credits}} 积分", + "purchased": "已购买 {{name}}", + "permanent": "永久", + "noProducts": "暂无商品", + "buyWithPoints": "{{points}} 积分购买", + "pointsUnavailable": "不支持积分购买" + }, "announcement": { "title": "公告", "dontShowAgain": "不再显示" diff --git a/frontend/src/api/api.ts b/frontend/src/api/api.ts index 59903988..c0ca6969 100644 --- a/frontend/src/api/api.ts +++ b/frontend/src/api/api.ts @@ -38,6 +38,7 @@ import { QueueMetric, SetSettingService, Share as ShareEnt, + Sku, Task, TestNodeDownloaderService, TestNodeService, @@ -112,6 +113,7 @@ import { RefreshTokenRequest, ResetPasswordService, SendResetEmailService, + ShopSku, SignUpService, Token, TwoFALoginRequest, @@ -2681,6 +2683,76 @@ export function adminDeleteGiftCode(id: number): ThunkResponse { }; } +export function getShopSkus(): ThunkResponse { + return async (dispatch, _getState) => { + return await dispatch( + send( + "/user/shop/skus", + { method: "GET" }, + { + ...defaultOpts, + }, + ), + ); + }; +} + +export function purchaseSku(sku: string): ThunkResponse { + return async (dispatch, _getState) => { + return await dispatch( + send( + "/user/shop/purchase", + { method: "POST", data: { sku } }, + { + ...defaultOpts, + }, + ), + ); + }; +} + +export function adminListSkus(): ThunkResponse { + return async (dispatch, _getState) => { + return await dispatch( + send( + "/admin/vas/sku", + { method: "GET" }, + { + ...defaultOpts, + }, + ), + ); + }; +} + +export function adminUpsertSku(sku: Sku): ThunkResponse { + return async (dispatch, _getState) => { + return await dispatch( + send( + sku.id > 0 ? `/admin/vas/sku/${sku.id}` : "/admin/vas/sku", + { method: "PUT", data: { sku } }, + { + ...defaultOpts, + }, + ), + ); + }; +} + +export function adminDeleteSku(id: number): ThunkResponse { + return async (dispatch, _getState) => { + return await dispatch( + send( + `/admin/vas/sku/${id}`, + { method: "DELETE" }, + { + ...defaultOpts, + }, + ), + ); + }; +} + export function adminListEvents(args: { page: number; pageSize: number; diff --git a/frontend/src/api/dashboard.ts b/frontend/src/api/dashboard.ts index 60e13bd0..eb311e64 100644 --- a/frontend/src/api/dashboard.ts +++ b/frontend/src/api/dashboard.ts @@ -656,6 +656,26 @@ export interface GiftCodeListResponse { total: number; } +export interface Sku { + id: number; + name: string; + type: "storage" | "group"; + amount: number; + duration?: number; + price?: number; + points?: number; + label?: string; + des?: string; + enabled: boolean; + weight: number; + created_at?: string; + updated_at?: string; +} + +export interface SkuUpsertService { + sku: Sku; +} + export interface ActivityEvent { id: string; type: number; diff --git a/frontend/src/api/user.ts b/frontend/src/api/user.ts index c416728e..71589784 100644 --- a/frontend/src/api/user.ts +++ b/frontend/src/api/user.ts @@ -314,3 +314,17 @@ export interface CreditTxnList { txns: CreditTxn[]; total: number; } + +export interface ShopSku { + id: string; + name: string; + type: "storage" | "group"; + amount: number; + group?: string; + group_id?: string; + duration: number; + price: number; + points?: number; + label?: string; + des?: string; +} diff --git a/frontend/src/component/Admin/Settings/VAS/GroupProducts.tsx b/frontend/src/component/Admin/Settings/VAS/GroupProducts.tsx deleted file mode 100644 index ca1f214a..00000000 --- a/frontend/src/component/Admin/Settings/VAS/GroupProducts.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Box, Table, TableBody, TableContainer, TableHead, TableRow, Typography } from "@mui/material"; -import { useTranslation } from "react-i18next"; -import { NoWrapCell, SecondaryButton, StyledTableContainerPaper } from "../../../Common/StyledComponents.tsx"; -import Add from "../../../Icons/Add.tsx"; - -const GroupProducts = () => { - const { t } = useTranslation("dashboard"); - - return ( - - - }> - {t("settings.addGroupProduct")} - - - - - - - - {t("settings.displayName")} - {t("settings.price")} - {t("settings.duration")} - {t("settings.description")} - {t("settings.actions")} - - - - - - - {t("application:setting.listEmpty")} - - - - -
-
-
- ); -}; - -export default GroupProducts; diff --git a/frontend/src/component/Admin/Settings/VAS/SkuTable.tsx b/frontend/src/component/Admin/Settings/VAS/SkuTable.tsx new file mode 100644 index 00000000..77f19956 --- /dev/null +++ b/frontend/src/component/Admin/Settings/VAS/SkuTable.tsx @@ -0,0 +1,349 @@ +import { + Box, + Chip, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + FormControl, + FormControlLabel, + IconButton, + InputLabel, + MenuItem, + Select, + Stack, + Switch, + Table, + TableBody, + TableContainer, + TableHead, + TableRow, + Typography, +} from "@mui/material"; +import { useCallback, useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { adminDeleteSku, adminListSkus, adminUpsertSku, getGroupList } from "../../../../api/api.ts"; +import { GroupEnt, Sku } from "../../../../api/dashboard.ts"; +import { useAppDispatch } from "../../../../redux/hooks.ts"; +import { sizeToString } from "../../../../util/index.ts"; +import { + DenseFilledTextField, + NoWrapCell, + SecondaryButton, + StyledTableContainerPaper, +} from "../../../Common/StyledComponents.tsx"; +import Add from "../../../Icons/Add.tsx"; +import Dismiss from "../../../Icons/Dismiss.tsx"; +import Edit from "../../../Icons/Edit.tsx"; +import SettingForm from "../../../Pages/Setting/SettingForm.tsx"; +import { NoMarginHelperText } from "../Settings.tsx"; + +const DAY_SECONDS = 86400; + +export interface SkuTableProps { + type: "storage" | "group"; +} + +interface SkuForm { + id: number; + name: string; + amount: number; + durationDays: number; + price: number; + allowPoints: boolean; + points: number; + label: string; + des: string; + enabled: boolean; +} + +const emptyForm = (type: string): SkuForm => ({ + id: 0, + name: "", + amount: 0, + durationDays: type === "storage" ? 365 : 30, + price: 0, + allowPoints: false, + points: 0, + label: "", + des: "", + enabled: true, +}); + +const SkuTable = ({ type }: SkuTableProps) => { + const { t } = useTranslation("dashboard"); + const dispatch = useAppDispatch(); + const [skus, setSkus] = useState(undefined); + const [groups, setGroups] = useState([]); + const [form, setForm] = useState(undefined); + const [saving, setSaving] = useState(false); + + const load = useCallback(() => { + dispatch(adminListSkus()).then((res) => setSkus(res.filter((s) => s.type === type))); + }, [type]); + + useEffect(() => { + load(); + dispatch(getGroupList({ page: 1, page_size: 200, order_by: "id", order_direction: "asc" })).then((res) => + setGroups(res.groups), + ); + }, [load]); + + const groupName = useCallback( + (id: number) => groups.find((g) => g.id === id)?.name ?? `#${id}`, + [groups], + ); + + const openEdit = (s?: Sku) => { + if (!s) { + setForm(emptyForm(type)); + return; + } + setForm({ + id: s.id, + name: s.name, + amount: s.amount, + durationDays: Math.round((s.duration ?? 0) / DAY_SECONDS), + price: s.price ?? 0, + allowPoints: s.points != null, + points: s.points ?? 0, + label: s.label ?? "", + des: s.des ?? "", + enabled: s.enabled, + }); + }; + + const onSave = () => { + if (!form) { + return; + } + setSaving(true); + dispatch( + adminUpsertSku({ + id: form.id, + name: form.name, + type, + amount: form.amount, + duration: Math.max(0, form.durationDays) * DAY_SECONDS, + price: Math.max(0, form.price), + points: form.allowPoints ? Math.max(1, form.points) : undefined, + label: form.label || undefined, + des: form.des || undefined, + enabled: form.enabled, + weight: 0, + }), + ) + .then(() => { + setForm(undefined); + load(); + }) + .finally(() => setSaving(false)); + }; + + const onDelete = (id: number) => { + dispatch(adminDeleteSku(id)).then(load); + }; + + const amountLabel = (s: Sku) => (type === "storage" ? sizeToString(s.amount) : groupName(s.amount)); + + return ( + + + } onClick={() => openEdit()}> + {type === "storage" ? t("vas.addStoragePack") : t("vas.addMembership")} + + + + + + + + + {t("vas.name")} + {type === "storage" ? t("vas.size") : t("vas.group")} + {t("vas.duration")} + {t("vas.price")} + {t("vas.priceCredits")} + {t("vas.status")} + {t("vas.actions")} + + + + {skus?.map((s) => ( + + + {s.name} + {s.label && } + + {amountLabel(s)} + + {(s.duration ?? 0) > 0 + ? t("application:vas.validDurationDays", { num: Math.round((s.duration ?? 0) / DAY_SECONDS) }) + : t("application:shop.permanent")} + + {s.price ?? 0} + {s.points != null ? s.points : "-"} + + + + + openEdit(s)}> + + + onDelete(s.id)}> + + + + + ))} + {(!skus || skus.length === 0) && ( + + + + {t("application:setting.listEmpty")} + + + + )} + +
+
+
+ + setForm(undefined)} maxWidth="sm" fullWidth> + {type === "storage" ? t("vas.editStoragePack") : t("vas.editMembership")} + + {form && ( + + + setForm({ ...form, name: e.target.value })} + /> + {t("vas.productNameDes")} + + + {type === "storage" ? ( + + setForm({ ...form, amount: parseInt(e.target.value) || 0 })} + /> + {t("vas.packSizeDes")} + + ) : ( + + + {t("vas.purchasableGroups")} + + + {t("vas.groupDes")} + + )} + + + setForm({ ...form, durationDays: parseInt(e.target.value) || 0 })} + /> + + {type === "storage" ? t("vas.durationDayDes") : t("vas.durationGroupDes")} + + + + + setForm({ ...form, price: parseInt(e.target.value) || 0 })} + /> + {t("vas.packPriceDes")} + + + + setForm({ ...form, allowPoints: e.target.checked })} + /> + } + label={t("vas.priceCredits")} + /> + {t("vas.priceCreditsDes")} + + + {form.allowPoints && ( + + setForm({ ...form, points: parseInt(e.target.value) || 0 })} + /> + + )} + + + setForm({ ...form, label: e.target.value })} + /> + {t("vas.highlightDes")} + + + + setForm({ ...form, des: e.target.value })} + /> + {t("vas.productDescriptionDes")} + + + + setForm({ ...form, enabled: e.target.checked })} /> + } + label={t("vas.enable")} + /> + + + )} + + + setForm(undefined)}>{t("common:cancel")} + + {t("common:ok")} + + + +
+ ); +}; + +export default SkuTable; diff --git a/frontend/src/component/Admin/Settings/VAS/StorageProducts.tsx b/frontend/src/component/Admin/Settings/VAS/StorageProducts.tsx deleted file mode 100644 index 2898a0ae..00000000 --- a/frontend/src/component/Admin/Settings/VAS/StorageProducts.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Box, Table, TableBody, TableContainer, TableHead, TableRow, Typography } from "@mui/material"; -import { useTranslation } from "react-i18next"; -import { NoWrapCell, SecondaryButton, StyledTableContainerPaper } from "../../../Common/StyledComponents.tsx"; -import Add from "../../../Icons/Add.tsx"; - -const StorageProducts = () => { - const { t } = useTranslation("dashboard"); - - return ( - - - }> - {t("settings.addStorageProduct")} - - - - - - - - {t("settings.displayName")} - {t("settings.price")} - {t("settings.duration")} - {t("settings.storageSize")} - {t("settings.actions")} - - - - - - - {t("application:setting.listEmpty")} - - - - -
-
-
- ); -}; - -export default StorageProducts; diff --git a/frontend/src/component/Admin/Settings/VAS/VAS.tsx b/frontend/src/component/Admin/Settings/VAS/VAS.tsx index 68058d38..ac6da986 100644 --- a/frontend/src/component/Admin/Settings/VAS/VAS.tsx +++ b/frontend/src/component/Admin/Settings/VAS/VAS.tsx @@ -17,10 +17,9 @@ import SettingForm from "../../../Pages/Setting/SettingForm.tsx"; import { NoMarginHelperText, SettingSection, SettingSectionContent } from "../Settings.tsx"; import { SettingContext } from "../SettingWrapper.tsx"; import GiftCodes from "./GiftCodes.tsx"; -import GroupProducts from "./GroupProducts.tsx"; import ManualCreditAdjust from "./ManualCreditAdjust.tsx"; import PaymentProviders from "./PaymentProviders.tsx"; -import StorageProducts from "./StorageProducts.tsx"; +import SkuTable from "./SkuTable.tsx"; const VAS = () => { const { t } = useTranslation("dashboard"); const { formRef } = useContext(SettingContext); @@ -170,7 +169,7 @@ const VAS = () => { - + {t("settings.storageProductsDes")} @@ -184,7 +183,7 @@ const VAS = () => { - + {t("settings.groupProductsDes")} diff --git a/frontend/src/component/Common/Form/RedeemCodeInput.tsx b/frontend/src/component/Common/Form/RedeemCodeInput.tsx new file mode 100644 index 00000000..4e0960c6 --- /dev/null +++ b/frontend/src/component/Common/Form/RedeemCodeInput.tsx @@ -0,0 +1,55 @@ +import { Button, InputAdornment } from "@mui/material"; +import { useSnackbar } from "notistack"; +import { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { redeemGiftCode } from "../../../api/api.ts"; +import { useAppDispatch } from "../../../redux/hooks.ts"; +import { DenseFilledTextField } from "../StyledComponents.tsx"; + +export interface RedeemCodeInputProps { + onRedeemed?: () => void; +} + +const RedeemCodeInput = ({ onRedeemed }: RedeemCodeInputProps) => { + const { t } = useTranslation(); + const dispatch = useAppDispatch(); + const { enqueueSnackbar } = useSnackbar(); + const [code, setCode] = useState(""); + const [redeeming, setRedeeming] = useState(false); + + const onRedeem = () => { + if (!code.trim()) { + return; + } + setRedeeming(true); + dispatch(redeemGiftCode(code.trim())) + .then(() => { + enqueueSnackbar(t("setting.giftCodeRedeemed"), { variant: "success" }); + setCode(""); + onRedeemed?.(); + }) + .finally(() => setRedeeming(false)); + }; + + return ( + setCode(e.target.value)} + placeholder={t("setting.giftCodePlaceholder")} + slotProps={{ + input: { + endAdornment: ( + + + + ), + }, + }} + /> + ); +}; + +export default RedeemCodeInput; diff --git a/frontend/src/component/Frame/NavBar/PageNavigation.tsx b/frontend/src/component/Frame/NavBar/PageNavigation.tsx index 067b64cf..004ff0f5 100644 --- a/frontend/src/component/Frame/NavBar/PageNavigation.tsx +++ b/frontend/src/component/Frame/NavBar/PageNavigation.tsx @@ -10,6 +10,8 @@ import SessionManager from "../../../session"; import { GroupBS } from "../../../session/utils.ts"; import BoxMultiple from "../../Icons/BoxMultiple.tsx"; import BoxMultipleFilled from "../../Icons/BoxMultipleFilled.tsx"; +import BuildingShop from "../../Icons/BuildingShop.tsx"; +import BuildingShopFilled from "../../Icons/BuildingShopFilled.tsx"; import CloudDownload from "../../Icons/CloudDownload.tsx"; import CloudDownloadOutlined from "../../Icons/CloudDownloadOutlined.tsx"; import CubeSync from "../../Icons/CubeSync.tsx"; @@ -84,6 +86,12 @@ const RemoteDownloadNavigationItem: NavigationItem = { path: "/downloads", }; +const ShopNavigationItem: NavigationItem = { + label: "navbar.shop", + icon: [BuildingShopFilled, BuildingShop], + path: "/shop", +}; + export const SideNavItemComponent = ({ item }: { item: NavigationItem }) => { const { t } = useTranslation("application"); const navigate = useNavigate(); @@ -274,6 +282,7 @@ const PageNavigation = () => { {connectEnabled && } {remoteDownloadEnabled && } + )} diff --git a/frontend/src/component/Pages/Pages.tsx b/frontend/src/component/Pages/Pages.tsx index 4de121a5..46b8e179 100644 --- a/frontend/src/component/Pages/Pages.tsx +++ b/frontend/src/component/Pages/Pages.tsx @@ -4,5 +4,6 @@ import DownloadList from "./Tasks/DownloadList.tsx"; import Devices from "./Devices/Devices.tsx"; import Setting from "./Setting/Setting.tsx"; import Profile from "./Profile/Profile.tsx"; +import Shop from "./Shop/Shop.tsx"; -export { Setting, TaskList, ShareList, DownloadList, Devices, Profile }; +export { Setting, TaskList, ShareList, DownloadList, Devices, Profile, Shop }; diff --git a/frontend/src/component/Pages/Setting/FinanceSetting.tsx b/frontend/src/component/Pages/Setting/FinanceSetting.tsx index ba00d607..9711c1dc 100644 --- a/frontend/src/component/Pages/Setting/FinanceSetting.tsx +++ b/frontend/src/component/Pages/Setting/FinanceSetting.tsx @@ -1,8 +1,6 @@ import { Box, - Button, Chip, - InputAdornment, Paper, Stack, Table, @@ -13,15 +11,14 @@ import { TableRow, Typography, } from "@mui/material"; -import { useSnackbar } from "notistack"; import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; -import { getCredit, getCreditTxns, redeemGiftCode } from "../../../api/api.ts"; +import { getCredit, getCreditTxns } from "../../../api/api.ts"; import { CreditInfo, CreditTxnList } from "../../../api/user.ts"; import { useAppDispatch } from "../../../redux/hooks.ts"; import { sizeToString } from "../../../util/index.ts"; import FacebookCircularProgress from "../../Common/CircularProgress.tsx"; -import { DenseFilledTextField } from "../../Common/StyledComponents.tsx"; +import RedeemCodeInput from "../../Common/Form/RedeemCodeInput.tsx"; import TablePagination from "../../Admin/Common/TablePagination.tsx"; import { NoMarginHelperText, SettingSection, SettingSectionContent } from "../../Admin/Settings/Settings.tsx"; import SettingForm from "./SettingForm.tsx"; @@ -29,13 +26,10 @@ import SettingForm from "./SettingForm.tsx"; const FinanceSetting = () => { const { t } = useTranslation(); const dispatch = useAppDispatch(); - const { enqueueSnackbar } = useSnackbar(); const [info, setInfo] = useState(undefined); const [txns, setTxns] = useState(undefined); const [page, setPage] = useState(1); const [pageSize, setPageSize] = useState(10); - const [code, setCode] = useState(""); - const [redeeming, setRedeeming] = useState(false); const loadInfo = () => { dispatch(getCredit()).then((res) => setInfo(res)); @@ -49,21 +43,6 @@ const FinanceSetting = () => { dispatch(getCreditTxns(page, pageSize)).then((res) => setTxns(res)); }, [page, pageSize]); - const onRedeem = () => { - if (!code.trim()) { - return; - } - setRedeeming(true); - dispatch(redeemGiftCode(code.trim())) - .then(() => { - enqueueSnackbar(t("setting.giftCodeRedeemed"), { variant: "success" }); - setCode(""); - loadInfo(); - dispatch(getCreditTxns(page, pageSize)).then((res) => setTxns(res)); - }) - .finally(() => setRedeeming(false)); - }; - const txnReason = (type: string) => t(`setting.txnType.${type}`, { defaultValue: type }); if (!info) { @@ -120,21 +99,10 @@ const FinanceSetting = () => { )} - setCode(e.target.value)} - placeholder={t("setting.giftCodePlaceholder")} - slotProps={{ - input: { - endAdornment: ( - - - - ), - }, + { + loadInfo(); + dispatch(getCreditTxns(page, pageSize)).then((res) => setTxns(res)); }} /> {t("setting.redeemGiftCodeDes")} diff --git a/frontend/src/component/Pages/Shop/Shop.tsx b/frontend/src/component/Pages/Shop/Shop.tsx new file mode 100644 index 00000000..3e2c4cfa --- /dev/null +++ b/frontend/src/component/Pages/Shop/Shop.tsx @@ -0,0 +1,152 @@ +import { Button, Chip, Container, Grid2, Paper, Stack, Typography } from "@mui/material"; +import dayjs from "dayjs"; +import { useSnackbar } from "notistack"; +import { useEffect, useMemo, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { useSearchParams } from "react-router-dom"; +import { getCredit, getShopSkus, purchaseSku } from "../../../api/api.ts"; +import { CreditInfo, ShopSku } from "../../../api/user.ts"; +import { useAppDispatch } from "../../../redux/hooks.ts"; +import { sizeToString } from "../../../util/index.ts"; +import { formatDuration } from "../../../util/datetime.ts"; +import FacebookCircularProgress from "../../Common/CircularProgress.tsx"; +import RedeemCodeInput from "../../Common/Form/RedeemCodeInput.tsx"; +import Nothing from "../../Common/Nothing.tsx"; +import ResponsiveTabs from "../../Common/ResponsiveTabs.tsx"; +import PageContainer from "../PageContainer.tsx"; +import PageHeader, { PageTabQuery } from "../PageHeader.tsx"; + +export enum ShopPageTab { + Membership = "membership", + Storage = "storage", + Redeem = "redeem", +} + +const Shop = () => { + const { t } = useTranslation(); + const dispatch = useAppDispatch(); + const { enqueueSnackbar } = useSnackbar(); + const [searchParams] = useSearchParams(); + const [tab, setTab] = useState(searchParams.get(PageTabQuery) ?? ShopPageTab.Membership); + const [skus, setSkus] = useState(undefined); + const [info, setInfo] = useState(undefined); + const [buying, setBuying] = useState(undefined); + + const loadInfo = () => { + dispatch(getCredit()).then((res) => setInfo(res)); + }; + + useEffect(() => { + dispatch(getShopSkus()).then((res) => setSkus(res)); + loadInfo(); + }, []); + + const tabs = useMemo( + () => [ + { label: t("application:shop.memberships"), value: ShopPageTab.Membership }, + { label: t("application:shop.storagePacks"), value: ShopPageTab.Storage }, + { label: t("application:shop.redeem"), value: ShopPageTab.Redeem }, + ], + [], + ); + + const filtered = useMemo( + () => + (skus ?? []).filter((s) => + tab === ShopPageTab.Membership ? s.type === "group" : s.type === "storage", + ), + [skus, tab], + ); + + const onPurchase = (s: ShopSku) => { + setBuying(s.id); + dispatch(purchaseSku(s.id)) + .then((res) => { + setInfo(res); + enqueueSnackbar(t("shop.purchased", { name: s.name }), { variant: "success" }); + }) + .finally(() => setBuying(undefined)); + }; + + const skuSubtitle = (s: ShopSku) => { + const parts = [ + s.type === "storage" ? sizeToString(s.amount) : s.group, + s.duration > 0 ? formatDuration(dayjs.duration(s.duration, "seconds")) : t("shop.permanent"), + ]; + return parts.filter(Boolean).join(" · "); + }; + + return ( + + + : undefined + } + /> + setTab(v)} tabs={tabs} /> + {tab === ShopPageTab.Redeem && ( + + + {t("setting.redeemGiftCode")} + + + + )} + {tab !== ShopPageTab.Redeem && skus === undefined && ( + + + + )} + {tab !== ShopPageTab.Redeem && skus !== undefined && filtered.length === 0 && ( + + )} + {tab !== ShopPageTab.Redeem && skus !== undefined && filtered.length > 0 && ( + + {filtered.map((s) => ( + + + + + + {s.name} + + {s.label && } + + + {skuSubtitle(s)} + + {s.des && ( + + {s.des + .split("\n") + .filter((l) => l.trim()) + .map((l, i) => ( + + {l} + + ))} + + )} + + + + + ))} + + )} + + + ); +}; + +export default Shop; diff --git a/frontend/src/router/index.tsx b/frontend/src/router/index.tsx index a22989c4..4d4aabb0 100644 --- a/frontend/src/router/index.tsx +++ b/frontend/src/router/index.tsx @@ -272,6 +272,13 @@ export const router = createBrowserRouter([ return { Component: Devices }; }, }, + { + path: "/shop", + async lazy() { + let { Shop } = await import("../component/Pages/Pages"); + return { Component: Shop }; + }, + }, { path: "/settings", async lazy() { diff --git a/inventory/vas.go b/inventory/vas.go index b01e8095..69a9d751 100644 --- a/inventory/vas.go +++ b/inventory/vas.go @@ -3,12 +3,14 @@ package inventory import ( "context" "errors" + "strconv" "time" "github.com/cloudreve/Cloudreve/v4/ent" "github.com/cloudreve/Cloudreve/v4/ent/credittxn" "github.com/cloudreve/Cloudreve/v4/ent/giftcode" "github.com/cloudreve/Cloudreve/v4/ent/schema" + "github.com/cloudreve/Cloudreve/v4/ent/sku" "github.com/cloudreve/Cloudreve/v4/ent/user" "github.com/cloudreve/Cloudreve/v4/ent/usergrant" "github.com/cloudreve/Cloudreve/v4/pkg/conf" @@ -16,8 +18,9 @@ import ( ) var ( - ErrGiftCodeNotFound = errors.New("gift code not found") - ErrGiftCodeUsed = errors.New("gift code already used") + ErrGiftCodeNotFound = errors.New("gift code not found") + ErrGiftCodeUsed = errors.New("gift code already used") + ErrSkuNotPurchasable = errors.New("sku not purchasable with points") ) type ( @@ -49,6 +52,20 @@ type ( // upgrades whose users still sit on the granted group. Users without a // recorded previous group fall back to defaultGroupID. ExpireGrants(ctx context.Context, defaultGroupID int) error + // ListSkus returns products ordered by weight desc then id. When + // onlyEnabled is set, disabled products are excluded. + ListSkus(ctx context.Context, onlyEnabled bool) ([]*ent.Sku, error) + // GetSku returns one product by id. + GetSku(ctx context.Context, id int) (*ent.Sku, error) + // UpsertSku creates the product when its ID is zero, otherwise + // updates the mutable product fields. + UpsertSku(ctx context.Context, sku *ent.Sku) (*ent.Sku, error) + // DeleteSkus removes products by id. + DeleteSkus(ctx context.Context, ids []int) error + // PurchaseSku atomically debits the sku points price and applies its + // grant. Fails with ErrInsufficientPoints when the balance cannot + // cover the price, leaving the grant unapplied. + PurchaseSku(ctx context.Context, userID int, sku *ent.Sku) error } CreateGiftCodeParams struct { @@ -228,15 +245,18 @@ func (c *vasClient) RedeemGiftCode(ctx context.Context, userID int, code string) } func (c *vasClient) applyGroupCode(ctx context.Context, userID int, gc *ent.GiftCode) error { + return c.applyGroupGrant(ctx, userID, int(gc.Amount), gc.Duration) +} + +func (c *vasClient) applyGroupGrant(ctx context.Context, userID, targetGroup int, durationSeconds int64) error { u, err := c.client.User.Get(ctx, userID) if err != nil { return err } - targetGroup := int(gc.Amount) if _, err := c.client.Group.Get(ctx, targetGroup); err != nil { return err } - if err := c.createGrant(ctx, userID, usergrant.TypeGroup, gc.Amount, gc.Duration, u.GroupUsers); err != nil { + if err := c.createGrant(ctx, userID, usergrant.TypeGroup, int64(targetGroup), durationSeconds, u.GroupUsers); err != nil { return err } return c.client.User.Update().Where(user.ID(userID)).SetGroupUsers(targetGroup).Exec(ctx) @@ -320,6 +340,83 @@ func (c *vasClient) ExpireGrants(ctx context.Context, defaultGroupID int) error return nil } +func (c *vasClient) ListSkus(ctx context.Context, onlyEnabled bool) ([]*ent.Sku, error) { + q := c.client.Sku.Query() + if onlyEnabled { + q = q.Where(sku.Enabled(true)) + } + return q.Order(ent.Desc(sku.FieldWeight), ent.Asc(sku.FieldID)).All(ctx) +} + +func (c *vasClient) GetSku(ctx context.Context, id int) (*ent.Sku, error) { + return c.client.Sku.Get(ctx, id) +} + +func (c *vasClient) UpsertSku(ctx context.Context, s *ent.Sku) (*ent.Sku, error) { + if s.ID == 0 { + return c.client.Sku.Create(). + SetName(s.Name). + SetType(s.Type). + SetAmount(s.Amount). + SetDuration(s.Duration). + SetPrice(s.Price). + SetNillablePoints(s.Points). + SetLabel(s.Label). + SetDes(s.Des). + SetEnabled(s.Enabled). + SetWeight(s.Weight). + Save(ctx) + } + return c.client.Sku.UpdateOneID(s.ID). + SetName(s.Name). + SetType(s.Type). + SetAmount(s.Amount). + SetDuration(s.Duration). + SetPrice(s.Price). + SetNillablePoints(s.Points). + SetLabel(s.Label). + SetDes(s.Des). + SetEnabled(s.Enabled). + SetWeight(s.Weight). + Save(ctx) +} + +func (c *vasClient) DeleteSkus(ctx context.Context, ids []int) error { + _, err := c.client.Sku.Delete(). + Where(sku.IDIn(ids...)). + Exec(schema.SkipSoftDelete(ctx)) + return err +} + +func (c *vasClient) PurchaseSku(ctx context.Context, userID int, s *ent.Sku) error { + if s.Points == nil { + return ErrSkuNotPurchasable + } + + txVc, tx, ctx, err := WithTx(ctx, c) + if err != nil { + return err + } + + if err := txVc.CreditAdjust(ctx, userID, -*s.Points, credittxn.TypePurchase, + strconv.Itoa(s.ID), s.Name); err != nil { + _ = Rollback(tx) + return err + } + + switch s.Type { + case sku.TypeStorage: + err = txVc.createGrant(ctx, userID, usergrant.TypeStorage, s.Amount, s.Duration, 0) + case sku.TypeGroup: + err = txVc.applyGroupGrant(ctx, userID, int(s.Amount), s.Duration) + } + if err != nil { + return Rollback(tx) + } + + return Commit(tx) +} + func newGiftCodeString() string { return uuid.Must(uuid.NewV4()).String() } diff --git a/inventory/vas_test.go b/inventory/vas_test.go index 6da413a0..7d809b83 100644 --- a/inventory/vas_test.go +++ b/inventory/vas_test.go @@ -10,6 +10,7 @@ import ( "github.com/cloudreve/Cloudreve/v4/ent/credittxn" "github.com/cloudreve/Cloudreve/v4/ent/enttest" "github.com/cloudreve/Cloudreve/v4/ent/giftcode" + "github.com/cloudreve/Cloudreve/v4/ent/sku" "github.com/cloudreve/Cloudreve/v4/ent/usergrant" "github.com/cloudreve/Cloudreve/v4/pkg/boolset" "github.com/stretchr/testify/require" @@ -185,3 +186,56 @@ func TestDeleteGiftCodes(t *testing.T) { // Used code survives revocation; unused is gone. require.Equal(t, 1, client.GiftCode.Query().CountX(ctx)) } + +func TestPurchaseSku(t *testing.T) { + ctx := context.Background() + client, c := newVasClient(t) + group, u := vasFixture(t, client) + vip := client.Group.Create().SetName("vip").SetPermissions(&boolset.BooleanSet{}).SaveX(ctx) + require.NoError(t, c.CreditAdjust(ctx, u.ID, 500, credittxn.TypeAdjust, "", "seed")) + + points := int64(200) + storageSku, err := c.UpsertSku(ctx, &ent.Sku{ + Name: "1GB pack", Type: sku.TypeStorage, Amount: 1024, + Duration: int64(time.Hour.Seconds()), Points: &points, Enabled: true, + }) + require.NoError(t, err) + + require.NoError(t, c.PurchaseSku(ctx, u.ID, storageSku)) + u = client.User.GetX(ctx, u.ID) + require.Equal(t, int64(300), u.Credits) + + bonus, err := c.StorageBonus(ctx, u.ID) + require.NoError(t, err) + require.Equal(t, int64(1024), bonus) + + txns, _, _ := c.ListCreditTxns(ctx, u.ID, 1, 10) + require.Equal(t, credittxn.TypePurchase, txns[0].Type) + require.Equal(t, int64(-200), txns[0].Amount) + + // Group sku → user moved, prev group recorded. + groupSku, err := c.UpsertSku(ctx, &ent.Sku{ + Name: "vip month", Type: sku.TypeGroup, Amount: int64(vip.ID), + Duration: int64(time.Hour.Seconds()), Points: &points, Enabled: true, + }) + require.NoError(t, err) + require.NoError(t, c.PurchaseSku(ctx, u.ID, groupSku)) + require.Equal(t, vip.ID, client.User.GetX(ctx, u.ID).GroupUsers) + grant := client.UserGrant.Query().Where(usergrant.TypeEQ(usergrant.TypeGroup)).OnlyX(ctx) + require.Equal(t, group.ID, grant.PrevGroupID) + + // No points price → not purchasable. + cashOnly, err := c.UpsertSku(ctx, &ent.Sku{ + Name: "cash only", Type: sku.TypeStorage, Amount: 1, Price: 700, Enabled: true, + }) + require.NoError(t, err) + require.ErrorIs(t, c.PurchaseSku(ctx, u.ID, cashOnly), ErrSkuNotPurchasable) + + // Insufficient balance → no grant applied. + balance := client.User.GetX(ctx, u.ID).Credits + require.NoError(t, c.CreditAdjust(ctx, u.ID, -balance, credittxn.TypeAdjust, "", "drain")) + require.ErrorIs(t, c.PurchaseSku(ctx, u.ID, storageSku), ErrInsufficientPoints) + bonus, err = c.StorageBonus(ctx, u.ID) + require.NoError(t, err) + require.Equal(t, int64(1024), bonus) +} diff --git a/pkg/hashid/hash.go b/pkg/hashid/hash.go index 65e910ee..5daddfe5 100644 --- a/pkg/hashid/hash.go +++ b/pkg/hashid/hash.go @@ -23,6 +23,7 @@ const ( DavAccountID PaymentID InvitationCodeID + SkuID ) var ( @@ -146,6 +147,11 @@ func EncodeInvitationCodeID(encoder Encoder, id int) string { return encodeID(encoder, id, InvitationCodeID) } +// EncodeSkuID encode sku id to hash id +func EncodeSkuID(encoder Encoder, id int) string { + return encodeID(encoder, id, SkuID) +} + func FromContext(c context.Context) int { return c.Value(ObjectIDCtx{}).(int) } diff --git a/routers/controllers/admin.go b/routers/controllers/admin.go index 048a0491..c0f572b4 100644 --- a/routers/controllers/admin.go +++ b/routers/controllers/admin.go @@ -333,6 +333,42 @@ func AdminAdjustCredit(c *gin.Context) { c.JSON(200, serializer.Response{}) } +func AdminListSkus(c *gin.Context) { + service := ParametersFromContext[*admin.SkuListService](c, admin.SkuListParamCtx{}) + res, err := service.List(c) + if respondErr(c, err) { + return + } + c.JSON(200, serializer.Response{Data: res}) +} + +func AdminCreateSku(c *gin.Context) { + service := ParametersFromContext[*admin.SkuUpsertService](c, admin.SkuUpsertParamCtx{}) + res, err := service.Create(c) + if respondErr(c, err) { + return + } + c.JSON(200, serializer.Response{Data: res}) +} + +func AdminUpdateSku(c *gin.Context) { + service := ParametersFromContext[*admin.SkuUpsertService](c, admin.SkuUpsertParamCtx{}) + res, err := service.Update(c) + if respondErr(c, err) { + return + } + c.JSON(200, serializer.Response{Data: res}) +} + +func AdminDeleteSku(c *gin.Context) { + service := ParametersFromContext[*admin.SingleSkuService](c, admin.SingleSkuParamCtx{}) + err := service.Delete(c) + if respondErr(c, err) { + return + } + c.JSON(200, serializer.Response{}) +} + func AdminListEvents(c *gin.Context) { service := ParametersFromContext[*admin.EventListService](c, admin.EventListParamCtx{}) res, err := service.Get(c) diff --git a/routers/controllers/user.go b/routers/controllers/user.go index e36de3fe..ebc79d13 100644 --- a/routers/controllers/user.go +++ b/routers/controllers/user.go @@ -291,6 +291,26 @@ func UserRedeemGiftCode(c *gin.Context) { c.JSON(200, serializer.Response{Data: res}) } +// UserListSkus lists enabled products for the shop page. +func UserListSkus(c *gin.Context) { + service := ParametersFromContext[*user.SkuListService](c, user.SkuListParamCtx{}) + res, err := service.List(c) + if respondErr(c, err) { + return + } + c.JSON(200, serializer.Response{Data: res}) +} + +// UserPurchaseSku buys a product with credit points. +func UserPurchaseSku(c *gin.Context) { + service := ParametersFromContext[*user.PurchaseSkuService](c, user.PurchaseSkuParamCtx{}) + res, err := service.Create(c) + if respondErr(c, err) { + return + } + c.JSON(200, serializer.Response{Data: res}) +} + // UserInit2FA 初始化二步验证 func UserInit2FA(c *gin.Context) { secret, err := user.Init2FA(c) diff --git a/routers/router.go b/routers/router.go index 047149af..b237815e 100644 --- a/routers/router.go +++ b/routers/router.go @@ -1322,6 +1322,29 @@ func initMasterRouter(dep dependency.Dep) *gin.Engine { controllers.FromJSON[adminsvc.AdjustCreditService](adminsvc.AdjustCreditParamCtx{}), controllers.AdminAdjustCredit, ) + // 列出商品 + vas.GET("sku", + controllers.FromQuery[adminsvc.SkuListService](adminsvc.SkuListParamCtx{}), + controllers.AdminListSkus, + ) + // 创建商品 + vas.PUT("sku", + middleware.RequiredScopes(types.ScopeAdminWrite), + controllers.FromJSON[adminsvc.SkuUpsertService](adminsvc.SkuUpsertParamCtx{}), + controllers.AdminCreateSku, + ) + // 更新商品 + vas.PUT("sku/:id", + middleware.RequiredScopes(types.ScopeAdminWrite), + controllers.FromJSON[adminsvc.SkuUpsertService](adminsvc.SkuUpsertParamCtx{}), + controllers.AdminUpdateSku, + ) + // 删除商品 + vas.DELETE("sku/:id", + middleware.RequiredScopes(types.ScopeAdminWrite), + controllers.FromUri[adminsvc.SingleSkuService](adminsvc.SingleSkuParamCtx{}), + controllers.AdminDeleteSku, + ) } event := admin.Group("event", middleware.AdminSection(types.GroupPermissionAdminEvents)) @@ -1516,6 +1539,23 @@ func initMasterRouter(dep dependency.Dep) *gin.Engine { controllers.UserRedeemGiftCode, ) } + + // 积分商城 + shop := user.Group("shop") + { + // 列出商品 + shop.GET("skus", + middleware.RequiredScopes(types.ScopeUserInfoRead), + controllers.FromQuery[usersvc.SkuListService](usersvc.SkuListParamCtx{}), + controllers.UserListSkus, + ) + // 积分购买商品 + shop.POST("purchase", + middleware.RequiredScopes(types.ScopeUserInfoWrite), + controllers.FromJSON[usersvc.PurchaseSkuService](usersvc.PurchaseSkuParamCtx{}), + controllers.UserPurchaseSku, + ) + } } // WebDAV and devices diff --git a/service/admin/vas.go b/service/admin/vas.go index 8deac5f0..259b90d9 100644 --- a/service/admin/vas.go +++ b/service/admin/vas.go @@ -8,6 +8,7 @@ import ( "github.com/cloudreve/Cloudreve/v4/ent" "github.com/cloudreve/Cloudreve/v4/ent/credittxn" "github.com/cloudreve/Cloudreve/v4/ent/giftcode" + "github.com/cloudreve/Cloudreve/v4/ent/sku" "github.com/cloudreve/Cloudreve/v4/inventory" "github.com/cloudreve/Cloudreve/v4/inventory/types" "github.com/cloudreve/Cloudreve/v4/pkg/activity" @@ -16,6 +17,22 @@ import ( ) type ( + // SkuListService lists all products for admins. + SkuListService struct{} + SkuListParamCtx struct{} + + // SkuUpsertService creates or updates one product. ID zero creates. + SkuUpsertService struct { + Sku *ent.Sku `json:"sku" binding:"required"` + } + SkuUpsertParamCtx struct{} + + // SingleSkuService targets one product by ID. + SingleSkuService struct { + ID int `uri:"id" json:"id" binding:"required"` + } + SingleSkuParamCtx struct{} + // GiftCodeListService lists gift codes for admins. GiftCodeListService struct { Page int `form:"page" json:"page" binding:"required,min=1"` @@ -94,6 +111,51 @@ func (service *SingleGiftCodeService) Delete(c *gin.Context) error { return nil } +func (service *SkuListService) List(c *gin.Context) ([]*ent.Sku, error) { + skus, err := dependency.FromContext(c).VasClient().ListSkus(c, false) + if err != nil { + return nil, serializer.NewError(serializer.CodeDBError, "Failed to list products", err) + } + return skus, nil +} + +func (service *SkuUpsertService) Update(c *gin.Context) (*ent.Sku, error) { + return upsertSku(c, service.Sku) +} + +func (service *SkuUpsertService) Create(c *gin.Context) (*ent.Sku, error) { + return upsertSku(c, service.Sku) +} + +func upsertSku(c *gin.Context, s *ent.Sku) (*ent.Sku, error) { + dep := dependency.FromContext(c) + + if s.Name == "" || s.Amount <= 0 || s.Duration < 0 || s.Price < 0 || s.Weight < 0 { + return nil, serializer.NewError(serializer.CodeParamErr, "Invalid product fields", nil) + } + if s.Points != nil && *s.Points <= 0 { + return nil, serializer.NewError(serializer.CodeParamErr, "Invalid points price", nil) + } + if s.Type == sku.TypeGroup { + if _, err := dep.GroupClient().GetByID(c, int(s.Amount)); err != nil { + return nil, serializer.NewError(serializer.CodeParamErr, "Invalid target group", err) + } + } + + res, err := dep.VasClient().UpsertSku(c, s) + if err != nil { + return nil, serializer.NewError(serializer.CodeDBError, "Failed to save product", err) + } + return res, nil +} + +func (service *SingleSkuService) Delete(c *gin.Context) error { + if err := dependency.FromContext(c).VasClient().DeleteSkus(c, []int{service.ID}); err != nil { + return serializer.NewError(serializer.CodeDBError, "Failed to delete product", err) + } + return nil +} + func (service *AdjustCreditService) Create(c *gin.Context) error { dep := dependency.FromContext(c) diff --git a/service/user/vas.go b/service/user/vas.go index 5d0fa11b..0f1e1935 100644 --- a/service/user/vas.go +++ b/service/user/vas.go @@ -6,9 +6,11 @@ import ( "github.com/cloudreve/Cloudreve/v4/application/dependency" "github.com/cloudreve/Cloudreve/v4/ent" "github.com/cloudreve/Cloudreve/v4/ent/credittxn" + "github.com/cloudreve/Cloudreve/v4/ent/sku" "github.com/cloudreve/Cloudreve/v4/inventory" "github.com/cloudreve/Cloudreve/v4/inventory/types" "github.com/cloudreve/Cloudreve/v4/pkg/activity" + "github.com/cloudreve/Cloudreve/v4/pkg/hashid" "github.com/cloudreve/Cloudreve/v4/pkg/serializer" "github.com/gin-gonic/gin" ) @@ -31,6 +33,32 @@ type ( } RedeemGiftCodeParamCtx struct{} + // SkuListService lists enabled products for the shop page. + SkuListService struct{} + SkuListParamCtx struct{} + + // PurchaseSkuService buys a product with credit points. + PurchaseSkuService struct { + Sku string `json:"sku" form:"sku" binding:"required,max=64"` + } + PurchaseSkuParamCtx struct{} + + // SkuResponse is the public product view; amount carries the target + // group hashid for membership products, bytes for storage packs. + SkuResponse struct { + ID string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` + Amount int64 `json:"amount"` + Group string `json:"group,omitempty"` + GroupID string `json:"group_id,omitempty"` + Duration int64 `json:"duration"` + Price int64 `json:"price"` + Points *int64 `json:"points,omitempty"` + Label string `json:"label,omitempty"` + Des string `json:"des,omitempty"` + } + CreditResponse struct { Credits int64 `json:"credits"` StorageBonus int64 `json:"storage_bonus"` @@ -97,6 +125,68 @@ func (service *RedeemGiftCodeService) Create(c *gin.Context) (*ent.GiftCode, err return gc, nil } +func (service *SkuListService) List(c *gin.Context) ([]*SkuResponse, error) { + dep := dependency.FromContext(c) + + skus, err := dep.VasClient().ListSkus(c, true) + if err != nil { + return nil, serializer.NewError(serializer.CodeDBError, "Failed to list products", err) + } + + res := make([]*SkuResponse, 0, len(skus)) + for _, s := range skus { + r := &SkuResponse{ + ID: hashid.EncodeSkuID(dep.HashIDEncoder(), s.ID), + Name: s.Name, + Type: string(s.Type), + Amount: s.Amount, + Duration: s.Duration, + Price: s.Price, + Points: s.Points, + Label: s.Label, + Des: s.Des, + } + if s.Type == sku.TypeGroup { + if g, err := dep.GroupClient().GetByID(c, int(s.Amount)); err == nil { + r.Group = g.Name + r.GroupID = hashid.EncodeGroupID(dep.HashIDEncoder(), g.ID) + } + } + res = append(res, r) + } + return res, nil +} + +func (service *PurchaseSkuService) Create(c *gin.Context) (*CreditResponse, error) { + dep := dependency.FromContext(c) + u := inventory.UserFromContext(c) + + skuID, err := dep.HashIDEncoder().Decode(service.Sku, hashid.SkuID) + if err != nil { + return nil, serializer.NewError(serializer.CodeParamErr, "Invalid product", err) + } + s, err := dep.VasClient().GetSku(c, skuID) + if err != nil || !s.Enabled { + return nil, serializer.NewError(serializer.CodeNotFound, "Product not found", err) + } + + if err := dep.VasClient().PurchaseSku(c, u.ID, s); err != nil { + switch { + case errors.Is(err, inventory.ErrSkuNotPurchasable): + return nil, serializer.NewError(serializer.CodeParamErr, "Product cannot be purchased with points", err) + case errors.Is(err, inventory.ErrInsufficientPoints): + return nil, serializer.NewError(serializer.CodeParamErr, "Insufficient credit balance", err) + default: + return nil, serializer.NewError(serializer.CodeDBError, "Failed to purchase product", err) + } + } + + activity.Record(c, dep.SettingProvider(), dep.ActivityClient(), types.EventPointsChange, + activity.Extra(map[string]any{"sku": s.ID, "name": s.Name, "delta": -*s.Points})) + + return (&CreditService{}).Get(c) +} + // TxnDescription maps ledger types to stable English descriptors consumed by // the Finance settings tab. func TxnDescription(t *ent.CreditTxn) string {